agents-cli
GitLab

Audit log

agents-cli writes a JSONL line to ~/.local/state/agents-cli/audit.log for every command that mutates state (profile registration, profile removal, symlink swap, update profile). Read-only commands (list, current, show, doctor) do not write to the log.

The location follows the XDG Base Directory Specification. Override with XDG_STATE_HOME or with AGENTS_CLI_DIR (see reference).

Format

Newline-delimited JSON — one entry per line, no array wrapper:

{"ts":"2026-06-09T10:21:33Z","event":"use","from":"alpha","to":"beta","actor":"lucas","cwd":"/Users/lucas/work","exit":0}
{"ts":"2026-06-09T10:21:38Z","event":"update_profile","profile":"beta","from":"7f3a8c1","to":"9e2b441","ff":true,"exit":0}
{"ts":"2026-06-09T10:22:11Z","event":"install","profile":"gamma","url":"git@example.com:workspace/gamma.git","target":"/Users/lucas/.config/agents-cli/profiles/gamma","exit":0}

The file is append-only — agents-cli never rewrites past entries. Truncation, rotation, and shipping to a log aggregator are the operator's responsibility.

Common fields

Every entry includes:

FieldTypeMeaning
tsstring (RFC 3339, UTC, second precision)When the event happened.
eventstringOne of install, add, remove, use, update_profile.
actorstringOS user that ran the command ($USER).
cwdstringWorking directory at invocation.
exitintegerProcess exit code. Non-zero means the command failed; the entry is still written.

Per-event fields

event=install

FieldMeaning
profileProfile name (after --name override, if any).
urlGit URL passed to install.
targetFinal clone destination on disk.
usedBoolean — true if --use was passed and the swap succeeded.

event=add

FieldMeaning
profileProfile name.
sourceOriginal path passed to add.
targetCanonical path the directory was copied to.

event=remove

FieldMeaning
profileProfile name that was unregistered.
forceBoolean — true if --force was used to remove the active profile.

event=use

FieldMeaning
fromPrevious active profile name. null if ~/.agents was unset or broken.
toNew active profile name.

event=update_profile

FieldMeaning
profileProfile name.
fromCommit SHA before the pull (short).
toCommit SHA after the pull (short). Identical to from if no change.
ffBoolean — whether the pull fast-forwarded. Always true on success (non-FF refuses).

Querying the log

The log is grep-friendly and jq-friendly:

# All profile swaps in the last 24 hours
jq -c 'select(.event=="use" and .ts > (now - 86400 | todateiso8601))' \
   ~/.local/state/agents-cli/audit.log

# Which profile was active at noon yesterday?
jq -c 'select(.event=="use" and .ts < "2026-06-08T12:00:00Z") | .to' \
   ~/.local/state/agents-cli/audit.log | tail -1

# Count failed update attempts per profile
jq -c 'select(.event=="update_profile" and .exit!=0) | .profile' \
   ~/.local/state/agents-cli/audit.log | sort | uniq -c

Rotation

agents-cli does not rotate the file. The expected workflow is either:

  • Let it grow (each entry is < 200 bytes; this is fine for years).
  • Use logrotate or newsyslog against ~/.local/state/agents-cli/audit.log if you want size-bounded retention.
  • Ship it to a log aggregator with a tail-and-forward agent of your choice.

What is NOT logged

By design, the log contains no secrets, no profile contents, no command output, and no environment dumps. The schema is fixed and small to make it auditable and easy to ship.