Skip to main content

Audit Policy

The audit policy category configures what gets logged during workflow execution and how long those logs are retained. Unlike most policies, it never blocks -- it is a must-record handler that runs even when an earlier handler has already blocked the run, so the audit trail captures the blocked attempt itself.

Use it to satisfy regulatory log-retention requirements (SOC2, ISO 27001, HIPAA audit controls) and to standardize redaction of sensitive fields across agents.

Rules

RuleTypeDefaultDescription
log_inputsbooleantrueLog workflow inputs (after redaction)
log_outputsbooleantrueLog workflow outputs (after redaction)
log_stepsbooleantrueLog individual workflow step counts
log_tool_callsbooleantrueLog tool invocation counts
redact_fieldsstring[][]Additional field names to redact (merged with defaults)
retention_daysinteger90How long to retain audit logs
min_log_levelstring"INFO"Minimum Python logging level (DEBUG/INFO/WARNING/ERROR)
max_log_entriesinteger500Max log entries per execution (0 = unlimited)
capture_stdoutbooleanfalseCapture print() output as log entries

Default Redacted Fields

These are always redacted, regardless of redact_fields configuration:

password, secret, token, api_key, apikey, authorization, credential, private_key

Matching is case-insensitive substring -- a field named user_password_hash will be redacted because it contains password.

How It Works

The audit handler runs at before_workflow, after_workflow, and on_failure. It always returns ALLOW; the action is purely informational. Because short_circuit_on_block = False, the handler executes even if a prior policy already blocked the run.

PhaseWhat It Logs
before_workflowRedacted inputs, agent/workflow IDs, active audit modes
after_workflowStep count, tool call count, redacted output
on_failureError type and message

Context Attributes Read

AttributePhasePurpose
context.inputsbefore_workflowRedact + log inputs
context.agent_nameallAudit log scoping
context.workflow_nameallAudit log scoping
context.workflow_idallAudit log correlation
context.step_logsafter_workflowCount steps (len(step_logs))
context.tool_call_countafter_workflowCount tool invocations
result (parameter)after_workflowRedact + log final output

The handler also writes context._audit_rules so downstream components can read the active config.

Example Policy

{
"log_inputs": true,
"log_outputs": true,
"log_steps": true,
"log_tool_calls": true,
"redact_fields": ["ssn", "dob", "patient_id"],
"retention_days": 365,
"min_log_level": "INFO",
"max_log_entries": 1000,
"capture_stdout": false
}

SDK Integration

import waxell_observe as waxell
waxell.init()

@waxell.observe(agent_name="claims-agent", enforce_policy=True)
async def process_claim(claim: dict) -> dict:
return await adjudicate(claim)

Inputs and outputs are automatically logged + redacted on entry/exit. No SDK calls are required to opt in -- assigning an audit policy to the agent is enough.

Observability

FieldExample
Categoryaudit
Actionallow
Reason"Audit logging active (inputs, outputs, steps, tool calls)"
Metadata{"log_config": {"min_log_level": "INFO", "max_log_entries": 500, "capture_stdout": false}, "audit_rules": {...}}

Common Gotchas

  1. audit never blocks. It is a must-record handler -- it returns ALLOW even on failure. Combine with kill-switch or safety for blocking behavior.

  2. Redaction is substring-based. redact_fields: ["id"] will redact ANY field whose name contains id (including client_id, request_id). Use explicit names like "customer_id" to scope the match.

  3. Defaults are always merged. You cannot disable redaction of password/token/api_key by leaving redact_fields empty. The defaults list is hardcoded.

  4. retention_days is enforced by infra, not the handler. The rule is surfaced in the audit log emission but actual retention is governed by the telemetry pipeline (S3 lifecycle, OpenSearch ILM).

  5. max_log_entries: 0 means unlimited. This is the documented sentinel -- do not treat it as "log nothing".

  6. capture_stdout is opt-in. print() calls are NOT captured by default; agents that rely on print debugging will produce no audit output without this flag.

Next Steps