Infrastructure

Runtime Restore and Image Architecture

Status: Partially implemented — image bake, home seeding, container identity, the restore ladder, schema migration, console instance surfaces, launch cockpit hard-exit, build-performance work, and the in-capsule dirty-exit flow (shared detection, the exit modal, host keep/discard execution) have all landed in code; only operator live end-to-end signoff and the Inspect diff pane remain.

Shipped facts

The dirty-exit decision now lives entirely in-container instead of on the host after the container has already exited. jackin-core's worktree_dirty module (assess_worktree, WorktreeState, ChangedFile, parse_porcelain) is the single source of truth for "clean vs dirty vs unpushed"; host assess_cleanup in crates/jackin-isolation/src/finalize.rs is a thin wrapper over it, and the capsule daemon runs the same function in-container against its workdir at last-session-close. When the last session exits dirty, handle_last_session_exit() / decide_exit() in crates/jackin-capsule/src/daemon.rs push the Dialog::ExitDirty modal (per-repo N changed · N unpushed summary lines, four rows: start a new agent, inspect changes, exit & keep, exit & discard) defined in crates/jackin-capsule/src/tui/components/dialog.rs; Esc is ignored (forced choice) and Ctrl+Q maps to Exit & keep. "Inspect changes" opens Dialog::ExitInspect, a read-only changed-file list grouped by repo. The capsule writes the chosen action to /jackin/state/exit-action.json; the host reads it via ExitActionPrompt in crates/jackin-isolation/src/finalize.rs (keep -> preserve, discard -> terminal cleanup, absent -> keep) at both finalize call sites in crates/jackin-runtime/src/runtime/launch.rs and crates/jackin-runtime/src/runtime/attach.rs, both of which now run finalize on a clean-exit non-zero docker exec result instead of short-circuiting it. Schema v1alpha8 carries the dirty_exit_policy config (global + per-workspace: ask / keep / discard).

The rest of the feature set named in the status line — image bake, home seeding, container identity, the restore ladder, and console instance surfaces — is implemented and documented as steady-state behavior in Runtime Instance Model, Construct Image: User Creation Responsibility, Image Labels & Recipe Hash, and Capsule Session Lifecycle. This item stopped tracking that work as design-in-progress once it landed; what remains here is signoff, not design.

Design rationale, the alternatives considered for the host signal (file vs. exit code vs. control frame), and the agreed TUI mockup for the exit modal are captured in In-Capsule Dirty-Exit: Design Rationale and Implementation Record.

Remaining work

  1. Inspect diff pane. Dialog::ExitInspect ships the changed-file list only; the side-by-side per-file diff pane is still a follow-up.
  2. Cross-screen double-Ctrl+C escape. The ExitDirty modal currently consumes Ctrl+C like any other key; the cross-screen double-Ctrl+C immediate-exit guarantee does not yet reach this modal. Tracked as a separate capsule-global concern, not a blocker for the keyboard-driven modal.
  3. Operator live signoff. CI passing does not substitute for a manual pass. Needs a live confirmation covering: the full dirty-exit flow (modal appears, each of the four rows behaves as designed, a clean exit shows no modal, keep/discard policies skip the modal); image-baked binaries/plugins/default home and the rebuild-on-agent-version-change trigger; home seeding and first-seed auth handoff; arbitrary-UID/GID container identity (libnss-extrausers, group-0 writability, first seed, git config --global, role-hook tool installs); all three restore-ladder tiers (docker start, image reuse, pinned rebuild from role_git_sha); the v1alpha8 migration chain and dirty_exit_policy resolution; console instance surfaces and stale-row/orphaned-lock reconciliation; launch cockpit hard-exit (Ctrl+Q, Ctrl+C, double-Ctrl+C mid-build) with gc_orphaned_resources reclaiming abandoned resources; and the image-build performance changes (no recursive permission repair, single-layer plugin install, uncompressed local export, shellfirm prebuild).

On this page