Agent OrchestrationFleet phase 2 — Live operator surface

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

  1. A "keep to resume" outcome for clean sessions. finalize_clean_exit returns Cleaned immediately whenever no mount is dirty/unpushed — this happens even under dirty_exit_policy = keep, since that policy is only consulted after the dirty/unpushed check. CleanExited also is not a restore candidate (is_restore_candidate() excludes it). A clean session has no way to say "keep this for tomorrow."
  2. Extend the exit policy to clean exits, not just dirty ones. The existing dirty_exit_policy field (ask/keep/discard) is the natural home for the proposed ask/keep/clean per-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.
  3. 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.
  4. 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.
  5. Socket-dir and sidecar rematerialization for the stopped-container restore path. start_or_reconnect_capsule_client calls docker start but never re-writes /jackin/run/agent.toml into the socket dir or re-checks -dind sidecar health first — only a fresh docker run currently writes agent.toml.
  6. Launch-time index reconciliation. The stale-active-row reconciliation in prune_instances needs to also run on launch/console flows, not only the manual prune command, so restore decisions are made against accurate state.
  7. 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."
  8. 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.
  9. Clone-specific assessment tests and cleanup. force_cleanup_clone is rm -rf only, and the dirty/unpushed assessment path has no clone-specific test coverage alongside the worktree tests.
  10. 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.
  11. Stale doc reference. finalize.rs cites a worktree-cleanup-assessment.mdx that does not exist; fold the cited policy table into a real doc and fix the reference.
  12. 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 --resume after a Tier 2/3 rebuild) — overlaps Console agent session control Phase 4 and should be scoped there.
  • 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.

On this page