Observability Commands
Observability commands read the audit ledger. They require CARACAL_ADMIN_TOKEN and a zone ID. No mutation is possible through these commands.
caracal audit tail
Section titled “caracal audit tail”Fetch recent audit events for a zone.
caracal audit tailcaracal audit tail --decision deny --limit 50caracal audit tail --since 2026-05-01T00:00:00Z --until 2026-05-02T00:00:00Zcaracal audit tail --event-type token_exchangeFlags:
| Flag | Type | Default | Description |
|---|---|---|---|
--since <timestamp> | ISO 8601 | — | Return events after this time |
--until <timestamp> | ISO 8601 | — | Return events before this time |
--request-id <id> | string | — | Filter to a single request ID |
--decision <d> | allow|deny|partial | — | Filter by policy decision |
--event-type <type> | string | — | Filter by event type |
--limit <n> | integer | 100 | Maximum rows to return |
--zone <id> | string | From env/config | Zone ID |
--json | boolean | false | Emit JSON |
Table columns: occurred_at, event_type, decision, evaluation_status, request_id, id
Example output:
occurred_at event_type decision evaluation_status request_id----------- ---------- -------- ----------------- ----------2026-05-11T20:00:01Z token_exchange allow complete req_abc1232026-05-11T20:00:02Z token_exchange deny complete req_def4562026-05-11T20:00:03Z agent_spawn allow complete req_ghi789Common patterns:
Find all denied token exchanges in the last hour:
caracal audit tail \ --since $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \ --decision deny \ --event-type token_exchangePipe to jq for analysis:
caracal audit tail --json | jq '.[] | select(.decision == "deny") | .request_id'caracal explain <request_id>
Section titled “caracal explain <request_id>”Show the full policy evaluation diagnostics for a single request.
caracal explain req_def456caracal explain req_def456 --jsonArguments:
| Argument | Description |
|---|---|
<request_id> | Request ID from an audit event. Use caracal audit tail to find it. |
Flags: --zone <id>, --json
Plain-text output:
event token_exchange decision=deny status=completeoccurred_at 2026-05-11T20:00:02Zrequest_id req_def456policy_set pset_pqr678 version=psetv_jkl012 sha=sha256:abc123...
determining_policies:[ { "policy_id": "pol_mno345", "policy_version_id": "polv_abc", "decision": "deny" }]
diagnostics:[ { "rule": "scope_guard", "message": "required scope 'transfer:write' not present", "data": {"requested_scopes": ["transfer:read"]} }]
metadata:{"subject": "user_vwx234", "application_id": "app_def456", "resource": "resource://payments-api"}JSON output:
With --json, the command emits the raw array of AuditDetail objects:
[ { "id": "audit_xyz", "event_type": "token_exchange", "decision": "deny", "evaluation_status": "complete", "occurred_at": "2026-05-11T20:00:02Z", "request_id": "req_def456", "policy_set_id": "pset_pqr678", "policy_set_version_id": "psetv_jkl012", "manifest_sha": "sha256:abc123...", "determining_policies_json": [...], "diagnostics_json": [...], "metadata_json": {...} }]Workflow:
- Notice a failed exchange in application logs or a failing test.
- Capture the
request_idfrom the error response or from the application’s trace headers. - Run
caracal explain <request_id>to see exactly which policy denied the request and why. - Inspect
diagnostics_jsonfor the specific rule and message. - Update the Rego policy or fix the grant and re-test.
For live streaming of audit events as they arrive, use the TUI, which polls the audit endpoint every 2 seconds and applies color coding to decisions.