feat(state): clean up per-bottle state on session end (except capability-block) #26
Reference in New Issue
Block a user
Delete Branch "state-cleanup-on-close"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Every bottle launch was leaving
~/.claude-bottle/state/<identity>/behind forever — metadata.json on every run, plus per-bottle Dockerfile + transcript snapshot on capability-block rebuilds. The metadata accumulated debris; the only state actually worth keeping was the capability-block rebuild bundle.Make cleanup the default; preserve only on capability-block.
Mechanism: a
.preservemarker file.capability_apply.apply_capability_changewrites the marker before teardown.cli.pyrunsis_preserved(identity)after the launch context closes — if true, prints theresume <identity>hint; if false,rm -rfthe state dir.prepare.pyclears any leftover marker at launch so a stale marker from a prior capability-block doesn't keep state alive past the next normal session-end.The resume hint also moves out of the launch with-block (where it was printed unconditionally) — operator now sees it only when state was actually kept.
What's preserved when
exit)cli.pycli.py resumeExtends the preserve-on-capability-block design to also preserve state on agent crash, and snapshots the transcript on every teardown so any resume (crash or capability-block) gets a warm claude session — not a cold start. - capability_apply: rename _snapshot_transcript → snapshot_transcript (public; reused below). No behavior change in the capability path. - cli/start.py: capture bottle.exec_claude's exit code; while the container is still alive (inside the launch context): * always snapshot_transcript(identity) * if exit_code != 0, mark_preserved(identity) Then the existing _settle_state runs after teardown. Now the preservation matrix is: exit 0 (clean) → snapshot + cleanup state exit ≠0 (crash, Ctrl-C) → snapshot + preserve + show resume hint capability-block → (already snapshotted/preserved by apply before teardown; this path is a no-op because the container is already gone by the time exec_claude returns) snapshot_transcript is best-effort — capability-block's earlier snapshot is not clobbered when the container is already torn down, and a missing /home/node/.claude is a warn + skip. Tested behavior: clean exit doesn't preserve, non-zero exit (including SIGINT/130 and SIGKILL/137) preserves; empty identity no-ops both helpers. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>