Approvals & warrants
How deferred calls route to human approval, and how warrants skip the wait.
When a rule defers, the agent process blocks and prints a token:
[raxit] waiting for human approval (up to 120s)… approval id dt_1373bb3e0bcf139d
[raxit PENDING] 'post_to_webhook' deferred — waiting for human approval (up to 120s).
Token: dt_1373bb3e0bcf139d
Approve: raxit approvals approve dt_1373bb3e0bcf139d
Deny: raxit approvals deny dt_1373bb3e0bcf139dFrom another terminal:
$ raxit approvals approve dt_1373bb3e0bcf139d --reason "docs fact pack approval"
dt_1373bb3e0bcf139d: approved (approver=operator)The first terminal resumes on its own — no re-run needed:
[raxit] approval approved (id dt_28930b3bf7da664a)
>>> agent calls post_to_webhook({'url': 'https://example.com/hook', 'payload': 'hi'})
[webhook] would POST to https://example.com/hook: hi
<<< result: okIf nobody approves in time (default 120s, RAXIT_DEFER_TIMEOUT), the call resolves to a hard
deny instead:
[raxit] approval expired (id dt_1373bb3e0bcf139d)
<<< [raxit BLOCKED] 'post_to_webhook' denied (reason: deny.approval_expired). The operation was
not executed. Details: raxit explain d867c63661454e8497369a08ebaec35dAn explicit denial produces deny.approval_denied instead — same terminal shape, different
reason code.
RaxitDeferred (Python SDK)
Since 0.0.3, a call that stays deferred — the human approval times out, or the control plane goes
unreachable while waiting — raises RaxitDeferred, a subclass of RaxitDenied, instead of
collapsing into an indistinguishable denial. Every existing except RaxitDenied: site still
catches it and fails closed (the tool body never runs); the subclass only lets a caller that owns
a retry loop tell "still pending" apart from "a human said no" — a RaxitDeferred carries the
approval token, so the same bound call can be resubmitted later instead of minting a fresh
pending approval.
RAXIT_DEFER_TIMEOUT=0returns the raw, unresolved defer immediately — no inline approval poll — reported with the policy's own defer reason code.- A positive timeout that elapses without resolution reports
defer.timeout. - An explicit human denial still raises the terminal
deny.approval_denied(plainRaxitDenied, notRaxitDeferred— that's a "no," not a pending retry).
raxit approvals
$ raxit approvals list
TOKEN AGENT RESOURCE STATUS
dt_1373bb3e0bcf139d default-agent post_to_webhook pending
dt_28930b3bf7da664a default-agent post_to_webhook pending
$ raxit approvals approve dt_28930b3bf7da664a --reason "..."
dt_28930b3bf7da664a: approved (approver=operator)
$ raxit approvals deny dt_1373bb3e0bcf139d --reason "..."
dt_1373bb3e0bcf139d: denied (approver=operator)raxit approvals authenticates to the daemon automatically using a local, 0600-permission token
file at .raxit/var/approvals.token — no --token flag needed on a local box. Denying an
already-expired token still succeeds; it just records the operator's explicit denial on top of
the automatic expiry.
Warrants — standing pre-approvals that skip the wait
A warrant is a time- and scope-bounded pre-approval: once issued, a matching defer upgrades
straight to permit (permit.warrant) without a per-call human loop. You declare the shape a
warrant may take in security.yaml:
warrants:
templates:
- name: refund-approval
tool: "stripe/refund"
max_ttl: 1h
max_uses: 5This is an envelope, never an issuance path — writing this block does not grant anything, and an
attacker who can edit security.yaml still cannot self-issue a warrant. Warrants are minted
separately, through the same human-approval flow, and are consumed exactly once per call id.
Warrants are in-memory only — there is no persistence across a daemon restart. This is
distinct from the session-store file backend (--session-store file), which persists taint,
budget, rate, and other session state across restarts but does not cover warrants. A
restarted daemon has zero warrants regardless of session-store configuration; any standing
approvals must be re-issued.
Where approvals route
Beyond the CLI/terminal flow shown above, a deferred call can also route out via webhooks:
(Slack or a generic webhook) — see Advanced. Whatever the
channel, the resolution is the same: permit.approved on approval, deny.approval_denied on
denial, deny.approval_expired on timeout.

