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

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 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 (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 (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 (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 (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:

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 (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:

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:

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:

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 (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
  • Security controls include automatic secret redaction and payload truncation as documented in 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →