Deploy jaiph in your own image or pod

Jaiph executes programs on the host. It does not ship a Docker sandbox driver. Isolation is an outer concern: wrap jaiph in a container, a Kubernetes pod, a CI runner, or another sandbox you already operate.

Each release publishes a lean runner image to GHCR: ghcr.io/jaiphlang/jaiph-runtime (:<version>, :v<version>, and :latest on a stable tag; :nightly on the rolling nightly). It has jaiph, python3, git, and curl on PATH, running as uid 10001. It is not a sandbox and not a toolchain image. Layer agent CLIs (claude, cursor-agent, codex) and any script dependencies yourself. From a clone, ./docs/build-jaiph-dev-image.sh builds the same image locally (docs/install-from-local.sh does not).

A complete, apply-ready Kubernetes example lives at docs/deploy/k8s.yaml. The example uses the published image. Pin a version tag in production.

Isolation is yours

jaiph run, jaiph serve, and jaiph mcp execute as ordinary host processes. They do not drop capabilities, clone a workspace snapshot, or filter the environment into a sandbox allowlist. Sterile script env, the prompt scrub, use, and --env only shape the env of each child process. They do not isolate a tool-using agent from the rest of that user — see Why Jaiph.

Dedicated user or container

The curl installer writes ~/.local/bin and does not create a system user. jaiph run on a laptop is your user. A coding-agent prompt is that same user.

To keep Jaiph off the rest of your session, run the whole process — CLI, runner, scripts, and agent — as an account that does not own your other terminals, browser, or $HOME. Create that account yourself. Options:

That account still needs only the keys the program uses (backend credentials, --env grants). Do not copy your login environment into it.

This isolates Jaiph from you. It does not isolate the agent from a script in the same run: they share that account. A token granted for gh push is still visible to a live agent that can run a shell. For that split, use two invocations — implement with no token, then a scripts-only run that grants it — or do not start a prompt next to the privileged script.

Run one program in a container you own

Mount your working directory and run the CLI as the container command. The published image has jaiph on PATH; add the agent CLI your program uses if the entry file has a prompt step:

# claude backend (Anthropic) — image must also have `claude` on PATH
docker run --rm -e ANTHROPIC_API_KEY -v "$PWD":/work -w /work \
  ghcr.io/jaiphlang/jaiph-runtime:latest jaiph run flow.jh

The credential env var depends on the backend the entry file selects:

# cursor backend
docker run --rm -e CURSOR_API_KEY -v "$PWD":/work -w /work \
  ghcr.io/jaiphlang/jaiph-runtime:latest jaiph run flow.jh

# codex backend (OpenAI HTTP API)
docker run --rm -e OPENAI_API_KEY -v "$PWD":/work -w /work \
  ghcr.io/jaiphlang/jaiph-runtime:latest jaiph run flow.jh

-e ANTHROPIC_API_KEY with no =value forwards the value from your shell environment. The claude backend also accepts CLAUDE_CODE_OAUTH_TOKEN in place of ANTHROPIC_API_KEY. A program with no prompt step needs no credential at all. Run artifacts land under /work/.jaiph/runs/ when /work is your bind-mounted directory.

In CI

Jaiph already runs headless on a standard Linux runner. Install the CLI (docs/install or docs/install-from-local.sh), install any agent CLI your programs need, and run jaiph run flow.jh. A GitHub-hosted Linux runner is itself a virtual machine; that outer boundary is the sandbox.

Use a container image when you want a preinstalled toolchain. Fit the one-shot docker run above into any CI step:

- name: Run jaiph
  run: |
    docker run --rm -e ANTHROPIC_API_KEY -v "$PWD":/work -w /work \
      ghcr.io/jaiphlang/jaiph-runtime:latest jaiph run flow.jh

Kubernetes

Create the jaiph-credentials Secret out-of-band first, then apply the example manifest. Pin image: to a version tag before production apply:

kubectl create secret generic jaiph-credentials \
  --from-literal=JAIPH_SERVE_TOKEN="$(openssl rand -hex 32)" \
  --from-literal=ANTHROPIC_API_KEY="sk-ant-..."   # only the backend key(s) your programs use
kubectl apply -f docs/deploy/k8s.yaml

The Deployment references the Secret as a required envFrom, so a missing Secret holds the pod in CreateContainerConfigError instead of ever starting an unauthenticated runner.

The manifest runs jaiph serve --host 0.0.0.0 as a long-lived HTTP runner (see Serve defs over HTTP), with JAIPH_SERVE_TOKEN sourced from the Secret and liveness and readiness probes on GET /healthz, which stays open and needs no bearer token. The same Service port serves both the REST and OpenAPI API and MCP Streamable HTTP at POST /mcp. The example sets:

Isolation is the pod boundary. There is no jaiph-managed sandbox inside.