plan-assist — layered planning docs
Three root docs. charter.md = stable directives (DO/DO NOT, invariants, build-order status table, gotchas). work-plan.md = current plan + handoff. log.md = append-only journal, canonical. Goal: prevent drift.
INVARIANTS (never break)
- I1. If charter.md and log.md disagree → log.md wins. charter.md only distills it.
- I2. log.md is append-only: never edit/delete old entries; newest at bottom; absolute dates only (resolve "today" to the real date).
- I3. log.md is a write-ahead log: append AND commit a dated entry BEFORE any risky op, not after — so a destructive op can't lose it. (A session once lost its tree on a
mv; the journal was the only recovery.)
SESSION CONTRACT — do each, in order
- START: read charter.md → work-plan.md → log.md (skim recent). Always, even if the prompt seems narrow.
- ON CHANGE: edit work-plan.md in the SAME commit as the code change — never let it lag.
- BEFORE RISKY OP (
mvworkdir ·git reset --hard· force-push · big migration): commit a dated log.md entry FIRST (per I3). - PHASE LANDS: summarize it into log.md, prune it from work-plan.md (keep < ~250 lines).
- STOP MID-TASK: write a SESSION HANDOFF block atop work-plan.md (shape below).
- SESSION END: append a dated log.md entry (decided/changed · new gotchas · status changes · open questions).
- EACH COMMIT + BOUNDARY: run the HEARTBEAT.
Keep live status OUT of charter.md (it lives in work-plan.md); the build-order table is the only exception.
SESSION HANDOFF shape (atop work-plan.md)
## ⏸ SESSION HANDOFF — <YYYY-MM-DD>
**Done + verified:** <what shipped, with commit hashes>
**Left to do:** <next concrete steps, in order>
**How to run / diagnose:** <build / test / smoke commands>
**Environment notes:** <traps, env vars, anything non-obvious>
Remove it once the next session picks the work back up.
HEARTBEAT (cheap; one line — "in sync, on-phase" — unless something fires)
drift? · stale build-order marker in charter.md (⏳ but shipped / ✅ but broken)? ·
journal debt → append to log.md now? · work-plan.md > 250 lines → prune? ·
periodically run build/tests/smoke? · stale open questions in log.md?
Full text + hook snippets: hooks/heartbeat.md. Only stop to act when a check fires.
BOOTSTRAP (only if the docs are absent)
Never clobber — if a target exists, read it and offer to merge, don't overwrite. Use today's date for <YYYY-MM-DD>.
- Infer the project name; skim the code for a first-pass DO/DO-NOT list and build-order skeleton (placeholders if nothing's discoverable).
- Create charter.md, work-plan.md, log.md from
templates/with<project-name>filled in. - Add the
templates/CLAUDE-orientation.mdblock to CLAUDE.md (create if absent; don't duplicate if present). - Seed log.md with a
## Session 1 work log — <today>baseline entry. - Offer the heartbeat hook — default skill-baked (no config); install the
hooks/heartbeat.mdsnippet only if the user wants harness enforcement. - (Opt-in) offer to add the read-only allowlist below to
.claude/settings.local.jsonso session-start/heartbeat inspection stops prompting. Only with the user's OK. Never allowlist risky ops (git reset --hard,mv, force-push, migrations) — keeping them prompt-gated is the safety guardrail this skill is built around.
{ "permissions": { "allow": [
"Bash(git status:*)", "Bash(git log:*)", "Bash(git diff:*)",
"Bash(git show:*)", "Bash(wc -l:*)", "Bash(date:*)"
] } }