A write in Repost is not a simulation. Replaying an event re-delivers it to the live target; pausing a forwarder stops real traffic; provisioning creates real infrastructure. Every mutating command an agent runs follows the same shape. Learn it once here, then each playbook shows its command-specific parts.
What mutates#
| Command | Effect | Scope | Guard |
|---|---|---|---|
replay | Re-delivers events to a live target | write | --dry-run, --yes for bulk, --idempotency-key |
forwarder pause / resume / disable | Starts, stops, or retires delivery | write | Explicit --bucket + --forwarder (no picker) |
bucket create / forwarder create | Provisions a new route | write | Positional name; re-check before re-creating |
init | Provisions a bucket + forwarder together | write | --idempotency-key (idempotent by design) |
Read-only commands (events, forwards, health, whoami, capabilities, docs) never need these guards. This page applies only to the writes above.
The pattern#
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.
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.
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.
Pass --idempotency-key so a retried command re-attaches to the existing work instead of doing it twice.
Agents run non-interactively, so bulk mutations refuse to proceed without --yes. Pass it deliberately, not reflexively.
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 running forwarder 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:
| Command | Required selectors |
|---|---|
replay | --forwarder (and --bucket when the forwarder is named) |
forwarder pause / resume / disable | --bucket (-b) and --forwarder (-f) |
bucket create / forwarder create | The positional name, plus --target for an external forwarder |
--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.
{ "schema": "repost.replay.create/v1", "data": { "job_id": "rpl_01JZ9F2K7M", "status": "IN_PROGRESS", "deduplicated": true } }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#
A conflict 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.