Cookbook

Task-oriented command shapes for ProcessKit CLI. Each recipe keeps the JSONL destination explicit and places the child after --, so the boundary between runner options and child argv remains visible.

For copyable scripts exercised on Linux and Windows in CI, see the runnable examples.

Run a command and preserve its exit code

processkit-cli run --jsonl run.jsonl -- cargo test

For a foreground run, the CLI exits with the child's exact code after tearing down the contained tree. Runner-owned failures and cancellations use the reserved band; read Exit-code contract when the caller must distinguish them from a child that returned the same number.

Run in another directory

processkit-cli run \
  --cwd ./services/catalog \
  --jsonl catalog-test.jsonl \
  -- cargo test --locked

run_started.cwd records the resolved absolute directory.

Start from a controlled environment

processkit-cli run \
  --env-clear \
  --env PATH=/usr/bin:/bin \
  --env HOME=/tmp/worker-home \
  --env CI=true \
  --jsonl hermetic.jsonl \
  -- worker

Use absolute program paths when clearing PATH entirely. Applied order is clear → remove → set.

Remove one inherited secret

processkit-cli run \
  --env-remove GITHUB_TOKEN \
  --env-remove AWS_SECRET_ACCESS_KEY \
  --jsonl sanitized.jsonl \
  -- third-party-tool

Environment values are not placed in JSONL, but the child can still echo them.

Capture output without echoing it live

processkit-cli run \
  --no-echo \
  --capture-dir ./capture \
  --capture-max-bytes 16m \
  --jsonl captured.jsonl \
  -- noisy-build

Read output_captured.truncated before treating either file as complete.

Feed a finite input file

processkit-cli run \
  --stdin-file request.json \
  --capture-dir ./response \
  --jsonl request-run.jsonl \
  -- json-transform

The file closes the child's stdin at EOF and its bytes never enter argv.

Run an interactive terminal program

processkit-cli run --inherit-stdio --jsonl interactive.jsonl -- repl-tool

The child sees the caller's existing terminal. Capture, no-echo, idle timeout, detach, and --create-no-window are unavailable in this mode. This preserves a terminal; it does not create a PTY.

Bound total runtime

processkit-cli run \
  --timeout 15m \
  --grace 10s \
  --jsonl timed.jsonl \
  -- integration-tests

Expiry emits timeout with reason: "overall", then the cleanup sequence and terminal runner_exit.

Kill a worker that stops producing output

processkit-cli run \
  --idle-timeout 2m \
  --grace 5s \
  --jsonl worker.jsonl \
  -- build-worker

Every observed stdout/stderr chunk re-arms the idle clock. Use only for tools whose silence is a meaningful health signal.

Give no soft-stop grace

processkit-cli run --timeout 30s --grace 0 --jsonl fast.jsonl -- disposable-task

0 is legal for grace and means immediate progression to the hard tier. It is rejected for overall, idle, and wait deadlines.

Launch out of band and supervise later

processkit-cli run \
  --detach \
  --run-id nightly-build \
  --capture-dir ./nightly-output \
  --jsonl nightly.jsonl \
  -- cargo build --release

processkit-cli inspect --run-id nightly-build
processkit-cli wait --run-id nightly-build --timeout 30m

The detached launcher's 0 means “started.” Read terminal JSONL for the child's eventual result.

Inspect a live tree as JSON

processkit-cli inspect --run-id nightly-build --json

The snapshot includes the mechanism, root pid, start time, and current members with nullable enriched fields. It is an observation at request time, not a durable history.

Ask one run to stop cooperatively

processkit-cli cancel --run-id nightly-build
processkit-cli wait --run-id nightly-build --timeout 30s

cancel acknowledges the request; wait is the completion barrier.

Hard-kill one run now

processkit-cli kill --run-id wedged-worker
processkit-cli wait --run-id wedged-worker --timeout 10s

This skips soft stop and grace and produces a distinct killed outcome.

Shut down every currently live run

processkit-cli cancel --all
processkit-cli wait --all --timeout 30s
processkit-cli prune --dry-run
processkit-cli prune

Both --all operations use their own snapshots. Prevent new launches during a global shutdown or repeat the sequence to catch later registrations.

Discover runs without knowing their ids

processkit-cli list
processkit-cli list --json
processkit-cli list --label pipeline=ci --health live

The human table abbreviates argv_sha256; JSON Lines carry the full digest. live, stale, and unprobed are intentionally distinct health states. Label filters are exact and conjunctive, matching the aggregate control commands. New records also expose absolute jsonl and optional capture_dir locators, so a supervisor discovering a detached run can open its artifacts without launch-time state.

Preview stale-record cleanup

processkit-cli prune --dry-run --json

Only entries whose liveness probe succeeded and reported stale appear as candidates. unprobed entries are preserved.

Verify a runner before using it

processkit-cli probe --json \
  --require-schema-version 1 \
  --require-exit-code-band 100-119 \
  --require-surface run:--capture-dir \
  --require-surface cancel:--all \
  --require-surface wait:--all

Exit 110 means the binary is incompatible with at least one requirement. No child or registry entry is created.

Export the exact event schema

processkit-cli probe --json --print-schema > processkit-cli.schema.json

This prints the schema embedded in that exact binary, which is useful when the consumer has an installed executable but no matching git checkout.

Require whole-tree resource caps

processkit-cli run \
  --max-memory 2g \
  --max-processes 64 \
  --cpu-quota 2 \
  --jsonl limited.jsonl \
  -- untrusted-compiler

Unsupported enforcement fails before spawn with limit_hit; it never runs the child without the requested policy. See Resource limits before using this in Linux containers or systemd.

Hide a detached Windows console

processkit-cli run --detach --create-no-window `
  --run-id headless-worker `
  --jsonl headless.jsonl `
  -- worker.exe

Use this only for a child that does not require a console. The runner never forces CREATE_NO_WINDOW by default.

Invoke a shell explicitly

processkit-cli run --jsonl shell.jsonl -- sh -c 'make all && make test'
processkit-cli run --jsonl shell.jsonl -- `
  pwsh -NoProfile -Command 'Get-ChildItem Env: | Sort-Object Name'

The shell is now an explicit child program. Its quoting, expansion, and pipeline semantics are outside ProcessKit CLI.

Keep child stdout machine-clean

processkit-cli run --jsonl events.jsonl -- report-generator > report.bin

JSONL never goes to stdout. Runner diagnostics use stderr, and child stderr is also forwarded there. Use --no-echo --capture-dir when stdout must not be forwarded at all.

Read a run's lifecycle events

processkit-cli events --run-id build-42            # what happened, rendered
processkit-cli events --run-id build-42 --follow   # ... as it happens
processkit-cli events --file build-42.jsonl        # once the record is gone
processkit-cli events --file build-42.jsonl --json # raw lines, for a parser

events is read-only: it resolves the stream through the registry (--run-id) or reads a path directly (--file), never contacts the run, and mutates nothing. It hands out only complete lines, and --follow stops at the terminal runner_exit — or, for a runner killed before it could write one, once the run is gone and the stream has stopped growing.

Check a stream against the event schema

processkit-cli events --file fixture.jsonl --validate

Checks every line against the schema embedded in that exact binary and reports each violation by line number; exit 0 when all lines conform, 114 (EVENTS_INVALID) when any does not. Useful in CI for an adapter's own recorded fixtures — no separate validator, and no second copy of the schema to keep in sync.

Tail lifecycle events safely in your own reader

When something other than events reads the stream, treat JSONL as an append-only sequence of complete lines. A reader should:

  1. buffer until newline;
  2. parse one object;
  3. verify schema_version;
  4. dispatch on the event discriminator, tolerating unknown event types, unknown fields, new always-present fields on an event it already parses, and repeats of an event type that previously occurred only once (see Compatibility and upgrades);
  5. stop only after terminal runner_exit or an explicit external recovery decision.

The file may end with a partial line if the runner is killed during a write. Do not parse that suffix as a complete event.

Recover after the supervising application restarts

processkit-cli list --json
processkit-cli inspect --run-id recovered-run --json
processkit-cli wait --run-id recovered-run --timeout 30s

Use the registry for current liveness and the JSONL file for durable history. Never reconnect by recorded PID.

Give an automation agent a bounded execution policy

Instruct the agent to launch external tools through a foreground runner with a unique run id, finite deadlines, lifecycle JSONL, and bounded capture:

mkdir -p .agent-runs/agent-task-42
processkit-cli run --run-id agent-task-42 \
  --timeout 20m --idle-timeout 3m \
  --capture-dir .agent-runs/agent-task-42/capture \
  --jsonl .agent-runs/agent-task-42/events.jsonl \
  -- <program> <args...>

The agent should cancel and wait by run id, never clean up by PID or process name, and reserve --detach for work with a separate supervisor. See Agent and automation workflows for a ready-to-paste instruction, recovery strategy, and the precise limits of cleanup when the agent itself stops.

Use as a container entrypoint

ENTRYPOINT ["/usr/local/bin/processkit-cli", "run", "--jsonl", "/run/events.jsonl", "--"]
CMD ["/app/worker"]

Exec form preserves signal delivery and avoids a shell wrapper. Ensure /run is writable and the orchestrator's termination grace exceeds the CLI's grace.

Diagnose a failed start

  1. Read stderr for the operator message.
  2. Read JSONL for spawn_failed, limit_hit, or container_failed.
  3. Read terminal runner_exit for runner code and nullable child code.
  4. If a registry entry remains after abrupt runner death, use list and prune --dry-run; do not kill the recorded pid.

Guide map

NeedRead
argv, cwd, environmentRunning commands
terminal, stdin, captureStandard I/O and capture
out-of-band lifecycleDetached runs
deadlines and stop behaviorTimeouts and cancellation
memory/process/CPU capsResource limits
OS differencesPlatform support
agent tool executionAgent and automation workflows
copyable end-to-end scriptsRunnable examples
adapter designIntegration guide
event fieldsJSONL event schema