Skip to content

These pages document master, which is unreleased and in development. The Quick Start installs the latest stable release; anything newer than that tag is marked in the text.

Headless harness recipes (#179)

Drive the enforced harness (CCT runtime loaded, all gates active) from scripts, internal platforms, or CI — no TUI. Built on the surface this harness has verified end-to-end: pi --mode json (the same mechanism the T7.2 subagent runner uses in production).

Terminal window
pi-code -- --mode json -p "Run the test suite and summarize failures" --no-session

Everything after -- reaches pi unmodified; pi-code loads the CCT enforcement runtime via --extension first, so permission rules, protected paths, and audit apply to the headless run exactly as they do interactively. Exit codes and signals are pi’s own (pi-code execs).

--no-session keeps one-shot runs from accumulating session state; drop it if you want the run resumable.

--mode json emits JSON lines; the final result envelope carries (the T10.3 contract, the same fields the subagent runner parses):

{ "type": "result", "subtype": "success", "total_cost_usd": 0.0123, "session_id": "..." }
Terminal window
out="$(pi-code -- --mode json -p "" --no-session)" || { echo "run failed: $?"; exit 1; }
# jq -e: exit nonzero when no envelope matched (missing envelope = error).
echo "$out" | jq -e -r 'select(.type == "result") | "\(.subtype) cost=\(.total_cost_usd)"'

A nonzero exit is a failed run regardless of any envelope (the T7.2 runner’s rule); also treat “no envelope in the output” as an error — that second rule is STRICTER than the runner, and recommended for CI.

jobs:
agent-task:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v4
with: { node-version: "22" }
# setup.sh lives in the CCT repo — check it out alongside your
# project (or vendor it) and run its adapter installer; it installs
# the pi-code launcher into ~/.local/bin (on PATH in Actions).
- name: Install pi + the CCT harness
run: |
npm install -g @earendil-works/pi-coding-agent
git clone --depth 1 https://github.com/gosha70/code-copilot-team cct
./cct/adapters/pi/setup.sh
- name: Enforced headless run
shell: bash # bash -eo pipefail: a nonzero pi exit fails the step even through the pipe
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
TASK_PROMPT: ${{ inputs.task }}
run: |
pi-code -- --mode json -p "$TASK_PROMPT" --no-session | tee run.jsonl
jq -e 'select(.type=="result") | .subtype == "success"' run.jsonl > /dev/null

For unattended postures (ask-resolution, sandbox requirements) see unattended-runs.md; for worker isolation use pi-code worktree run (worktree-workers.md).

pi also ships an RPC mode (docs/rpc.md in the pi package) for long-lived, bidirectional programmatic control. This harness has not exercised it — the recipes above are the CCT-verified path. If you adopt RPC mode directly, you are on pi’s contract, not this harness’s; the CCT runtime still loads via --extension, but none of the harness’s headless semantics documented here (envelope parsing, exit-code rules) have been validated against it.

The extension template composes with headless runs: auto-discovery applies when the project is trusted in the headless environment; otherwise pass a pinned, absolute --extension path you control (see the template README’s security note about explicit paths bypassing the trust gate — in CI, the pinned path is the appropriate form). The template’s gates cover Pi’s write/edit tools only — they are not a filesystem boundary, which is exactly why the CI validation step above remains the authoritative gate.