Session Keep and Resume
Status: Partially implemented — shipped baseline covers dirty/unsafe exit assessment with a rich exit dialog (return/keep/discard) and an optional file-level Inspect surface, durable per-instance host state, the "Unfinished jackin instances" restore picker, launch-recipe identity pins (role SHA, base image ref/digest, image tag), stopped-container docker start reconnect paths, and purge/prune machinery (terminal-status pruning, orphan-lock reaping, stale-active reconciliation). Remaining work is a "keep to resume" outcome for clean sessions, extending the per-workspace exit policy to clean exits, faithful recreate/rebuild tiers with full launch-recipe replay, socket-dir/sidecar rematerialization for the stopped-container restore path, launch-time index reconciliation (including the failed_setup mislabel after a host-level kill), and continuity-framed resume UX (Phase 2 — Live operator surface, Agent Orchestration Program).
Shipped facts
A clean container exit already runs a real assessment: crates/jackin-isolation/src/finalize.rs checks every isolated worktree/clone mount for uncommitted changes or unpushed commits, auto-deletes anything provably safe, and — when something is dirty/unpushed and the terminal is interactive — shows a rich exit dialog (Return to agent / Exit and keep / Exit and clean up) with an I-key Inspect surface that renders the full per-file diff for each preserved mount, not just a count. A per-workspace dirty_exit_policy config field (ask / keep / discard, versioned since config schema v1alpha8) already lets an operator skip the prompt entirely for dirty/unpushed exits.
Durable per-instance host state already survives docker rm: ~/.jackin/data/<container>/ holds the manifest, isolation records, every agent runtime's home (including plugins and auth slots), and the materialized worktree/clone trees. resolve_restore_candidate() in crates/jackin-runtime/src/runtime/launch.rs already presents a restore picker (currently labelled "Unfinished jackin instances") for Crashed / PreservedDirty / PreservedUnpushed / RestoreAvailable / FailedSetup instances, and start_or_reconnect_capsule_client in crates/jackin-runtime/src/runtime/attach.rs already calls docker start to reconnect a stopped-but-present container, used by both the hardline-attach path and the launch pipeline's StartCurrentRole restore resolution. The manifest also already carries launch-recipe identity fields — image_tag, role_git_sha, base_image_ref, base_image_digest, role_source_git/role_source_ref, and DockerResources — and the Tier 3 rebuild path already threads the pinned role SHA through when recreating a container whose image is gone.
The mirror-image cleanup path has also shipped: crates/jackin-runtime/src/runtime/cleanup.rs routes terminal statuses (CleanExited, Superseded, FailedSetup, Purged) through purge_container_filesystem (data dir, socket dir, sibling lock file) and InstanceIndex::remove_many, and prune_instances reconciles stale active rows whose container no longer exists down to Crashed and reaps orphaned name-claim lock files. None of this runs automatically from the live exit/launch flow yet — it is all reachable only through the manual jackin prune instances command today.
A detailed design write-up — problem narrative, TUI mockups for the exit/resume screens, the full restore-tier ladder, the launch-recipe field table, and the audited findings this status line summarizes — lives in Session Keep and Resume Design.
Remaining work
- A "keep to resume" outcome for clean sessions.
finalize_clean_exitreturnsCleanedimmediately whenever no mount is dirty/unpushed — this happens even underdirty_exit_policy = keep, since that policy is only consulted after the dirty/unpushed check.CleanExitedalso is not a restore candidate (is_restore_candidate()excludes it). A clean session has no way to say "keep this for tomorrow." - Extend the exit policy to clean exits, not just dirty ones. The existing
dirty_exit_policyfield (ask/keep/discard) is the natural home for the proposedask/keep/cleanper-workspace policy — reuse it rather than adding a parallel setting. Whether this needs a new config schema version (new variant, new field) or is a pure behavior change to the already-migrated field needs to be settled before implementation. - Continuity-framed restore UX. Reframe the restore picker from "Unfinished jackin instances" to a resume/continuity framing, and include kept-clean instances alongside dirty/unpushed ones.
- Full launch-recipe replay for recreate/rebuild tiers. The manifest stores role SHA and base image ref/digest, but the mount plan, env-var names + source refs, and Docker run shape are not yet captured or replayed on Tier 2/3 restore — those tiers still re-resolve from current config instead of the launch-time snapshot.
- Socket-dir and sidecar rematerialization for the stopped-container restore path.
start_or_reconnect_capsule_clientcallsdocker startbut never re-writes/jackin/run/agent.tomlinto the socket dir or re-checks-dindsidecar health first — only a freshdocker runcurrently writesagent.toml. - Launch-time index reconciliation. The stale-
active-row reconciliation inprune_instancesneeds to also run on launch/console flows, not only the manual prune command, so restore decisions are made against accurate state. - Honest status for host-level kills. A daemon/VM crash currently mislabels every killed session
failed_setup; there is no distinct status for "killed by host" versus "setup actually failed." - Unpushed-branch detail and a required acknowledge step. The exit dialog's Inspect surface already shows full file diffs; it still doesn't surface the unpushed branch name/ahead-count, and reviewing it is optional rather than required before Keep/Discard.
- Clone-specific assessment tests and cleanup.
force_cleanup_cloneisrm -rfonly, and the dirty/unpushed assessment path has no clone-specific test coverage alongside the worktree tests. - In-place bind sessions. A session with a direct host bind (no worktree/clone isolation) still orphans its home on clean exit; the exit/resume flow needs a "skip mount verification, still keep-to-resume the home" path for this class.
- Stale doc reference.
finalize.rscites aworktree-cleanup-assessment.mdxthat does not exist; fold the cited policy table into a real doc and fix the reference. - Operator docs. Once the above lands, document the resume flow in operator-facing guides without leaking internal paths or Rust names.
Out of scope
- The immutable-snapshot / undo-to-pre-launch-state model — that is the opposite direction, tracked separately in Session snapshot and rollback.
- In-container agent session log resumption (e.g.
claude --resumeafter a Tier 2/3 rebuild) — overlaps Console agent session control Phase 4 and should be scoped there.
Related work
- Session Keep and Resume Design — full design notes, TUI mockups, restore-tier ladder, and audit findings.
- Launch Progress TUI — the rich surface the exit cockpit and resume picker render into.
- Console agent session control — instance discovery and the selection surface; Phase 4 session reconciliation is the in-container continuity counterpart.
- Session snapshot and rollback — the orthogonal direction: undo a session back to its pre-launch host state, where this item resumes a session forward to continue it.
- Déjà Vu — the backstop for "never lose valuable context": even when a session is unrecoverable, the cross-agent conversation archive survives instance teardown.
- Runtime Instance Model — the per-instance host layout this item rebinds on resume.