Manage · Audit log
Trace an action before you export it
RepoOps gathers mirrored audit envelope events into one newest-first table. Narrow the question by repo, time, actor, action, or account, inspect the row, then export the same bounded result set.
For: the repository operator investigating an action, and the team member reviewing events already pushed to the hosted account
What it does, and why it helps
The desktop Audit log reads kind:"audit" envelopes from each visible tracked repository's event store. It projects the time, repository, actor, action, account, scope, and payload into one row shape. Search applies all selected filters and sorts the result newest first. Last 7d fills an inclusive date window. Export CSV sends the same filters and limit to the API.
That distinction matters: this is the envelope mirror, not the original audit ledger. Writers in lib/audit-log.mjs append the primary day-partitioned record first, then try the envelope mirror without failing the primary write if mirroring fails. The table can therefore omit a primary row. It also returns at most the chosen limit, 200 by default and 5,000 at most. Start with a bounded question, inspect the payload in context, and treat the export as that filtered record rather than proof that no other event exists.
The pain. A timestamp or action name is not enough to explain an incident. The useful question joins who acted, which repository and account were in scope, what action was recorded, and what bounded payload came with it.
The point of view. Narrow the audit question before exporting. A filtered row is evidence for an investigation, not a verdict about intent and not a claim that the trail is complete.
What gets easier. Finding recent rows across tracked repositories, matching an actor id without case sensitivity, selecting an action the current window has recorded, and carrying the same filters into a CSV download.
When it helps. Use it after an account, repository, supervisor, connector, SAML, SCIM, or other producer writes an audit envelope and you need the actor, action, time, account, or payload fields in one view.
Its limits. The page does not reconstruct intent, verify a payload against its source system, or prove completeness. The desktop payload cell shows at most 240 characters, though CSV keeps the projected payload. Undated local reads do not open monthly archives. The result and CSV are capped at 5,000 rows.
Understand it in 30 seconds
Read the narration
- 0:00 An event happened.
- 0:01 A timestamp alone cannot answer who acted or what changed.
- 0:06 Filter by actor and action first, then narrow the time window and repository.
- 0:13 RepoOps shows the mirrored envelope's actor, account, action, and bounded payload.
- 0:18 The CSV applies the same filters and inclusive dates you inspected.
- 0:23 Keep the filtered record, then investigate the source event in its context.
Synthetic example. Read the guide
Where to find it
Where to find it
- Desktop:
localhost:4000, then Local settings in the sidebar, then Audit log under Workspace utilities. - Hosted:
repoops.ai/team/cloud-audit, from Team & settings in the sidebar, then Cloud audit under Account and access. - Keyboard: ⌘ K, then type “Audit log”.
When to use it
Trace an action reported by an operator
Situation. An operator remembers part of the actor id and the day, but not which tracked repository emitted the row.
What you do. Leave Repo at All repos. Set Since (date) and Until (date), enter the fragment in Actor (substring), choose the recorded Action, and press Search.
What you see. The table shows When (UTC), Repo, Actor, Action, Account, and Payload. Actor matching is case-insensitive substring matching; Action and Account ID are exact matches.
What it establishes. You have a bounded set of mirrored envelopes to compare with the source action. A matching row establishes what the envelope recorded, not why the actor acted.
Hand off a filtered event set
Situation. A reviewer needs the rows behind a date and action question in a file, without copying a truncated payload preview from the table.
What you do. Apply the filters, choose a Limit that covers the intended working set, press Search, inspect the count, then press Export CSV.
What you see. The CSV uses stable columns for timestamp, repository, actor type, actor id, action, account, scope, and payload. It carries the current filter query and limit.
What it establishes. The reviewer gets the same capped, filtered rows as the query. If the cap was reached, narrow the date or repository and export another window; the file does not claim to contain the whole trail.
Before you start
- Supported versions
- RepoOps desktop v0.3.1, the release this guide was read against.
- Where it runs
- Local: Local settings, Workspace utilities, Audit log. Hosted: repoops.ai/team/cloud-audit reads audit envelopes the account has received. The hosted surface omits the desktop Repo and Account ID inputs, but keeps Since, Until, Actor (substring), Action, Limit, Search, and Export CSV.
- Permissions
- A local install without an explicit tenant scope scans every tracked repository, including repositories with different account labels. An explicit tenant scope reads that account's repositories plus unassigned repositories. Hosted access needs an authenticated, entitled team member. The sidebar marks Audit log owner/admin, but the page itself checks membership and does not call canManage, so the navigation label is not an access-control boundary.
- Connections
- The desktop needs tracked repository paths containing .claude/brain/events day files. The hosted view needs audit envelopes in the account's events table, either pushed from a bound device through the opted-in cloud path or written by a hosted producer.
- Plan
- The local route has no plan gate. The hosted page is inside the hosted dashboard entitlement and seat checks. This shared Audit log CSV is not the separate Enterprise team administration export at /team/audit.
Configure it
- State the question before choosing a limit.
Decide whether repository, date, actor, action, or account is the fact you are testing. The API joins all supplied filters, so each added field narrows the same result set.
- Set the repository and time window.
Keep Repo at All repos for a cross-repository question, or choose one tracked repo. Since (date) and Until (date) are inclusive. Last 7d fills both dates and runs the query.
- Narrow by actor, action, or account.
Actor (substring) ignores case. Action is exact and its choices come from actions recorded in the current result window. Account ID is an exact payload match and narrows within the already visible repository scope; it never widens account access.
- Inspect before exporting.
Press Search, check the row count and limit, then read the table. Payload omits action and accountId because each has its own column, and the preview truncates after 240 characters. Use Export CSV when you need the full projected payload.
| Setting | Where | A sensible choice | Why it matters |
|---|---|---|---|
Repo | Audit log controls | All repos (the default), or one tracked repository | This chooses which visible repository roots the local reader scans. |
Since (date) | Audit log controls | Blank, or the first day to include | A date also lets the local reader open matching monthly archives when recent raw files do not fill the limit. |
Until (date) | Audit log controls | Blank, or the last day to include | A date-only value includes the whole named day. |
Actor (substring) | Audit log controls | Blank, or part of an email or id | The match is case-insensitive against actor.id. |
Action | Audit log controls | Any (the default), or an action recorded in the window | The match is exact. The list is derived from recorded rows rather than a fixed vocabulary. |
Account ID | Audit log controls | Blank, or an exact payload account id | It narrows the current scope and cannot expose another tenant's repository. |
Limit | Audit log controls | 200 (the default); 50, 1,000, or 5,000 | The limit caps both the displayed result and the CSV. The API clamps any other value from 1 to 5,000. |
What you should see
A recent cross-repository view
Configuration. Repo is All repos, the other filters are blank, and Limit is 200.
Expect. The desktop returns up to 200 newest mirrored audit envelopes from visible tracked repositories. An undated query reads current raw day files and does not open monthly archives.
Verify. The meta line reports the row count, limit, and account. The first column is When (UTC), and the empty state reads No audit rows match these filters.
The Last 7d date window
Configuration. Press Last 7d, then optionally add Actor (substring) or Action.
Expect. RepoOps fills Since (date) with the date seven days before the current date, fills Until (date) with the current date, and runs Search. Both boundary dates are included.
Verify. The meta line names the since and until values. Each returned When (UTC) value falls inside that date window.
A CSV that matches the query
Configuration. Set a bounded date, repository, actor, action, or account question, choose the limit, inspect Search, then press Export CSV.
Expect. The browser downloads audit-YYYY-MM-DD.csv with the current filters and no more than the selected limit.
Verify. The local header starts ts, repoId, actorType, actorId, action, accountId, scope, payload. Compare its row count and filter values with the on-screen query before treating it as evidence.
Data and cost
- What is captured
- The reader projects an envelope id, timestamp, actor type and id, scope, payload action, payload accountId, repository id, and the remaining payload. The page does not create those events. Writers decide their payload; for example, cross-client ask stores a SHA-256 query hash rather than the query text.
- Who can see it
- On a local single-operator install, the view spans every tracked repository. An explicit local tenant scope narrows repository roots. Hosted queries require an authenticated account membership and filter the events table by account id. The hosted navigation hides this row from non-managers, but the route currently enforces membership rather than an owner/admin role.
- How long it is kept
- Local envelope day files stay raw for 30 days by default, controlled by REPOOPS_EVENTS_RETENTION_DAYS, then move into monthly gzip archives rather than being deleted. Primary day-partitioned audit ledgers stay raw for 90 days by default through REPOOPS_AUDIT_RETENTION_DAYS, then archive. The local reader opens envelope archives only for a dated query. Hosted audit rows are hard-deleted after 13 months. A tab visit is stored as an audit row but records usage, so it goes after 30 days with the rest of the hosted telemetry, and REPOOPS_NEON_RETENTION_DAYS can shorten that 30 and nothing else. An organization window may tighten either, but not extend them. account.delete-requested rows are exempt from the hosted event sweep.
- What leaves the machine
- Local Search and Export CSV read repository files and make no model call. The download leaves the process only to the requesting browser. When cloud event sync is enabled, redacted envelopes are pushed to the bound hosted account; the hosted page reads only events already stored there.
- What it costs
- There is no model or third-party API call for Search, Last 7d, or Export CSV. Local cost is file reads and storage. Hosted use consumes the existing database, network, and hosted plan resources, with no per-query model spend.
When the result differs
| Symptom | Likely cause | Next action |
|---|---|---|
| An old event is missing from an unfiltered local search. | Undated reads do not open monthly gzip archives, even when fewer rows than the limit were found in raw day files. | Set Since (date) or Until (date) to the period that contains the event, then press Search again. |
| A row exists in a primary audit ledger but not in Audit log. | The primary write happens first and the envelope mirror is best effort. This page reads only audit envelopes that reached the mirror. | Inspect the producer's day-partitioned audit ledger. Do not use an absent mirror row as proof that the primary action did not occur. |
| The payload cell ends before the expected field. | The table preview is capped at 240 characters and omits action and accountId, which have their own columns. | Export the filtered rows and inspect the payload column in the CSV. |
| The export stops at 200 or 5,000 rows. | Limit defaults to 200 and the API hard cap is 5,000. Export CSV uses that same limit. | Choose the intended Limit and narrow the date or repository into separate windows if the result reaches the cap. |
| The hosted table has no row that appears locally. | The hosted page sees only audit envelopes pushed or written into that account's events table, and hosted retention may already have removed an older row. | Check the bound account, event sync state, selected dates, and account membership. Keep the local primary ledger as the source record for its producer. |
- Disable
- Not provided. Audit log is a read and export surface with no enable switch; disabling a producer or cloud sync is a separate action and does not remove stored rows.
- Roll back
- Not provided. Search, Last 7d, and Export CSV do not mutate the audit store, so there is no Audit log change to roll back.
- Revoke access
- Not provided on this page. Hosted access follows session, device-token, and team-membership controls. Revoke those credentials or membership on their owning surfaces; the local Audit log has no feature-specific credential.
- Delete
- Not provided. The page has no row-delete action. Local envelopes live under .claude/brain/events and primary rows under .claude/brain/audit; hosted event rows leave through retention or the separate account deletion process.
Related tasks
Maintenance evidence
- Feature id
audit-log(spine leafaudit-log)- Owner
- Identity production (K5.F), Guide: LDG-0717
- Supported product version
- RepoOps v0.3.1
- Last verified
- 2026-09-15, read against origin/main at 52366bb6d; labels read from the served tab source; local and hosted routes, retention jobs, scope checks, and tests read in the same pass
- Example fixtures
- lib/audit-events.test.mjs, lib/audit-api.test.mjs, lib/audit-log.events.test.mjs, website/app/api/audit/audit.test.ts, website/lib/audit-until-param.test.ts, website/lib/audit-actions.db.test.ts
- Source references
lib/canonical-spine.json,public/audit-log.html,lib/audit-api.mjs,lib/audit-events.mjs,lib/audit-log.mjs,lib/audit-partition.mjs,lib/brain-events.mjs,website/app/team/(home)/cloud-audit/page.tsx,website/lib/audit-events-repo.ts,website/app/api/audit/route.ts,website/app/team/(home)/layout.tsx,website/app/api/cron/events-retention/route.ts- Documentation review
- Independent review requested on the slice pull request; not yet recorded.
- Video review
- Narrated story rendered and published 2026-09-26 (render 24f0bd0dd5f6, LDG-1018) with the breadcrumb Local settings, checked against main at 0f24215b5. One frame, the captions and the transcript were reviewed by the authoring agent, not an independent reviewer; the audio was not listened to by a person. Narration is the provisional Windows voice until LDG-0721.
Last updated