feat(state): keep long-run skill state on disk so compaction stops losing it - #76
Merged
Merged
Conversation
…sing it
A rig skill outlives its own transcript. `/rig-task` spans seven steps and
four delegated agents; `/rig-epic run` loops that over every child. Between
those steps the host agent's only memory is the conversation, so a compaction
mid-run drops the acceptance criteria, the failing assertion, and which review
findings are already fixed — and the agent re-derives them from git and gh, or
guesses.
`rig-epic` already worked around this with a hand-rolled `.rig/epics/*.json`
("replaces any external memory") — unvalidated, unschema'd, and used nowhere
else. This generalizes that one good idea into a primitive.
`scripts/rig-state.ts` keeps one small structured document per run under
`.rig/state/`, with an append-only journal beside it for humans debugging a
failed run. Updates are patches, merged and validated outside the model:
unknown keys, wrong types, undeclared phases, and impossible states are
rejected with the reason, leaving the state untouched for a retry. Size
budgets (500 chars per string, 50 items per array, 8 KB per document) are what
keep the state a state instead of a transcript by another name.
Guards make a document assert the gates the skills already describe in prose:
rig-task can't reach `pr-open` with a red suite or an open P1, rig-epic can't
reach `finish` with an unmerged child, rig-review can't call a round `clean`
while a finding is open.
rig-task, rig-epic, and rig-review now read and patch it; rig-epic's epic file
moves to `.rig/state/<integration-branch>.json`, so there's one mechanism
rather than two. rig-doctor checks `.rig/state/` is gitignored and reports
stale runs. Every state call is optional — with the script absent the skills
run as before.
This does not shorten the host agent's context; rig ships markdown procedures
and Claude Code and pi own their own loops. What changes is the cost of losing
the transcript.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MBaTgFSa8va6PTaFfuSRsz
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A rig skill outlives its own transcript.
/rig-taskspans seven steps and four delegated agents;/rig-epic runloops that over every child. Between those steps the host agent's only memory is the conversation, so a compaction mid-run drops the acceptance criteria, the failing assertion, and which review findings are already fixed. The agent then re-derives them fromgitandgh, or guesses.rig-epicalready worked around this with a hand-rolled.rig/epics/*.json— its own heading called it "replaces any external memory" — unvalidated, unschema'd, and used by exactly one skill. This generalizes that idea into a primitive, following the SKILL.state pattern (arXiv 2608.26263).What's here
scripts/rig-state.tskeeps one small structured document per run under.rig/state/, with an append-only journal beside it for humans debugging a failed run. Four rules, all enforced outside the model:nulldeletes, arrays replace wholesale.runId/skill/createdAtare set at init and unpatchable.rig-taskcan't reachpr-openwith a red suite or an open P1;rig-epiccan't reachfinishwith an unmerged child;rig-reviewcan't call a roundcleanwhile a finding is open.A rejected patch leaves the state untouched, prints the reason on stderr and the unchanged state on stdout — rollback-and-retry with no extra read.
rig-task,rig-epic, andrig-reviewread and patch it.rig-epic's epic file moves to.rig/state/<integration-branch>.json, so there's one mechanism rather than two;rig-doctorchecks.rig/state/is gitignored and reports stale runs. Every state call is optional — with the script absent the skills run exactly as before.What this does not do
It doesn't shorten the host agent's context. rig ships markdown procedures, and Claude Code and pi own their own loops. What changes is the cost of losing the transcript.
Test plan
bun test scripts/ tooling/— 161 pass, 46 new. Covers merge semantics, every rejection class, all eight guards, and the budgets.tsc --noEmitclean on the new files.finish-with-unmerged-child rejection fires; a full two-child epic's resumable state is 940 bytes.install.sh --target claude-codedeliversrig-state.tswith no test files leaked.scripts/check-style.tsagainsttemplates/STYLE.md.Not yet measured: whether this actually improves a real run. The honest test is a two-arm A/B — same ticket,
mainvs this branch,claude -p --autocompact 100kto force real compaction mid-run — scored on whether the resumed session re-runs work or re-asks a question already answered. Worth gating on the journal first: if the model skips the patch instructions, the mechanism is dead weight.Architecture
New script (
scripts/rig-state.ts) and one new state directory (.rig/state/). No new dependencies. It replacesrig-epic's ad-hoc.rig/epics/rather than adding a second mechanism beside it. Skill prose follows the<SCRIPTS>resolution convention #71 established.🤖 Generated with Claude Code
https://claude.ai/code/session_01MBaTgFSa8va6PTaFfuSRsz