What mutates
Read-only commands (
events, forwards, health, whoami, capabilities, docs) never need these guards — this page applies only to the writes above.
The pattern
1
Confirm the write scope
Mutations need a
write token. A missing scope fails cleanly with forbidden_scope (exit 3) before anything changes — check repost auth status --json up front. See Authentication.2
Resolve stable IDs first
Act on concrete IDs or a bounded selector you got from a search — never a vague or open-ended one. Arrive at a mutation from Diagnose webhooks, not a guess.
3
Preview the blast radius
Where a command supports it (
replay --dry-run), read the predicted count and gate on it before executing. If it is larger than expected, tighten the selector instead of proceeding.4
Make it idempotent
Pass
--idempotency-key so a retried command re-attaches to the existing work instead of doing it twice.5
Gate bulk behind --yes
Agents run non-interactively, so bulk mutations refuse to proceed without
--yes. Pass it deliberately, not reflexively.6
Wait, then branch on the exit code
Don’t assume success. Wait for terminal state (
replay wait, or re-verify with health) and branch on the exit code — never the status string.Run non-interactively
A human runningforwarder pause with no arguments gets an interactive picker. An agent must never reach it — it blocks forever. Always pass the selectors each mutating command needs:
--bucket is the canonical selector for agents. --bucket-slug remains accepted as a compatibility alias, but new automation should use --bucket or -b.Idempotency
--idempotency-key makes a write safe to retry. If a command times out or the connection drops, re-run the identical command with the same key: the API re-attaches to the original work instead of starting a second one.
deduplicated: true means the work is already running — treat it as success. init is idempotent the same way: re-running with the same key (or the same name and target) returns the existing bucket and forwarder rather than creating duplicates.
Recover from conflict
Aconflict error (exit 1, HTTP 409/412) means the state changed under you between read and write — a forwarder was paused by someone else, or a job already moved on. Don’t retry blindly: re-read the current state, reconcile, then retry the mutation. The full error contract is in Output & errors.
Continue
Replay deliveries
The full replay flow: dry-run, selectors, idempotency, and exit-code waiting.
Guard a deployment
Pause forwarders around a deploy and gate on health.
Provision a target
Create a bucket and forwarder idempotently.