# jackin-exec: Secure Execution Wrapper (https://jackin.tailrocks.com/roadmap/jackin-exec/)



**Status**: Partially implemented — the full mechanism is wired and shipped end to end (config schema, dispatch, picker, host.sock resolution, MCP tool). Linux `host.sock` callers are now authenticated with peer credentials so direct agent-side socket calls cannot bypass the picker; non-Linux/Docker Desktop coverage remains with the future daemon track. One credential-materialization gap remains, and the flow has not had a live smoke pass through `jackin load`.

## Shipped facts [#shipped-facts]

`jackin-exec` is a subcommand of `jackin-capsule`, invoked either as `jackin-exec <command> [args...]` (argv0 dispatch) or `jackin-capsule exec <command>`. The `on_demand` flag on `EnvValue` (`EnvValue::Extended` plus `OpRef.on_demand` in <RepoFile path="crates/jackin-core/src/env_value.rs" />) marks env vars that are never resolved or injected at container launch — <RepoFile path="crates/jackin-env/src/resolve.rs" /> filters them out before `docker run`, and the workspace migration chain carries the schema at `v1alpha8` with fixtures through `from-v1alpha7`. Launch injects `JACKIN_EXEC_BINDINGS` (the on-demand var names, not values) as an always-available env var, which drives both an entrypoint system-prompt block and the `jackin_exec` MCP tool (<RepoFile path="crates/jackin-capsule/src/mcp_server.rs" />, registered from <RepoFile path="crates/jackin-capsule/src/runtime_setup.rs" /> whenever bindings are non-empty).

`Dialog::ExecPicker` is wired end to end in the daemon: an `ExecCommand` control message opens the picker (built from the workspace's on-demand bindings), the reply is deferred while the operator toggles credentials (Space) and confirms (Enter) or cancels (Esc). On confirm, the daemon resolves the selected credentials through `host.sock`, runs the command with them injected on the `CommandBuilder`, redacts the output, and replies `ExecResult`; on cancel or any resolver/spawn error it replies `ExecDenied` and runs nothing — fail-closed at the daemon dispatch path. The picker state machine and selection/confirm dispatch are unit-tested (<RepoFile path="crates/jackin-capsule/src/exec/tests.rs">crates/jackin-capsule/src/exec/tests.rs</RepoFile>, <RepoFile path="crates/jackin-capsule/src/daemon/tests.rs">crates/jackin-capsule/src/daemon/tests.rs</RepoFile>).

`host.sock` (started by the launch path, bind-mounted to `/jackin/run/host.sock`) enforces an allow-list — it resolves only the operator-*configured* on-demand bindings, never arbitrary refs. On Linux it also authenticates the caller with `UnixStream::peer_cred` and accepts only the capsule daemon container-init peer, so a direct in-container process cannot resolve configured credentials without going through the picker. Non-Linux hosts and Docker Desktop socket-bridging remain residual until the daemon-based host bridge replaces this ad-hoc listener. See [jackin-exec design record](/reference/research/security/credential-exposure/jackin-exec-design/) for the full protocol, type changes, and phased implementation history.

## Remaining work [#remaining-work]

1. Live smoke of the picker/render/keystroke path through `jackin load` — no integration or e2e coverage exists yet, only unit tests of the state machine.
2. Extend caller authentication beyond Linux same-kernel `SO_PEERCRED`, or retire the gap by moving resolution into the future jackin❯ daemon / host bridge.
3. Temp-file materialization for key-type credentials — write an SSH private key to `/jackin/run/secrets/<uuid>` and set `SSH_KEY_FILE`, deleting after exit. Today an SSH key resolves as a raw `SSH_KEY=<pem>` env var, which `ssh` cannot consume directly.

## Related work [#related-work]

* [jackin-exec design record](/reference/research/security/credential-exposure/jackin-exec-design/) — full protocol, Rust type changes, picker/host.sock design, and implementation-phase history
* [Agent isolation architecture](/reference/research/security/isolation-architecture/agent-isolation-architecture/) — master architecture doc; jackin-exec is Layer 3
* [Container credential exposure](/reference/research/security/credential-exposure/container-credential-exposure/) — the problem this item solves
* [jackin❯ daemon](/roadmap/jackin-daemon/) — future: daemon replaces the Phase 1 ad-hoc host.sock listener
* [Host bridge — secrets and approved host actions](/roadmap/host-bridge/) — future daemon-based credential resolution that retires host.sock
* [Process-level sandboxing](/reference/research/security/process-sandboxing/process-level-sandboxing/) — complementary — zerobox handles per-operation filesystem/network policy
* [Apple Container backend](/roadmap/apple-container-backend/) — jackin-exec works on any backend
* [Session contract and explain mode](/roadmap/session-contract-explain-mode/) — jackin-exec calls and picker selections should appear in session contract output
