Skip to content

Audit Logging

Wave can log all tool calls and file operations during pipeline execution, producing structured audit trails for compliance, debugging, and monitoring.

Enabling Audit Logging

yaml
# In wave.yaml
runtime:
  audit:
    log_dir: .wave/traces/           # Output directory
    log_all_tool_calls: true           # Log every tool invocation
    log_all_file_operations: true      # Log every file read/write/delete

Audit Log Format

Audit logs are written as NDJSON files, one per pipeline execution:

.wave/traces/
├── a1b2c3d4-speckit-flow-2026-02-01T10:00:00.ndjson
├── e5f6a7b8-bug-fix-2026-01-30T14:30:00.ndjson
└── ...

Log Entry Schema

json
{
  "timestamp": "2026-02-01T10:01:15.234Z",
  "pipeline_id": "a1b2c3d4",
  "step_id": "implement",
  "persona": "craftsman",
  "type": "tool_call",
  "tool": "Write",
  "args": {
    "path": "src/models/user.go"
  },
  "result": "success",
  "duration_ms": 12
}

Entry Types

TypeDescriptionRequires
tool_callAny tool invocation (Read, Write, Bash, etc.)log_all_tool_calls: true
file_readFile read operationlog_all_file_operations: true
file_writeFile write or editlog_all_file_operations: true
file_deleteFile deletionlog_all_file_operations: true
permission_deniedBlocked tool callAlways logged
hook_executedPre/post hook executionAlways logged
contract_validationContract check resultAlways logged

Credential Scrubbing

Audit logs never capture credential values. Wave automatically redacts environment variables matching these patterns:

  • *_KEY[REDACTED]
  • *_TOKEN[REDACTED]
  • *_SECRET[REDACTED]
  • *_PASSWORD[REDACTED]
  • *_CREDENTIAL*[REDACTED]

Example:

json
{
  "type": "tool_call",
  "tool": "Bash",
  "args": {
    "command": "curl -H 'Authorization: Bearer [REDACTED]' https://api.example.com"
  }
}

Querying Audit Logs

Find All Writes by a Persona

bash
cat .wave/traces/a1b2c3d4-*.ndjson \
  | jq 'select(.persona == "craftsman" and .type == "file_write")'

Find Permission Denials

bash
cat .wave/traces/a1b2c3d4-*.ndjson \
  | jq 'select(.type == "permission_denied")'

Summarize Tool Usage

bash
cat .wave/traces/a1b2c3d4-*.ndjson \
  | jq -r 'select(.type == "tool_call") | .tool' \
  | sort | uniq -c | sort -rn

Get Timeline of a Step

bash
cat .wave/traces/a1b2c3d4-*.ndjson \
  | jq 'select(.step_id == "implement") | {time: .timestamp, type: .type, tool: .tool}'

Audit Logging Levels

ConfigurationWhat's LoggedUse Case
Both falseOnly security events (denials, hooks, contracts)Production, low overhead
log_all_tool_calls: trueAll tool invocations + security eventsDebugging, compliance
Both trueEverything — full file-level audit trailSecurity audits, forensics

Performance Impact

Audit logging adds minimal overhead:

  • Logs are written asynchronously to disk.
  • NDJSON format is append-only (no parsing or rewriting).
  • File I/O is buffered.

For long-running pipelines, audit log files can grow large. Monitor disk usage in .wave/traces/.

CI/CD Integration

yaml
# GitHub Actions: upload audit logs as artifacts
- name: Run Wave pipeline
  run: wave run flow "deploy"
  env:
    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

- name: Upload audit logs
  uses: actions/upload-artifact@v4
  if: always()
  with:
    name: wave-audit-logs
    path: .wave/traces/

Further Reading

Released under the MIT License.