mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-24 18:19:05 +02:00
feat(skills): make summarize-status actions-first (#10117)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - Its built-in Summarizer keeps status slots useful for people overseeing issue trees > - Those summaries need to tell the reader what they must do now to unblock progress > - The existing skill instead imposed rigid Decide:/Review:/Recent work: sections, cost commentary, and restrictive issue-fetch guidance > - This pull request rewrites the summarize-status instructions to lead with 1–3 specific, concrete unblock actions while letting the model use its judgment for the remaining context > - The benefit is a shorter, clearer summary that is immediately actionable without changing slot writes or the streaming status protocol ## Linked Issues or Issue Description Refs #9713 The built-in summarizer currently prioritizes a fixed reporting template over the reader's immediate unblock actions. Summaries should instead open with the 1–3 specific actions the reader needs to take right now, then provide only the context needed to act. This prompt-only update preserves all summary-slot mechanics and protocols. ## What Changed - Rewrote the bundled `summarize-status` skill to open with 1–3 specific, concrete, actionable items needed right now to unblock the work. - Removed the rigid Decide:/Review:/Recent work: template, the Cost discipline section, and the restrictions against fetching issue detail. - Kept slot-write mechanics and the streaming `STATUS`/sentinel protocol unchanged. - Updated all materialized copies and tests for the same skill text: the `SKILL.md` source, regenerated catalog manifest hashes, compiled fallback string, summarizer built-in `AGENTS.md` and routine, summary generation-issue instructions, and the two tests pinning those strings. - Although the diff touches eight files, every file is either the same skill text in another materialized form or a test asserting it. No behavior outside the summarizer's prompt text changes. ## Verification - `pnpm --filter @paperclipai/skills-catalog test` — 20/20 tests pass. - `pnpm exec vitest run server/src/__tests__/summary-slots.test.ts server/src/__tests__/built-in-agents.test.ts` — 46/46 tests pass. - `git diff --check origin/master...HEAD` — clean. - `pnpm exec vitest run server/src/__tests__/summary-slots.test.ts` — 16/16 tests pass after the Greptile consistency fix. - Latest-head GitHub checks — 25 terminal checks, all successful, neutral, or skipped. ## Risks - Low risk: this intentionally changes generated summary wording and prioritization, but does not change APIs, persistence, slot-write behavior, or the streaming protocol. - The branch name contains an internal task identifier because it was pre-created and pre-pushed for this assigned change; the PR title and body do not expose the internal ticket. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex using `gpt-5.6-sol`, high reasoning mode, with repository, terminal, GitHub CLI, and code-execution tools. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [ ] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
8 files changed
+47
-160
No files matched your search
@@ -232,26 +232,24 @@ describeEmbeddedPostgres("summary slot service", () => {
|
||||
expect(issueRow.description).toContain(
|
||||
`GET /api/companies/${companyId}/summary-slots/project/header?scopeId=${projectId}`,
|
||||
);
|
||||
expect(issueRow.description).toContain(
|
||||
expect(issueRow.description).not.toContain(
|
||||
"do not call the revisions or issues-list endpoints",
|
||||
);
|
||||
expect(issueRow.description).toContain(
|
||||
`PUT /api/companies/${companyId}/summary-slots/project/header`,
|
||||
);
|
||||
expect(issueRow.description).toContain(
|
||||
"one or two plain-prose paragraphs on the (max two) things that matter most",
|
||||
"opens with the 1–3 specific, concrete, actionable items",
|
||||
);
|
||||
expect(issueRow.description).toContain("opens with a `**Decide:**` block");
|
||||
expect(issueRow.description).toContain("`**I suggest:**` recommendation");
|
||||
expect(issueRow.description).toContain("followed by a `**Review:**` block");
|
||||
expect(issueRow.description).toContain("unblock this work");
|
||||
expect(issueRow.description).toContain(
|
||||
"what the reader can approve on a skim vs what needs their eyes",
|
||||
"read whatever issues you need to understand the state",
|
||||
);
|
||||
expect(issueRow.description).toContain(
|
||||
"End the summary with a `**Recent work:**` block",
|
||||
"a reader who has not memorized issue ids or threads",
|
||||
);
|
||||
expect(issueRow.description).toContain(
|
||||
"at most three or four issues inline; never a trailing list of issue links",
|
||||
"a trailing list of issue links or any link dump",
|
||||
);
|
||||
expect(issueRow.description).toContain("Not a task list");
|
||||
expect(issueRow.description).toContain(
|
||||
|
||||
@@ -8,10 +8,10 @@ Your job is to turn the current state of a Paperclip scope — a project, the wo
|
||||
|
||||
- Read the scope named by the generation issue (`scopeKind` = `project` | `workspaces_overview` | `project_workspace`, plus `scopeId` and `slotKey`).
|
||||
- Read the summary slot's most recent revision first, so you lead with what's new instead of repeating a headline the reader already saw.
|
||||
- Triage, don't enumerate: pick the one or two decisions (max) that most need the reader — a decision waiting on a human first, then risk, then progress — and leave everything else off the page.
|
||||
- Open every summary with a `**Decide:**` block: at most two bullets, each giving the decision's context, a link, and a committed `**I suggest:**` recommendation. When nothing needs a decision, open with one `**Nothing to decide right now.**` line followed by a `**Review:**` block (at most two bullets) triaging what is waiting on review — what the reader can approve on a skim vs what needs their eyes, each with a link and an `**I suggest:**` recommendation. Follow the opening block with at most one or two short paragraphs of plain, colloquial prose (no headings, no status lists).
|
||||
- End every summary with a `**Recent work:**` block: at most two bullets, one line each, naming a recent piece of work and where it stands in plain language ("just merged", "through QA, waiting on a reviewer") — the most recent things worth knowing about, not a changelog.
|
||||
- Never dump issue links: at most three or four issue references in the whole summary, inline where mentioned — no trailing `Issues:` line or link roundup. The summary renders next to the board, which already lists everything.
|
||||
- Triage, don't enumerate: from everything in the scope, work out the 1–3 specific, concrete actions the reader should take right now to unblock the work, and leave everything else off the page. Read whatever issues, comments, or blocker chains you need to genuinely understand where things are.
|
||||
- Open every summary with those 1–3 actionable items — each saying what to do and why it's the thing holding up progress, with an inline link. If genuinely nothing needs the reader, say so plainly in one line and name the next thing worth watching.
|
||||
- Follow the actions with a paragraph or two of plain, colloquial prose on where things stand (no headings, no status lists), written for a reader who has not memorized issue ids or threads — give enough context inline that each point makes sense without clicking.
|
||||
- Never dump issue links: link the few issues you mention inline where they're mentioned — no trailing `Issues:` line or link roundup. The summary renders next to the board, which already lists everything.
|
||||
- Write one Markdown revision back to the slot with a one-line `changeSummary`, the `baseRevisionId` you read, the `generationIssueId`, and the `model` you ran on.
|
||||
- Follow the skill's streaming protocol: post the first `STATUS:` line immediately — named from the first task you see in context, before any reads or analysis — keep emitting `STATUS:` lines as your thinking moves so the reader gets live feedback, then emit the complete final Markdown between `<<<SUMMARY-DRAFT>>>` and `<<<END-SUMMARY-DRAFT>>>` before writing that exact Markdown to the slot.
|
||||
- Close the generation issue with a short comment: scope summarized, revision number, and the headline in one clause.
|
||||
@@ -24,11 +24,10 @@ Your job is to turn the current state of a Paperclip scope — a project, the wo
|
||||
- Keep every read company-scoped. Do not cross company boundaries.
|
||||
- Never surface secrets (API keys, tokens, credentials) that appear in issue bodies or configs.
|
||||
|
||||
## Cost discipline
|
||||
## Model lane
|
||||
|
||||
You run on the low-cost model profile lane (`cheap`) by default and spend no tokens in the background. Only generate when a summary-generation issue is assigned or a manual refresh is triggered.
|
||||
|
||||
- Pull only the data you need to pick the headline and the next action; prefer list endpoints over per-issue detail fetches.
|
||||
- Keep summaries short — a header summary that scrolls or reads like a task list has failed its job.
|
||||
- An operator may override the cheap default with a specific model in this agent's `cheap` model profile configuration. Respect whatever model the run actually provides.
|
||||
|
||||
|
||||
@@ -51,14 +51,14 @@ This routine is **paused by default** and spends no tokens until an operator ena
|
||||
## What this run must do
|
||||
|
||||
1. Select summary slots whose scope has changed since their last revision and whose `lastGeneratedAt` is older than `{{staleAfterHours}}` hours. Restrict to `{{scopeKinds}}` when a specific kind is chosen. Cap the set at `{{maxSlots}}`, most-stale first.
|
||||
2. For each selected slot, run the `summarize-status` skill as the operating procedure: read the current revision, gather minimal company-scoped state, and write one new Markdown revision back to the slot.
|
||||
2. For each selected slot, run the `summarize-status` skill as the operating procedure: read the current revision, read the company-scoped state you need to understand where things are, and write one new Markdown revision back to the slot.
|
||||
3. Skip slots with no meaningful change since their last revision — do not spend tokens rewriting an unchanged summary.
|
||||
|
||||
## Hard limits for this routine
|
||||
|
||||
- Read-and-report only. This routine must never change issues, workspaces, code, or agent configuration — its only write is the summary revision.
|
||||
- Keep every read company-scoped. Do not cross company boundaries.
|
||||
- Run on the low-cost model profile lane (`cheap`). Keep each summary short and pull only the data the summary needs.
|
||||
- Run on the low-cost model profile lane (`cheap`). Keep each summary short.
|
||||
- Never fabricate status and never surface secrets from issue bodies or configs.
|
||||
|
||||
## Output
|
||||
|
||||
@@ -196,13 +196,13 @@ const FALLBACK_SUMMARIZER_ROUTINE = [
|
||||
const FALLBACK_SUMMARIZER_SKILL = [
|
||||
"---",
|
||||
"name: summarize-status",
|
||||
"description: Write a short, colloquial summary for a Paperclip summary slot: open with the one or two decisions the reader must make — or, when nothing needs deciding, what to review — each with a recommendation, close with one or two recent pieces of work and where they stand, streaming status as it works.",
|
||||
"description: Write a short, colloquial summary for a Paperclip summary slot: open with the 1–3 specific, concrete actions the reader needs to take right now to unblock the work, then a brief plain-language status, streaming progress as it works.",
|
||||
"key: paperclipai/bundled/paperclip-operations/summarize-status",
|
||||
"---",
|
||||
"",
|
||||
"# Summarize status",
|
||||
"",
|
||||
"Turn a Paperclip scope's current state into a short, colloquial Markdown summary — opening with a `**Decide:**` block of at most two bullets (each with the decision's context, a link, and an `**I suggest:**` recommendation), followed by plain prose on the one or two things that matter most, with at most three or four inline issue links and never a trailing link list — then write it back to the scope's summary slot. When nothing needs a decision, open with `**Nothing to decide right now.**` plus a `**Review:**` block (at most two bullets) triaging what is waiting on review — easy approves vs what needs the reader's eyes — each with a link and an `**I suggest:**` recommendation. End every summary with a `**Recent work:**` block: at most two bullets, one line each, naming a recent piece of work and where it stands. Post the first `STATUS:` line immediately from the first task in context and keep streaming `STATUS:` lines while working. Not a task list. Read-and-report only; never fabricate status.",
|
||||
"Turn a Paperclip scope's current state into a short, colloquial Markdown summary and write it back to the scope's summary slot. Open with the 1–3 specific, concrete, actionable items the reader should do right now to unblock the work — each saying what to do and why it's the thing holding up progress, with an inline link — then a brief plain-prose status of where things stand, written for a reader who has not memorized issue ids or threads. Read whatever issues you need to understand the state, then focus on what's most important; never a task list or a dump of issue links. If genuinely nothing needs the reader, say so plainly in one line and name the next thing worth watching. Post the first `STATUS:` line immediately from the first task in context, keep streaming `STATUS:` lines while working, and emit the final Markdown between the summary-draft sentinels before the slot write. Read-and-report only; never fabricate status.",
|
||||
"",
|
||||
].join("\n");
|
||||
|
||||
|
||||
@@ -419,8 +419,8 @@ export function summarySlotService(db: Db) {
|
||||
),
|
||||
"```",
|
||||
"",
|
||||
"Write one short, colloquial Markdown summary that opens with a `**Decide:**` block: at most two bullets, each giving the decision's context, a link, and an `**I suggest:**` recommendation, then one or two plain-prose paragraphs on the (max two) things that matter most. If nothing needs a decision, open with one `**Nothing to decide right now.**` line followed by a `**Review:**` block (at most two bullets) that triages what is waiting on review — what the reader can approve on a skim vs what needs their eyes — each with a link and an `**I suggest:**` recommendation; if nothing is in review either, one clause naming the next event worth watching. End the summary with a `**Recent work:**` block: at most two bullets, one line each, naming a recent piece of work and where it stands in plain language. Reference at most three or four issues inline; never a trailing list of issue links or any link dump. Not a task list.",
|
||||
"The current-slot response includes the latest document body and `latestRevisionId`; do not call the revisions or issues-list endpoints.",
|
||||
"Write one short, colloquial Markdown summary that opens with the 1–3 specific, concrete, actionable items the reader should do right now to unblock this work — each saying what to do and why it's the thing holding up progress, with an inline link — followed by a brief plain-prose status of where things stand. Use your judgment: read whatever issues you need to understand the state, then focus on what's most important. Write for a reader who has not memorized issue ids or threads. If genuinely nothing needs the reader, say so plainly in one line and name the next thing worth watching. Never a trailing list of issue links or any link dump. Not a task list.",
|
||||
"The current-slot response includes the latest document body and `latestRevisionId`; use those directly.",
|
||||
"Follow the skill's streaming protocol: emit the first plain-text `STATUS:` line immediately — named from the first task in the snapshot, before any analysis — keep emitting `STATUS:` lines as you think, and emit the sentinel-wrapped summary draft before the authoritative summary-slot write.",
|
||||
"Pass the `generationIssueId` from the payload, the previous revision id when present, and the model actually used to the summary-slot write API.",
|
||||
"",
|
||||
|
||||
Reference in new issue
Block a user