Compaction Survival
A long autonomous run loses most often to this — the context that
held the plan gets compacted or reset, and the next turn resumes from a summary
that dropped the load-bearing detail. The defense is an anchor on disk that the
run re-reads and rewrites as it goes, so the plan lives in a file, not only in
the context window.
This is a flexible skill: the anchor's schema and update cadence adapt to
the task. What stays firm is small — the anchor is the single source of truth
for run state, re-read at the start of each turn and updated before the state
it describes can be lost.
The anchor
One file, at a stable path the run can find again after a reset. It has two
tiers, split by a literal <!-- anchor:tail --> marker line: above it the live
HEAD — the only part the re-injection hook emits — and below it the
TAIL, which stays on disk. A marker-less anchor still injects whole, but
then a long run's live state is whatever the 8K bound keeps.
HEAD — bounded, rewritten in place. The order below is the survival order.
The injection spends its budget top-down and drops whole trailing sections,
naming them, so a section's position is its priority and putting one above
another demotes that other.
- Mission — the goal in a sentence or two, the hard constraints, and any
user instruction that constrains mechanism rather than outcome, quoted in
the user's own words with a stable id. Paraphrase is where an order dies:
once the wording is gone a substituted mechanism reads as a design choice.
A reversal of a standing rule is quoted the same way and names what it
supersedes; the old rule lives in other copies and will not overwrite itself.
- Cursor — done / in progress / next action on resume: one imperative
step plus the precondition to verify before it, rewritten in place as it
mutates. An unanswered question or approval is armed here for verbatim
re-ask after the reset. This is the part that earns the anchor.
- Resume steps — how a cold reader re-orients: read this file, check the
real state (version control log, the artifact on disk), continue from the
cursor. They run somewhere they were not authored, so write them in
absolute paths — a relative command does not fail after a restart, it
succeeds in the wrong place. Record the anchor's own absolute path where the
environment surfaces it next turn: an anchor that cannot be found is no anchor.
- Invariants — decisions and constraints that hold across the whole run, so
a post-compaction turn does not relitigate them.
- Parallel tracks — only when a peer run shares these trees: the other
track's anchor path and this track's never-touch surface, written before any
work. Disclose on every commit that touches shared surface, and route a
cross-track lesson into both anchors.
- In-flight work — background or async tasks the cursor depends on: their
ids, log paths, and a "do not relaunch over the same output" guard. A run that
fans out to background work records them here as first-class cursor state, so
each async boundary resumes idempotently instead of being re-derived.
- Last-known-good — the concrete recoverable state: commit hashes, branches
and PRs opened, tags pushed, the files written, the checkpoint reached.
- Plan pointer — where the full plan lives (a separate doc), so the anchor
stays a cursor, not a second copy of the plan.
TAIL — append-only, read on demand:
- Decisions log — why the non-obvious calls were made.
- Folded history — closed phases' one-line outcomes, resolved incidents.
The protocol
- Create the anchor at the start of the run, before the first irreversible
step, so there is something to resume from immediately. Arming is also the
sweep moment — read
anchor_inject.py --list-dormant <anchors dir> and close
or adopt any track it names. It reaches what close --stale cannot: a track
abandoned mid-cursor never marks itself done.
- Update the cursor after each step or phase, before moving on. State that
lives only in the context window is one compaction away from gone; write it
down while it is still true.
- Re-read the anchor at the start of each turn — especially when a summary
has appeared or the context feels thinner than the work already done — the
signs of a compaction. Re-read before acting, not after. A
cursor is an Edit, so during tool outages it can lag reality by a phase; when
it disagrees with durable state (the version-control log, run ledgers), trust
the durable state.
- Write atomically and keep one anchor. Overwrite the single file rather
than scattering state across several; a half-written or duplicated anchor is
worse than a terse one.
- Keep the HEAD bounded. As a phase closes, fold its detail into a
one-line outcome in the TAIL, below the marker — a closed phase's spec, and
the cursor's own done-list, which is what actually accumulates.
- Make resume idempotent. The resume steps let a fresh context recover the
run from the anchor and the real on-disk state alone; re-entering a
half-finished step checks the artifact before redoing it, so re-reading is
always safe. A stored recovery command (a ledger-count grep, a resume key)
is validated against the live artifact before the run goes unattended —
unchecked, it is a fabricated inference waiting to misfire.
- Close by stubbing, then renaming. When the run ends, rewrite the anchor
to a minimal landed stub — status, a one-line outcome, resume: none — and
rename it
<name>.closed.md. The rename is the only close signal the hook
honors: a prose "status: CLOSED" line does not stop re-injection, and a
full-ledger close overflows the injection budget on the next session. Close
at the moment the cycle ends; a track closed only in prose accumulates. And
close on the deliverable, not the session: if the session carries on into
new substantive work, arm the next anchor in the same breath — a closed
anchor beside a live session is an uncovered window. At
wind-down, /anchor close --stale sweeps the dir for anchors marked done
in-content but never renamed and offers the exact rename for each.
Explicit surfaces
- Invoked directly (
/compaction-survival), arm the protocol now: create or
refresh the anchor immediately from the current conversation state, then
follow the update-and-re-read cadence for the rest of the run.
/anchor (session-workflow command) is the one-off backstop: a single
snapshot on demand, with or without this protocol armed — the deliberate
checkpoint before a manual /compact. It replaces asking in prose for the
state to be persisted; it does not replace the cadence, which is what
protects against automatic compactions that arrive unannounced.
- Automatic re-injection ships on;
SESSION_WORKFLOW_ANCHOR_HOOKS=0 opts
out. A SessionStart hook on compact, resume, clear, and startup
re-injects the newest active anchor's HEAD (to the tail marker) into fresh
context mechanically — the re-read step stops depending on the model
remembering the protocol. Without session-start hooks, the manual re-read at
each turn start is the whole mechanism. Over budget, the HEAD is spent
top-down on whole sections and the dropped ones are named, so the survival
order above is a policy the author sets rather than wherever the bytes ran
out. An anchor marked done in-content is de-ranked below live tracks, and the
injection names any other open anchors; the rename to *.closed.md remains
the only signal that stops injection entirely. An anchor untouched for 24h
injects as a short pointer — path, title, age, close command, and the cursor
it still asserts, which is the part a reader can check against reality.
startup (crash restart) injects only an anchor updated within 6h.
Anchor-less sessions pay nothing.
- Cold start without the plugin surface — a session whose plugin snapshot
predates the skill, or a harness whose menu omits it, arms everything by hand:
references/cold-start.md has the full recipe (the anchor file by hand, manual
hook registration, a verify-by-piping step). Because that recipe is unreachable
exactly when the skill is absent, keep the compact minimal contract — anchor
path, the <!-- anchor:tail --> split, a cursor with a next action, the
.closed.md rename — in the CLAUDE.md protocol snippet, where a menu-less
session still has it.
Common failure modes
The seven recurring ones and what each costs: references/failure-modes.md.
Boundaries
The description names the three neighbours this is not. The discriminator worth
having in hand: a handoff is written once and read by someone else; an anchor is
rewritten continuously and read by the same run.
1---2name: compaction-survival3description: Maintain a persisted, re-readable control anchor so a long autonomous run survives context compaction without losing the plot — one file holding the mission, a plan pointer, a live cursor (done / in progress / next action), invariants, last-known-good state, and exact resume steps, updated after each step and re-read at the start of each turn. Use when starting or driving a multi-hour or multi-phase autonomous task, a self-driving loop, or any unattended run that will cross one or more automatic compactions or context-window resets; on asks like "make sure compaction doesn't lose the work", "keep state across auto-compact", "persist the current state so a reset doesn't disrupt this", "this is a long autonomous run", or "resume cleanly after a reset". The anchor is intra-actor state recovery — the same actor re-reading its own working state across a discontinuity. Not for handing work to a fresh context or a teammate (that is context-handoff's inter-actor brief), not for post-hoc capture of what a finished ses4---56# Compaction Survival78A long autonomous run loses most often to this — the context that9held the plan gets compacted or reset, and the next turn resumes from a summary10that dropped the load-bearing detail. The defense is an anchor on disk that the11run re-reads and rewrites as it goes, so the plan lives in a file, not only in12the context window.1314This is a **flexible** skill: the anchor's schema and update cadence adapt to15the task. What stays firm is small — the anchor is the single source of truth16for run state, re-read at the start of each turn and updated before the state17it describes can be lost.1819## The anchor2021One file, at a stable path the run can find again after a reset. It has two22tiers, split by a literal `<!-- anchor:tail -->` marker line: above it the live23**HEAD** — the only part the re-injection hook emits — and below it the24**TAIL**, which stays on disk. A marker-less anchor still injects whole, but25then a long run's live state is whatever the 8K bound keeps.2627HEAD — bounded, rewritten in place. **The order below is the survival order.**28The injection spends its budget top-down and drops whole trailing sections,29naming them, so a section's position is its priority and putting one above30another demotes that other.3132- **Mission** — the goal in a sentence or two, the hard constraints, and any33 user instruction that constrains *mechanism* rather than outcome, quoted in34 the user's own words with a stable id. Paraphrase is where an order dies:35 once the wording is gone a substituted mechanism reads as a design choice.36 A reversal of a standing rule is quoted the same way and names what it37 supersedes; the old rule lives in other copies and will not overwrite itself.38- **Cursor** — done / in progress / **next action on resume**: one imperative39 step plus the precondition to verify before it, rewritten in place as it40 mutates. An unanswered question or approval is armed here for verbatim41 re-ask after the reset. This is the part that earns the anchor.42- **Resume steps** — how a cold reader re-orients: read this file, check the43 real state (version control log, the artifact on disk), continue from the44 cursor. They run somewhere they were not authored, so write them in45 **absolute paths** — a relative command does not fail after a restart, it46 succeeds in the wrong place. Record the anchor's own absolute path where the47 environment surfaces it next turn: an anchor that cannot be found is no anchor.48- **Invariants** — decisions and constraints that hold across the whole run, so49 a post-compaction turn does not relitigate them.50- **Parallel tracks** — only when a peer run shares these trees: the other51 track's anchor path and this track's never-touch surface, written before any52 work. Disclose on every commit that touches shared surface, and route a53 cross-track lesson into both anchors.54- **In-flight work** — background or async tasks the cursor depends on: their55 ids, log paths, and a "do not relaunch over the same output" guard. A run that56 fans out to background work records them here as first-class cursor state, so57 each async boundary resumes idempotently instead of being re-derived.58- **Last-known-good** — the concrete recoverable state: commit hashes, branches59 and PRs opened, tags pushed, the files written, the checkpoint reached.60- **Plan pointer** — where the full plan lives (a separate doc), so the anchor61 stays a cursor, not a second copy of the plan.6263TAIL — append-only, read on demand:6465- **Decisions log** — why the non-obvious calls were made.66- **Folded history** — closed phases' one-line outcomes, resolved incidents.6768## The protocol69701. **Create the anchor at the start of the run**, before the first irreversible71 step, so there is something to resume from immediately. Arming is also the72 sweep moment — read `anchor_inject.py --list-dormant <anchors dir>` and close73 or adopt any track it names. It reaches what `close --stale` cannot: a track74 abandoned mid-cursor never marks itself done.752. **Update the cursor after each step or phase**, before moving on. State that76 lives only in the context window is one compaction away from gone; write it77 down while it is still true.783. **Re-read the anchor at the start of each turn** — especially when a summary79 has appeared or the context feels thinner than the work already done — the80 signs of a compaction. Re-read before acting, not after. A81 cursor is an Edit, so during tool outages it can lag reality by a phase; when82 it disagrees with durable state (the version-control log, run ledgers), trust83 the durable state.844. **Write atomically and keep one anchor.** Overwrite the single file rather85 than scattering state across several; a half-written or duplicated anchor is86 worse than a terse one.875. **Keep the HEAD bounded.** As a phase closes, fold its detail into a88 one-line outcome in the TAIL, below the marker — a closed phase's spec, and89 **the cursor's own done-list**, which is what actually accumulates.906. **Make resume idempotent.** The resume steps let a fresh context recover the91 run from the anchor and the real on-disk state alone; re-entering a92 half-finished step checks the artifact before redoing it, so re-reading is93 always safe. A stored recovery command (a ledger-count grep, a resume key)94 is validated against the live artifact before the run goes unattended —95 unchecked, it is a fabricated inference waiting to misfire.967. **Close by stubbing, then renaming.** When the run ends, rewrite the anchor97 to a minimal landed stub — status, a one-line outcome, resume: none — and98 rename it `<name>.closed.md`. The rename is the only close signal the hook99 honors: a prose "status: CLOSED" line does not stop re-injection, and a100 full-ledger close overflows the injection budget on the next session. Close101 at the moment the cycle ends; a track closed only in prose accumulates. And102 close on the *deliverable*, not the session: if the session carries on into103 new substantive work, arm the next anchor in the same breath — a closed104 anchor beside a live session is an uncovered window. At105 wind-down, `/anchor close --stale` sweeps the dir for anchors marked done106 in-content but never renamed and offers the exact rename for each.107108## Explicit surfaces109110- Invoked directly (`/compaction-survival`), arm the protocol now: create or111 refresh the anchor immediately from the current conversation state, then112 follow the update-and-re-read cadence for the rest of the run.113- **`/anchor`** (session-workflow command) is the one-off backstop: a single114 snapshot on demand, with or without this protocol armed — the deliberate115 checkpoint before a manual `/compact`. It replaces asking in prose for the116 state to be persisted; it does not replace the cadence, which is what117 protects against *automatic* compactions that arrive unannounced.118- **Automatic re-injection** ships on; `SESSION_WORKFLOW_ANCHOR_HOOKS=0` opts119 out. A SessionStart hook on `compact`, `resume`, `clear`, and `startup`120 re-injects the newest **active** anchor's HEAD (to the tail marker) into fresh121 context mechanically — the re-read step stops depending on the model122 remembering the protocol. Without session-start hooks, the manual re-read at123 each turn start is the whole mechanism. Over budget, the HEAD is spent124 top-down on whole sections and the dropped ones are named, so the survival125 order above is a policy the author sets rather than wherever the bytes ran126 out. An anchor marked done in-content is de-ranked below live tracks, and the127 injection names any other open anchors; the rename to `*.closed.md` remains128 the only signal that stops injection entirely. An anchor untouched for 24h129 injects as a short pointer — path, title, age, close command, and the cursor130 it still asserts, which is the part a reader can check against reality.131 `startup` (crash restart) injects only an anchor updated within 6h.132 Anchor-less sessions pay nothing.133- **Cold start without the plugin surface** — a session whose plugin snapshot134 predates the skill, or a harness whose menu omits it, arms everything by hand:135 `references/cold-start.md` has the full recipe (the anchor file by hand, manual136 hook registration, a verify-by-piping step). Because that recipe is unreachable137 exactly when the skill is absent, keep the compact minimal contract — anchor138 path, the `<!-- anchor:tail -->` split, a cursor with a next action, the139 `.closed.md` rename — in the CLAUDE.md protocol snippet, where a menu-less140 session still has it.141142## Common failure modes143144The seven recurring ones and what each costs: [`references/failure-modes.md`](references/failure-modes.md).145146## Boundaries147148The description names the three neighbours this is not. The discriminator worth149having in hand: a handoff is written once and read by someone else; an anchor is150rewritten continuously and read by the same run.