Coco

Modes

Observe records, assist prompts, enforce denies. One line of config moves between them, and the ledger records the real verdict in all three.

Modes

One line of config moves between three modes, which is the point. A bank runs observe on real traffic, reads the catch report, and flips to enforce when the contracts have stopped surprising them.

ModeWhat happens
observeRecords the verdict. Stops nothing. This is the default
assistA failing check becomes a prompt. Nothing is denied outright
enforceBLOCK denies. ESCALATE asks you

The verdict does not change with the mode

The verdict recorded in the ledger is always the verdict the contract produced. Only the effect on the call changes.

That is what makes an observe-mode ledger a truthful account of what enforce would have done, and it is why coco report can tell you what enforcement would have cost you before it costs you anything.

Setting it

Locally, edit ~/.coco/config.json and restart Claude Code.

{ "mode": "enforce" }

On the SDK road, the mode is an environment variable on the gate and nothing in your code changes.

COCO_MODE=enforce

The gate reads the mode once at boot rather than per request, so it cannot change underneath a call that is already being decided. Restart the container for a change to take.

A mode change is also on the record without any extra work, because every receipt carries gate_mode. The ledger itself shows the moment enforcement turned on or off, so the decision to flip it is auditable from the same rows an auditor already reads, and who may flip it is who you gave write access to the config.

Assist mode

assist sits between the two. A failing check becomes a prompt without denying anything outright, and it is a reasonable place to stop for a team that wants a person in the loop and not a hard stop.

Over HTTP a prompt has nowhere to appear, so in assist mode any failing check comes back as ESCALATE and your harness decides who answers. A non-interactive harness should treat that the way it treats any escalation, park the action and put it in front of a person.

It is a resting place rather than a destination. A prompt on every failing check trains people to approve reflexively, which is the failure mode observe mode exists to avoid from the other direction.

Turning enforcement on

Read the report with the people who own the rules, fix what is drafted wrong, and then flip one setting. Nothing in your code changes.

From that moment the same call comes back like this, and the call does not run.

{"verdict": "BLOCK", "reason": "Coco: The command is a destructive operation with no safe reading in a governed workflow", "mode": "enforce"}

When something is blocked and should not be

  • coco ledger --verdict BLOCK shows the contract and the reason.
  • Fix the contract, not the ledger. Run coco compile, then restart.
  • To stop enforcing immediately, set the mode back to observe. Nothing is lost and decisions keep recording.

Fixing the contract is the slower answer and it is the right one. A ledger full of blocks nobody agreed with is not evidence of anything.

What observe mode does not protect you from

Observe mode records the verdict and stops nothing, so it stops nothing. A team that runs observe indefinitely ends up with a complete audit trail of harm it did not prevent.

The report is the argument for moving, and the point of the mode is that the argument is made from your own traffic rather than from ours.

On this page