* Audit: add durable decision receipts * Audit: route generic decision facts through writer * Audit: satisfy strict decision count typing * Test: align decision writer type coverage * Refactor: isolate decision receipt projection * Fix: preserve ambiguous approval correlation * Fix decision coverage across pages * Fix approval coverage across corrupt pages * Fix decision summaries across retention and paging * Remove superseded decision fact count path * Keep session-derived approval links conservative * Test decision paging at owner boundary * Audit: bind approval receipts to exact execution * Test: keep decision receipt coverage focused * docs(agents): preserve decision receipt ownership * Docs: refresh Plugin SDK split baselines * Docs: require opt-in for future decision facts * Fix: bound decision receipt inspection
15 KiB
summary, read_when, title
| summary | read_when | title | |||
|---|---|---|---|---|---|
| CLI reference for activity records, execution identity, and decision receipts |
|
Audit records |
openclaw audit
Query the Gateway's metadata-only activity ledger, discover executions that share a run correlation, or inspect immutable identity context for one exact agent execution.
Run and tool activity records are on by default. Execution identity is separately off by default on fresh installs and upgrades. Enable it explicitly:
openclaw config set logging.audit.executionIdentity true
openclaw gateway restart
Identity collection requires logging.audit.enabled to remain enabled.
Message records are also separately disabled by default; set
logging.audit.messages to direct or all and restart the Gateway to
record them. Existing records stay queryable until they expire (30 days).
Direct local commands use the same bounded writer lifecycle as the Gateway.
openclaw agent exec deletes its temporary state directory by default, so its
audit evidence is intentionally discarded with the rest of that isolated run.
Use agent exec --state-dir <dir> when the run state must remain available,
and inspect it through a Gateway using that same state directory.
The ledger is separate from conversation transcripts: it records identity, ordering, provenance, action, status, and normalized outcome codes, but never stores content, and message identifiers appear only as installation-local keyed pseudonyms. Audit history owns the full data model, privacy semantics, storage/retention bounds, and coverage limits; this page covers the command surface.
openclaw audit
openclaw audit --agent main --status failed
openclaw audit --session "agent:main:main" --after 2026-07-01T00:00:00Z
openclaw audit --run 8c69f72e-8b11-4c54-98d5-1a3dd67450c3
openclaw audit --run 8c69f72e-8b11-4c54-98d5-1a3dd67450c3 --explain
openclaw audit --execution 5da4c4c3-e1c9-4c95-a17d-6e5c10fd45cf --explain
openclaw audit --execution 5da4c4c3-e1c9-4c95-a17d-6e5c10fd45cf --explain --json
openclaw audit --run 8c69f72e-8b11-4c54-98d5-1a3dd67450c3 --explain --json
openclaw audit --kind tool_action --limit 50 --json
openclaw audit --kind message --direction outbound --channel telegram --json
Filters
--agent <id>: exact agent id--session <key>: exact session key--run <id>: exact run id; filters activity unless--explainis also set--execution <id>: exact execution id; requires--explain--kind <kind>:agent_run,tool_action, ormessage--status <status>:started,succeeded,failed,cancelled,timed_out,blocked, orunknown--direction <direction>: message direction,inboundoroutbound--channel <channel>: exact message channel--after <timestamp>/--before <timestamp>: inclusive ISO timestamp or Unix milliseconds--limit <count>: activity page size from 1 to 500 (default100), decision page size from 1 to 100, or ambiguous execution-candidate page size from 1 to 50 with--explain(default50)--cursor <sequence>: continue an activity, decision, or ambiguous execution-candidate page--explain: inspect immutable execution identity and run-admission reasoning; requires exactly one of--runor--executionand accepts only--limit,--cursor, and--json--json: print the bounded page as JSON
The CLI queries the versioned activity RPC so one command shows the complete
configured ledger. Text output shows time, kind, direction, channel, status,
agent, run, and action. Missing message provenance renders as -; OpenClaw
does not invent agent or run ids. Tool actions also show the tool name. JSON
output includes nextCursor when another page exists. Pass that value to
--cursor to continue without reordering records that arrive during paging.
These exports remain sensitive operational metadata even though message bodies and raw message identity fields are absent. Agent, session, and run ids, timing, channels, outcomes, and stable HMAC references can correlate activity. Protect them with the same access controls and retention practices as other operator records.
The Gateway intentionally exposes retained execution-identity diagnostics to
every client with operator.read in its operator domain. That scope is a
trusted read-only boundary, not hostile multi-tenant isolation. Use separate
Gateway trust domains when operators must not share audit identity data.
Discover and explain executions
Every admitted outer turn receives an opaque executionId. contextId
identifies its immutable evidence record; the existing runId stays a
possibly shared session, routing, or recovery correlation. Use --run <id> --explain to discover retained executions rather than query the best-effort
activity list. One match resolves directly. Multiple matches return
ambiguous, list at most 50 candidates, and tell you to select one explicitly:
openclaw audit --execution <execution-id> --explain
OpenClaw never silently selects the first or latest execution. The exact text view renders these sections:
- Identity: trust domain, invoker, ingress, agent principal, agent definition, runtime instance, represented subject, and sponsor.
- Authority: applicable grants and assurance evidence.
- Lineage: parent context or an explicit absent, unknown, or unsupported state.
- Decisions: bounded run-admission and authoritative action-decision receipts, including terminal operator approvals.
- Missing evidence and Next steps.
Every field includes present, absent, unknown, or unsupported; the CLI
does not infer a user from a session key, device id, display name, or shared
credential. A direct local run currently shows authoritative local-cli
ingress, an absent invoker, and
unattributed coverage. Its admission receipt says not-applicable because no
identity-aware policy or grant evaluation was proven.
For Gateway runs, a resolved authenticated profile can make the invoker
present and coverage attribution-only. Paired devices and shared credentials
do not establish a person: without a durable profile the invoker stays absent,
or unknown when authenticated user evidence promised a profile that could not
be resolved. Session creation retains the live canonical durable profile id so
profile linking does not orphan ownership, while run inspection consumes the
immutable connection-time audit fact. Ordinary session provenance stores no
display label. An optional bounded, secret-redacted label can be retained only
in execution identity after that audit storage is explicitly enabled.
A terminal approval receipt shows allowed or denied, its stable reason
code, enforcement state, authoritative source boundary, policy and grant
references, context fields used, and remediation. Expired and cancelled
approvals are denied non-actions with distinct reason codes. no-route is an
enforced denial only when the approval owner recorded that terminal state. A
corrupt approval is unknown. The text view labels operator_approvals as an
authoritative owner-native SQLite record retained for 30 days; JSON preserves
the same source owner and record reference without lossy reformatting.
enforced requires the approval's immutable owner-local binding to match the
selected context, execution, and run exactly. A missing, malformed, or
mismatched binding reports operator_approval_execution_link_missing,
operator_approval_execution_link_malformed, or
operator_approval_execution_link_mismatch with unknown coverage and no grant
references. The inspector never reconstructs that binding from runId, session
metadata, timestamps, or the number of retained executions.
JSON output is the Gateway result without lossy reformatting. An exact result contains one
bounded V1 context (maximum 16 KiB), up to 100 decision receipts, coverage and
missing-evidence codes, and an optional nextDecisionCursor. An ambiguous run
result instead contains at most 50 execution candidates and an optional
nextExecutionCursor. Sensitive domain,
runtime, invoker, assurance, ingress-source, and grant references are
installation-local HMAC projections. Configured agent ids and exact run ids
remain visible, as do context and execution ids, so redirected output is still
private operator data.
An older Gateway produces an explicit unsupported result with
gateway_upgrade_required and an upgrade-and-rerun next step. The CLI never
reconstructs identity from legacy audit rows. A current Gateway distinguishes
an unknown run, an unavailable pre-feature, disabled, or failed context write,
an expired context, and a corrupt context without claiming that missing
best-effort activity proves no execution. A newly admitted run can also be
temporarily unavailable while its bounded identity envelope waits in the audit
writer queue; retry inspection after the run or normal process shutdown.
Admission never waits for writer readiness, schema or HMAC-key initialization,
SQLite, or persistence.
Once a context is older than 30 days, the CLI returns no fields or linked
decisions from it. While bounded cleanup is pending, the result is unsupported
with an expiry-and-rerun next step. After cleanup it can become unknown if no
separately retained activity remains; this absence does not prove that the run
did not occur. Startup and hourly maintenance prune at most 1,024 identity
contexts per tick and continue when collection is disabled. Queue saturation,
worker/storage failure, cleanup failure, or abrupt process termination can lose
best-effort evidence but never block or abort the agent run. Normal Gateway and
direct-local CLI shutdown flushes accepted work when its writer lifecycle
permits.
Recorded events
The Gateway projects trusted lifecycle streams into six actions:
agent.run.startedagent.run.finishedtool.action.startedtool.action.finishedmessage.inbound.processedmessage.outbound.finished
Every returned record has a stable event id, a monotonically increasing ledger
sequence, a lifecycle timestamp, actor, action, status, a
schemaVersion: 1 marker, source sequence, and redaction: "metadata_only".
Agent/session/run provenance and event-specific fields are present only when
the trusted source provides them. Message records intentionally omit
sessionKey and sessionId, so --session filters run and tool records only.
Terminal run and tool records distinguish success, failure, cancellation,
timeout, and policy blocks with closed status and error codes. unknown is an
explicit non-success result when an upstream runtime does not expose an
authoritative terminal outcome. Tool call ids are exported only as stable
fingerprints. Tool names must match the compact model-facing name
contract; other values become unknown.
Message records add direction, channel, conversation kind, outcome, and
optional delivery kind, failure stage, duration, result count, normalized
reason code, and keyed account/conversation/message/target pseudonyms. The
current inbound boundary covers accepted messages that reach core dispatch,
including core duplicate and terminal processing outcomes. The outbound
boundary writes one terminal row per original logical reply payload that reaches
shared durable delivery; chunking and adapter fan-out are aggregated in
resultCount. Queued retryable or ambiguous sends are recorded only after an
acknowledgement, dead letter, or reconciliation makes the outcome terminal.
Plugin-local and direct-send paths that bypass those shared boundaries are not
yet covered; absence of a row does not prove that no message existed.
The audit ledger does not replace transcripts, task history, cron run history, or logs. It provides a small cross-run index for operator questions without copying conversation content into another store.
For inbound rows, durationMs measures core dispatch and resultCount counts
finalized queued tool, block, and reply payloads. For outbound rows,
durationMs includes delivery ownership through its terminal (and therefore
queued wait time), while resultCount counts identified physical platform
sends. deliveryKind, when present, describes the effective post-hook,
post-render payload; suppressed and crash-ambiguous rows omit it.
Gateway RPC
audit.activity.list requires operator.read and accepts the same filters. It
returns the named V1 activity event union, including run, tool, inbound-message,
and outbound-message records.
openclaw gateway call audit.activity.list --params '{"channel":"telegram","limit":50}'
The result is { "events": AuditActivityEventV1[], "nextCursor"?: string }.
Results are newest first and limited to 500 records per request.
audit.run.inspect also requires operator.read:
openclaw gateway call audit.run.inspect \
--params '{"runId":"8c69f72e-8b11-4c54-98d5-1a3dd67450c3","decisionLimit":50}'
openclaw gateway call audit.run.inspect \
--params '{"executionId":"5da4c4c3-e1c9-4c95-a17d-6e5c10fd45cf","decisionLimit":50}'
Its result is { "schemaVersion": 1, "run": ..., "identity": ..., "decisions": ..., "coverage": ..., "nextDecisionCursor"?: ..., "nextExecutionCursor"?: ... }.
The closed request accepts exactly one of executionId or runId.
decisionLimit is 1–100 and decisionCursor is optional. Run discovery also
accepts executionLimit from 1–50 and an optional executionCursor. A run
with multiple retained executions returns the typed ambiguous identity state
and no identity context or decisions until the caller selects an execution id.
For one selected context, receipt paging starts with admission, then reads
owner-native terminal approvals, then generic facts for boundaries without a
native durable record. Approval inspection never writes a generic duplicate.
Generic fact writes and projections also require the full context, execution,
and run tuple to match the immutable execution context.
The activity ledger remains best-effort. By contrast, a returned approval receipt comes from the authoritative first-answer-wins approval row, and a returned generic receipt comes from the additive immutable decision-fact table. All three surfaces use 30-day retention, but absence from the activity ledger cannot prove that an approval or action did not occur. Generic fact delivery is also best-effort until its bounded worker write persists the row; owner-native approval persistence does not use that queue.
The shipped audit.list RPC remains unchanged for older run/tool clients. When
audit.activity.list is unavailable on an older Gateway, the CLI retries
audit.list only if every requested filter is supported by that legacy method. --kind message,
--direction, and --channel fail with an upgrade message on an older Gateway
instead of being silently discarded.