The audit log
OpenCompanion keeps a local, append-only log of everything it does. Every run is written before it executes and fails closed if it cannot be, so no app can cause a run that leaves no trace.
OpenCompanion keeps a local, append-only audit log of everything it does. The log lives on your machine and is authored by the daemon. No app can write to it, edit it, or read it. It is how you can see, after the fact, exactly what ran and under what policy.
Logged before executed, fail-closed
Every dispatched run is written to the audit log before it executes. The write is a hard precondition: if the entry cannot be durably written, the run does not run. So the log can never be missing an execution that actually happened. This is the core of the trust model - an app that dispatches work cannot cause a run that leaves no trace.
Read it from the CLI
opencompanion log prints the trail without you hunting for the file. It shows the newest 50 entries oldest-first (so the terminal reads chronologically), one line each:
opencompanion log # newest 50, pretty, oldest-first
opencompanion log -n 200 # show more
opencompanion log --url https://your-app.example/api # one app only
opencompanion log --json | jq . # raw JSONL for pipingIt only ever reads: it never writes to the log and never creates the audit directory. On a machine that has run nothing yet, it just tells you where entries will appear.
What each entry records
Every line stamps its own ts (ISO-8601 time) and seq (a per-install sequence number), the backendUrl the event belongs to, and the event kind. The event kinds are a closed set:
| Event | Meaning |
|---|---|
pair / unpair | A pairing was added or removed. |
connect | A coding CLI was connected to an app. |
policy-change | A capability ceiling was clamped (records the old and new ceiling). |
dispatched | A run was accepted and is about to execute. |
completed / failed / cancelled | A run reached its terminal state. |
Run-scoped entries also carry the runId, the productId whose work folder was used, the toolId that executed it, the effective policy, and, for terminal events, an outcome and durationMs.
Your prompt text is never written to the log. Only its SHA-256 (promptSha256) is recorded, so you can confirm which prompt ran without the log itself storing your instructions or code.
Where it lives
The log is JSONL (one JSON object per line) under OpenCompanion's per-user data directory:
| OS | Path |
|---|---|
| macOS | ~/Library/Application Support/opencompanion/audit/audit.log |
| Linux | $XDG_DATA_HOME/opencompanion/audit/audit.log (defaults to ~/.local/share/opencompanion/audit/audit.log) |
| Windows | %APPDATA%\opencompanion\audit\audit.log |
It rotates by size (the active audit.log plus a few audit.log.1, audit.log.2, ... backups), so it never grows without bound. Read it with any tool you like:
tail -n 20 ~/.local/share/opencompanion/audit/audit.log | jq .Policy and confinement
Each paired app has a capability ceiling OpenCompanion enforces on every run - a permission mode and a network setting it can only clamp down, never raise - plus the work folder its dispatched runs are pinned to and the folders you grant a terminal session.
Updating
OpenCompanion auto-updates by default - staged, checksum-verified, and applied only while idle. Update on demand, check without changing anything, pin a version, roll back, or point at a mirror.