Skip to content

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 ​

json
{"ts":"2026-01-01T00:00:00Z","actor":"devin","op":"run","rref":"billing/stripe","env":"dev","outcome":"ok"}
fieldnotes
tsRFC 3339, UTC
actor--actor → ARCA_ACTOR → $USER/$LOGNAME → anon. Self-claimed — attribution, not identity
opthe verb: init put get list rm rotate run env check deploy ui serve manifest schema
rrefthe resolved ref path, env pin stripped — same on denied/error when the arg parses, else the raw arg verbatim. Absent on op-scoped events
envthe env the op ran under
outcomeok | denied | error
policyserve-path only, optional — the PDP verdict {allow, reason?, obligations?} behind the outcome; absent on every other path

When events fire ​

eventmeaning
ok, ref-scopedone per ref materialized or mutated — put, get, rotate, rm, deploy, and per resolved ref inside run/env
ok, op-scopedref-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)
errorthe 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-docs run before config load — pure introspection, no event.
  • A run child's non-zero exit is the child's outcome — no error event 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.