Ship harnesses

2 min read

Ship harnesses

Ship is the control plane, not the agent. The loop that edits the tree sits behind one interface, and a run's harness is recorded in its input at enqueue:

SHIP_HARNESS=native        # default: Ship's own loop — no binary needed, air-gapped
SHIP_HARNESS=claude-code   # `claude -p`, headless, inside the sandbox
SHIP_HARNESS=opencode      # `opencode run`, headless, inside the sandbox
SHIP_HARNESS_ATTEMPTS=native,claude-code   # every harness tries; the critic picks

Per repo, the harness is the harness field on the Projects page.

Declaring and installing are separate acts

The harness binary is baked into the sandbox image:

images/build.sh --harness claude-code go    # pinned in images/versions.json

Never installed per run. A run-time install would need the sandbox egress that default-deny exists to close, and would let the binary drift under a running worker — a run replays only under the harness version its log recorded.

What Ship owns regardless

Whichever harness runs, intake, approvals, the publish gate, the evidence legs, spend and audit are Ship's. A harness fed by a subscription is counted as an unpriced run rather than shown as $0. The native loop stays the default and the measured baseline.

The CLI contracts, forwarded credentials and cost-honesty rules for each adapter are in docs/adapters.md in the repository.