Split artifacts into their own gallery

High completed
2026-07-08 agentics feature High effort

Give artifacts a first-class, separately-browsable home: move the save-artifact save target to a clean local inbox at .claude/artifacts/ , add a generator that publishes those files into docs/artifacts/ and builds a standalone Artifacts gallery — reusing the exact same template, chips, and theme — then surface it as its own card on the docs hub.

Implement Read and implement all steps in the plan at docs/plans/split-artifacts-into-own-gallery.md — Split artifacts into their own gallery. Verify against the plan's Tests, Verification, and Acceptance Criteria before reporting done. If everything passed, mark completion in docs/plans/split-artifacts-into-own-gallery.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
Pursue as goal — optimize for the outcome, in parallel
Achieve this goal: Split artifacts into their own gallery. The plan at docs/plans/split-artifacts-into-own-gallery.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/split-artifacts-into-own-gallery.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 as workflow — launch parallel subagents
Run a workflow to implement the plan at docs/plans/split-artifacts-into-own-gallery.md — Split artifacts into their own gallery. Brief subagents with the plan file at docs/plans/split-artifacts-into-own-gallery.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/split-artifacts-into-own-gallery.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.
File split-artifacts-into-own-gallery.html
Path docs/plans/split-artifacts-into-own-gallery.html
Spec docs/plans/split-artifacts-into-own-gallery.md
Definition of done 7 / 7 done

Context

The story behind this plan — what prompted the work and why it matters now.

The deployed docs site ( docs/ on GitHub Pages) has a hub at docs/index.html linking to a Plans gallery, a Social Media library, and a Prototypes gallery. HTML artifacts — saved by the social-media-tools:save-artifact skill — currently land in docs/plans/artifacts/ , where the plans-gallery generator ( build-index.sh , which os.walk s the whole plans tree) sweeps them into the Plans gallery as cards. That conflates two different kinds of content and clutters the plans list.

The fix separates authoring from publishing. Artifacts move to a clean, gitignored local inbox at .claude/artifacts/ — outside the deployed tree. A new generator then publishes them: it copies each artifact into docs/artifacts/ (committed, deployed) and builds docs/artifacts/index.html , a standalone gallery reusing the plans-gallery template. The hub links to it. Because artifacts no longer live under docs/plans/ , the plans generator needs no change — the two content types now occupy physically separate trees, so nothing conflates them.

Files that change

Every file this plan touches, and what happens to each one.

agentics/
  • kit/plugins/plan-agent/hooks/build-artifacts-index.sh new publish .claude/artifacts → docs/artifacts + gallery
  • kit/plugins/plan-agent/templates/plans-gallery.html modified add GALLERY_TITLE + ITEM_NOUN placeholders
  • kit/plugins/plan-agent/hooks/build-index.sh modified remove artifact handling; substitute GALLERY_TITLE=Plans; prefer project template; prune artifacts/
  • kit/plugins/plan-agent/skills/plans-library/SKILL.md modified drop artifact scanning; document GALLERY_TITLE substitution
  • kit/plugins/plan-agent/CHANGELOG.md modified add 2.15.0 entry
  • kit/plugins/social-media-tools/skills/save-artifact/SKILL.md modified save to .claude/artifacts; publish via build-artifacts-index.sh
  • kit/plugins/social-media-tools/CHANGELOG.md modified add 2.17.0 entry
  • .claude-plugin/marketplace.json modified bump plan-agent 2.15.0, social-media-tools 2.17.0
  • .gitignore modified ignore .claude/artifacts/ (local inbox)
  • tests/pages/test-artifacts-gallery.sh new objective smoke test for the split
  • docs/index.html modified add Artifacts hub card
  • docs/plans/artifacts/ deleted 2 existing artifacts migrated to .claude/artifacts/
  • docs/artifacts/index.html generated new standalone artifacts gallery (published)

Steps

The step-by-step work, in order — each step says what to do, why it matters, and how to check it worked.

1
done Parametrize kit/plugins/plan-agent/templates/plans-gallery.html with {{GALLERY_TITLE}} and {{ITEM_NOUN}} .
Why
One template must render both the Plans and Artifacts galleries so the artifacts page inherits the exact markup, filter chips, and theme — no second design system. Replace the hard-coded "Plans" heading/title text with {{GALLERY_TITLE}} and the lowercase plural noun ("plans" in the subtitle, no-results text, footer count, and the JS count string) with {{ITEM_NOUN}} ; leave {{PLAN_COUNT}} and {{GENERATED_AT}} intact. Both generators supply the value: build-index.sh substitutes Plans (and is stripped of its artifact-rendering special-case, so the Plans gallery is plans-only) and the new artifacts generator substitutes Artifacts ; the plans-library SKILL.md scan/substitution docs are aligned to match. (The template already uses "items" for counts, so no separate noun placeholder is needed.)
Verify
grep -c '{{GALLERY_TITLE}}\|{{ITEM_NOUN}}' kit/plugins/plan-agent/templates/plans-gallery.html returns the expected count, and no user-facing "Plans"/"plans" wording remains hard-coded in the template.
2
done Create the publisher kit/plugins/plan-agent/hooks/build-artifacts-index.sh .
Why
This is the new "publish" step. It resolves the local inbox .claude/artifacts/ , copies every *.html (except index.html ) into docs/artifacts/ , then builds docs/artifacts/index.html from plans-gallery.html with {{GALLERY_TITLE}}=Artifacts and {{ITEM_NOUN}}=artifacts . Mirror build-index.sh 's structure (meta parsing, HTML escaping, newest-first sort, always exit 0). Guard the empty case: when the inbox has no artifacts, do not write an empty gallery.
Verify
With one .claude/artifacts/demo.html present, bash kit/plugins/plan-agent/hooks/build-artifacts-index.sh "$PWD" exits 0, docs/artifacts/demo.html exists, and docs/artifacts/index.html contains a card for demo.html with the heading "Artifacts".
3
done Repoint save-artifact SKILL.md to .claude/artifacts/ and rebuild the artifacts gallery.
Why
The save target moves from {plansDirectory}/artifacts to the fixed local inbox .claude/artifacts/ . Update the frontmatter description, Overview, Step 2 destination (drop the plansDirectory resolution; DEST=.claude/artifacts ), and Step 4 so it runs build-artifacts-index.sh instead of the plans build-index.sh ; fix Step 5 report wording.
Verify
grep -n '\.claude/artifacts\|build-artifacts-index' kit/plugins/social-media-tools/skills/save-artifact/SKILL.md shows the new destination and rebuild call, and no remaining reference to {plansDirectory}/artifacts or docs/plans/artifacts .
4
done Add .claude/artifacts/ to .gitignore .
Why
.claude/artifacts/ is a local authoring inbox — the deployed, committed copy lives in docs/artifacts/ . Ignoring the inbox avoids double-committing the same HTML while keeping the published gallery in git.
Verify
git check-ignore .claude/artifacts/x.html reports the path is ignored, while git status docs/artifacts/ shows the published files as tracked/untracked (not ignored).
5
done Add an "Artifacts" card to the hub, docs/index.html .
Why
Makes artifacts a first-class, discoverable category. Copy the existing .gallery-card markup used for Plans/Social Media/Prototypes, point href at artifacts/index.html , and give it a title and one-line description.
Verify
grep 'artifacts/index.html' docs/index.html matches, and the new card renders alongside the others in the browser preview.
6
done Bump plan-agent to 2.15.0 and social-media-tools to 2.17.0 with CHANGELOG entries.
Why
Both are shipped-plugin changes; the value set in marketplace.json is what ships (no CI bump). plan-agent gains the artifacts publisher + template param and drops artifact rendering from the plans gallery; social-media-tools changes the save destination and publish target — a minor bump each (from the current 2.14.2 / 2.16.0). Add matching sections to both plugins' CHANGELOG.md .
Verify
python3 -c "import json;d=json.load(open('.claude-plugin/marketplace.json'));print({p['name']:p['version'] for p in d['plugins'] if p['name'] in ('plan-agent','social-media-tools')})" shows plan-agent 2.15.0 and social-media-tools 2.17.0 , and both CHANGELOG heads show the new entry.
7
done Migrate the existing artifacts, then publish and verify end-to-end.
Why
Two artifacts already live in docs/plans/artifacts/ from the old flow. Copy them into the new inbox ( .claude/artifacts/ ), git rm the originals, and remove the empty docs/plans/artifacts/ . Then run both generators ( build-index.sh and build-artifacts-index.sh ) and inspect the hub, the artifacts gallery, and the plans gallery in the browser.
Verify
Artifacts gallery lists exactly the 2 migrated artifacts under an "Artifacts Library" heading; the hub's Artifacts card link resolves; docs/plans/index.html has zero href="artifacts/" cards; the smoke test passes.

Tests

The tests that prove the change does what it promises.

Tier 1 — Code-touching plan
Objective Artifacts render in their own gallery, never in the Plans gallery File: tests/pages/test-artifacts-gallery.sh Type: smoke test Asserts: in a temp project seeded with a .claude/artifacts/<name>.html inbox file, running build-artifacts-index.sh copies it into docs/artifacts/ and writes docs/artifacts/index.html containing exactly that artifact card with the heading "Artifacts" — while docs/plans/index.html stays free of artifact cards. The plan's objective, verified end-to-end through the real generator. Run: bash tests/pages/test-artifacts-gallery.sh
Integration Publisher copies inbox → docs and builds the gallery File: tests/pages/test-artifacts-gallery.sh Targets: build-artifacts-index.sh copy step + template substitution ( {{GALLERY_TITLE}}=Artifacts , {{ITEM_NOUN}}=artifacts ). Key cases: inbox .html copied into docs/artifacts/ ; gallery heading reads "Artifacts"; empty inbox → no docs/artifacts/index.html written (empty-gallery guard); script exits 0 when plan-agent template is missing.
Unit Hub exposes the Artifacts card File: tests/pages/test-hub-links.sh Targets: docs/index.html gallery-card links. Key cases: a .gallery-card with href="artifacts/index.html" is present alongside the Plans, Social Media, and Prototypes cards.

Definition 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.

Seed a fixture artifact in the inbox at .claude/artifacts/demo.html (a minimal self-contained HTML file with a <title> ), then run the publisher: bash kit/plugins/plan-agent/hooks/build-artifacts-index.sh "$PWD" .

Confirm, in order: (1) docs/artifacts/demo.html was copied from the inbox; (2) docs/artifacts/index.html exists and contains a card for demo.html with the heading reading "Artifacts"; (3) grep 'artifacts/index.html' docs/index.html matches the hub card; (4) docs/plans/index.html is unchanged and carries no artifact cards; (5) the objective smoke test bash tests/pages/test-artifacts-gallery.sh exits 0. Then open docs/index.html , docs/artifacts/index.html , and docs/plans/index.html in the browser and confirm the hub Artifacts card resolves and the artifacts gallery renders with the same styling as the plans gallery. Finally, remove the demo.html inbox fixture and its published copy under docs/artifacts/ so no throwaway artifact ships.

Wrapping up

Three gates that must all pass before this plan is marked completed.

Required

Completion Report

No items to report — all requirements met.

Next steps

Follow-up ideas that came up along the way — none of them are required to finish this plan.

Auto-rebuild the artifacts gallery via a PostToolUse hook

Paste this prompt into Claude to execute this follow-up:

In the agentics repo, add a PostToolUse hook to the plan-agent plugin that runs kit/plugins/plan-agent/hooks/build-artifacts-index.sh whenever an .html file is written under .claude/artifacts/, mirroring how rebuild-plans-index.py rebuilds docs/plans/index.html on plan writes. Since save-artifact uses cp (which no Write/Edit matcher catches), also confirm the skill's explicit rebuild call still runs. Include a debounce like the plans hook and make failures non-blocking (always exit 0). Bump plan-agent and add a CHANGELOG entry.
Give the Artifacts gallery a live preview thumbnail per card Wish List

Speculative / blue-sky idea — not on the critical path. Paste into Claude when ready to explore:

Paste this prompt into Claude to execute this follow-up:

Explore adding a rendered thumbnail (e.g. an inline scaled iframe or a pre-generated screenshot) to each card in the Artifacts gallery, so users can preview an artifact visually before opening it — mirroring how the Media library shows social cards. Keep it self-contained (no CDN, no external screenshot service) and degrade gracefully when no preview is available. Recommend an approach and prototype it behind a flag.