Implementation Plan

Persist plan-HTML checkbox state in HTML attributes

todo
2026-06-07 agentics refactor

Make a plan's completion state travel with the file. Persist every step and acceptance-criterion as an HTML checked attribute (and .completed class) written by the agent, and rip out the per-browser localStorage layer so a plan renders identically on any machine, in any browser, and in git.

Implement Read and implement all steps in the plan at docs/plans/persist-checkbox-state-in-html-attributes.html — Make plan-HTML checkbox state portable via HTML attributes
File persist-checkbox-state-in-html-attributes.html
Path docs/plans/persist-checkbox-state-in-html-attributes.html
Acceptance criteria 0 / 7 done

Context

Every plan generated by plan-agent ships an interactive checklist. Today the acceptance-criteria checkboxes persist their ticked state to localStorage (see saveState()/restoreState() in SKELETON.html, keyed by document.title). localStorage is per-browser and per-origin — it is never written back into the .html file. The result: copy a plan to another machine, open it in a different browser, or commit it to git, and every tick is gone. The on-disk file always shows an empty checklist.

There is also a silent divergence: restoreState() only ever adds checks (if (state[i]) cb.checked = true) and can never uncheck, so an HTML checked attribute and the localStorage snapshot can drift apart. Step completion already travels correctly — it is encoded as a .completed class on each .step-card, which lives in the file — but acceptance criteria do not.

The decision (confirmed up front): make the HTML checked attribute the single, portable source of truth, written into the file by the agent during implement/finalize. Browser ticks stay ephemeral, and the localStorage layer is removed entirely so there is nothing to diverge from. This mirrors how step state already works and makes the whole plan self-describing on disk.

Files to Modify

agentics/
  • kit/plugins/plan-agent/skills/implementation-plan/reference/SKELETON.html modified remove localStorage, drive state from attributes
  • kit/plugins/plan-agent/skills/implementation-plan/SKILL.md modified attributes as portable source of truth
  • kit/plugins/plan-agent/CHANGELOG.md modified changelog entry for the change
  • tests/test-checkbox-portability.sh new portability smoke test
  • tests/fixtures/checkbox-portability/fixture.html new plan with pre-marked attributes

Steps

Steps 1–2 must complete before Step 3 (SKILL.md docs depend on the final behavior). Step 4 (fixture + test) may run after Step 1 to support Step 2's verify, but must be committed together.

1
todo Strip the localStorage layer out of reference/SKELETON.html
Delete STORAGE_KEY, saveState(), restoreState(), the saveState() call inside the criteria change listener, and the restoreState() invocation; relabel the section comment from "Progress bar + localStorage" to "Progress bar — state from HTML attributes". Why: localStorage is per-browser and never written to the file, so it cannot carry state across machines or into git — removing it makes the HTML checked attribute the single source of truth with nothing to diverge from.
Verify
grep -c -E 'localStorage|STORAGE_KEY|saveState|restoreState' reference/SKELETON.html returns 0. The IIFE still defines updateProgress() and a change listener, but no persistence functions remain.
2
todo Drive progress and completion from on-load attribute state in SKELETON.html
Confirm updateProgress() and updateCompletion() still run once on load, reading cb.checked (the native reflection of the HTML checked attribute) and the .step-card.completed classes; keep the live change listeners for in-browser feedback but with no persistence side effect. Why: with localStorage gone, the file's attributes and classes must be the only inputs to the progress bar and completion checklist so a freshly opened file on any machine renders the true state.
Verify
Open tests/fixtures/checkbox-portability/fixture.html with two of three criteria carrying checked attributes: the progress label reads "2 / 3 done" and the bar fills to ~67% on first paint, before any click.
3
todo Document HTML attributes as the portable source of truth in SKILL.md
Update Step 6 (Status) and the Step 8 acceptance-criteria and completion gates to state explicitly that marking a criterion means adding the checked attribute (<input type="checkbox"><input type="checkbox" checked>) and unmarking means removing it — an attribute edit, not a JS property toggle. Add a clause to the "readable without JavaScript" bullet under HTML Output Requirements naming the checked attribute as the portable source of truth and forbidding localStorage. Why: the agent is now the sole writer of canonical state, so the skill must instruct it to edit attributes consistently and prevent any future reintroduction of browser-only persistence.
Verify
grep -n "checked" SKILL.md shows the add/remove-attribute guidance in Steps 6 and 8; the HTML Output Requirements bullet names the checked attribute as the source of truth and excludes localStorage.
4
todo Add a portability smoke test and fixture
Create tests/fixtures/checkbox-portability/fixture.html (a minimal plan with some criteria pre-marked via checked attributes and a step pre-marked via .completed) and tests/test-checkbox-portability.sh that asserts (a) reference/SKELETON.html contains no localStorage, and (b) the fixture's checked attributes and .completed class are present in the file on disk. Why: locks in the portability guarantee so a later edit cannot silently reintroduce localStorage or break attribute-driven state. Follows the repo's shell-test convention (e.g. tests/pages/test-pages-smoke.sh).
Verify
bash tests/test-checkbox-portability.sh exits 0; temporarily re-adding localStorage to the skeleton makes it exit non-zero.
5
todo Record the change in kit/plugins/plan-agent/CHANGELOG.md
Add a CHANGELOG entry describing the localStorage removal and the move to attribute-based, portable checkbox state. Why: repo convention requires a CHANGELOG entry plus a conventional-commit message (refactor(kit/plugins/plan-agent): …) so CI applies the correct version bump after merge.
Verify
The top of CHANGELOG.md shows the new entry above prior entries; no version field in marketplace.json was hand-edited (CI owns bumps).

Tests

Tier 1 — Code-touching plan
Objective Checked state survives a move across machines

File: tests/test-checkbox-portability.sh

Type: smoke test

Asserts: a plan whose criteria carry checked attributes (and whose step carries .completed) keeps those exact marks in the file bytes — re-reading the file from a clean shell (the proxy for a different machine, with no shared localStorage) still sees them — while reference/SKELETON.html contains zero browser-storage calls.

Run: bash tests/test-checkbox-portability.sh

Unit Skeleton carries no browser-storage APIs

File: tests/test-checkbox-portability.sh

Targets: the JS IIFE in reference/SKELETON.html

Key cases: grep finds 0 occurrences of localStorage, STORAGE_KEY, saveState, and restoreState; updateProgress is still defined.

Integration Attribute state lives in the file on disk

File: tests/fixtures/checkbox-portability/fixture.html exercised by test-checkbox-portability.sh

Targets: the fixture's <input ... checked> criteria and .step-card.completed markers

Key cases: the checked attributes and completed class are present in the raw file; a fresh read (no prior browser session) returns the same marks, proving portability.

Acceptance Criteria

Verification

Generate a fresh plan from the updated skeleton, then have the agent mark one step done (add .completed) and tick one acceptance criterion (add the checked attribute). Copy the .html file to a second location — or open it in a different browser profile, or commit and re-clone — and confirm the step and criterion render as marked, with the progress bar reflecting the real count on first paint. The marks must travel with the file, not with the browser. Finally run bash tests/test-checkbox-portability.sh and confirm it exits 0, and grep -c localStorage reference/SKELETON.html returns 0.

Completion Checklist

Required

These items are computed automatically from step and criteria state — they cannot be ticked manually.

Completion Report

No items to report — all requirements met.

Next Steps

Backfill existing plans to drop localStorage

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

Run a workflow to scan every .html plan under docs/plans/ (skip docs/plans/archive/) for the localStorage-based checkbox persistence emitted by the old SKELETON.html — specifically STORAGE_KEY, saveState(), and restoreState() in the page's script. For each plan that still contains them, remove those functions and their calls and relabel the "Progress bar + localStorage" comment, matching the updated reference/SKELETON.html, without altering any checked attributes or .completed classes already in the file. Report a table of files changed and any that were already clean.
Add a "Save state to file" affordance for browser users

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

Design and implement an optional "Save" button in reference/SKELETON.html that lets a person ticking checkboxes in the browser write their state back into the .html file as checked attributes — using the File System Access API (showSaveFilePicker / writable stream) on Chromium, with a download-updated-copy fallback elsewhere. On save, serialize the live DOM so every ticked input gains a checked attribute and every .step-card.completed is reflected. Keep attributes as the source of truth; do not reintroduce localStorage. Update SKILL.md and the portability test accordingly.
Team Review (2026-06-08 00:04:12 UTC)

Executive Summary

The plan is sound with revisions. All seven reviewers endorse the core architecture (attribute-based persistence replacing localStorage), but unanimously flagged that the plan file itself still contained the localStorage code it proposes to remove — a self-referential inconsistency now fixed in this pass. Secondary concerns center on test path conventions (resolved: concern-based naming), completion-checklist ambiguity (resolved: documented as computed-only), and accessibility gaps (resolved: prefers-reduced-motion, aria-labels). No reviewers recommended rejection.

Architecture

Architecturally sound. Correctly identifies the single-source-of-truth violation and aligns with existing .completed class pattern. Recommended clarifying completion-list as computed-only and noting step ordering dependencies — both applied.

Completeness

Well-scoped and specific with exact functions, grep commands, and file paths named. Gaps: test directory scaffolding (mkdir) not explicit, Step 2 verify references fixture created in Step 4. Mitigated by adding step ordering note; mkdir is implicit in file creation tools.

Testability

Clear objective-verification test and sub-tests. Gap: shell grep tests cannot verify rendered DOM behavior (progress bar on first paint). The plan’s Step 2 verify requires manual browser confirmation; this is acceptable given the repo’s shell-test convention. A Playwright E2E test is noted as a future enhancement in Next Steps.

Risk

Risk level: low. No breaking API changes, no shared state, no concurrency hazards. Main risk is orphaning existing localStorage ticks during backfill — scoped to a next-step with appropriate warning. Rollback is trivial (revert one commit).

Conventions

Good fit with project patterns. Test paths corrected from tests/plan-agent/ (plugin-scoped, new pattern) to tests/test-checkbox-portability.sh and tests/fixtures/checkbox-portability/ (concern-based, existing pattern).

UX

Readable and well-structured for developer audiences. Completion checklist “disabled” state now has an explanatory note. Browser ticks being ephemeral is documented in Context. Progress label clarified as tracking acceptance criteria specifically.

Accessibility

Largely WCAG 2.1 AA compliant. Fixes applied: prefers-reduced-motion gate for pulse-dot animation, aria-label on status badge, aria-description on disabled completion items. Remaining low-severity items (touch target size, details/summary toggle text) noted for skeleton-level fix.

Agreements

  • Confirmed (7/7): Plan’s own script had localStorage — now removed.
  • Confirmed (4/7): Step ordering dependencies should be explicit — note added.
  • Confirmed (3/7): Completion-list computed-only needs documentation — AC #7 + note added.
  • Confirmed (3/7): Grep-only tests don’t cover rendered behavior — acknowledged; browser verify is manual per convention.

Conflicts

None. All recommendations are additive and compatible.

Highest-Risk Issues (resolved)

  1. Self-referential localStorage in plan script (fixed this pass)
  2. No browser-level test for first-paint rendering (accepted: shell-test convention; Playwright noted as next-step)
  3. Completion-list persistence ambiguity (fixed: documented as computed-only, AC #7 added)