Skip to content

Audit dashboard

The consolidated audit dashboard at /admin/audit is the instance‑admin‑only operator surface that merges every per‑company audit table into one feed, so you don't have to bounce between separate /companies/<id>/... audit pages to answer "who did what, where, when?".

What it surfaces

The dashboard pulls the most recent rows from every audit source, merges them by created_at, applies any active filters, and renders the top of the merged list. The sources:

Raw source Friendly label What it records
secret_audit_events Secret access secret read/reveal/write/rotate (SEC‑017)
plugin_approval_events Plugin approval plugin allow / ban / rescind (incl. denied attempts)
egress_anomaly_events Egress denied deny‑by‑default DNS denials / warnings
a2a_dispatch_events A2A dispatch agent‑to‑agent RPC outcomes
pairing_audit_events DM pairing Slack/Telegram pairing state transitions
agent_prompt_proposals GEPA proposal prompt‑evolution proposer lifecycle
instance_flag_events Instance flag instance‑flag toggles
backup_runs Backup run trimus-cli backup / cron backup invocations
mcp_tool_calls MCP tool calls outbound tools/call invocations to external MCP servers — agent-initiated via the /mcp: verb (agent_id set) or from the external /mcp/{companyId} endpoint (agent_id NULL); see mcp.md

The per‑table cap and the merged cap are constants in the handler; raise them if you routinely miss rows. The friendly label is presentation‑only — the raw name is preserved as the cell's title and is what filtering/CSV/JSON use. A source that lands before its label mapping echoes its raw name (never silently mislabeled).

Read‑only

The dashboard never modifies state. Each row links ("view →") to the per‑table page where the action originated (instance‑flag rows link to /admin/operations/flags/<name>/history). Use those pages to make changes — the dashboard is for investigation.

Filters, sort, and export

The filter row composes with AND:

  • Company id (substring) — match any company UUID containing the value (a UUID prefix is most useful).
  • Actor — exact email, or the literal system for system‑attributed rows.
  • Source table — restrict to one raw source.
  • From / To — inclusive lower bound, exclusive upper bound on created_at.

Combine with ?sort=<column>&order=<asc|desc> for column sort.

  • CSV/admin/audit.csv takes the same query params and returns the filtered, sorted feed as CSV.
  • JSONGET /admin/audit?format=json (or Accept: application/json) returns the same feed wrapped in {items, count, pre_filter_count, filtered, filter, sort, generated_at}. Poll it from a runbook.

Per‑actor timeline and insights

  • /admin/audit/actor/{email} — every event by one actor, across sources, newest first. There's also an actors index.
  • /admin/audit/insights?window={24h|7d|30d} — pre‑aggregated companion: Top failures (top (source × action) failure pairs), Top actors (by event count, success/failure split), Source activity (per‑source counts with a bar chart), and a Daily breakdown. The window selector is the only knob; an unrecognised ?window= collapses to 24h.

Browser‑local triage helpers

The feed adds several operator‑private, browser‑local triage aids — no DB, not shared, not exported, gone if you clear localStorage:

  • Saved views — bookmark a filter+sort combo by name (trimus_audit_views).
  • Tags — free‑text labels per row, with a filter‑by‑tag box (trimus_audit_tags).
  • Review status — a three‑state per‑row dropdown (✓ Reviewed / ⚠ Action needed / 🚫 Ignored) with a bucket filter and counts; a checkbox column + action bar bulk‑mark a block of visible rows.
  • Alert rules (/admin/audit/alerts) — a foreground‑tab polling prototype: define "ping me if egress‑denied rows exceed N in the last hour", and the page polls the JSON feed every 30 s and flips the tab title + a banner on breach. No email/Slack/webhook escalation and polling stops when the tab is backgrounded — use it while actively triaging, not as a 24/7 watchdog.
  • Keyboard shortcuts — press ? for a vim‑style help overlay (j/k move rows, Enter opens the focused row, / focuses the actor filter, n refreshes). Bindings stand down inside text inputs.

When localStorage is unavailable (private mode, extension blocking), each affordance hides itself rather than showing half‑working controls.

CLI attribution

Audit rows written by the CLI are stamped actor=__cli__, or rendered system when the actor is NULL (the convention used by secret reveal/rotate, unpair-user, and trimus-cli flag set/clear). So an instance‑flag change made from a shell shows up as system in the feed.

Sibling instance‑admin pages share the same filter conventions:

  • /admin/operations — worker tick snapshots and the effective value of every operational flag, with per‑flag history. See monitoring.md.
  • /admin/subagents — recent subagent heartbeat runs across every tenant, with date/depth/parent‑agent filters, a per‑run detail page (cancel / re‑dispatch), a tree view, and per‑run cost bands. The cost bands tint rows yellow at TRIMUS_SUBAGENT_COST_WARN_USD (default $1.00) and red at TRIMUS_SUBAGENT_COST_CRITICAL_USD (default $5.00).
  • /admin/mcp/calls + /admin/mcp/servers/stats — the MCP‑specific drill‑downs. See mcp.md.
  • /admin/costs — cross‑tenant LLM spend. See costs.md.

Flag CLI

trimus-cli flag exposes the instance_flags runtime‑override layer to runbooks and CI. It uses the same DATABASE_URL as the rest of the operator CLI — no session cookie or HTTP bearer needed. Every set / clear writes an instance_flag_events row attributed to system.

# List every override
DATABASE_URL=postgres://... trimus-cli flag list

# Get one flag's effective override. Without --strict a miss exits 0;
# with --strict a miss exits 3 so a script can branch on "is it set?".
DATABASE_URL=postgres://... trimus-cli flag get TRIMUS_EMBEDDING_ENABLED --strict

# Set an override. Go's flag package wants --description BEFORE the
# positional <name> <value> pair.
DATABASE_URL=postgres://... trimus-cli flag set \
    --description="release window" DEBUG_VERBOSE_LOGGING true

# Clear an override (resolver falls back to env / default).
DATABASE_URL=postgres://... trimus-cli flag clear DEBUG_VERBOSE_LOGGING

Common pattern — wrap a release window with a temporary override:

trimus-cli flag set --description="release" DEBUG_VERBOSE_LOGGING true
deploy.sh "$@"
trimus-cli flag clear DEBUG_VERBOSE_LOGGING

The HTTP API at /api/admin/flags{,/{name}} covers the same surface for operators with a session cookie or bearer token. Effective values and toggles are also on /admin/operations.

Auth posture

Instance‑admin only. A non‑admin user, an API‑key actor, or an unauthenticated request all get 403 before any DB access — matching the rest of the /admin/... family.

Where to next