# Runtime Restore and Image Architecture (https://jackin.tailrocks.com/roadmap/instant-launch-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 [#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 <RepoFile path="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 <RepoFile path="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 <RepoFile path="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 <RepoFile path="crates/jackin-isolation/src/finalize.rs" /> (keep -> preserve, discard -> terminal cleanup, absent -> keep) at both finalize call sites in <RepoFile path="crates/jackin-runtime/src/runtime/launch.rs" /> and <RepoFile path="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](/reference/runtime/runtime-instance-model/), [Construct Image: User Creation Responsibility](/reference/runtime/user-identity/), [Image Labels & Recipe Hash](/reference/runtime/image-labels/), and [Capsule Session Lifecycle](/reference/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](/reference/research/runtime/in-capsule-dirty-exit-design/).

## Remaining work [#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).

## Related work [#related-work]

* Research: [In-Capsule Dirty-Exit: Design Rationale and Implementation Record](/reference/research/runtime/in-capsule-dirty-exit-design/)
* [Runtime Instance Model](/reference/runtime/runtime-instance-model/)
* [Construct Image: User Creation Responsibility](/reference/runtime/user-identity/)
* [Image Labels & Recipe Hash](/reference/runtime/image-labels/)
* [Capsule Session Lifecycle](/reference/capsule/session-lifecycle/)
* <RepoFile path="crates/jackin-core/src/worktree_dirty.rs" /> — shared detection.
* <RepoFile path="crates/jackin-capsule/src/daemon.rs" /> — multiplexer daemon; the `no_live_sessions()` last-session-close branch is the in-capsule hinge.
* <RepoFile path="crates/jackin-capsule/src/tui/components/dialog.rs" /> — capsule dialog system, `ExitDirty` / `ExitInspect`, and `new_agent_picker` reused for "Start a new agent".
* <RepoFile path="crates/jackin-isolation/src/finalize.rs" /> — host `assess_cleanup` wrapper and `ExitActionPrompt` keep/discard execution.
* <RepoFile path="crates/jackin-runtime/src/runtime/launch.rs" /> — `launch_role_runtime` load path that runs finalize on clean exit.
* <RepoFile path="crates/jackin-runtime/src/runtime/attach.rs" /> — hardline reconnect path that no longer short-circuits finalize on clean exit.
