Getting started

Audit log

What the audit trail records, filtering it by group, primitive, action, actor and time, and retention per plan.

Every change to a primitive is recorded in an audit trail you can read for the whole workspace, one group or one primitive. Entries are written in the same transaction as the change they record, so the trail never drifts from the data.

What's recorded

AreaActions
Groupsgroup.create
Primitive lifecycleprimitive.create, primitive.delete, primitive.pause, primitive.resume, primitive.export, snapshots, restore and fork
Databasedb.exec, db.batch (the SQL text, never parameter values) and branch create, promote and discard
Filesystemfile writes, moves and deletes
Queuesends, acks, retries, dead letters, purges and topic publishes (never message bodies)
Memoryremember, forget and supersede
Vaultset, delete, grant and revoke, every use (vault.use with host, method, path and status) and every refusal (vault.denied)

Reads are not audited. Secret values never appear in an entry.

Each entry is an AuditEntry:

{
  "id": 42,
  "ts": 1760600000000,
  "group": "agent-42",
  "primitive": "db",
  "primitive_id": "01jbz3k8m5q2w7x9v4n6t0r1ce",
  "instance": "orders",
  "actor": "key:01k…",
  "action": "db.exec",
  "target": null,
  "detail": { "sql": "insert into tasks …" }
}

primitive is "group" for group-level events such as group creation, and then primitive_id and instance are null. Every event about a primitive, including lifecycle events such as create, pause, snapshot, fork and move, carries that primitive's type, primitive_id and instance name. actor is who did it: a dashboard user's id, key:<id> for an API key, key:oag_<id> for an MCP client signed in with OAuth, local for primitives dev.

Reading the trail

// The whole workspace, newest first
const { data, next_cursor } = await p.audit({ limit: 50 });

// Filters combine
await p.audit({ group: "agent-42", type: "db", action: "db.", since: Date.now() - 86_400_000 });

// One group, one primitive
await p.group("agent-42").audit({ actor: "key:01k…" });
await orders.audit({ action: "db.exec" });

// Every page
for await (const entry of p.auditAll({ group: "agent-42" })) console.log(entry.action);
page = await p.audit(group="agent-42", action="db.", limit=50)
async for entry in p.audit_all(type="vault"):
    print(entry.action, entry.target)
trail = await orders.audit(action="db.exec")
FilterMeaning
groupOne group
typegroup for group-level events, or db, fs, queue, memory, vault for every event about primitives of that type
primitiveOne primitive by id: its data events and its lifecycle events (create, pause, snapshot, restore, fork, move, branches), never another primitive's
actionExact (db.exec) or a prefix ending in . or * (db., db.branch*)
actorExact actor (key:01k…, local) or a prefix ending in * (key:* for every API key)
since, untilInclusive bounds in milliseconds since the epoch
limit, cursorPage size (up to 200) and the previous page's next_cursor

The trail includes SQL text and secret-use hosts, so it is account-only: it needs a workspace API key, and scoped keys get 403 forbidden. Reading it is not an operation.

In the dashboard

Audit logs (under Manage) shows the workspace trail with the same filters, kept in the URL so a filtered view can be shared. Each primitive's page links to its own entries, and each group's page to the group's.

Retention

PlanAudit log
StarterNot included: the API answers 403 plan_limit
ProThe last 30 days
EnterpriseCustom

On Pro, since is raised to 30 days ago if you ask for more. Self-hosted engines keep the full trail.