Skip to content

Audit Logging

Every governance decision is recorded as a structured JSON event.

Event types

EventWhen
session_startAgent session begins
session_endAgent session ends (includes summary)
tool_allowedTool call passed all checks
tool_deniedTool call blocked by policy
bash_deniedBash command classified as dangerous
path_deniedFile access outside allowed paths
approval_requestedHITL approval prompted
approval_grantedHuman approved the action
approval_deniedHuman denied the action
tool_dry_runTool call blocked in dry-run mode
budget_exceededTool call blocked — session budget exhausted
config_reloadedGovernance config hot-reloaded successfully

Sinks

Configure one or more audit sinks. Events are written to all configured sinks in parallel.

yaml
audit:
  sinks:
    - type: jsonl
      path: ~/.pi/agent/audit.jsonl
    - type: webhook
      url: ${AUDIT_WEBHOOK_URL}

Available sinks

SinkDescriptionConfiguration
jsonlAppend-only local JSONL file (default)path — file path
webhookHTTP POST to a URLurl — endpoint URL
postgresINSERT to a Postgres tableconnection — DSN

JSONL sink

The default sink. Writes buffered JSONL (one JSON object per line) to a local file. Buffers are flushed every 10 records or on session end.

yaml
audit:
  sinks:
    - type: jsonl
      path: ~/.pi/agent/audit.jsonl

Webhook sink

Sends each audit event as an HTTP POST with a JSON body. Useful for centralized logging, SIEM integration, or custom dashboards.

yaml
audit:
  sinks:
    - type: webhook
      url: https://audit.example.com/api/v1/events

Multi-sink

Use multiple sinks for redundancy or separation of concerns:

yaml
audit:
  sinks:
    - type: jsonl
      path: ~/.pi/agent/audit.jsonl # Local backup
    - type: webhook
      url: ${AUDIT_WEBHOOK_URL} # Central collection

Session summary

At session end, a session_end event is logged with aggregated stats:

json
{
  "event": "session_end",
  "metadata": {
    "stats": {
      "allowed": 42,
      "denied": 3,
      "approvals": 5,
      "dryRun": 0,
      "budgetExceeded": 0
    },
    "budget": {
      "used": 50,
      "remaining": 499950
    }
  }
}

Querying JSONL logs

The JSONL format is easy to query with standard Unix tools:

bash
# Count events by type
jq -r '.event' ~/.pi/agent/audit.jsonl | sort | uniq -c | sort -rn

# Find all denied tool calls
jq 'select(.event == "tool_denied")' ~/.pi/agent/audit.jsonl

# Filter by user
jq 'select(.userId == "alice")' ~/.pi/agent/audit.jsonl

# Find budget exceeded events
jq 'select(.event == "budget_exceeded")' ~/.pi/agent/audit.jsonl

Environment variable substitution

Sink URLs support ${VAR_NAME} syntax, resolved at config load time:

yaml
audit:
  sinks:
    - type: webhook
      url: ${AUDIT_WEBHOOK_URL}

See the Audit Schema Reference for the complete record format.

Released under the Apache-2.0 License.