Retrofit responsive CSS into every HTML plan

High completed
2026-06-12 agentics fix High effort

Eliminate horizontal overflow in every HTML plan — retrofit all 55 shipped files in docs/plans/ with a versioned 8-line CSS block via an idempotent script, and bake the same block into the plan skeleton so every future plan is born responsive.

Implement Read and implement all steps in the plan at docs/plans/retrofit-responsive-plan-css.md — Retrofit responsive CSS into every HTML plan. Verify against the plan's Tests, Verification, and Acceptance Criteria before reporting done. If everything passed, mark completion in docs/plans/retrofit-responsive-plan-css.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: Retrofit responsive CSS into every HTML plan. The plan at docs/plans/retrofit-responsive-plan-css.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/retrofit-responsive-plan-css.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/retrofit-responsive-plan-css.md — Retrofit responsive CSS into every HTML plan. Brief subagents with the plan file at docs/plans/retrofit-responsive-plan-css.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/retrofit-responsive-plan-css.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 retrofit-responsive-plan-css.html
Path docs/plans/retrofit-responsive-plan-css.html
Spec docs/plans/retrofit-responsive-plan-css.md
Definition of done 8 / 8 done

Context

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

A 390px-viewport browser audit found 16 of the 54 HTML files in docs/plans/ overflow horizontally — the worst ( add-multi-host-deploy-targets.html ) by 294px of sideways scroll. Current-generation, digest-era plans are affected too: the defect is content-dependent, not template-generation-dependent.

Three root causes combine:

Unbreakable tokens with no wrap rule. File paths and commands like kit/plugins/docs-publisher/reference/.gitlab-ci.yml inside inline <code> , list items, and bare divs have no overflow-wrap anywhere in the template — a token wider than a phone screen simply cannot break.

Grid min-content propagation. Grid items default to min-width: auto , so one unwrappable token in main inflates the shared single-column track and stretches the sidebar with it. overflow-wrap: break-word wraps visually but does not reduce min-content size — only anywhere does, which is why both min-width: 0 and inherited overflow-wrap: anywhere are needed.

Component stragglers. The three-column .compare-grid does not collapse below 600px in some template generations, and table cells have no wrap rule.

The fix is proven: injecting the block below into all 54 rendered files in a width-controlled iframe harness took the overflow count from 16 to 0, with no effect on already-clean files ( anywhere only activates when a single word exceeds the line, so normal prose is untouched).

/* plan-responsive-fix v1 — injected by scripts/retrofit-responsive-plans.mjs */
body { overflow-wrap: anywhere; }
main, nav, aside { min-width: 0; }
.layout > *, .wrap > *, .compare-grid > * { min-width: 0; }
pre { white-space: pre-wrap; max-width: 100%; }
table { max-width: 100%; }
img, video { max-width: 100%; height: auto; }
@media (max-width: 600px) { .compare-grid { grid-template-columns: 1fr; } }
Because every plan is a self-contained single-file HTML document (embedded CSS, no external assets — by design, so plans survive file:// opens, copies, and email), skeleton improvements never reach already-shipped plans. The retroactive mechanism is a versioned injector script, mirroring the scripts/backfill-plan-digests.mjs (2.3.0) and scripts/backfill-save-pdf.mjs (2.4.0) precedents — this is the third injector in that family. The block is wrapped as <style id="plan-responsive-fix" data-version="1"> and inserted immediately before </head> ; the id + version pair is the idempotency key (current → skip, older → replace, missing → inject). docs/plans/index.html is always excluded — it is regenerated from scratch by docs/plans/build-index.sh via the rebuild hook and already renders clean at phone width.

Files that change

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

agentics/
  • scripts/retrofit-responsive-plans.mjs new idempotent injector with --check gate
  • docs/plans/*.html modified 55 files (incl. this plan) — v1 block injected before </head>
  • skills/implementation-plan/reference/SKELETON.html modified same v1 block embedded natively
  • CHANGELOG.md modified 2.4.1 entry
  • .claude-plugin/marketplace.json modified plan-agent 2.4.0 → 2.4.1
  • tests/plugins/test-responsive-retrofit.sh new corpus + fixtures + skeleton-sync guard

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 Create scripts/retrofit-responsive-plans.mjs — the idempotent injector
Why
A deterministic, re-runnable script is the only fix that reaches already-shipped self-contained plans without an LLM pass. Mirror the backfill-plan-digests.mjs / backfill-save-pdf.mjs conventions: Node ≥ 18, zero dependencies, summary output. Contract: wrap the canonical CSS constant as <style id="plan-responsive-fix" data-version="1"> ; insert immediately before </head> (case-insensitive); skip files already at the current version; replace the whole block when an older version is found; always exclude index.html ; report and skip files with no </head> rather than half-writing them. Flags: --check , --dry-run , --dir <path> , --include-archive .
Verify
node scripts/retrofit-responsive-plans.mjs --check exits 1 listing 55 files; --dry-run prints the same 55 as would-inject while git status stays clean; a synthetic fixture without </head> is reported as a skip, never modified.
2
done Run the injector once over docs/plans/
Why
This is the retroactive payload — all 55 plan files (every file except the hook-generated index.html , including this plan document itself, which was built from the pre-fix skeleton) pick up the v1 block in a single reviewable diff.
Verify
grep -L 'id="plan-responsive-fix"' docs/plans/*.html returns only index.html ; an immediate second run reports 55 skipped and adds nothing to git diff (idempotency proven on the real corpus).
3
done Embed the identical v1 block in SKELETON.html
Why
New plans must be born responsive and pass --check natively — otherwise every freshly generated plan reintroduces the defect the retrofit just cleared. Insert the same <style id="plan-responsive-fix" data-version="1"> block immediately before </head> in kit/plugins/plan-agent/skills/implementation-plan/reference/SKELETON.html , byte-identical to the script's CSS constant (the script is the single source of truth; the skeleton carries a copy).
Verify
grep 'plan-responsive-fix' kit/plugins/plan-agent/skills/implementation-plan/reference/SKELETON.html finds the block before </head> ; the CSS extracted from the skeleton block diffs empty against the script constant.
4
done Add tests/plugins/test-responsive-retrofit.sh — corpus, fixtures, and sync guard
Why
Turns the one-time migration into a standing invariant: the corpus check fails the moment a plan ships without the current block, and the sync assert stops the skeleton and the script from drifting apart. Cases: (a) --check exits 0 over the repo's docs/plans/ ; (b) fixture injection — missing block injected exactly once before </head> , second run byte-identical; (c) data-version="0" fixture replaced with v1, no duplicate block; (d) index.html and no- </head> fixtures untouched; (e) skeleton block CSS byte-identical to the script constant; (f) head-only guarantee — the injector's output is byte-identical to its input from <body onward, so the retrofit can never alter markup, ARIA, or semantics.
Verify
bash tests/plugins/test-responsive-retrofit.sh exits 0; stripping the block from a tmp corpus copy makes the --check assert exit 1 naming the stripped file.
5
done Bump plan-agent to 2.4.1 and write the CHANGELOG entry
Why
The skeleton is plugin-shipped behaviour — .claude/rules/marketplace.md mandates a manual semver bump (patch for a fix) in .claude-plugin/marketplace.json plus a kit/plugins/plan-agent/CHANGELOG.md entry with every plugin change.
Verify
marketplace.json shows plan-agent 2.4.1 (higher than main's 2.4.0 ) and passes the settings-hook JSON validation; CHANGELOG.md opens with a ## 2.4.1 entry dated 2026-06-12 describing the responsive block and the injector.
6
done Re-audit all 55 plans at 390px and 320px in a real browser
Why
Measured scrollWidth in a width-controlled harness is the ground truth the investigation used — the retrofit is done when the overflow count is zero, not merely when markers are present. The 320px pass grounds the result in WCAG 2.1 AA reflow (1.4.10), which requires no horizontal scrolling at 320px CSS width.
Verify
Serve docs/ locally ( bash scripts/serve-docs.sh or python3 -m http.server --directory docs ), load every plan in a 390px-wide and then a 320px-wide iframe, and assert documentElement.scrollWidth ≤ iframe width for all 55 files at both widths; spot-open add-multi-host-deploy-targets.html (previously +294px) and confirm no horizontal scrollbar.

Tests

The tests that prove the change does what it promises.

Tier 1 — Code-touching plan
Objective No plan ships without the v1 responsive block File: tests/plugins/test-responsive-retrofit.sh Type: smoke test (runs against the real corpus) Asserts: every docs/plans/*.html except index.html carries <style id="plan-responsive-fix" data-version="1"> , and the skeleton's embedded block is byte-identical to the script's CSS constant — i.e. every shipped plan and every future plan is responsive-hardened, which is this plan's stated objective. Run: bash tests/plugins/test-responsive-retrofit.sh
Unit Injector behaviour on synthetic fixtures File: tests/plugins/test-responsive-retrofit.sh (fixture section) Targets: marker detection, version comparison, insertion point, and exclusions in scripts/retrofit-responsive-plans.mjs Key cases: missing block → injected exactly once, immediately before </head> ; data-version="0" → replaced with v1 without duplicating the block; current v1 → skipped byte-identical; index.html and a fixture with no </head> → untouched and reported; head-only guarantee → output byte-identical from <body onward (no markup, ARIA, or semantics changes ever).
Integration CLI end-to-end over a corpus copy File: tests/plugins/test-responsive-retrofit.sh (corpus section) Targets: the full CLI — default run, --check , and --dry-run — against a tmp copy of docs/plans/ Key cases: first run injects every non-index file (55 at the time of writing); second run no-ops (tree byte-identical); --check exits 0 after the run and 1 when one file is stripped; --dry-run writes nothing.

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.

Confirm the whole change end-to-end, in this order:

Run bash tests/plugins/test-responsive-retrofit.sh — exit 0 covers the corpus check, fixture cases, and the skeleton/script sync assert.

Serve docs/ locally and re-run the width-controlled iframe audit at 390px and 320px across all 55 plan files: load each file in an iframe of each width and compare documentElement.scrollWidth against the iframe width. Expected overflow count: 0 at both widths (it was 16 at 390px before the retrofit; 320px grounds WCAG 1.4.10 reflow).

Visually open add-multi-host-deploy-targets.html (worst offender, previously +294px) and persist-checkbox-state-in-html-attributes-review.html (table-heavy review file) at phone width — no horizontal scrollbar, long paths wrap, tables fit.

Run the injector a second time — it reports all files skipped and git diff gains nothing.

Confirm .claude-plugin/marketplace.json shows plan-agent 2.4.1 with a matching CHANGELOG.md entry, and that the JSON passed the settings-hook validation on save.

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.

Patch the review-card templates at their source

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

In the agentics repo: the *-review.html files in docs/plans/ are generated from review-output templates and currently ship without the responsive block. Locate the HTML templates that produce review documents (search kit/plugins/plan-agent and kit/plugins/product-plans for review skeleton/template HTML), insert the same <style id="plan-responsive-fix" data-version="1"> block used by scripts/retrofit-responsive-plans.mjs immediately before </head> in each template, bump each owning plugin's version (patch) in .claude-plugin/marketplace.json with CHANGELOG entries, and verify a freshly generated review file passes node scripts/retrofit-responsive-plans.mjs --check.
Retrofit the archived plans

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

In the agentics repo, run node scripts/retrofit-responsive-plans.mjs --include-archive to inject the v1 responsive block into docs/plans/archive/**/*.html as well. Review the diff, run the command a second time to confirm idempotency (no further changes), and commit as a docs-only change.
Audit the remaining docs surfaces at phone width

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

In the agentics repo, serve docs/ locally (bash scripts/serve-docs.sh) and audit docs/index.html, docs/guides/*.html, and docs/media/social/index.html at 390px and 320px for horizontal overflow using a width-controlled iframe harness: load each page in an iframe of that width and compare documentElement.scrollWidth to the iframe width. Report each offender with the leaf element causing the overflow, and propose minimal CSS fixes per file.
CI guard on every plan-touching PR 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:

In the agentics repo, add a GitHub Actions workflow (or extend an existing one) that runs node scripts/retrofit-responsive-plans.mjs --check and bash tests/plugins/test-responsive-retrofit.sh on pull requests touching docs/plans/** or kit/plugins/plan-agent/**, so a plan can never merge without the current responsive block.
Auto-retrofit hook on plan writes 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:

In the agentics repo, add a PostToolUse hook to kit/plugins/plan-agent/hooks/ (mirroring the existing plans-index rebuild hook) that runs node scripts/retrofit-responsive-plans.mjs --dir docs/plans whenever a Write or Edit touches an .html file under docs/plans/, so manually added plans receive the responsive block immediately. Bump plan-agent (minor — new hook) and document it in the CHANGELOG.