Skip to content

Reference

Audit Trail

Every file write the agent performs appends one line to an actor-stamped log. It is on by default, needs no configuration, and is designed so that reading it later tells you who changed what, when, and from where.

Location

Default~/.oasis/audit.jsonl
OverrideOASIS_AUDIT_FILE

The file is JSON Lines: one complete JSON object per line, appended, never rewritten.

Line format

json
{"ts":"2026-08-24T11:42:07Z","actor":"milo@plant-3","tool":"Write","path":"/srv/plc/main.py","bytes":2841,"cwd":"/srv/plc"}
FieldMeaning
tsRFC 3339 timestamp in UTC, seconds precision
actorThe opaque actor string from --actor / OASIS_ACTOR
toolWhich tool performed the write
pathThe resolved absolute path written
bytesSize of the resulting file
cwdThe sandbox root the write happened under

What is recorded

The four tools that mutate files on disk:

ToolRecorded
WriteYes
AppendYes
EditYes
MultiEditYes, one line per file touched

The audit trail records file writes, not everything the agent does

Bash can write files without appearing here, and protocol writes (ModbusWrite, OpcUaWrite, EtherCatWriteIo) are not in this log. For a full record of agent activity, capture the event stream: <id>-agent.jsonl for a background agent, or the control protocol for a live session.

Setting the actor

bash
oasis-agent --actor "milo@plant-3"
export OASIS_ACTOR="ci-runner"

The string is opaque. The agent never parses it. Use whatever your organisation reconciles against: an email, a service account, a change-request number, a ticket id.

Without it, actor is null. On a shared machine, or anywhere the log will be read by someone who was not there, set it.

Design properties

PropertyBehaviour
Best-effortAn unwritable audit path never fails a tool call. The agent keeps working; the failure is reported to stderr once
Append-onlyThe file is opened O_APPEND and each line written with a single call, so concurrent tool executions interleave whole lines rather than fragments
No rotationThe agent does not rotate or prune. Use logrotate or an equivalent

Best-effort is a deliberate trade-off

The audit log records what happened; it does not gate what may happen. A full disk or a read-only home directory will stop the log without stopping the agent.

If your environment requires that no unaudited write can occur, enforce that outside the agent: a read-only mount, or a filesystem-level audit such as auditd.

Reading it

bash
# Everything one actor did today
jq 'select(.actor == "milo@plant-3")' ~/.oasis/audit.jsonl

# Every write under a project, newest last
jq -r 'select(.cwd == "/srv/plc") | "\(.ts) \(.tool) \(.path)"' ~/.oasis/audit.jsonl

# Total bytes written per actor
jq -s 'group_by(.actor) | map({actor: .[0].actor, bytes: (map(.bytes) | add)})' ~/.oasis/audit.jsonl

Shipping it elsewhere

Point OASIS_AUDIT_FILE at a named pipe or a location your log shipper tails:

bash
export OASIS_AUDIT_FILE=/var/log/oasis/audit.jsonl

Make sure the directory exists and is writable. The agent creates the parent directory if it can, and silently skips the line if it cannot.

Rotation

text
/var/log/oasis/audit.jsonl {
    weekly
    rotate 52
    compress
    missingok
    notifempty
    copytruncate
}

Use copytruncate rather than create. The agent holds the file open in append mode, and a rename would leave it writing to the rotated inode.

RecordContainsWhere
Audit trailOne line per file write~/.oasis/audit.jsonl
Session historyThe full conversation transcript~/.oasis/sessions/
Agent event streamEvery event from a background agent<id>-agent.jsonl
Conformance evidenceWhat was true about the machineAudit reports

The audit trail and an audit report are different things despite the shared word. The trail records what the agent did; the report records what the machine is.

software-defined automation