Extract the shared recap workflow from eng-recap, team-recap, and product-doc into a single references/recap-core.md, reducing each command to the framing that actually differs: audience, sections, and republish key.
Three artifact-tools recap commands say the same thing three times — eng-recap and team-recap alone share 1,568 identical words. Pulling the shared workflow into one reference file leaves each command as a short framing brief, and we will know it worked when the three commands share fewer than 50 identical lines while each still publishes to its own artifact URL key.
Read and implement all steps in the plan at docs/plans/extract-recap-command-core.md — Say the recap workflow once, not three times. Verify against the plan's Tests, Verification, and Acceptance Criteria before reporting done. If everything passed, mark completion in docs/plans/extract-recap-command-core.md — tick each step's [x] marker and each criterion's - [x], set status: completed — and re-render the HTML from the spec. If any check failed, leave status: in-progress and say which.
More ways to run this plan — goal & workflow prompts, file path
Achieve this goal: Say the recap workflow once, not three times. The plan at docs/plans/extract-recap-command-core.md describes one approach — use it as reference, but optimize for the outcome. Fan out across parallel subagents where that serves the outcome. Verify against the plan's Tests, Verification, and Acceptance Criteria before reporting done. If everything passed, mark completion in docs/plans/extract-recap-command-core.md — tick each step's [x] marker and each criterion's - [x], set status: completed — and re-render the HTML from the spec. If any check failed, leave status: in-progress and say which.
Run a workflow to implement the plan at docs/plans/extract-recap-command-core.md — Say the recap workflow once, not three times. Brief subagents with the plan file at docs/plans/extract-recap-command-core.md. Reserve a final verification phase for the lead agent, not a subagent. Verify against the plan's Tests, Verification, and Acceptance Criteria before reporting done. If everything passed, mark completion in docs/plans/extract-recap-command-core.md — tick each step's [x] marker and each criterion's - [x], set status: completed — and re-render the HTML from the spec. If any check failed, leave status: in-progress and say which.
extract-recap-command-core.html
docs/plans/extract-recap-command-core.html
docs/plans/extract-recap-command-core.md
Context
The story behind this plan — what prompted the work and why it matters now.
The Claude 5 context-engineering guidance names redundancy across context
layers as an anti-pattern: say a thing once, in the place that owns it. The
three artifact-tools recap commands violate this at scale. Measured across
the three files:
- eng-recap and team-recap share 168 identical lines / 1,568 words
- all three share 68 identical lines / 417 words
- combined they are 6,190 words
They are three framings of one workflow — gather the session or PR, scrub it,
build the page, publish, record the republish URL. Only the audience, the
section list, the plain-language rule, and the republish frontmatter key
genuinely differ.
The republish keys are the sharp edge. Four distinct keys live on the same
shared session record, and each of the three commands owns exactly one of
them: session-artifact owns artifact-url:, eng-recap writeseng-artifact-url:, team-recap writes team-artifact-url:, andproduct-doc writes product-artifact-url:. All three command files also
name artifact-url: in a prohibition — product-doc.md says "Never writeartifact-url:" precisely because that key belongs to session-artifact.
Collapsing the commands must not collapse the keys: two commands writing the
same key would silently overwrite each other's published artifact, and any
command reassigned to artifact-url: would clobber the reviewer-first session
recap. Step 3 pins each command's own key explicitly, and Step 4 verifies the
assignments rather than merely counting key names — a distinction that
matters because the prohibition text mentions keys a command must not write.
artifact-tools is the only plugin touched, so exactly onemarketplace.json version bump applies (minor — behavior preserved, structure
changed).
Files that change
Every file this plan touches, and what happens to each one.
kit/plugins/artifact-tools/references/recap-core.mdnew the shared gather/scrub/build/publish workflow- kit/plugins/artifact-tools/commands/
eng-recap.mdmodified reduce to engineer framing +eng-artifact-url:team-recap.mdmodified reduce to whole-team framing + its keyproduct-doc.mdmodified reduce to product framing +product-artifact-url:
.claude-plugin/marketplace.jsonmodified bump artifact-tools minor versionkit/plugins/artifact-tools/CHANGELOG.mdmodified record the refactortests/plugins/test-recap-command-dedupe.shnew objective test.github/workflows/check-plugin-versions.ymlmodified wire the new test
Steps
The step-by-step work, in order — each step says what to do, why it matters, and how to check it worked.
kit/plugins/artifact-tools/references/recap-core.md containing only the Step 1 "shared workflow" lines — PR and session gathering including the 20-file diff cap and --name-only fallback, the blocking security-scrub gate, page build, publish, local-HTML fallback, and the republish-record protocol parameterised by key name.
recap-core.md exists and contains no audience-specific words (engineer, stakeholder, glossary).references/recap-core.md.
references/recap-core.md.artifact-url: prohibition, checking assignments per file rather than counting key names across files.
artifact-url: would clobber the session recap.Never write .artifact-url:; note that a bare grep -o ... commands/*.md | sort -u cannot prove this, because grep prefixes each match with its filename and the prohibition text names keys the command must not write (that form returns 9 lines today, not 3).artifact-tools to the next minor version in .claude-plugin/marketplace.json and add a kit/plugins/artifact-tools/CHANGELOG.md entry describing the extraction.
kit/plugins/<name>/ requires a version bump higher than main, per repo convention.BASE_REF=main node scripts/check-plugin-versions.mjs exits 0.tests/plugins/test-recap-command-dedupe.sh asserting the three commands share fewer than 50 identical lines, each is under 500 words, references/recap-core.md exists, and — per file, not across files — that eng-recap.md writes eng-artifact-url:, team-recap.md writes team-artifact-url:, product-doc.md writes product-artifact-url:, and none of the three assigns artifact-url: to itself.
bash tests/plugins/test-recap-command-dedupe.sh exits 0; pasting 60 lines of recap-core back into two commands makes it exit 1..github/workflows/check-plugin-versions.yml.
test-recap-command-dedupe.sh and parses as valid YAML.Tests
The tests that prove the change does what it promises.
references/recap-core.md exists, and each command file writes its own key (eng-artifact-url: / team-artifact-url: / product-artifact-url:) with none assigning artifact-url: to itself; Run: bash tests/plugins/test-recap-command-dedupe.shDefinition of done
The plan counts as done when every statement below is true — check each one off as you verify it.
Final check
One last pass to confirm the whole change works end to end.
Run bash tests/plugins/test-recap-command-dedupe.sh and confirm exit 0, then
paste 60 lines of recap-core.md into two of the commands, re-run, and confirm
exit 1 before reverting — proving the check detects regression rather than
passing unconditionally.
The behavioral check is the one that matters: pick one merged PR and run all
three of /artifact-tools:eng-recap, /artifact-tools:team-recap, and/artifact-tools:product-doc against it. Confirm three separate artifacts
publish, that each carries the sections its audience expects (eng-recap has
architecture and no glossary; team-recap has a glossary and diagrams;
product-doc has features and known gaps), and that each writes its own
republish key on the shared session record without clobbering the others. Then
re-run one of the three and confirm it republishes to the same URL rather
than minting a new one.
Finally run git diff --stat and confirm no plugin outside artifact-tools
appears, other than the shared test and workflow files.
Wrapping up
Three gates that must all pass before this plan is marked completed.
Completion Report
- Integration test
- the behavioral run named in Verification (run all three commands against one merged PR and confirm three artifacts publish) was not performed — it publishes three pages to an external service, which is not something to trigger unprompted. Verified structurally instead: each command names a distinct favicon (🔧 / 🧭 / 📋), a distinct inbox stem, and a distinct republish key; the audience-appropriate sections the Verification section names all survive (eng-recap has Architecture and code paths and no Glossary; team-recap has Glossary and the diagram section; product-doc has Features and Known gaps); and the read-key-before-publishing protocol is intact in
recap-core.md. Every acceptance criterion was verified directly. This one Verification item was not. tests/plugins/test-artifact-tools.sh(modified, not in the plan's Files list)- checks 8, 8b, and 9 asserted the gh preflight, the PR gather block, and the 20-file diff cap lived inside
commands/*.md, and check 8 requiredfound >= 3. Extracting the workflow made all three fail. They now assert the same contracts againstreferences/recap-core.md— the file that owns them after this change — and additionally assert that each command loads the core, that none keeps a second gather block, and that exactly one command (eng-recap) opts in to the diff budget. Retargeted, not weakened. tests/plugins/test-remaining-skill-splits.sh(modified, not in the plan's Files list)- its orphaned-reference check globbed only
skills/*/SKILL.mdas linkers, sorecap-core.md— the first reference read by commands rather than skills — was reported as orphaned. The check now globs commands too. Confirmed the widened logic still flags a genuinely unlinked reference. product-docgained the page-build requirements and the SVG-inlining destination- it had neither before, because they lived only in the two siblings. Inheriting them from the shared workflow is the extraction working as intended, and it needed a favicon (📋) to publish under, which it also lacked.
kit/plugins/artifact-tools/README.md(modified, not in the plan's Files list)- one line added to the structure tree for
recap-core.md. The tree was already stale by the six references added in 1.9.0; that pre-existing gap was left alone as out of scope.