Ship a machine-readable markdown digest inside every HTML plan — a non-rendering <script type="text/markdown" id="plan-digest"> block as the first element child of <body> — so the implementer, the workflow author, and the 5–7 review-team agents read ~3.7k tokens of spec instead of re-reading ~21k tokens of styled HTML, with zero second source-of-truth file.
Read and implement all steps in the plan at docs/plans/embed-markdown-digest-in-html-plans.html — Embed a markdown digest in every HTML plan for cheap reads
Run as workflow — launch parallel subagents
Run a workflow to implement the plan at docs/plans/embed-markdown-digest-in-html-plans.html — Embed a markdown digest in every HTML plan for cheap downstream reads
embed-markdown-digest-in-html-plans.html
docs/plans/embed-markdown-digest-in-html-plans.html
Context
A generated HTML plan is a single self-contained file of ~86–97 KB (~21.5k tokens), but only about 17% of that is plan content — the other ~83% is the fixed skeleton CSS and JS, byte-for-byte identical in every plan. The Read tool cannot skip <style> or <script> blocks, so every consumer that opens a plan pays for the whole file.
That cost is paid repeatedly. The implementer reads it; a Run a workflow… author reads it; and a single review-plan cycle has the lead plus up to 7 reviewer agents each instructed to read the plan — roughly ~170k tokens per review, of which ~140k is the same CSS read eight times. review-plan already says "exclude <style> and <script>" but the Read tool can't honor that — it's aspiration, not mechanism.
This plan embeds a spec-only markdown digest inside the plan rather than writing a sibling .md file. A sibling file is a second source of truth that drifts the moment implementation flips checkboxes or review-plan edits content, and it collides with the plan-interview .md tooling. An embedded <script type="text/markdown"> block keeps the single-file guarantee, never renders, and is extractable in any session — no plugin install required — via a flag-and-exit awk: awk '/<script[^>]*id="plan-digest"/{f=1;next} f&&/<\/script>/{exit} f' <file> (a simple awk range would re-trigger on later mentions of the id, as this very plan demonstrates).
Resolved decisions (from clarification): the block is the first element child of <body> (extracted with awk); the digest is spec-only so status flips and checkbox ticks never invalidate it; this plan backfills the ~50 existing plans via an idempotent script; and the 7 reviewers read the digest only while the lead keeps full HTML for its selector-based edits.
Files to Modify
- .claude-plugin/
marketplace.jsonmodified bump plan-agent 2.1.0 → 2.2.0- kit/plugins/plan-agent/
CHANGELOG.mdmodified add 2.2.0 entryREADME.mdmodified document the digest + extraction- agents/
plan-reviewer-*.mdmodified 7 defs read the digest, not full HTML- skills/implementation-plan/
SKILL.mdmodified contract, generation, refresh, prompts; includesbuildImplementPrompt()instruction updatereference/SKELETON.htmlmodified add #plan-digest block (first element child of body)- skills/review-plan/
SKILL.mdmodified digest-only reviewers, Step 7 refreshreferences/role-prompts.mdmodified 7 briefs read the digest- scripts/
backfill-plan-digests.mjsnew idempotent injector over existing plans- tests/plugins/
test-plan-digest.shnew objective smoke testtest-backfill-digest.mjsnew backfill unit + integration
Diagram
plan-agent drafts the specfill #plan-digestawk on the consumer sideon any spec editSteps
#plan-digest block to SKELETON.html as the first element child of <body>
<body> (before the icon sprite) as <script type="text/markdown" id="plan-digest">{plan-digest}</script> — a non-executable script type the browser never renders or fetches, preserving the no-CDN, single-file guarantee. Add a guiding HTML comment above it documenting the spec-only rule and the flag-and-exit awk extraction — the comment is a comment node, not an element, so the script remains the first element child of <body> (the property the smoke test asserts, mirroring DOM firstElementChild semantics).Verify
grep -n 'id="plan-digest"' SKELETON.html shows the block within the first lines after <body>; open the skeleton in a browser and confirm the block produces no visible output and no console error. Also confirm the placeholder token used (e.g. {plan-digest}) is documented in a comment or in implementation-plan/SKILL.md Step 2 so the generator knows exactly what string to replace when filling the block.implementation-plan/SKILL.md
<\/script) so it cannot terminate the block early. Define the canonical extractor as the flag-and-exit awk '/<script[^>]*id="plan-digest"/{f=1;next} f&&/<\/script>/{exit} f' — a simple awk range re-triggers on any later line that mentions the id, so it must not be the documented form.Verify
SKILL.md; the new subsection enumerates the included fields, the excluded live-state fields, the "raw markdown, not HTML-escaped" rule, and the <\/script guard.SKILL.md Step 2, after the sections are drafted, build {plan-digest} from the final content and fill the skeleton placeholder. Add a rule to HTML Output Requirements: any later Edit that changes spec content (Step 5b interview findings, the Step 8 "Edit the plan" loop) must regenerate the block in the same pass; status flips (Step 6) and acceptance-criteria checks must not touch it. This keeps the digest authoritative without coupling it to progress churn. The digest carries no checksum or timestamp — staleness is prevented by this refresh rule plus the CI guard in Next Steps, not by an integrity field.Verify
SKILL.md Step 2 and HTML Output Requirements name the digest fill and the refresh-on-content-edit rule; Step 6 and the acceptance-criteria gate explicitly state they do not regenerate the digest. Generate a throwaway plan and confirm the digest matches the visible spec.{implement-prompt}/{workflow-prompt} templates and the buildImplementPrompt() instruction list to direct the consumer to start from the digest, e.g. append: "Start from the markdown spec in the #plan-digest block (extract: awk '/<script[^>]*id="plan-digest"/{f=1;next} f&&/<\/script>/{exit} f' <file>) before opening the full HTML."Verify
<code> row and the workflow prompt carry the extraction one-liner, and the copied prompt from buildImplementPrompt() includes the "start from the digest" instruction.review-plan reviewers to digest-only reads
references/role-prompts.md, change every "Read the implementation plan at <ABSOLUTE_PATH>" to extract and read the #plan-digest block; mirror the change in all 7 individual agents/plan-reviewer-*.md defs (plan-reviewer-architecture.md, plan-reviewer-completeness.md, plan-reviewer-testability.md, plan-reviewer-risk.md, plan-reviewer-conventions.md, plan-reviewer-ux.md, plan-reviewer-accessibility.md) that say "Read the plan's full content." In review-plan/SKILL.md Step 4, state the split: reviewers get the digest, the lead reads full HTML for Step 7 selector edits. When a plan has no digest yet (e.g. an old plan not backfilled), reviewers fall back to reading the full HTML for that run so reviews never break.Verify
grep -L plan-digest kit/plugins/plan-agent/agents/plan-reviewer-*.md returns nothing (all 7 defs updated); role-prompts.md references the digest for all 7 roles plus the no-digest full-HTML fallback; SKILL.md Step 4 documents the lead-vs-reviewer read split.review-plan Step 7
#plan-digest block from the now-updated plan content. Skip it when output mode is "review only" (no content was changed).Verify
review-plan/SKILL.md Step 7 lists Pass 3; a dry walk-through confirms it runs only after Pass 1 applied edits in "update plan in place" mode and is skipped in "review only".scripts/backfill-plan-digests.mjs
scripts/*.mjs convention) that scans docs/plans/*.html (skipping index.html and any file already containing #plan-digest), parses title/objective/files/steps/tests/criteria/verification from the stable skeleton structure (IDs/classes: #objective, .step-card, #tests, #criteria-list, #verification, .file-tree), builds the digest (with the <\/script guard), and inserts it as the first element child of <body>. It must never touch status, checkboxes, or progress state, must only inject when all expected sections parse — skipping and reporting any plan it cannot fully parse rather than writing a partial digest — and must support --dry-run, printing injected / skipped / failed counts.Verify
node scripts/backfill-plan-digests.mjs --dry-run reports counts with zero failures; a real run injects digests; a second real run injects 0 (all skipped). Plans that cannot be fully parsed are listed as skipped, not partially injected; git diff on a completed plan shows only the added digest block, no status/checkbox changes.CLAUDE.md requires docs/changelog updates with any plugin change — the new value must be higher than main's, and 2.1.0 was taken on main by the findings-walkthrough feature. Set plan-agent version to 2.2.0 in marketplace.json, add a 2.2.0 CHANGELOG.md entry describing the digest + backfill, and add a "Machine-readable digest" subsection to the plugin README.md showing the awk extraction one-liner.Verify
marketplace.json shows plan-agent at 2.2.0 (and the .claude/settings.json JSON-validation hook passes); CHANGELOG.md top entry is 2.2.0; the README has the digest subsection with the extraction command.Tests
File: tests/plugins/test-plan-digest.sh
Type: smoke test (shell, matching the repo's tests/<area>/*.sh convention)
Asserts: (1) SKELETON.html wraps the {plan-digest} placeholder in a <script type="text/markdown" id="plan-digest"> that is the first element child of <body> (comment nodes before it are allowed — match the first tag after <body>, skipping comments); (2) running the awk extractor against a committed fixture plan returns non-empty markdown containing the fixture's objective and at least one step action; (3) review-plan role-prompts.md and all 7 agents/plan-reviewer-*.md files reference plan-digest and the no-digest full-HTML fallback.
Run: bash tests/plugins/test-plan-digest.sh
File: tests/plugins/test-backfill-digest.mjs
Targets: buildDigest(), hasDigest(), extractSections() exported from scripts/backfill-plan-digests.mjs
Key cases: extractSections() pulls objective/steps/criteria from a sample plan string; buildDigest() emits the spec fields and applies the <\/script guard; hasDigest() is true for a plan already containing the block and false otherwise.
File: tests/plugins/test-backfill-digest.mjs
Targets: the backfill-plan-digests.mjs CLI end-to-end against a throwaway temp directory
Key cases: a todo, an in-progress, and a completed fixture plan each gain a digest; a pre-seeded plan is skipped (idempotency); a plan missing a parseable section is skipped and listed (no partial digest); the bytes of data-status, <meta name="plan-status">, and every acceptance-criteria checkbox are byte-identical before and after; a fixture plan whose content contains the literal string </script in a code block is injected and the guard fires correctly (closing tag does not terminate the digest block early).
File: tests/plugins/test-plan-digest.sh
Targets: the digest-refresh pass (Pass 3) in review-plan/SKILL.md Step 7
Key cases: after a spec-content edit is applied to a fixture plan via review-plan update-in-place mode, the #plan-digest block reflects the updated content; in "review only" mode, the digest is unchanged; status/checkbox bytes are unaffected by either mode.
File: tests/plugins/test-plan-digest.sh
Targets: reviewer fallback path in review-plan/SKILL.md Step 4 and each agents/plan-reviewer-*.md
Key cases: when a plan has no #plan-digest block, the reviewer defs and role-prompts instruct fallback to full HTML; the smoke test asserts that every agents/plan-reviewer-*.md file contains both the digest-extraction clause and the fallback clause.
Acceptance Criteria
Verification
Generation path: run /plan-agent:implementation-plan on a throwaway objective and confirm the resulting plan has a #plan-digest block as the first element child of <body>, that its markdown matches the visible objective/steps/criteria/verification, that the block renders nothing in a browser, and that the canonical flag-and-exit awk extractor returns the spec. Confirm both the implement and workflow prompts carry the extraction clause.
Backfill path: run node scripts/backfill-plan-digests.mjs --dry-run then a real run over docs/plans/; spot-check one completed, one in-progress, and one todo plan — each must gain a digest while git diff shows no change to data-status, <meta name="plan-status">, or any criteria checkbox. Re-run and confirm 0 injected.
Review path: run review-plan on a sample plan; confirm each reviewer was briefed with the digest (not full HTML), that a digest-less plan falls back to full HTML, and that Step 7 regenerated the digest after applying inline edits.
Tests: bash tests/plugins/test-plan-digest.sh and node tests/plugins/test-backfill-digest.mjs both exit 0.
Completion Checklist
Completion Report
- Version criterion — planned 2.2.0, shipped 2.3.0
- PR #317 (markdown plan conversion) took 2.2.0 on main while this plan was in flight. The criterion's intent — bump plan-agent above the value on main with a matching CHANGELOG entry — is met at 2.3.0.
Unresolved Questions
-
Do digest-only reviewers lose the ability to flag rendering / DOM-structure defects?
In the agentics plan-agent review-plan skill, the 7 reviewer teammates now read only the #plan-digest markdown, not the full HTML. Assess whether any reviewer role (especially architecture, conventions, or accessibility/UX) needs full-HTML access to catch defects the spec-only digest cannot express — e.g. malformed markup, broken copy buttons, missing nav links, or contrast issues. Recommend either (a) keep all 7 digest-only, (b) give a named subset on-demand full-HTML access, or (c) add a single lead-side structural lint pass. Justify with concrete examples of defects each option would catch or miss.
Team Review (2026-06-10 22:54:34 UTC)
Executive Summary: The plan is well-scoped, technically sound, and addresses a genuine token-cost problem with a clean embedded-digest approach. The architecture is defensible — single-file guarantee, no sibling drift, awk-extractable without plugins. The main gaps are: (1) the 7 reviewer agent defs are listed as a glob rather than enumerated names, risking one being missed; (2) three test paths are absent — digest-refresh after Step 7 edits, no-digest fallback behavior, and the </script escape edge case; (3) the {plan-digest} placeholder substitution contract is not fully specified in Step 1; (4) buildImplementPrompt() has no explicit file path in the Files section. All have been addressed inline.
Architecture: Fit is strong. The single-file embedding via <script type="text/markdown"> is the correct pattern — no CDN, no second source-of-truth, browser-silent. The lead/reviewer read split is well-reasoned. One medium concern: the digest contract is partially duplicated across implementation-plan/SKILL.md, review-plan/SKILL.md, role-prompts.md, 7 agent defs, and the backfill script. A future contract change requires coordinated edits in all five locations — worth noting in an Unresolved Question or a Next Step for contract centralization.
Completeness: Steps are specific with action/why/verify triples. Key gap addressed: Step 5 now enumerates all 7 reviewer filenames rather than using a glob. The Files section now notes buildImplementPrompt() is inside implementation-plan/SKILL.md. Step 1 verify now references the placeholder substitution contract.
Testability: The existing smoke + unit + integration tests are solid for the generation and backfill paths. Three missing test cases added: (a) digest refresh after review-plan Step 7 inline edits; (b) no-digest fallback path; (c) </script escape edge case in the backfill integration test.
Risk: Highest risk is the backfill over ~50 existing plans. The "only inject when all sections parse" + dry-run + skip-and-report design is sound mitigation. The </script guard is documented but was untested — now covered. The prose-only enforcement of "status flips must not touch the digest" is a medium-term drift risk; the deferred CI guard (Next Steps) is the correct long-term fix.
Conventions: File naming and script placement follow project conventions. One medium issue: the {plan-digest} placeholder was not explicitly documented as the replacement token — Step 1 verify now calls this out. The 7 reviewer files listed as plan-reviewer-*.md glob is now enumerated explicitly in Step 5.
Highest-Risk Issues (resolved inline):
- (High) 7 agent defs listed as glob — now enumerated in Step 5 with all 7 filenames.
- (High) No test for
</scriptescape edge case — added to backfill integration test. - (Medium) No test for digest-refresh path after Step 7 edits — added as new integration test card.
- (Medium) No test for no-digest fallback — added as new integration test card.
- (Medium)
buildImplementPrompt()missing from Files section — noted in SKILL.md file entry. - (Medium)
{plan-digest}placeholder contract not specified in Step 1 verify — added.