Audit Logging¶
Cub maintains detailed JSONL (JSON Lines) logs for every session, enabling debugging, performance analysis, cost tracking, and compliance reporting.
JSONL Log Format¶
Each log file contains one JSON object per line:
{"timestamp": "2026-01-17T10:30:00.123Z", "event_type": "task_start", "data": {"task_id": "cub-054", "task_title": "Add user caching"}}
{"timestamp": "2026-01-17T10:31:45.456Z", "event_type": "task_end", "data": {"task_id": "cub-054", "exit_code": 0, "duration_sec": 105.3, "tokens_used": 156892}}
Why JSONL?¶
| Benefit | Description |
|---|---|
| Appendable | New events append without rewriting |
| Streamable | Process line-by-line, no loading entire file |
| Queryable | Use jq for powerful queries |
| Portable | Standard format, works with many tools |
Log Location¶
Logs are stored following XDG conventions:
Example paths:
~/.local/share/cub/logs/myproject/cub-20260117-103000.jsonl
~/.local/share/cub/logs/backend-api/cub-20260116-143022.jsonl
Custom Log Location¶
Set via environment variable:
Event Types¶
task_start¶
Logged when a task begins execution:
{
"timestamp": "2026-01-17T10:30:00Z",
"event_type": "task_start",
"data": {
"task_id": "cub-054",
"task_title": "Add user caching",
"harness": "claude"
}
}
task_end¶
Logged when a task completes:
{
"timestamp": "2026-01-17T10:31:45Z",
"event_type": "task_end",
"data": {
"task_id": "cub-054",
"exit_code": 0,
"duration_sec": 105.3,
"tokens_used": 156892,
"budget_remaining": 343108,
"budget_total": 500000
}
}
loop_start¶
Logged at the start of each iteration:
loop_end¶
Logged at the end of each iteration:
{
"timestamp": "2026-01-17T10:32:00Z",
"event_type": "loop_end",
"data": {
"iteration": 1,
"tasks_processed": 1,
"duration_sec": 120.5
}
}
budget_warning¶
Logged when approaching budget limits:
{
"timestamp": "2026-01-17T11:30:00Z",
"event_type": "budget_warning",
"data": {
"remaining": 100000,
"threshold": 400000,
"total": 500000,
"percentage_remaining": 20.0
}
}
error¶
Logged on errors:
{
"timestamp": "2026-01-17T10:35:00Z",
"event_type": "error",
"data": {
"message": "Task execution failed: tests not passing",
"context": {
"task_id": "cub-055",
"exit_code": 1
}
}
}
Querying Logs with jq¶
Basic Queries¶
# Pretty print all events
cat session.jsonl | jq .
# Filter by event type
cat session.jsonl | jq 'select(.event_type == "task_end")'
# Get specific fields
cat session.jsonl | jq '{time: .timestamp, task: .data.task_id}'
Task Analysis¶
# List all completed tasks
cat session.jsonl | jq -r 'select(.event_type == "task_end") | .data.task_id'
# Find failed tasks
cat session.jsonl | jq 'select(.event_type == "task_end" and .data.exit_code != 0)'
# Task durations
cat session.jsonl | jq 'select(.event_type == "task_end") | {task: .data.task_id, duration: .data.duration_sec}'
Token Analysis¶
# Total tokens used
cat session.jsonl | jq -s '[.[] | select(.event_type == "task_end") | .data.tokens_used] | add'
# Tokens per task
cat session.jsonl | jq 'select(.event_type == "task_end") | {task: .data.task_id, tokens: .data.tokens_used}'
# Most expensive task
cat session.jsonl | jq -s '[.[] | select(.event_type == "task_end")] | sort_by(-.data.tokens_used) | .[0]'
Duration Analysis¶
# Average task duration
cat session.jsonl | jq -s '[.[] | select(.event_type == "task_end") | .data.duration_sec] | add / length'
# Slow tasks (>60 seconds)
cat session.jsonl | jq 'select(.event_type == "task_end" and .data.duration_sec > 60)'
# Total session time
cat session.jsonl | jq -s '[.[] | select(.event_type == "loop_end") | .data.duration_sec] | add'
Error Analysis¶
# All errors
cat session.jsonl | jq 'select(.event_type == "error")'
# Error messages only
cat session.jsonl | jq -r 'select(.event_type == "error") | .data.message'
# Errors with context
cat session.jsonl | jq 'select(.event_type == "error") | {message: .data.message, context: .data.context}'
Cross-Session Analysis¶
Query multiple sessions:
# All sessions for a project
cat ~/.local/share/cub/logs/myproject/*.jsonl | jq ...
# Recent sessions (last 7 days)
find ~/.local/share/cub/logs/myproject/ -mtime -7 -name "*.jsonl" -exec cat {} \; | jq ...
# Total tokens across all sessions
cat ~/.local/share/cub/logs/myproject/*.jsonl | \
jq -s '[.[] | select(.event_type == "task_end") | .data.tokens_used // 0] | add'
Log Retention¶
Cub does not automatically delete logs. Manage retention manually:
Delete Old Logs¶
Compress Old Logs¶
# Compress logs older than 7 days
find ~/.local/share/cub/logs/ -name "*.jsonl" -mtime +7 -exec gzip {} \;
Archive to Cloud¶
Status Files¶
In addition to JSONL logs, Cub writes status files for real-time monitoring:
Status File Contents¶
{
"run_id": "cub-20260117-103000",
"session_name": "default",
"phase": "running",
"started_at": "2026-01-17T10:30:00Z",
"current_task_id": "cub-054",
"current_task_title": "Add user caching",
"iteration": {
"current": 3,
"max": 50,
"percentage": 6.0
},
"budget": {
"tokens_used": 456892,
"tokens_limit": 1000000,
"cost_usd": 2.34,
"tasks_completed": 2
},
"events": [
{"timestamp": "2026-01-17T10:30:00Z", "level": "info", "message": "Run started"}
]
}
Querying Status¶
# Current status
cat .cub/runs/*/status.json | jq .
# Most recent run
ls -t .cub/runs/*/status.json | head -1 | xargs cat | jq .
Building Dashboards¶
Use logs to build monitoring dashboards:
Simple Stats Script¶
#!/bin/bash
# cub-stats.sh - Generate session statistics
LOG_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/cub/logs"
PROJECT=${1:-$(basename $(pwd))}
echo "=== Cub Statistics for $PROJECT ==="
echo
# Total sessions
sessions=$(ls -1 "$LOG_DIR/$PROJECT"/*.jsonl 2>/dev/null | wc -l)
echo "Total sessions: $sessions"
# Total tasks completed
tasks=$(cat "$LOG_DIR/$PROJECT"/*.jsonl 2>/dev/null | \
jq -s '[.[] | select(.event_type == "task_end" and .data.exit_code == 0)] | length')
echo "Tasks completed: $tasks"
# Total tokens
tokens=$(cat "$LOG_DIR/$PROJECT"/*.jsonl 2>/dev/null | \
jq -s '[.[] | select(.event_type == "task_end") | .data.tokens_used // 0] | add')
echo "Total tokens: $tokens"
# Success rate
total_tasks=$(cat "$LOG_DIR/$PROJECT"/*.jsonl 2>/dev/null | \
jq -s '[.[] | select(.event_type == "task_end")] | length')
if [ "$total_tasks" -gt 0 ]; then
rate=$(echo "scale=1; $tasks * 100 / $total_tasks" | bc)
echo "Success rate: ${rate}%"
fi
Export to CSV¶
# Export task data to CSV
cat session.jsonl | \
jq -r 'select(.event_type == "task_end") | [.timestamp, .data.task_id, .data.duration_sec, .data.tokens_used, .data.exit_code] | @csv' \
> tasks.csv
Compliance and Auditing¶
For compliance requirements:
Immutable Logs¶
Write logs to append-only storage:
Log Integrity¶
Hash logs for integrity verification:
# Generate checksums
sha256sum ~/.local/share/cub/logs/myproject/*.jsonl > checksums.txt
# Verify later
sha256sum -c checksums.txt
Audit Trail¶
Logs provide complete audit trail:
- When tasks ran
- What harness was used
- How long tasks took
- Token consumption
- Errors encountered
Troubleshooting with Logs¶
Task Keeps Failing¶
# Find the task's attempts
cat *.jsonl | jq 'select(.data.task_id == "cub-054")'
# Check error messages
cat *.jsonl | jq 'select(.event_type == "error" and .data.context.task_id == "cub-054")'
High Token Usage¶
# Find token-heavy tasks
cat *.jsonl | jq -s '[.[] | select(.event_type == "task_end")] | sort_by(-.data.tokens_used) | .[0:5]'