# Using Agent-Native Audit Log to Track Agent vs Human Mutations

> Learn how to use the Agent Native audit log to track agent vs human mutations. This built-in subsystem automatically records data changes, identifying the caller and the run.

- Repository: [Builder.io/agent-native](https://github.com/BuilderIO/agent-native)
- Tags: how-to-guide
- Published: 2026-06-27

---

**Agent-Native provides a built-in audit-log subsystem that automatically records every data mutation, capturing the identity of the caller—whether a human user or the AI agent—along with the specific run that caused the change.**

The **agent-native audit log** in BuilderIO/agent-native creates an immutable, append-only record of all mutating actions, enabling compliance auditing, debugging, and governance without manual instrumentation. This subsystem captures the actor type, run context, and sanitized payload for every operation performed through the framework's action layer.

## Core Architecture Components

The audit system spans multiple packages, with schema definitions in Dispatch and automatic capture handled by the Core framework.

### The agent_audit_log Table Schema

The database schema in [`packages/dispatch/src/db/schema.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/dispatch/src/db/schema.ts) defines the `agent_audit_log` table as the durable storage layer. Each row captures:

- `actor_id` – The identifier of the user or agent performing the action
- `actor_type` – Enum value of `human` or `agent` distinguishing the caller type
- `run_id` – The specific agent-run UUID that performed the mutation
- `app_id` – The target application namespace (e.g., `assets`, `slides`)
- `summary` – A redacted, safe description of the operation
- `payload` – Truncated JSON representation of the change

This structure ensures that every mutation is traceable to its originator and execution context.

### Automatic Action Wrapping

Every action created with `defineAction` is automatically wrapped by the audit layer. As noted in [`packages/core/CHANGELOG.md`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/CHANGELOG.md) (line 1051), mutating actions are logged by default, while read-only actions can opt-in via `audit.onRead`.

When an action executes, the framework inspects `request.actor` from the context—either a signed-in user ID or the synthetic "agent" identity—and persists this as `actor_type` in the audit record.

### Security and Data Handling

Before persistence, the audit layer applies security controls documented in [`packages/core/docs/content/audit-log.md`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/docs/content/audit-log.md) (lines 8-22):

- **Secret Redaction**: Fields containing tokens, passwords, or bearer strings are automatically stripped
- **Size Limits**: Oversized payloads are truncated to prevent database bloat
- **Safe Summaries**: The `summary` field contains only redacted, safe descriptions

These guarantees ensure the audit log never becomes a credential dump while maintaining forensic value.

## Distinguishing Agent vs Human Mutations

The framework differentiates between agent and human mutations through the `actor_type` field. When the AI agent performs operations, `request.actor` contains the synthetic agent identity; for human users, it contains their authenticated user ID.

For example, in [`templates/assets/actions/generate-image.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/assets/actions/generate-image.ts) (line 36), actions add a `source` field (`"chat"`, `"ui"`, `"a2a"`) that appears in the audit row, making it trivial to answer: "Did the agent generate this image, or did a user click Generate?"

## Querying and Accessing Audit Events

The system exposes two core actions for retrieving audit data, registered in [`packages/core/src/server/action-discovery.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/server/action-discovery.ts) (lines 594-595):

- **`list-audit-events`** – Paginated search with filtering capabilities
- **`get-audit-event`** – Fetch a single row by primary key

Both actions enforce access-filtering logic identical to standard data queries. Organization administrators can view the entire org-wide feed, while regular users see only their own runs.

### Filtering by Actor Type

You can query specifically for agent or human mutations:

```typescript
import listAuditEvents from "./list-audit-events.js";

const agentRuns = await listAuditEvents.run(
  { limit: 50, where: { actor_type: "agent", app_id: "assets" } },
  ctx
);

```

The UI for the **Audit** view consumes this same API, as implemented in [`templates/assets/app/hooks/use-navigation-state.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/assets/app/hooks/use-navigation-state.ts) (line 99).

## Configuration and Retention

The audit subsystem is configurable through environment variables:

- `AGENT_NATIVE_AUDIT_RETENTION_DAYS` – Defaults to 365 days; controls table purging
- `AGENT_NATIVE_AUDIT_ENABLED` – Set to `false` to disable the subsystem entirely

These settings provide operational flexibility for storage management and compliance requirements.

## Practical Implementation Examples

### Logging Custom Mutating Actions

When you create actions using `defineAction`, audit entries are automatic. You only need to implement the business logic:

```typescript
import { defineAction } from "@agent-native/core";
import { z } from "zod";

export default defineAction({
  // Mutating action: creates a new note
  input: z.object({ title: z.string(), body: z.string() }),
  // No extra audit config needed – the system logs actor, run, and payload
  async handler({ input, ctx }) {
    await db.note.insert({ ...input, createdBy: ctx.request.actor.id });
  },
});

```

### Filtering Audit Events by Actor

To programmatically distinguish between agent and human activity:

```typescript
import listAuditEvents from "./list-audit-events.js";

async function recentAgentMutations(ctx) {
  const rows = await listAuditEvents.run(
    { limit: 10, where: { actor_type: "agent" } },
    ctx
  );
  return rows.map(r => ({
    id: r.id,
    summary: r.summary,
    when: r.created_at,
    app: r.app_id,
  }));
}

```

### Displaying Audit Provenance in UI

The Assets template demonstrates UI integration in [`templates/assets/app/hooks/use-navigation-state.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/assets/app/hooks/use-navigation-state.ts):

```tsx
function AuditTab() {
  const { data } = useActionQuery(listAuditEvents, { limit: 50 });
  return (
    <section>
      <h2>Audit Log</h2>
      <ul>
        {data?.map(ev => (
          <li key={ev.id}>
            {ev.actor_type === "agent" ? "🤖 Agent" : "👤 Human"} – {ev.summary}
          </li>
        ))}
      </ul>
    </section>
  );
}

```

The i18n strings in [`templates/assets/app/i18n/en-US.ts`](https://github.com/BuilderIO/agent-native/blob/main/templates/assets/app/i18n/en-US.ts) (lines 455-460) provide admin-only view distinctions for organization-wide auditing.

## Summary

- The **agent-native audit log** automatically captures every mutation with `actor_type`, `run_id`, and sanitized payloads stored in the `agent_audit_log` table
- **Agent vs human** mutations are distinguished via the `actor_type` field populated from `request.actor` context
- Query using `list-audit-events` and `get-audit-event` actions with role-based access control enforced at [`packages/core/src/server/action-discovery.ts`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/src/server/action-discovery.ts)
- Security controls include automatic secret redaction and payload truncation as documented in [`packages/core/docs/content/audit-log.md`](https://github.com/BuilderIO/agent-native/blob/main/packages/core/docs/content/audit-log.md)
- Configure retention via `AGENT_NATIVE_AUDIT_RETENTION_DAYS` (default 365) and disable with `AGENT_NATIVE_AUDIT_ENABLED=false`

## Frequently Asked Questions

### How does agent-native distinguish between agent and human mutations?

The framework inspects `request.actor` from the execution context, which contains either a signed-in user ID or a synthetic agent identity. This value is persisted in the `actor_type` column as either `human` or `agent`, allowing queries to filter mutations by their originator without additional application code.

### Can I disable the audit log if I don't need compliance tracking?

Yes. Set the environment variable `AGENT_NATIVE_AUDIT_ENABLED=false` to disable the subsystem entirely. When enabled, you can control data retention using `AGENT_NATIVE_AUDIT_RETENTION_DAYS` (default 365 days) to automatically purge old records and manage storage costs.

### Do I need to manually instrument my actions to support audit logging?

No. Any action created with `defineAction` is automatically wrapped by the audit layer. Mutating actions are logged by default; read-only actions can opt-in via `audit.onRead`. The system automatically captures the actor, run ID, and payload without requiring boilerplate code in your handlers.

### How are sensitive values prevented from leaking into the audit log?

Before persistence, the audit layer scans payloads for patterns matching secrets, tokens, and passwords, stripping them automatically. Additionally, oversized payloads are truncated and summaries are redacted to safe descriptions, ensuring compliance with security policies while maintaining forensic utility.