Skip to content
lube

Audit logs

Same transactionSource-attributedBefore / after

The audit trail can't lie.

Every change writes its audit row inside the same database transaction as the change itself. If the change rolls back, so does the record. Who did it, what moved, and what it looked like before are all right there.

Its place in the loop

Audit logs remember what everyone else forgets.

One connected loop, held on the stage this capability serves. The other stages stay as context so you can see what feeds in and what comes next.

BD
Discovery
Feedback
Product
Engineering
Release
Reliability
Evidence

Stage inventory

Evidence

Prove what happened.

Audit logs

Review every workspace change and who made it.

Available now

Coming later reflects product vision, not a delivery commitment.

Recorded with the change, not after it

Every state-changing mutation writes its audit row inside the same database transaction as the change. If the change rolls back, its record rolls back with it — there are no phantom entries and no writes that quietly went missing. This is enforced at runtime: a handler that mutates without recording its audit row fails the request outright. It is transactional integrity on an append-only trail, not a paragraph you have to trust.

The trail, the way you query it

Time, actor, source, action, resource — expand any row.

The dashboard is one table. Each row carries who acted and where it came from; open one to read the structured before/after diff of exactly which fields moved.

TimeActorSourceActionResource
  • 2m agosarahDashboardflag.updatecheckout-v2

    Changes · before → after

    • rollout5%25%
    • statusoffon

    Written in the same transaction as the change.

  • 14m agodevDashboarddeployment.createstaging · #4821
  • 1h agoProvider eventintegration.subscription.updateacct_9f2 · req_1M2xR
  • 3h agoadminDashboardmember.rolejo · viewer to admin
/audit-logs · newest first

Every row knows where it came from

A Dashboard action, or a provider event.

A person acting in the dashboard is recorded with their identity and request context. A provider event — a Stripe webhook, say — has a null actor and is attributed to the provider through its request id.

Dashboardsarah
  • flag.updatecheckout-v2 · rollout 5% → 25%
  • apikey.revokeci-token · ip · user-agent
Provider eventactor: null
  • integration.subscription.updateactor: null · plan → team
  • integration.invoice.paidactor: null · $240
  • attributed via req_1M2xR (Stripe)
Attribution by origin

One diff, three ways to read it

Narrative, spec sheet, or the raw JSON tree.

The same structured change reads as a plain-English sentence for a reviewer, a typed field table for an engineer, or the full before/after tree when you need the exact shape. Your choice is saved to your account.

flag.update · checkout-v2

Narrative

  • rollout changed from 5% to 25%.
  • status changed from off to on.

Spec sheet

  • rollout5%25%changed
  • statusoffonchanged

JSON tree

{
  "before": {
    "rollout": "5%",
    "status": "off"
  },
  "after": {
    "rollout": "25%",
    "status": "on"
  }
}
Changes display · flag.update

Signal over churn

High-signal changes, not field noise.

Work-object rows are classified at write time. A status change is kept; a row that only nudged a field is marked noise — so the high-signal filter shows what actually mattered without you sifting.

work_object · activity

high_signal
  • work_object.updatestatus: In Progress → Resolvedkept
  • work_object.updatedescription editedfield noise
  • work_object.updatestatus: Backlog → In Progresskept
  • work_object.updatedisplayOrder shiftedfield noise
work_object activity · high_signal

Ask the trail a question

Filter by resource, actor, action, and date, or search the full text — then walk the results on keyset cursors, so deep pages stay fast and stable no matter how the trail grows. Every filter lives in the URL, so the exact investigation is a link you can share.

The investigation surface

Filter it down, then page through it.

Structured filters and a full-text query narrow the trail; opaque cursor tokens page through what is left. The whole query is URL-synced and shareable.

rollout OR revoke
  • resourcefeature_flag
  • actorsarah
  • actionflag.update
  • datelast 7d
cursor: v3|createdAt|…|2026-07-14T09:14Z|a1f9Load more →
GET /api/audit-logs

Why the trail is trustworthy

Recorded with the change, tailing as it happens.

Transactional

The audit row rolls back with the change.

An entry is written inside the same database transaction as the mutation. If the change rolls back, so does its record, enforced at runtime.

same txno phantomsenforced
  1. 01

    Mutation

    a change begins

  2. 02

    Audit row

    written in the same tx

  3. 03

    Commit

    both land together

  4. 04

    Rollback

    both undone together

One transaction, one record

Before and after

Read the delta, not a description.

Each entry keeps a structured, per-field diff, so you see exactly which fields moved and to what.

per fieldbefore → aftertyped

flag.update · checkout-v2

  • rollout

    5%25%
  • status

    offon

Written in the same transaction as the change.

A change, applied

Append-only

The record writes itself as the workspace changes.

Every state-changing action appends one row, newest on top, so an incident review reads the timeline instead of reconstructing it.

append-onlynewest firstretained

audit trail · tail

live
waiting for next event
  • sarah · flag.updatecheckout-v2 · rollout 5% to 25%2m ago
  • dev · deployment.createstaging · #482114m ago
  • admin · member.rolejo · viewer to admin1h ago
  • sarah · apikey.revokeci-token3h ago
  • dana · incident.resolveapi latency5h ago
Append-only, newest first

Who did what

See who is active in the trail.

Every row keeps its actor, so activity across the workspace is attributable at a glance.

actorteamip · agent
  • sarah42 actions
  • dev31 actions
  • admin18 actions
  • renovate9 actions
Actions per actor

The breadth of the trail

If it changes state, it is recorded.

Audit coverage spans the whole workspace. These are real action families, each with typed change schemas behind them, across release, reliability, access, product, and cost.

Release

Rollout and delivery.

feature_flag.*deployment.*environment.*api_spec.*

Reliability

Operations.

uptimeIncident.*uptimeMonitor.*uptimeStatusPage.*

Access

Who can do what.

member.*team.*api_key.*

Product

What you build.

feedback.*idea.*work_object.*product.*

Cost

Usage and spend.

ai_usage.*usage_meter.*integration.*

Filters

How you investigate.

resourceactoractiondatefull-text

Audit facts

1 tx

The audit row and the mutation share a single database transaction.

Enforced

A mutation that skips its audit row fails the request at runtime.

Diff

Each entry keeps a before-and-after view, readable three ways.

Keyset

Investigation pages ride stable, opaque cursor tokens.

What it records

See the changes audit history captures.

Answer 'who changed that?' in one search.

Start free

Every state change, recorded with its actor and diff.