Logging & audit retention
Where logs live, how big they grow, and how to manage retention.
grith produces two kinds of log: the operational log (daemon health, errors, configuration changes) and the audit log (every supervised call decision). They live in different places and have different retention characteristics.
Operational log
| Location | Purpose | Format |
|---|---|---|
| stderr (foreground daemon) | Live | Text |
~/.local/share/grith/daemon.log (detached) | Rotating | Text |
| journald (systemd) | Live & retained | Structured |
Tune verbosity:
[general]
log_level = "info" # "trace" | "debug" | "info" | "warn" | "error"trace is verbose enough to noticeably slow the supervisor. Use debug for
filter tuning; leave at info otherwise.
Operational log rotation defaults: 10MB cap, 5 generations.
Audit log
The big one. Lives at ~/.local/share/grith/audit/audit.db. Each record is
~200–500 bytes. A busy agent (~50 calls/minute) produces:
| Window | Approx size |
|---|---|
| 1 hour | ~1.5MB |
| 1 day | ~40MB |
| 1 week | ~250MB |
| 1 month | ~1GB |
| 1 year | ~12GB |
Retention
Those figures are the raw rate at which records accumulate; the active database
does not grow without bound, because grith prunes it on a schedule. The active
audit database keeps a bounded window of recent records — older records are
archived (when cold storage is enabled) and then deleted from the active
database in a contiguous prune that preserves the audit chain's integrity.
Retention lives under the [audit] section:
[audit]
retain_full_days = 30 # days of records kept in the active database
# (0 disables retention — keep everything)
retain_compact_days = 7 # reserved; the single hash chain currently
# prunes on one cutoff, so this tracks
# retain_full_days today
cold_storage_enabled = true # archive pruned records before deleting them
prune_interval_hours = 24 # how often the prune runs (0 = once on startup)The daemon prunes once on startup and then every prune_interval_hours. With
retain_full_days = 0, nothing is ever pruned and the active database keeps
every record.
Cold archives
When cold_storage_enabled = true, each prune first writes the records it is
about to delete to
~/.local/share/grith/audit/cold/YYYY-MM-DD.jsonl.zst — date-partitioned,
zstd-compressed NDJSON — and only then removes them from the active database.
The archive is written before the delete, so an interrupted prune leaves the
records in both places rather than losing them.
Reclaiming disk space
Deleting rows from SQLite does not shrink the database file: the freed pages go on an internal freelist and are reused by later writes, so the file can stay large after a prune. To rewrite the database and reclaim that space, run:
grith audit compactcompact rewrites the database into a fresh copy, verifies the copy's audit
chain, and atomically swaps it in — on any failure the original is left
untouched. It is a manual maintenance operation and never runs on a timer.
Because it rewrites the file, it needs exclusive write access: stop the daemon
first (grith daemon stop), and it refuses to run on a quarantined chain.
To inspect the audit chain's integrity — the verification result and any forks
or gaps — without modifying anything, use the read-only grith audit diagnose.
Export and offload
Export records for offline retention or ad-hoc analysis:
grith audit export --format json > audit.jsonl
grith audit export --format csv --offset 0 --limit 5000 > audit.csvexport takes --format (json or csv), --offset, and --limit. Records
removed by retention are already kept automatically in the cold archive
described above, so there is no separate "prune to offload" step.
Or stream to a SIEM continuously (Enterprise): SIEM integration.
What's in an audit record
{
"id": "uuid-...",
"ts": "...",
"session": "...",
"operation": "file_read",
"target": "...",
"decision": "allow|queue|deny",
"resolved": "allow|deny|null",
"composite_score": 4.2,
"filters": [{ "name": "...", "score": ... }, ...],
"profile": "...",
"pid": 17421,
"command": "claude",
"user": "alice", // for multi-user setups
"annotations": {...} // free-form, e.g. from filter contributions
}Sensitive content (file bytes, payload contents) is not stored — grith
records the fact of each operation, never the data it moved. How much routine
activity is recorded is controlled by audit.completeness (decisions,
spawns, io, all); higher tiers record more events for forensics at the
cost of database growth, but none of them capture file or payload bytes.
Privacy
The audit log captures what the agent did. By design it doesn't include prompts, model outputs, or human-typed messages. For full session capture (e.g. for compliance), see Pro's session-recording feature (planned v0.2).
See also
grith audit— CLI for browsing/exporting- Audit API
[general]config- SIEM integration