This recipe runs a .jh workflow inside the Docker sandbox, picks the right workspace-presentation mode, and bypasses the confirmation prompt in CI.
For the design (what the sandbox protects against, what it does not), see Sandboxing. This page is the enabling procedure only.
docker info succeeds on the host..jh file with a default workflow.prompt — see Authenticate agent backends.jaiph run ./flow.jh
Docker is on by default. The CLI picks the workspace-presentation mode automatically:
/dev/fuse exists on the host (typically Linux). Reads come from the read-only host workspace; writes land in a fuse-overlayfs upper layer and are discarded at container exit./dev/fuse is missing (typically macOS Docker Desktop), or when JAIPH_DOCKER_NO_OVERLAY=1 or JAIPH_DOCKER_NO_OVERLAY=true is set. The CLI clones the workspace into .jaiph/runs/.sandbox-<id>/ (or <runs-root>/.sandbox-<id>/ when JAIPH_RUNS_DIR overrides the default) and mounts the clone read-write.In both modes the host checkout is unmodified after the run. Run artifacts always land under host .jaiph/runs/ via a separate read-write mount.
When you want the run’s edits to land live on the host (typical for an agent-driven dev loop), opt in to inplace mode:
jaiph run --inplace ./flow.jh
or set the environment variable (1 or true):
JAIPH_INPLACE=1 jaiph run ./flow.jh
The --inplace flag normalizes into JAIPH_INPLACE=1 for one run only. The container’s other protections (--cap-drop ALL, --security-opt no-new-privileges, env allowlist, mount allowlist) are unchanged — only the workspace-isolation half is removed.
Before launch the CLI prints a warning tailored to your git state (clean tree → git restore . recovers; dirty tree → commit/stash first; no repo → no safety net) and waits for y. The default answer on empty input or EOF is no.
When stdout is not a TTY (typical in CI), the inplace prompt cannot run interactively. Pass -y / --yes with --inplace, or set JAIPH_INPLACE_YES=1 or JAIPH_INPLACE_YES=true:
jaiph run --inplace --yes ./flow.jh
JAIPH_INPLACE=1 JAIPH_INPLACE_YES=1 jaiph run ./flow.jh
Without one of these in a non-TTY environment, the run aborts with E_DOCKER_INPLACE_NO_CONFIRM before any container is launched.
jaiph run --unsafe ./flow.jh
or:
JAIPH_UNSAFE=true jaiph run ./flow.jh
This disables Docker entirely; the workflow runs on the host. Combining --unsafe with --inplace is rejected with E_FLAG_CONFLICT before any container starts (one keeps the sandbox on, the other turns it off).
The CLI banner reports the sandbox mode it picked:
Docker sandbox, fusefs — overlay mode.Docker sandbox, tmp workspace — copy mode.Docker sandbox, in-place (live host edits) — inplace mode.no sandbox — --unsafe / JAIPH_UNSAFE=true is active (Docker disabled).Run artifacts always land under host .jaiph/runs/<date>/<time>-<entry>/ regardless of mode. Open run_summary.jsonl there to inspect the live __JAIPH_EVENT__ timeline the CLI also rendered.
docker run invocation.