Treeship
CLI reference

halt

The kill switch. Stop an actor, or every actor, with a signed halt.v1 receipt that the harness gate obeys; lift it with a second signed receipt. Both are sealed into the session.

treeship halt is the kill switch. It signs a halt.v1 receipt naming an actor (or *, every actor in the workspace), chains it onto the active session, and writes a marker that the enforcement points read. While the halt stands, the Claude Code plugin's PreToolUse gate refuses every tool call for that actor, before any card rule, and signs each refusal as a blocked.v1 receipt with reason_class: operator_revocation. Lifting it signs a second receipt and clears the marker. A verifier reading the sealed package sees when the switch was thrown, by whom, and when it was lifted.

treeship halt agent://claude-code --reason "off-task network calls"
treeship halt '*' --reason "incident 2026-09-18"
treeship halt list
treeship halt --lift agent://claude-code

What it reaches, and what it does not

A halt stops what the instrumented surface routes through Treeship: every tool call the Claude Code plugin sees, every callTool through the MCP bridge, and every task the A2A middleware admits or receives. Each of those asks treeship halt list before the call and, under a standing halt, refuses and signs a blocked.v1. A check that cannot run (no CLI on the PATH, a CLI older than 0.31.6) fails open and says so once on stderr; under TREESHIP_STRICT=1 the bridges refuse instead. A halt does not reach a process an agent started outside those paths, a runtime with no hooks, or another machine. The coverage level says where that boundary is for each harness. A halt is an order the instrumented surface obeys, not a guarantee about the uninstrumented one.

Halting

✓ actor halted
  actor:      agent://claude-code
  halt:       art_9c1e…
  issued_at:  2026-09-18T16:29:15Z
  reason:     off-task network calls
   → every tool call the harness routes through hooks is now refused and signed as blocked.v1
   → treeship halt --lift agent://claude-code   to lift it

The actor must be a URI (agent://…, human://…) or *. A second halt on an actor already halted is refused until the first is lifted, so there is one halt to point at. When a session is active, the halt chains onto its head, inside the signature, so the sealed package shows it in order with the actions it stopped.

Lifting

✓ halt lifted
  actor:  agent://claude-code
  lift:   art_2b7a…
  halt:   art_9c1e…
  issued_at: 2026-09-18T16:41:02Z

The lift names the halt it ends in its signed payload and chains onto the session like the halt did. The lift is the order that stands: a marker file restored from a backup, or copied in, for a halt this workspace has lifted is listed as lifted_by: <the lift>, not honoured, and removed on sight. Whoever can write to the halts directory cannot re-arm a halt the ship signed away.

Listing

treeship halt list
treeship halt list --format json

Each row shows the actor, the halt artifact, when it was issued, the reason, and whether it is honoured. A marker is honoured only when it names a halt.v1 record on disk whose envelope verifies under this workspace's key, and no lift that verifies under that key names the halt. The check reads the record files, not the index.json cache, and checks signatures, not the records' unsigned key_id field: rolling back the index alongside the marker, or dropping in a record signed by another ship, changes nothing. A marker that fails is listed with the reason (lifted by art_…, or not signed by this workspace) and the gate does not act on it; a marker outliving its lift is removed.

Who can halt

Only the workspace's own key signs a halt, the same rule as revoking a grant: an order anyone could mint would be a denial of service against every actor whose name they know. The trust domain is same-user local access, which is the harness's trust domain too.

Options

OptionDescription
--liftLift the halt on this actor instead of imposing one
--reason <REASON>Why, in your words. Goes into the signed receipt

See also