@agent-native/core 0.70.3 → 0.72.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +51 -0
  3. package/corpus/core/docs/content/actions.md +23 -0
  4. package/corpus/core/docs/content/audit-log.md +111 -0
  5. package/corpus/core/docs/content/multi-app-workspace.md +2 -2
  6. package/corpus/core/docs/design/durable-agent-runs.md +458 -4
  7. package/corpus/core/package.json +2 -1
  8. package/corpus/core/src/action.ts +80 -1
  9. package/corpus/core/src/agent/durable-background.ts +192 -0
  10. package/corpus/core/src/agent/production-agent.ts +357 -13
  11. package/corpus/core/src/agent/run-manager.ts +66 -3
  12. package/corpus/core/src/agent/run-store.ts +143 -23
  13. package/corpus/core/src/agent/types.ts +20 -0
  14. package/corpus/core/src/application-state/store.ts +5 -0
  15. package/corpus/core/src/audit/actions/get-audit-event.ts +23 -0
  16. package/corpus/core/src/audit/actions/list-audit-events.ts +65 -0
  17. package/corpus/core/src/audit/cleanup-job.ts +100 -0
  18. package/corpus/core/src/audit/config.ts +91 -0
  19. package/corpus/core/src/audit/index.ts +43 -0
  20. package/corpus/core/src/audit/record.ts +143 -0
  21. package/corpus/core/src/audit/redact.ts +109 -0
  22. package/corpus/core/src/audit/store.ts +244 -0
  23. package/corpus/core/src/audit/types.ts +125 -0
  24. package/corpus/core/src/chat-threads/store.ts +10 -0
  25. package/corpus/core/src/client/AgentPanel.tsx +12 -9
  26. package/corpus/core/src/client/AssistantChat.tsx +6 -0
  27. package/corpus/core/src/client/blocks/library/FileTreeBlock.tsx +72 -14
  28. package/corpus/core/src/client/chat/repo-helpers.ts +38 -0
  29. package/corpus/core/src/db/client.ts +4 -0
  30. package/corpus/core/src/db/widen-columns.ts +75 -0
  31. package/corpus/core/src/deploy/build.ts +96 -0
  32. package/corpus/core/src/deploy/workspace-deploy.ts +121 -0
  33. package/corpus/core/src/mcp/build-server.ts +23 -13
  34. package/corpus/core/src/oauth-tokens/store.ts +6 -0
  35. package/corpus/core/src/provider-api/custom-registry.ts +8 -0
  36. package/corpus/core/src/resources/store.ts +10 -0
  37. package/corpus/core/src/scripts/runner.ts +6 -3
  38. package/corpus/core/src/server/action-discovery.ts +6 -0
  39. package/corpus/core/src/server/action-routes.ts +1 -0
  40. package/corpus/core/src/server/agent-chat-plugin.ts +133 -66
  41. package/corpus/core/src/server/auth.ts +5 -0
  42. package/corpus/core/src/server/core-routes-plugin.ts +14 -0
  43. package/corpus/core/src/server/security-headers.ts +9 -6
  44. package/corpus/core/src/settings/store.ts +6 -0
  45. package/corpus/core/src/templates/workspace-core/.agents/skills/audit-log/SKILL.md +93 -0
  46. package/corpus/core/src/usage/store.ts +6 -0
  47. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +19 -0
  48. package/corpus/templates/analytics/AGENTS.md +8 -0
  49. package/corpus/templates/analytics/actions/compose-dashboard.ts +317 -0
  50. package/corpus/templates/analytics/changelog/2026-06-23-build-large-first-party-analytics-dashboards-in-one-fast-cal.md +6 -0
  51. package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +574 -0
  52. package/corpus/templates/calendar/app/components/calendar/GoogleConnectBanner.tsx +60 -6
  53. package/corpus/templates/calendar/changelog/2026-06-23-added-a-heads-up-explaining-google-s-app-not-verified-screen.md +6 -0
  54. package/corpus/templates/clips/app/components/recorder/recorder-engine.ts +20 -43
  55. package/corpus/templates/clips/app/components/recorder/recording-toolbar.tsx +5 -1
  56. package/corpus/templates/clips/app/lib/countdown-audio-cue.ts +3 -51
  57. package/corpus/templates/clips/changelog/2026-06-23-dragging-the-desktop-camera-bubble-now-glides-to-a-stop-at-t.md +6 -0
  58. package/corpus/templates/clips/changelog/2026-06-23-public-clips-now-play-inline-in-slack-connect-a-workspac.md +6 -0
  59. package/corpus/templates/clips/chrome-extension/PERMISSIONS.md +72 -0
  60. package/corpus/templates/clips/chrome-extension/public/manifest.json +1 -10
  61. package/corpus/templates/clips/chrome-extension/src/background.ts +163 -32
  62. package/corpus/templates/clips/chrome-extension/src/content-script.ts +301 -24
  63. package/corpus/templates/clips/chrome-extension/src/offscreen.ts +245 -67
  64. package/corpus/templates/clips/chrome-extension/src/overlay.css +77 -43
  65. package/corpus/templates/clips/chrome-extension/src/overlay.html +7 -1
  66. package/corpus/templates/clips/chrome-extension/src/overlay.ts +102 -38
  67. package/corpus/templates/clips/chrome-extension/src/popup.html +62 -5
  68. package/corpus/templates/clips/chrome-extension/src/popup.ts +275 -4
  69. package/corpus/templates/clips/chrome-extension/src/styles.css +34 -0
  70. package/corpus/templates/clips/chrome-extension/vite.config.ts +5 -0
  71. package/corpus/templates/clips/desktop/src/lib/audio-cue.ts +21 -16
  72. package/corpus/templates/clips/desktop/src/lib/recorder.ts +10 -17
  73. package/corpus/templates/clips/desktop/src/overlays/bubble.tsx +73 -23
  74. package/corpus/templates/clips/desktop/src/overlays/countdown.tsx +0 -6
  75. package/corpus/templates/clips/desktop/src/overlays/toolbar.tsx +56 -46
  76. package/corpus/templates/clips/desktop/src/styles.css +33 -5
  77. package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +113 -0
  78. package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +3 -0
  79. package/corpus/templates/clips/server/lib/media-permissions.ts +5 -1
  80. package/corpus/templates/clips/shared/recording-audio.ts +62 -0
  81. package/corpus/templates/clips/shared/recording-core.ts +94 -0
  82. package/dist/action.d.ts +31 -0
  83. package/dist/action.d.ts.map +1 -1
  84. package/dist/action.js +45 -1
  85. package/dist/action.js.map +1 -1
  86. package/dist/agent/context-xray/schema.d.ts +1 -1
  87. package/dist/agent/durable-background.d.ts +60 -0
  88. package/dist/agent/durable-background.d.ts.map +1 -0
  89. package/dist/agent/durable-background.js +144 -0
  90. package/dist/agent/durable-background.js.map +1 -0
  91. package/dist/agent/observational-memory/schema.d.ts +1 -1
  92. package/dist/agent/production-agent.d.ts +20 -0
  93. package/dist/agent/production-agent.d.ts.map +1 -1
  94. package/dist/agent/production-agent.js +320 -14
  95. package/dist/agent/production-agent.js.map +1 -1
  96. package/dist/agent/run-manager.d.ts +48 -0
  97. package/dist/agent/run-manager.d.ts.map +1 -1
  98. package/dist/agent/run-manager.js +45 -3
  99. package/dist/agent/run-manager.js.map +1 -1
  100. package/dist/agent/run-store.d.ts +30 -1
  101. package/dist/agent/run-store.d.ts.map +1 -1
  102. package/dist/agent/run-store.js +138 -24
  103. package/dist/agent/run-store.js.map +1 -1
  104. package/dist/agent/types.d.ts +20 -0
  105. package/dist/agent/types.d.ts.map +1 -1
  106. package/dist/agent/types.js.map +1 -1
  107. package/dist/application-state/store.d.ts.map +1 -1
  108. package/dist/application-state/store.js +5 -0
  109. package/dist/application-state/store.js.map +1 -1
  110. package/dist/audit/actions/get-audit-event.d.ts +11 -0
  111. package/dist/audit/actions/get-audit-event.d.ts.map +1 -0
  112. package/dist/audit/actions/get-audit-event.js +22 -0
  113. package/dist/audit/actions/get-audit-event.js.map +1 -0
  114. package/dist/audit/actions/list-audit-events.d.ts +22 -0
  115. package/dist/audit/actions/list-audit-events.d.ts.map +1 -0
  116. package/dist/audit/actions/list-audit-events.js +61 -0
  117. package/dist/audit/actions/list-audit-events.js.map +1 -0
  118. package/dist/audit/cleanup-job.d.ts +12 -0
  119. package/dist/audit/cleanup-job.d.ts.map +1 -0
  120. package/dist/audit/cleanup-job.js +93 -0
  121. package/dist/audit/cleanup-job.js.map +1 -0
  122. package/dist/audit/config.d.ts +30 -0
  123. package/dist/audit/config.d.ts.map +1 -0
  124. package/dist/audit/config.js +65 -0
  125. package/dist/audit/config.js.map +1 -0
  126. package/dist/audit/index.d.ts +13 -0
  127. package/dist/audit/index.d.ts.map +1 -0
  128. package/dist/audit/index.js +6 -0
  129. package/dist/audit/index.js.map +1 -0
  130. package/dist/audit/record.d.ts +24 -0
  131. package/dist/audit/record.d.ts.map +1 -0
  132. package/dist/audit/record.js +106 -0
  133. package/dist/audit/record.js.map +1 -0
  134. package/dist/audit/redact.d.ts +28 -0
  135. package/dist/audit/redact.d.ts.map +1 -0
  136. package/dist/audit/redact.js +109 -0
  137. package/dist/audit/redact.js.map +1 -0
  138. package/dist/audit/store.d.ts +14 -0
  139. package/dist/audit/store.d.ts.map +1 -0
  140. package/dist/audit/store.js +219 -0
  141. package/dist/audit/store.js.map +1 -0
  142. package/dist/audit/types.d.ts +114 -0
  143. package/dist/audit/types.d.ts.map +1 -0
  144. package/dist/audit/types.js +15 -0
  145. package/dist/audit/types.js.map +1 -0
  146. package/dist/chat-threads/store.d.ts.map +1 -1
  147. package/dist/chat-threads/store.js +10 -0
  148. package/dist/chat-threads/store.js.map +1 -1
  149. package/dist/client/AgentPanel.d.ts.map +1 -1
  150. package/dist/client/AgentPanel.js +2 -2
  151. package/dist/client/AgentPanel.js.map +1 -1
  152. package/dist/client/AssistantChat.d.ts.map +1 -1
  153. package/dist/client/AssistantChat.js +6 -1
  154. package/dist/client/AssistantChat.js.map +1 -1
  155. package/dist/client/blocks/library/FileTreeBlock.d.ts.map +1 -1
  156. package/dist/client/blocks/library/FileTreeBlock.js +37 -4
  157. package/dist/client/blocks/library/FileTreeBlock.js.map +1 -1
  158. package/dist/client/chat/repo-helpers.d.ts +16 -0
  159. package/dist/client/chat/repo-helpers.d.ts.map +1 -1
  160. package/dist/client/chat/repo-helpers.js +40 -0
  161. package/dist/client/chat/repo-helpers.js.map +1 -1
  162. package/dist/db/client.d.ts.map +1 -1
  163. package/dist/db/client.js +3 -0
  164. package/dist/db/client.js.map +1 -1
  165. package/dist/db/widen-columns.d.ts +39 -0
  166. package/dist/db/widen-columns.d.ts.map +1 -0
  167. package/dist/db/widen-columns.js +73 -0
  168. package/dist/db/widen-columns.js.map +1 -0
  169. package/dist/deploy/build.d.ts +29 -0
  170. package/dist/deploy/build.d.ts.map +1 -1
  171. package/dist/deploy/build.js +85 -0
  172. package/dist/deploy/build.js.map +1 -1
  173. package/dist/deploy/workspace-deploy.d.ts.map +1 -1
  174. package/dist/deploy/workspace-deploy.js +108 -0
  175. package/dist/deploy/workspace-deploy.js.map +1 -1
  176. package/dist/mcp/build-server.d.ts.map +1 -1
  177. package/dist/mcp/build-server.js +24 -9
  178. package/dist/mcp/build-server.js.map +1 -1
  179. package/dist/oauth-tokens/store.d.ts.map +1 -1
  180. package/dist/oauth-tokens/store.js +6 -0
  181. package/dist/oauth-tokens/store.js.map +1 -1
  182. package/dist/provider-api/custom-registry.d.ts.map +1 -1
  183. package/dist/provider-api/custom-registry.js +8 -0
  184. package/dist/provider-api/custom-registry.js.map +1 -1
  185. package/dist/resources/store.d.ts.map +1 -1
  186. package/dist/resources/store.js +9 -0
  187. package/dist/resources/store.js.map +1 -1
  188. package/dist/scripts/runner.js +4 -3
  189. package/dist/scripts/runner.js.map +1 -1
  190. package/dist/server/action-discovery.d.ts.map +1 -1
  191. package/dist/server/action-discovery.js +6 -0
  192. package/dist/server/action-discovery.js.map +1 -1
  193. package/dist/server/action-routes.d.ts.map +1 -1
  194. package/dist/server/action-routes.js +1 -0
  195. package/dist/server/action-routes.js.map +1 -1
  196. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  197. package/dist/server/agent-chat-plugin.js +68 -13
  198. package/dist/server/agent-chat-plugin.js.map +1 -1
  199. package/dist/server/auth.d.ts.map +1 -1
  200. package/dist/server/auth.js +5 -0
  201. package/dist/server/auth.js.map +1 -1
  202. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  203. package/dist/server/core-routes-plugin.js +13 -0
  204. package/dist/server/core-routes-plugin.js.map +1 -1
  205. package/dist/server/security-headers.d.ts +8 -5
  206. package/dist/server/security-headers.d.ts.map +1 -1
  207. package/dist/server/security-headers.js +9 -6
  208. package/dist/server/security-headers.js.map +1 -1
  209. package/dist/settings/store.d.ts.map +1 -1
  210. package/dist/settings/store.js +6 -0
  211. package/dist/settings/store.js.map +1 -1
  212. package/dist/templates/workspace-core/.agents/skills/audit-log/SKILL.md +93 -0
  213. package/dist/usage/store.d.ts.map +1 -1
  214. package/dist/usage/store.js +5 -0
  215. package/dist/usage/store.js.map +1 -1
  216. package/docs/content/actions.md +23 -0
  217. package/docs/content/audit-log.md +111 -0
  218. package/docs/content/multi-app-workspace.md +2 -2
  219. package/docs/design/durable-agent-runs.md +458 -4
  220. package/package.json +2 -1
  221. package/src/templates/workspace-core/.agents/skills/audit-log/SKILL.md +93 -0
package/corpus/README.md CHANGED
@@ -27,5 +27,5 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
27
27
 
28
28
  ## Generated Counts
29
29
 
30
- - core files: 1147
31
- - template files: 3996
30
+ - core files: 1160
31
+ - template files: 4005
@@ -1,5 +1,56 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.72.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 9a984f2: Add a framework audit log: a durable, complete, access-scoped, append-only record of who mutated what app data, when, from where, and — when it was the agent — in which run. Capture is automatic at the `defineAction` seam (default-on for mutating actions; read-only actions opt in via `audit.onRead`), with credential redaction, agent-vs-human actor attribution, and agent thread/turn linkage. Reads go through two new core actions every app inherits — `list-audit-events` and `get-audit-event` — scoped in SQL to the caller's identity and org. Stored in `agent_audit_log` (provider-agnostic), with a retention purge configurable via `AGENT_NATIVE_AUDIT_RETENTION_DAYS` (default 365) and a global kill switch `AGENT_NATIVE_AUDIT_ENABLED=false`. Distinct from observability (sampled telemetry) and tracking (fire-and-forget analytics).
8
+
9
+ ### Patch Changes
10
+
11
+ - 9a984f2: Relax the default `Permissions-Policy` from `camera=()` to `camera=*` so media-capture UI is no longer blocked at the policy level. `camera=()` disabled the camera for the page **and every iframe inside it**, which broke same-page recording UI and the Clips browser extension's camera bubble (injected as a cross-origin iframe, so it can't be re-enabled per-frame). Microphone stays `self`, geolocation and wake-lock stay disabled, and the browser still gates actual camera/mic use behind a per-origin permission prompt — this only removes the policy-level block, not user consent.
12
+ - 9a984f2: Fix a chat crash where the agent transcript could fail to render with
13
+ "MessageRepository(performOp/link): A message with the same id already exists in
14
+ the parent tree". Thread repositories whose message list contained a repeated id
15
+ (from optimistic+echo races, streaming reconnect replays, or multi-tab merges)
16
+ were imported into assistant-ui verbatim, and its `MessageRepository` throws on a
17
+ duplicate id. The import path now collapses duplicate ids to their most recent
18
+ copy before handing the repository to assistant-ui, so the throw can't occur. The
19
+ no-duplicate case is an exact no-op, leaving normal threads unchanged.
20
+ - 9a984f2: Fix `value "<ms epoch>" is out of range for type integer` on long-lived
21
+ Postgres/Neon databases — most visibly, agent chat failing on **every** prompt.
22
+ Millisecond `Date.now()` timestamps are written into columns that, on databases
23
+ created before the Postgres BIGINT-compatibility shim, are physically 32-bit
24
+ `INTEGER` (int4, max 2,147,483,647); a millisecond epoch like `1782269273204`
25
+ overflows. The source had since switched to `BIGINT`, but `CREATE TABLE IF NOT
26
+ EXISTS` can't re-type an existing column, so those databases kept the int4
27
+ column and writes kept failing (`insertRun()` runs at the start of every turn,
28
+ so the agent chat aborted as a `connection_error`).
29
+
30
+ Adds a `widenIntColumnsToBigInt()` helper (new module
31
+ `@agent-native/core/db/widen-columns`) that, on Postgres only, widens such
32
+ columns in place to `BIGINT` once via each store's existing `ensureTable()`
33
+ bootstrap. It is idempotent (only ALTERs columns still typed `integer`, so
34
+ already-bigint tables are never rewritten), non-destructive (int4 → int8
35
+ widening), and a no-op on SQLite. Applied to the millisecond-timestamp columns
36
+ of `agent_runs`, `agent_tool_ledger`, `chat_threads`, `application_state`,
37
+ `token_usage`, `settings`, `oauth_tokens`, `resources`, `sessions`, and
38
+ `custom_api_providers`. (`staged_datasets` already self-heals via its own
39
+ widener.)
40
+
41
+ ## 0.71.0
42
+
43
+ ### Minor Changes
44
+
45
+ - 38266fc: Add opt-in durable background agent-chat runs (off by default, host-agnostic). Behind `AGENT_CHAT_DURABLE_BACKGROUND` (active only when hosted AND `A2A_SECRET` is set AND the flag is truthy), a long in-app agent-chat turn is routed through a server-driven background worker via the framework's portable self-dispatch instead of completing synchronously under the ~40s interactive soft-timeout: the foreground POST claims the run slot, inserts the run row, fires an HMAC-signed self-dispatch to a new `/_agent-native/agent-chat/_process-run` route, and returns the existing `subscribeToRun` SSE stream so the client streams the same events via the cross-isolate SQL-poll path with no client change. The background worker idempotently claims the run, runs the full multi-step loop to completion under a host-natural soft-timeout (`backgroundFunction` mode lifts the 40s clamp for that invocation only — the foreground/interactive clamp is unchanged), and chains a server-driven continuation if a chunk hits its budget unfinished. A background-aware stale window (`dispatch_mode`) prevents a cold-starting background run from being falsely reaped. With the flag off, the agent-chat run path is byte-for-byte the current synchronous behavior.
46
+
47
+ As a per-host optimization layered on the portable baseline, the Netlify deploy build emits a second function whose name ends in `-background` (re-exporting the same `main.mjs` handler bundle, with a `config.path` of the process-run route) so the `_process-run` POST runs on Netlify's async 15-minute budget and a long turn completes in one invocation; on that invocation the worker's soft-timeout is raised to ~13 min (`backgroundFunction` mode) instead of 40s. This emit is build-time gated on the same `AGENT_CHAT_DURABLE_BACKGROUND` flag for both the single-template (`deploy/build.ts`) and workspace (`deploy/workspace-deploy.ts`) deploy paths: when the flag is unset at build time the emit functions are never invoked, so the deploy output (functions, routing, config) is byte-identical to today and the default single-function deploy is unchanged.
48
+
49
+ ### Patch Changes
50
+
51
+ - 38266fc: Move "Collapse sidebar" to the top of the agent panel's options menu (the `⋯` dropdown in the sidebar header), above All chats / Agent runs / Settings, with a separator below it. Makes the most common dismiss action the first item in the list.
52
+ - 38266fc: Fix inline MCP App embeds being hard-killed on `resources/read`. The inline-embed kill switch was enforced inside the shared `resolveMcpAppResource` resolver, which also backs `resources/read` — so when a host read a `ui://` URI it already held (e.g. a cached descriptor) while embeds were disabled, it got a hard `-32603` instead of the shell. The switch is now enforced only at the advertisement/render sites (`tools/list` descriptor meta, `tools/call` result meta, `resources/list`), so disabled embeds are never advertised while `resources/read` still degrades gracefully to the served shell.
53
+
3
54
  ## 0.70.3
4
55
 
5
56
  ### Patch Changes
@@ -329,6 +329,28 @@ export default defineAction({
329
329
  > [!WARNING]
330
330
  > Keep approvals rare. Each gated action is a hard stop in the agent loop. The default is **off**, and almost every action should leave it off. See [Human-in-the-Loop Approvals](/docs/human-approval) for the predicate API, the `approval_required` event, and the full flow.
331
331
 
332
+ ### Audit logging {#audit}
333
+
334
+ Every mutating action is **audited automatically** — the framework records who ran it, when, from which surface, and (when it was the agent) which thread/turn, with credential-redacted inputs. Read-only (`GET`) actions are skipped. You don't write any code for this; it happens at the `defineAction` seam.
335
+
336
+ Add an `audit` block only to _tune_ capture — most usefully to declare the resource the action changed so the change shows up in that resource's owner's trail:
337
+
338
+ ```ts
339
+ export default defineAction({
340
+ description: "Delete a recording.",
341
+ schema: z.object({ id: z.string() }),
342
+ audit: {
343
+ target: (args, result) => ({ type: "recording", id: args.id }),
344
+ summary: (args) => `Deleted recording ${args.id}`,
345
+ },
346
+ run: async (args, ctx) => {
347
+ /* ...delete... */
348
+ },
349
+ });
350
+ ```
351
+
352
+ Other knobs: `audit: { onRead: true }` audits a sensitive read (secret access, bulk export); `audit: { enabled: false }` opts a noisy write out; `audit: { recordInputs: false }` skips capturing arguments. Read the trail back with the built-in `list-audit-events` / `get-audit-event` actions. Full details in [Audit Log](/docs/audit-log).
353
+
332
354
  ## Calling it from the UI {#ui}
333
355
 
334
356
  Two hooks, both in `@agent-native/core/client`. Types are inferred from your `defineAction` schemas — no manual type declarations.
@@ -553,6 +575,7 @@ const args = parseArgs(["--name", "Steve", "--verbose", "--count=3"]);
553
575
 
554
576
  ## What's next
555
577
 
578
+ - [**Audit Log**](/docs/audit-log) — the automatic who-changed-what trail around every action
556
579
  - [**Human-in-the-Loop Approvals**](/docs/human-approval) — the `needsApproval` gate in depth
557
580
  - [**Drop-in Agent**](/docs/drop-in-agent) — `useActionMutation` / `useActionQuery` in React
558
581
  - [**Context Awareness**](/docs/context-awareness) — the `view-screen` + `navigate` pattern in depth
@@ -0,0 +1,111 @@
1
+ ---
2
+ title: "Audit Log"
3
+ description: "A durable, append-only record of who changed what app data, when, and whether it was you or the agent — captured automatically at the action seam."
4
+ ---
5
+
6
+ # Audit Log
7
+
8
+ Every agent-native app gets an audit log out of the box: a durable, complete, access-scoped, append-only record of **who mutated what app data, when, from where, and — when it was the agent — in which run.** Capture is automatic at the action seam; you write no code for it.
9
+
10
+ Because the agent can change data on your behalf, the headline question an audit log answers here isn't just "who edited this record" — it's **"was that me or the agent, and which turn caused it?"** No other system in the framework can answer that.
11
+
12
+ ## Audit vs. observability vs. tracking {#which}
13
+
14
+ Three systems record "what happened," for three different reasons. Pick by the question you're asking:
15
+
16
+ | System | The question it answers | Fidelity | Audience |
17
+ | ---------------------------------------- | ------------------------------------------------------ | -------------------------------- | ----------------------------- |
18
+ | **Audit Log** (this page) | "Who changed this record, when, and was it the agent?" | **Complete, durable, scoped** | User, admin, the agent itself |
19
+ | **[Observability](/docs/observability)** | "Why did the agent do that, and what did it cost?" | Sampled span telemetry | Developer |
20
+ | **[Tracking](/docs/tracking)** | "How are people using the product?" | Fire-and-forget to external SaaS | PM / growth |
21
+
22
+ An audit log that's sampled or shipped off to an analytics provider is useless — the whole point is that it's complete, local, and queryable. So it's its own subsystem, not a mode of the other two.
23
+
24
+ ## What's captured automatically {#captured}
25
+
26
+ When any **mutating** action runs (anything that isn't a read-only `GET`), the framework appends one row to `agent_audit_log` with:
27
+
28
+ - **Action** — the action name (e.g. `delete-recording`).
29
+ - **Actor** — `agent`, `human`, or `system`, plus the actor's email — populated **even for agent calls**, so you get "the agent, acting for alice@, …".
30
+ - **Run linkage** — the agent `threadId` / `turnId` that triggered the call (a tool call), so a mutation traces back to the exact agent turn.
31
+ - **Surface** — `tool` (agent), `frontend`, `http`, `cli`, `mcp`, or `a2a`.
32
+ - **Outcome** — `success`, `error` (with an error code), or `denied` (blocked by a human-approval gate).
33
+ - **Inputs** — the call arguments, with credential-shaped values [redacted](#privacy).
34
+ - **Target & owner** — the resource the action changed, used to [scope reads](#reading).
35
+
36
+ No wiring needed — the capture hooks into `defineAction` transparently. Read-only actions are skipped, and a few high-frequency framework actions (app-state sync, context-xray, navigation) are skipped by default to avoid flooding the log.
37
+
38
+ ## Declare what an action changed {#target}
39
+
40
+ By default an event is scoped to the **actor** — you see your own changes and the agent's changes on your behalf. To make a change to a _shared_ resource also appear in the **owner's** trail, and to label events by resource, declare a `target`:
41
+
42
+ ```ts
43
+ export default defineAction({
44
+ description: "Delete a recording.",
45
+ schema: z.object({ id: z.string() }),
46
+ audit: {
47
+ target: (args, result) => ({
48
+ type: "recording",
49
+ id: args.id,
50
+ // Optional — defaults to the actor. Set when editing someone else's resource.
51
+ ownerEmail: result?.ownerEmail,
52
+ visibility: "org",
53
+ }),
54
+ summary: (args) => `Deleted recording ${args.id}`,
55
+ },
56
+ run: async (args, ctx) => {
57
+ /* ...delete... */
58
+ },
59
+ });
60
+ ```
61
+
62
+ Everything in `audit` is optional. The minimum useful addition is `target: () => ({ type, id })`.
63
+
64
+ ### Tuning capture {#tuning}
65
+
66
+ | Option | Effect |
67
+ | -------------------- | --------------------------------------------------------------- |
68
+ | `audit.target` | Label the event with the resource and scope reads to its owner. |
69
+ | `audit.summary` | A short human-readable line for the event. |
70
+ | `audit.onRead` | Audit a sensitive **read** (secret access, bulk export). |
71
+ | `audit.enabled` | `true` forces capture on; `false` opts a noisy mutation out. |
72
+ | `audit.recordInputs` | `false` skips capturing the (already redacted) arguments. |
73
+
74
+ ## Reading the trail {#reading}
75
+
76
+ Two read actions are available to the agent **and** the frontend in every app, scoped in SQL to the caller — they never return another tenant's rows:
77
+
78
+ - **`list-audit-events`** — filter by `targetType` / `targetId`, `actorKind` (`agent` | `human` | `system`), `status`, `threadId` / `turnId`, `action`, `sinceMs`, and `limit`.
79
+ - **`get-audit-event`** — one event by id, including its redacted input payload.
80
+
81
+ Build an activity feed or a "who changed this" line by calling `list-audit-events` from the UI with `useActionQuery` — never hand-write a fetch to the audit table:
82
+
83
+ ```tsx
84
+ import { useActionQuery } from "@agent-native/core/client";
85
+
86
+ const { data } = useActionQuery("list-audit-events", {
87
+ targetType: "recording",
88
+ targetId: recordingId,
89
+ });
90
+ // data.events → [{ action, actorKind, actorEmail, turnId, status, summary, createdAt }, …]
91
+ ```
92
+
93
+ The agent can call the same action — ask it "what did you change on this recording?" and it answers from the trail.
94
+
95
+ ## Privacy & retention {#privacy}
96
+
97
+ - **Redaction** — before any inputs are stored, credential-shaped keys and values (tokens, secrets, passwords, bearer strings) are stripped and oversized payloads truncated. The audit log never becomes a secondary store of secrets. Keep `summary` text free of sensitive data too.
98
+ - **Append-only** — there is no update or delete action for audit rows. The only deletion is the retention purge, which makes the log trustworthy as an audit trail.
99
+ - **Tenant isolation** — reads are scoped to the caller's identity and org; with no identity, nothing matches.
100
+
101
+ Configure via environment:
102
+
103
+ - `AGENT_NATIVE_AUDIT_RETENTION_DAYS` — how long rows are kept (default `365`; `0` = keep forever).
104
+ - `AGENT_NATIVE_AUDIT_ENABLED=false` — global kill switch.
105
+
106
+ ## What's next
107
+
108
+ - [**Actions**](/docs/actions) — the `defineAction` seam where capture happens
109
+ - [**Human-in-the-Loop Approvals**](/docs/human-approval) — gated actions, recorded as `denied`
110
+ - [**Security & Data Scoping**](/docs/security) — the ownership model audit reads reuse
111
+ - [**Observability**](/docs/observability) — agent-run telemetry (the other "what happened")
@@ -117,8 +117,8 @@ The merge happens by file name. If an app provides a local file that also exists
117
117
 
118
118
  ```an-diagram title="Three layers, merged by file name" summary="Each app resolves plugins, skills, actions, and AGENTS.md from app-local first, then the shared package, then the framework default."
119
119
  {
120
- "html": "<div class=\"layer\"><div class=\"diagram-card accent\"><span class=\"diagram-pill accent\">1 &middot; App local</span><small class=\"diagram-muted\"><code>apps/&lt;name&gt;/</code> &mdash; highest priority</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&darr;</div><div class=\"diagram-card\"><span class=\"diagram-pill\">2 &middot; Workspace shared</span><small class=\"diagram-muted\"><code>packages/shared/</code> &mdash; the mid-layer</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&darr;</div><div class=\"diagram-card\"><span class=\"diagram-pill\">3 &middot; Framework default</span><small class=\"diagram-muted\"><code>@agent-native/core</code> &mdash; lowest</small></div><div class=\"diagram-arrow diagram-accent\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-box ok\">first match wins</div></div>",
121
- "css": ".layer{display:flex;flex-direction:column;align-items:flex-start;gap:8px}.layer .diagram-card{display:flex;flex-direction:column;gap:3px;padding:12px 16px;min-width:300px}.layer .diagram-arrow{font-size:20px;align-self:center}.layer .diagram-box{align-self:center;margin-top:4px}"
120
+ "html": "<div class=\"layer\"><div class=\"diagram-card accent\"><span class=\"diagram-pill accent\">1 &middot; App local</span><small class=\"diagram-muted\"><code>apps/&lt;name&gt;/</code> &mdash; highest priority</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&darr;</div><div class=\"diagram-card\"><span class=\"diagram-pill\">2 &middot; Workspace shared</span><small class=\"diagram-muted\"><code>packages/shared/</code> &mdash; the mid-layer</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&darr;</div><div class=\"diagram-card\"><span class=\"diagram-pill\">3 &middot; Framework default</span><small class=\"diagram-muted\"><code>@agent-native/core</code> &mdash; lowest</small></div><div class=\"diagram-arrow diagram-accent\" aria-hidden=\"true\">&darr;</div><div class=\"diagram-box ok\">first match wins</div></div>",
121
+ "css": ".layer{display:flex;flex-direction:column;align-items:center;gap:6px}.layer .diagram-card{display:flex;flex-direction:column;gap:3px;padding:12px 16px;width:320px}.layer .diagram-arrow{font-size:18px;line-height:1}.layer .diagram-box{margin-top:2px}"
122
122
  }
123
123
  ```
124
124