Audit events
The audit wire: one ndjson line on stderr per op outcome. arca keeps no local ledger (ADR-0001 — aggregation is peregrin's); the stderr stream is the contract, so a wrapper — peregrin, sepia, your own harness — can capture it, and a human sees a breadcrumb.
Shape
{"ts":"2026-01-01T00:00:00Z","actor":"devin","op":"run","rref":"billing/stripe","env":"dev","outcome":"ok"}| field | notes |
|---|---|
ts | RFC 3339, UTC |
actor | --actor → ARCA_ACTOR → $USER/$LOGNAME → anon. Self-claimed — attribution, not identity |
op | the verb: init put get list rm rotate run env check deploy ui serve manifest schema |
rref | the resolved ref path, env pin stripped — same on denied/error when the arg parses, else the raw arg verbatim. Absent on op-scoped events |
env | the env the op ran under |
outcome | ok | denied | error |
policy | serve-path only, optional — the PDP verdict {allow, reason?, obligations?} behind the outcome; absent on every other path |
When events fire
| event | meaning |
|---|---|
ok, ref-scoped | one per ref materialized or mutated — put, get, rotate, rm, deploy, and per resolved ref inside run/env |
ok, op-scoped | ref-less verb completed — init, list, check, ui, serve |
denied | [guardrails] — or a serve-path PDP verdict of allow: false (including fail-closed on an unreachable PDP) — refused the op before it touched the vault; rref is the requested ref (normalized when parseable) |
error | the op ran and failed — missing secret, vault i/o, bad ref; a check with findings also audits error (it exits 1); also emitted when config load itself fails (best-effort actor/env from flags + process env) |
Two deliberate silences:
manifest,schema,gen-cli-docsrun before config load — pure introspection, no event.- A
runchild's non-zero exit is the child's outcome — noerrorevent for it. arca's own exit code is the child's.
serve and the policy field
arca serve emits the same events — get/put/rm/rotate requests audit exactly like the CLI verbs, under the request's claimed actor when it carries one. The PDP consult covers the ops that can materialize — get/put/rm/rotate andlist/check (record decrypts, vault probes, scoped-token gets) — so a check's incidental token gets ride the same policy-bearing events. On the serve path only, every event a consulted [serve.pdp] gated gains a policy object — {allow, reason?, obligations?} — so the stream shows the verdict behind the outcome: a PDP allow, a PDP deny (outcome: "denied", policy.allow: false), or a degraded allow recorded when allow_on_error overrode an unreachable PDP. The serve verb itself closes with one op-scoped ok. See the serve protocol.
ui and the TUI
arca ui emits one op-scoped ok when the browser exits cleanly. Inside it, browsing is silent — listing refs and metadata is not a materialization. The r→r reveal goes through the audited get path: a real {"op":"get","rref":…,"outcome":"ok"} event per value shown.
Failure posture
Audit emission is best-effort: a closed stderr (broken pipe) never takes the broker down — the write error is swallowed by design.