@agent-native/core 0.63.0 → 0.63.2

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 (134) hide show
  1. package/dist/agent/harness/ai-sdk-adapter.d.ts +44 -0
  2. package/dist/agent/harness/ai-sdk-adapter.d.ts.map +1 -1
  3. package/dist/agent/harness/ai-sdk-adapter.js +120 -1
  4. package/dist/agent/harness/ai-sdk-adapter.js.map +1 -1
  5. package/dist/agent/harness/index.d.ts +1 -1
  6. package/dist/agent/harness/index.d.ts.map +1 -1
  7. package/dist/agent/harness/index.js.map +1 -1
  8. package/dist/cli/code-agent-executor.js +1 -1
  9. package/dist/cli/code-agent-executor.js.map +1 -1
  10. package/dist/cli/create.js +1 -1
  11. package/dist/cli/create.js.map +1 -1
  12. package/dist/client/NewWorkspaceAppFlow.js +1 -1
  13. package/dist/client/NewWorkspaceAppFlow.js.map +1 -1
  14. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  15. package/dist/client/blocks/library/AnnotatedCodeBlock.js +29 -10
  16. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  17. package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
  18. package/dist/client/blocks/library/DiffBlock.js +48 -20
  19. package/dist/client/blocks/library/DiffBlock.js.map +1 -1
  20. package/dist/client/blocks/library/diagram.d.ts.map +1 -1
  21. package/dist/client/blocks/library/diagram.js +14 -3
  22. package/dist/client/blocks/library/diagram.js.map +1 -1
  23. package/dist/client/blocks/library/wireframe.d.ts.map +1 -1
  24. package/dist/client/blocks/library/wireframe.js +14 -3
  25. package/dist/client/blocks/library/wireframe.js.map +1 -1
  26. package/dist/client/blocks/types.d.ts +5 -0
  27. package/dist/client/blocks/types.d.ts.map +1 -1
  28. package/dist/client/blocks/types.js.map +1 -1
  29. package/dist/client/chat/index.d.ts +2 -1
  30. package/dist/client/chat/index.d.ts.map +1 -1
  31. package/dist/client/chat/index.js +2 -1
  32. package/dist/client/chat/index.js.map +1 -1
  33. package/dist/client/chat-view-transition.d.ts +17 -0
  34. package/dist/client/chat-view-transition.d.ts.map +1 -1
  35. package/dist/client/chat-view-transition.js +46 -0
  36. package/dist/client/chat-view-transition.js.map +1 -1
  37. package/dist/client/index.d.ts +2 -1
  38. package/dist/client/index.d.ts.map +1 -1
  39. package/dist/client/index.js +2 -1
  40. package/dist/client/index.js.map +1 -1
  41. package/dist/client/use-agent-chat-home-handoff.d.ts +27 -0
  42. package/dist/client/use-agent-chat-home-handoff.d.ts.map +1 -0
  43. package/dist/client/use-agent-chat-home-handoff.js +120 -0
  44. package/dist/client/use-agent-chat-home-handoff.js.map +1 -0
  45. package/dist/index.d.ts +1 -1
  46. package/dist/index.d.ts.map +1 -1
  47. package/dist/index.js +3 -1
  48. package/dist/index.js.map +1 -1
  49. package/dist/server/action-discovery.d.ts.map +1 -1
  50. package/dist/server/action-discovery.js +24 -2
  51. package/dist/server/action-discovery.js.map +1 -1
  52. package/dist/server/deep-link.d.ts +2 -2
  53. package/dist/server/deep-link.d.ts.map +1 -1
  54. package/dist/server/deep-link.js +2 -2
  55. package/dist/server/deep-link.js.map +1 -1
  56. package/dist/styles/agent-native.css +2 -6
  57. package/dist/tailwind.preset.d.ts.map +1 -1
  58. package/dist/tailwind.preset.js +8 -1
  59. package/dist/tailwind.preset.js.map +1 -1
  60. package/dist/templates/default/package.json +1 -0
  61. package/dist/templates/headless/AGENTS.md +3 -0
  62. package/dist/templates/headless/DEVELOPING.md +4 -0
  63. package/dist/templates/headless/actions/run.ts +6 -0
  64. package/dist/templates/workspace-root/README.md +4 -4
  65. package/docs/content/actions.md +32 -42
  66. package/docs/content/agent-surfaces.md +105 -84
  67. package/docs/content/agent-teams.md +2 -14
  68. package/docs/content/agent-web-surfaces.md +4 -4
  69. package/docs/content/authentication.md +40 -24
  70. package/docs/content/automations.md +18 -36
  71. package/docs/content/blueprint-installer.md +3 -0
  72. package/docs/content/cli-adapters.md +24 -168
  73. package/docs/content/client.md +11 -77
  74. package/docs/content/cloneable-saas.md +1 -1
  75. package/docs/content/code-agents-ui.md +44 -0
  76. package/docs/content/components.md +10 -23
  77. package/docs/content/context-awareness.md +3 -3
  78. package/docs/content/creating-templates.md +20 -18
  79. package/docs/content/database.md +1 -1
  80. package/docs/content/deployment.md +5 -37
  81. package/docs/content/dispatch.md +17 -28
  82. package/docs/content/drop-in-agent.md +24 -111
  83. package/docs/content/durable-resume.md +4 -0
  84. package/docs/content/embedding-sdk.md +141 -135
  85. package/docs/content/evals.md +3 -3
  86. package/docs/content/extensions.md +1 -1
  87. package/docs/content/external-agents.md +35 -61
  88. package/docs/content/faq.md +5 -5
  89. package/docs/content/frames.md +13 -4
  90. package/docs/content/getting-started.md +96 -142
  91. package/docs/content/harness-agents.md +53 -9
  92. package/docs/content/human-approval.md +1 -1
  93. package/docs/content/key-concepts.md +14 -99
  94. package/docs/content/local-file-mode.md +2 -2
  95. package/docs/content/mcp-apps.md +9 -2
  96. package/docs/content/mcp-clients.md +8 -3
  97. package/docs/content/mcp-protocol.md +11 -29
  98. package/docs/content/messaging.md +1 -1
  99. package/docs/content/migration-workbench.md +14 -175
  100. package/docs/content/multi-app-workspace.md +1 -1
  101. package/docs/content/multi-tenancy.md +18 -47
  102. package/docs/content/native-chat-ui.md +15 -12
  103. package/docs/content/observability.md +16 -4
  104. package/docs/content/observational-memory.md +1 -1
  105. package/docs/content/pure-agent-apps.md +17 -124
  106. package/docs/content/real-time-collaboration.md +14 -14
  107. package/docs/content/routing.md +71 -0
  108. package/docs/content/sandbox-adapters.md +78 -4
  109. package/docs/content/security.md +59 -39
  110. package/docs/content/server.md +16 -8
  111. package/docs/content/sharing.md +1 -6
  112. package/docs/content/skills-guide.md +3 -1
  113. package/docs/content/template-analytics.md +1 -1
  114. package/docs/content/template-assets.md +12 -3
  115. package/docs/content/template-brain.md +64 -72
  116. package/docs/content/template-chat.md +32 -4
  117. package/docs/content/template-clips.md +35 -4
  118. package/docs/content/template-design.md +19 -3
  119. package/docs/content/template-dispatch.md +9 -0
  120. package/docs/content/template-forms.md +15 -10
  121. package/docs/content/template-plan.md +13 -5
  122. package/docs/content/template-slides.md +14 -14
  123. package/docs/content/template-videos.md +10 -12
  124. package/docs/content/tracking.md +66 -55
  125. package/docs/content/using-your-agent.md +6 -16
  126. package/docs/content/what-is-agent-native.md +5 -11
  127. package/docs/content/workspace-management.md +2 -2
  128. package/docs/content/workspace.md +20 -160
  129. package/package.json +6 -2
  130. package/src/templates/default/package.json +1 -0
  131. package/src/templates/headless/AGENTS.md +3 -0
  132. package/src/templates/headless/DEVELOPING.md +4 -0
  133. package/src/templates/headless/actions/run.ts +6 -0
  134. package/src/templates/workspace-root/README.md +4 -4
@@ -1,139 +1,32 @@
1
1
  ---
2
2
  title: "Pure-Agent Apps"
3
- description: "Apps where the first product surface is the app-agent loop: define actions, run them locally, and add UI only when users need it."
3
+ description: "Apps where the agent is the whole product: the app-agent loop is the front door, and UI is added only when humans need it."
4
4
  ---
5
5
 
6
6
  # Pure-Agent Apps
7
7
 
8
- This is the minimal end of agent-native: an app whose first product surface is
9
- the agent loop, not a dashboard. That loop can start headlessly from CLI, jobs,
10
- webhooks, Slack, email, or A2A. Add Chat when a human-facing conversation UI is
11
- the right way to inspect and steer the work. For the full-UI end, start from a
12
- [template](/docs/cloneable-saas). If you are choosing between headless, chat,
13
- embedded, and full-app shapes, start with [Agent Surfaces](/docs/agent-surfaces).
8
+ A pure-agent app is the minimal end of agent-native: the app-agent loop is the
9
+ product, not a dashboard. You send a request from the terminal, Slack, email, a
10
+ scheduled job, another agent, or Chat "summarize my unread emails," "post the
11
+ daily metrics to Slack" and the agent acts and returns the result wherever it
12
+ belongs. It is still a real app: actions, sessions, app state, history,
13
+ settings, credentials, and share records all live in SQL.
14
14
 
15
- Imagine starting with one action and the app-agent loop. No dashboard. No
16
- sidebar full of menus. No forms. You ask for what you want from the terminal,
17
- from Slack, from email, from a scheduled job, from another agent, or from Chat -
18
- "summarize my unread emails," "post the daily metrics to Slack," "find the
19
- candidates who replied last week" - and the agent goes off and does it. The
20
- output shows up in the channel that asked, wherever it belongs.
15
+ Reach for this shape when the work runs in the background, the output leaves the
16
+ app, the domain is one-shot, or you're prototyping. The agent still needs a UI
17
+ not a dashboard, but a place for humans to supervise, configure, and steer it —
18
+ which is why even pure-agent apps usually mount the built-in Chat shell.
21
19
 
22
- That's a pure-agent app. The agent _is_ the product.
20
+ This is the **headless** product shape. The full decision guide, what ships in
21
+ the box, the scaffold, repo access, and run sharing now live in one place:
23
22
 
24
- It is still an app, not a stateless prompt. Actions, auth sessions, app state, thread history, run history, settings, credentials, and share records live in SQL. Locally that defaults to SQLite; hosted deployments should use a persistent SQL database.
25
-
26
- ## What it feels like to use one {#user-experience}
27
-
28
- Most apps are built around a UI: a database table you browse, a form you fill, a chart you read. The agent is a sidekick.
29
-
30
- In a pure-agent app, that's flipped. The agent loop is the front door. You type
31
- or send a request; the agent takes action; you see the result. Chat can be the
32
- browser front door, but headless apps can also start from CLI, jobs, webhooks,
33
- or A2A. Everything else - settings, history, what's currently running - is
34
- available when you need it, but most of the time you do not need a custom
35
- dashboard.
36
-
37
- Examples of where this works really well:
38
-
39
- - **Background workers** — a triage agent that watches your inbox and labels things, a daily-report agent that posts to Slack each morning, an on-call agent that responds to alerts.
40
- - **One-shot helpers** — "research this company and write a one-pager," "scan my GitHub issues and tell me which ones look stale."
41
- - **Channel-driven assistants** — agents you mostly talk to from Slack, Telegram, email, or another agent (via [A2A](/docs/a2a-protocol)). The "app" itself is mostly a control panel.
42
- - **Internal tools** — an agent that knows your runbooks, your APIs, your conventions, and can act on them.
43
-
44
- The hot take is "agents will replace apps." The honest version is "agents still need a UI — for humans to supervise, configure, and steer them." Pure-agent apps give you that UI without the dashboard sprawl.
45
-
46
- ## When this beats a traditional app {#when}
47
-
48
- Pick the pure-agent pattern when:
49
-
50
- - **The work happens in the background.** Most of the value is created while the user isn't looking.
51
- - **The output leaves the app.** The agent posts to Slack, sends email, updates a third-party system. There's nothing to browse in-app — the value is elsewhere.
52
- - **The domain is one-shot.** Research bot, summary generator, report writer. There's no persistent object that needs a list view.
53
- - **You're prototyping.** Ship the agent now; add a richer UI later if it turns out users actually want one.
54
-
55
- If your product is built around persistent objects users browse, pivot, and share - emails, events, documents, charts - pick a [template](/docs/cloneable-saas) instead. Those have full UIs _plus_ the agent.
56
-
57
- ## What ships in the box when you add Chat {#minimum-ui}
58
-
59
- When you add the built-in Chat shell, a pure-agent app gets five built-in
60
- surfaces, all provided by the framework - you don't build them:
61
-
62
- 1. **Chat** — the main input. Users talk to the agent, steer it, queue tasks.
63
- 2. **Workspace** — skills, memory, instructions, custom sub-agents, connected MCP servers, scheduled jobs. Customize the agent's behavior without shipping code.
64
- 3. **Job history** — which scheduled jobs ran, when, whether they succeeded, what they did.
65
- 4. **Thread history** — every past conversation, each preserved with its tool calls and final output.
66
- 5. **Settings** — API keys, connected accounts, onboarding status.
67
-
68
- Those five are usually enough. No analytics dashboard. No Kanban. No forms. Just: talk to it, see what it's done, configure how it behaves.
69
-
70
- ## Why you'd pick this over "an app with an AI sidebar" {#vs-traditional}
71
-
72
- Two reasons:
73
-
74
- 1. **You don't have to build the UI.** A pure-agent app skips weeks of dashboard work. The chat handles input; the framework handles supervision and history; the agent handles output.
75
- 2. **It's channel-agnostic from day one.** The same agent that runs in your web UI also runs from Slack, Telegram, email, and other agents — because everything goes through the agent, not the UI. See [Messaging the agent](/docs/messaging) for how that works.
76
-
77
- The trade-off: pure-agent apps don't give users a "browse-everything-at-a-glance" view. If your users need that, mix patterns: start pure-agent, add a small status page or list view if you discover users want one.
78
-
79
- ## Building one {#building}
80
-
81
- If you're not a developer, you can usually start with the [Dispatch template](/docs/template-dispatch) — it's a workspace-style pure-agent app with Slack/Telegram, scheduled jobs, and shared secrets out of the box.
82
-
83
- For developers who want the absolute minimum, start from a headless scaffold:
84
-
85
- ```bash
86
- npx @agent-native/core@latest create my-agent --headless
87
- ```
88
-
89
- This gives you the framework runtime, SQL-backed state, an `actions/` directory, and `pnpm agent` for running the local app-agent loop. Add one useful `defineAction()` and you have a real agent-native app. The same action can later render in chat, appear behind a button, expose an MCP tool, or move into a full UI without changing the core operation.
90
-
91
- Use [**Chat**](/docs/template-chat) when you are ready to add a browser UI but do not want a domain template. Chat is the add-UI scaffold path, not the required default for a pure-agent app.
92
-
93
- If you really want _zero_ custom UI except the agent, keep the app route focused on the built-in chat surface. The only thing the user sees is the chat. Everything else - job history, workspace, settings - is one click away in the panel's tabs.
94
-
95
- ### What you still get for free {#still-free}
96
-
97
- Even with no custom UI, you still inherit every framework benefit:
98
-
99
- - **Actions** as agent tools, HTTP endpoints, MCP tools, and A2A tools. External agents, Claude Desktop, and your own HTTP clients can drive the agent without going through the chat UI.
100
- - **Recurring jobs** for scheduled work — "every morning at 7, summarize my unread emails and post to Slack."
101
- - **The workspace** for per-user customization, skills, memory, MCP connections.
102
- - **Sub-agent delegation** via [agent teams](/docs/agent-teams).
103
- - **Portability** — deploys to any serverless host with any supported SQL database.
104
- - **Multi-tenant by default** — each user gets their own workspace without a dev-box.
105
-
106
- ### Adding a tiny bit of UI {#tiny-ui}
107
-
108
- Most pure-agent apps eventually want a little custom UI — not a dashboard, but maybe a status page, a job history, or a config screen. The [drop-in agent](/docs/drop-in-agent) components coexist with anything else you render. Add a single `/status` route that lists recent runs; keep everything else in the chat. That's usually enough.
109
-
110
- Future UI-grafting tooling should use a distinct verb or namespace. `agent-native add` already means integration blueprints such as providers, channels, and sandbox adapters, so it should not also mean "add UI to this headless app."
111
-
112
- ## Repo access for cloud headless {#repo-access}
113
-
114
- Local headless apps run against the folder on your machine. For cloud headless
115
- apps that need repository access, use connector-scoped access: a GitHub
116
- connector and token CRUD that can list repositories, search files, read files,
117
- create or edit files, and delete files with the user's permission.
118
-
119
- Do not design this as "clone the user's repo into our VM" or "give the agent a long-lived sandbox copy of the repo" as the primary model. Sandboxes are useful for isolated code execution, but repo access should be a provider integration with explicit tokens, scoped permissions, auditability, and revocation.
120
-
121
- ## Sharing sessions and runs {#sharing-runs}
122
-
123
- Pure-agent work produces durable sessions and runs. Shareability should roll out in phases:
124
-
125
- - **First:** read-only share links so a teammate can open a thread or run, inspect the sanitized transcript, outputs, and status, and follow along without taking control.
126
- - **Later:** permissioned writable collaboration, such as continuing a run, editing schedules, approving actions, or changing configuration with explicit access checks.
127
-
128
- That staged model keeps the first sharing surface useful without pretending collaborative control is solved before the permission model is ready.
23
+ [**Agent Surfaces Headless agent**](/docs/agent-surfaces#headless)
129
24
 
130
25
  ## What's next
131
26
 
132
- - [**Getting Started**](/docs/getting-started) — create a chat app or headless action first
133
- - [**Agent Surfaces**](/docs/agent-surfaces) — choose headless, rich chat, embedded sidecar, or full app
27
+ - [**Agent Surfaces — Headless**](/docs/agent-surfaces#headless) — the full headless decision guide and APIs
28
+ - [**Getting Started**](/docs/getting-started) — create a chat app or headless agent first
29
+ - [**Dispatch**](/docs/template-dispatch) — the workspace template that's a great pure-agent starting point
134
30
  - [**Messaging the agent**](/docs/messaging) — how users talk to the agent across web, Slack, Telegram, email
135
31
  - [**Recurring Jobs**](/docs/recurring-jobs) — scheduled prompts the agent runs on its own
136
- - [**Dispatch**](/docs/template-dispatch) — the workspace template that's a great starting point for pure-agent apps
137
- - [**Drop-in Agent**](/docs/drop-in-agent) — mounting `<AgentPanel>` fullscreen or in a sidebar
138
32
  - [**Actions**](/docs/actions) — the tools your pure-agent will call
139
- - [**Workspace**](/docs/workspace) — the customization surface for skills, memory, and MCP servers
@@ -125,7 +125,7 @@ pnpm add @tiptap/extension-collaboration @tiptap/extension-collaboration-caret @
125
125
 
126
126
  Prevents Vite from re-bundling TipTap in incompatible ways during dev:
127
127
 
128
- ```typescript
128
+ ```ts
129
129
  // vite.config.ts
130
130
  export default defineConfig({
131
131
  plugins: [reactRouter()],
@@ -149,7 +149,7 @@ via `registerShareableResource`. Without it, collab push events are delivered
149
149
  to all authenticated users without document-level scoping, and the server
150
150
  logs a one-time warning.
151
151
 
152
- ```typescript
152
+ ```ts
153
153
  // server/plugins/collab.ts
154
154
  import { createCollabPlugin } from "@agent-native/core/server";
155
155
 
@@ -163,7 +163,7 @@ export default createCollabPlugin({
163
163
 
164
164
  ### 4. Use the client hook
165
165
 
166
- ```typescript
166
+ ```ts
167
167
  import {
168
168
  useCollaborativeDoc,
169
169
  emailToColor,
@@ -186,7 +186,7 @@ const { ydoc, awareness, isLoading, activeUsers, agentActive, agentPresent } =
186
186
 
187
187
  ### 5. Add TipTap extensions
188
188
 
189
- ```typescript
189
+ ```ts
190
190
  import Collaboration from "@tiptap/extension-collaboration";
191
191
  import CollaborationCaret from "@tiptap/extension-collaboration-caret";
192
192
 
@@ -208,7 +208,7 @@ const editor = useEditor({
208
208
  The Collaboration extension does not auto-seed from a `content` prop. If the
209
209
  Y.Doc is empty and the document has existing content, seed it:
210
210
 
211
- ```typescript
211
+ ```ts
212
212
  useEffect(() => {
213
213
  if (!ydoc || !editor || !isLoaded) return;
214
214
  const fragment = ydoc.getXmlFragment("default");
@@ -337,7 +337,7 @@ Awareness state changes now propagate at ~150ms instead of the 2s poll cycle:
337
337
 
338
338
  Returns a reactive list of remote participants and a setter for the local presence payload:
339
339
 
340
- ```typescript
340
+ ```ts
341
341
  import { usePresence } from "@agent-native/core/client";
342
342
 
343
343
  const { others, setPresence } = usePresence(awareness, ydoc?.clientID);
@@ -400,7 +400,7 @@ import { RemoteSelectionRings } from "@agent-native/core/client";
400
400
 
401
401
  Invoke a callback whenever the followed participant's viewport changes:
402
402
 
403
- ```typescript
403
+ ```ts
404
404
  import { useFollowUser } from "@agent-native/core/client";
405
405
 
406
406
  const { isFollowing, stopFollowing } = useFollowUser({
@@ -435,7 +435,7 @@ The `PresenceBar` component now accepts optional follow-mode props:
435
435
 
436
436
  ### Normalized coordinate helpers {#norm-coords}
437
437
 
438
- ```typescript
438
+ ```ts
439
439
  import { toNormalized, fromNormalized } from "@agent-native/core/client";
440
440
 
441
441
  // In a pointer event handler:
@@ -454,7 +454,7 @@ const px = fromNormalized(norm, container.getBoundingClientRect());
454
454
 
455
455
  Server-side actions call `agentUpdateSelection()` to publish where the agent is working. The design template's `edit-design` and `generate-design` actions call this automatically. Other templates can do the same:
456
456
 
457
- ```typescript
457
+ ```ts
458
458
  import {
459
459
  agentEnterDocument,
460
460
  agentLeaveDocument,
@@ -511,7 +511,7 @@ plugin:
511
511
 
512
512
  ### Always set `resourceType`
513
513
 
514
- ```typescript
514
+ ```ts
515
515
  createCollabPlugin({
516
516
  resourceType: "document", // the name passed to registerShareableResource
517
517
  });
@@ -535,7 +535,7 @@ Write routes (`update`, `text`, `json`, `patch`, `search-replace`) reject
535
535
  payloads exceeding the configured limit with HTTP 413. The default is 2 MB.
536
536
  Override per-plugin:
537
537
 
538
- ```typescript
538
+ ```ts
539
539
  createCollabPlugin({
540
540
  resourceType: "document",
541
541
  maxPayloadBytes: 512 * 1024, // 512 KB
@@ -561,7 +561,7 @@ applies them atomically, so concurrent edits to different items both survive.
561
561
  **Slides (`patch-deck`)** — Instead of replacing the entire deck JSON on every
562
562
  change, the action accepts per-slide operations:
563
563
 
564
- ```typescript
564
+ ```ts
565
565
  // Conceptual patch-deck action shape
566
566
  type PatchDeckOp =
567
567
  | { type: "patch"; slideId: string; fields: Partial<SlideFields> }
@@ -593,7 +593,7 @@ The Design template uses `Y.UndoManager` to scope undo/redo to the local
593
593
  user's own edits. Remote peer edits and agent edits are never undone by a
594
594
  user's Cmd+Z.
595
595
 
596
- ```typescript
596
+ ```ts
597
597
  import * as Y from "yjs";
598
598
 
599
599
  const LOCAL_EDIT_ORIGIN = "local";
@@ -660,7 +660,7 @@ layers on top of the same awareness state.
660
660
 
661
661
  ## Related docs {#related}
662
662
 
663
- - [Real-Time Sync](/docs/real-time-sync) — the `useDbSync` + `useChangeVersion`
663
+ - [Real-Time Sync](/docs/client#usedbsync) — the `useDbSync` + `useChangeVersion`
664
664
  system that delivers the `updatedAt` bump driving editor reconciliation.
665
665
  - [Security](/docs/security) — `registerShareableResource`, `resolveAccess`,
666
666
  and `assertAccess` for the access model referenced by `resourceType`.
@@ -0,0 +1,71 @@
1
+ ---
2
+ title: "Routing"
3
+ description: "File-based routing for agent-native apps with React Router v7 — pages, dynamic params, and navigation."
4
+ ---
5
+
6
+ # Routing
7
+
8
+ Agent-native apps use **React Router v7** with file-based routing via `flatRoutes()` from `@react-router/fs-routes`. Every file in `app/routes/` becomes a URL. Templates use the dot-notation convention — dots separate URL segments inside a single filename.
9
+
10
+ ## File-Based Routing {#file-based-routing}
11
+
12
+ ### File → URL mapping
13
+
14
+ | File | URL | Notes |
15
+ | --------------------- | ------------------ | -------------------------------------- |
16
+ | `_index.tsx` | `/` | Index route |
17
+ | `settings.tsx` | `/settings` | Simple page |
18
+ | `inbox.$threadId.tsx` | `/inbox/:threadId` | Dot = `/`, `$` = dynamic param |
19
+ | `_app.tsx` | (no URL segment) | Pathless layout — prefix with `_` |
20
+ | `inbox/route.tsx` | `/inbox` | Folder form — `route.tsx` is the index |
21
+
22
+ Prefix a segment with `$` for a dynamic param. Prefix with `_` to make it a pathless layout route (no URL segment). Templates use `flatRoutes()` — the dot-notation file above is primary; the nested-folder form `inbox/route.tsx` also works.
23
+
24
+ ## Adding a new page {#adding-a-page}
25
+
26
+ Create the file and export a default component:
27
+
28
+ ```tsx
29
+ // app/routes/settings.tsx
30
+ export function meta() {
31
+ return [{ title: "Settings" }];
32
+ }
33
+
34
+ export default function SettingsPage() {
35
+ return <div>Settings</div>;
36
+ }
37
+ ```
38
+
39
+ That's it — React Router picks it up automatically, no registration needed.
40
+
41
+ ## Dynamic params {#dynamic-params}
42
+
43
+ ```tsx
44
+ // app/routes/inbox/$threadId.tsx
45
+ import { useParams } from "react-router";
46
+
47
+ export default function ThreadPage() {
48
+ const { threadId } = useParams();
49
+ return <div>Thread: {threadId}</div>;
50
+ }
51
+ ```
52
+
53
+ ## Navigation {#navigation}
54
+
55
+ Use `<Link>` for client-side navigation and `useNavigate()` for programmatic navigation:
56
+
57
+ ```tsx
58
+ import { Link, useNavigate } from "react-router";
59
+
60
+ // In JSX
61
+ <Link to="/settings">Settings</Link>;
62
+
63
+ // Programmatic
64
+ const navigate = useNavigate();
65
+ navigate(`/inbox/${threadId}`);
66
+ ```
67
+
68
+ ## What's next
69
+
70
+ - [**Client**](/docs/client) — the agent-native browser hooks and utilities
71
+ - [**Server**](/docs/server) — file-based server routes and the `/_agent-native/` namespace
@@ -1,8 +1,35 @@
1
1
  ---
2
- title: "Sandbox Adapters"
3
- description: "Swap the backend that runs the agent's run-code tool local child process by default, a remote/durable runner when you need to exceed the hosted code-exec ceiling."
2
+ title: "Adapters"
3
+ description: "The framework's two adapter seams: sandbox adapters swap the backend that runs the agent's run-code tool, and CLI adapters give the agent structured access to command-line tools."
4
+ search: "adapters sandbox adapter cli adapter run-code SandboxAdapter CliAdapter ShellCliAdapter durable runner remote sandbox edge serverless child_process"
4
5
  ---
5
6
 
7
+ # Adapters
8
+
9
+ > **Who is this for:** host authors extending the runtime. App developers rarely
10
+ > need this — the defaults work out of the box.
11
+
12
+ Agent-Native has two adapter seams that factor a concern out behind a narrow,
13
+ swappable interface:
14
+
15
+ - **Sandbox adapters** swap the backend that runs the agent's `run-code` tool —
16
+ a local child process by default, or a Docker / remote / durable runner.
17
+ - **CLI adapters** give the agent structured access to command-line tools
18
+ (`gh`, `ffmpeg`, `stripe`) with discovery, availability checks, and a
19
+ consistent result shape.
20
+
21
+ Both share one runtime constraint: they rely on Node.js system bindings and do
22
+ not run on edge/worker runtimes — see [Edge and serverless](#edge-serverless).
23
+
24
+ ## Which coding doc do I want? {#which-doc}
25
+
26
+ | You want to… | Use |
27
+ | -------------------------------------------------------------------------- | -------------------------------------------- |
28
+ | Swap the backend that runs the agent's **`run-code` tool** | **Sandbox adapters** (this page) |
29
+ | Wrap a CLI tool (`gh`, `ffmpeg`) for the agent to call | **CLI adapters** (this page) |
30
+ | Render a Claude-Code/Codex-style **coding workspace UI** | [Agent-Native Code UI](/docs/code-agents-ui) |
31
+ | Run Claude Code / Codex / Pi **as the agent**, with their own loop + tools | [Harness Agents](/docs/harness-agents) |
32
+
6
33
  # Sandbox Adapters
7
34
 
8
35
  The `run-code` tool runs agent-supplied JavaScript in an isolated environment. **Sandbox adapters** factor the _execution_ concern out of that tool so the backend can be swapped — a local child process by default, or a Docker / remote / durable runner — without touching the agent loop, `run-code.ts`, the localhost bridge, the env scrub, or the output formatting.
@@ -74,13 +101,13 @@ Out of the box, `getSandboxAdapter()` returns `LocalChildProcessAdapter` (`id: "
74
101
  - Temp files are cleaned up best-effort after the run.
75
102
 
76
103
  > [!WARNING]
77
- > The default adapter uses `node:child_process`, which does not exist on edge/worker runtimes (Cloudflare Workers, Netlify Edge Functions). Run `run-code` in a standard Node.js environment, or register a remote adapter.
104
+ > The default adapter uses `node:child_process`, which does not exist on edge/worker runtimes. Run `run-code` in a standard Node.js environment, or register a remote adapter — see [Edge and serverless](#edge-serverless).
78
105
 
79
106
  ## Selecting an adapter {#selection}
80
107
 
81
108
  Resolution order — an explicitly registered adapter wins; otherwise the env var selects a built-in; otherwise the local default is used:
82
109
 
83
- ```txt
110
+ ```text
84
111
  registerSandboxAdapter(adapter) → AGENT_NATIVE_SANDBOX → local default
85
112
  ```
86
113
 
@@ -127,8 +154,55 @@ Register it under a new `AGENT_NATIVE_SANDBOX` value (e.g. `remote`) and/or via
127
154
  > [!TIP]
128
155
  > The `agent-native add sandbox docker` blueprint emits a full, self-contained recipe for implementing a Docker adapter against this seam. See [Blueprint Installer](/docs/blueprint-installer).
129
156
 
157
+ # CLI Adapters
158
+
159
+ The other adapter seam wraps a single command-line tool (`gh`, `ffmpeg`, `stripe`, `aws`) so the agent can discover it, check whether it's installed, and run it with a consistent stdout/stderr/exit-code result. Every CLI adapter implements `CliAdapter`:
160
+
161
+ ```ts
162
+ import type { CliAdapter, CliResult } from "@agent-native/core/adapters/cli";
163
+
164
+ interface CliAdapter {
165
+ name: string; // "gh", "stripe", "ffmpeg"
166
+ description: string; // What the agent sees during discovery
167
+ isAvailable(): Promise<boolean>;
168
+ execute(args: string[]): Promise<CliResult>;
169
+ }
170
+
171
+ interface CliResult {
172
+ stdout: string;
173
+ stderr: string;
174
+ exitCode: number;
175
+ }
176
+ ```
177
+
178
+ For most CLIs, `ShellCliAdapter` wraps any binary with sensible defaults, and `CliRegistry` collects adapters for runtime discovery:
179
+
180
+ ```ts
181
+ import { CliRegistry, ShellCliAdapter } from "@agent-native/core/adapters/cli";
182
+
183
+ const cliRegistry = new CliRegistry();
184
+ cliRegistry.register(
185
+ new ShellCliAdapter({
186
+ command: "gh",
187
+ description: "GitHub CLI — manage repos, PRs, issues, and releases",
188
+ }),
189
+ );
190
+
191
+ await cliRegistry.describe(); // [{ name, description, available }] for discovery
192
+ const gh = cliRegistry.get("gh");
193
+ const result = await gh?.execute(["pr", "list", "--json", "title,url"]);
194
+ ```
195
+
196
+ Wrap a CLI call in `defineAction` to expose it on the action surface. See the [CLI Adapters](/docs/cli-adapters) quick reference for `ShellCliAdapter` options, custom adapters, and the action-wrapping pattern.
197
+
198
+ ## Edge and serverless {#edge-serverless}
199
+
200
+ > [!WARNING]
201
+ > Both adapter seams rely on Node.js system bindings. The sandbox `LocalChildProcessAdapter` and CLI adapters (`ShellCliAdapter` and custom adapters) use `node:child_process` (`execFile` / `spawn`), which **does not exist** on edge/worker runtimes such as Cloudflare Workers or Netlify Edge Functions. If you deploy server routes to these edge presets, executing these adapters throws a runtime exception. Run adapter endpoints and tasks in a standard Node.js environment (traditional server containers or serverless Node functions) — or, for the sandbox seam, register a remote adapter that ships work out of process.
202
+
130
203
  ## What's next
131
204
 
205
+ - [**CLI Adapters**](/docs/cli-adapters) — the quick reference for the CLI seam
132
206
  - [**Blueprint Installer**](/docs/blueprint-installer) — `agent-native add sandbox docker` prints a Docker-adapter recipe
133
207
  - [**Agent Teams**](/docs/agent-teams) — delegating heavy work to sub-agents
134
208
  - [**Security**](/docs/security) — the env scrub and bridge allowlist posture
@@ -7,6 +7,23 @@ description: "Security model for agent-native apps: input validation, SQL inject
7
7
 
8
8
  Agent-native apps are designed to be secure by default. The framework provides automatic protections at multiple layers — you get SQL-level data isolation, parameterized queries, input validation, and authentication out of the box.
9
9
 
10
+ ## What you get for free, and what you own {#what-you-own}
11
+
12
+ When you build on the standard patterns, the framework already handles most of the threat surface for you:
13
+
14
+ - **Data isolation** — agent SQL is rewritten so it can only see the current user's (and active org's) rows. See [Data Scoping](#data-scoping).
15
+ - **SQL injection** — `db-query`/`db-exec` and Drizzle always parameterize. See [SQL Injection Prevention](#sql-injection).
16
+ - **XSS** — React auto-escapes, TipTap and `react-markdown` sanitize. See [XSS Prevention](#xss).
17
+ - **Auth & CSRF** — every `defineAction` is auth-guarded; cookies are `httpOnly` + `SameSite=lax`. See [Authentication](#auth).
18
+ - **Secret encryption** — credentials and the vault are encrypted at rest. See [Secrets Management](#secrets).
19
+
20
+ That leaves a small surface you actually have to think about:
21
+
22
+ - **A. Tag your tables for scoping.** Add `owner_email` (and `org_id` for team data) via [`ownableColumns()`](#data-scoping), and route Drizzle reads/writes through the [access guards](#access-guards).
23
+ - **B. Validate and route external input.** Give every action a Zod [`schema:`](#input-validation), and send any server-side fetch of a user/agent URL through the [SSRF guard](#ssrf).
24
+
25
+ Get those two right and the rest is defaults. The [Production Checklist](#production-checklist) is the one-page confirmation before you ship.
26
+
10
27
  ## Security by Design {#secure-by-design}
11
28
 
12
29
  The framework architecture prevents common vulnerabilities when you use the standard patterns:
@@ -26,7 +43,7 @@ The framework architecture prevents common vulnerabilities when you use the stan
26
43
 
27
44
  Use `defineAction` with a Zod `schema:` for every action. The framework validates input automatically before your code runs:
28
45
 
29
- ```typescript
46
+ ```ts
30
47
  import { z } from "zod";
31
48
  import { defineAction } from "@agent-native/core/action";
32
49
 
@@ -48,7 +65,7 @@ Invalid input returns clear error messages (400 for HTTP, structured error for a
48
65
 
49
66
  The framework's `db-query` and `db-exec` tools use parameterized queries. User input is passed as arguments, never interpolated into the SQL string:
50
67
 
51
- ```typescript
68
+ ```ts
52
69
  // SAFE — parameterized query (framework default)
53
70
  await exec({ sql: "INSERT INTO notes (title) VALUES (?)", args: [title] });
54
71
 
@@ -72,7 +89,7 @@ React auto-escapes all JSX expressions. Additional guidelines:
72
89
 
73
90
  Any server-side `fetch` of a user- or agent-controlled URL must go through the framework SSRF guard, or it can be pointed at cloud metadata (`169.254.169.254`), `localhost`, or internal services:
74
91
 
75
- ```typescript
92
+ ```ts
76
93
  import { ssrfSafeFetch } from "@agent-native/core/extensions/url-safety";
77
94
 
78
95
  const res = await ssrfSafeFetch(userProvidedUrl, {}, { maxRedirects: 3 });
@@ -98,7 +115,7 @@ The signed-in session carries `email` and (when an org is active) `orgId`. The f
98
115
 
99
116
  Every table with user-specific data **must** have an `owner_email` text column. Use the camelCase Drizzle property name — `accessFilter` reads `resourceTable.ownerEmail`:
100
117
 
101
- ```typescript
118
+ ```ts
102
119
  import {
103
120
  table,
104
121
  text,
@@ -141,7 +158,7 @@ For multi-user apps where teams share data, add an `org_id` column. When both co
141
158
 
142
159
  The `ownableColumns()` schema helper adds `owner_email`, `org_id`, and `visibility` in one call, so new tenant-aware tables get the full scoping contract by default:
143
160
 
144
- ```typescript
161
+ ```ts
145
162
  import { table, text, ownableColumns } from "@agent-native/core/db/schema";
146
163
 
147
164
  export const projects = table("projects", {
@@ -212,7 +229,43 @@ Without `A2A_SECRET` in production, every A2A endpoint and the `/_agent-native/i
212
229
 
213
230
  Inbound webhook handlers (Resend, SendGrid, Slack, Telegram, WhatsApp, Recall.ai, Deepgram, Zoom, Google Docs Pub/Sub) refuse forged requests by default in production: when the corresponding signing secret env var is missing, the handler returns 401 instead of accepting and dispatching.
214
231
 
215
- This was previously a "warn and accept" stance — set the secret you'd otherwise be missing, or opt back into the old behavior with `AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS=1` for local dev only. See [deployment.md → Inbound Webhooks](/docs/deployment#env-webhooks) for the full env-var list.
232
+ This was previously a "warn and accept" stance — set the secret you'd otherwise be missing, or opt back into the old behavior with `AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS=1` for local dev only. See [Messaging](/docs/messaging#env-vars) for the per-integration signing-secret variables.
233
+
234
+ ## Production Checklist {#production-checklist}
235
+
236
+ ### Auth & secrets
237
+
238
+ - [ ] `BETTER_AUTH_SECRET` set to a random 32+ char string (`openssl rand -hex 32`), unless this is a hosted workspace deploy deriving it from `A2A_SECRET`
239
+ - [ ] `OAUTH_STATE_SECRET` set to a separate random 32+ char string (don't reuse `BETTER_AUTH_SECRET`) — see [OAuth State Signing](#oauth-state)
240
+ - [ ] `A2A_SECRET` set on every app that calls or receives A2A traffic — see [A2A Identity Verification](#a2a-identity)
241
+ - [ ] `SECRETS_ENCRYPTION_KEY` set (or rely on the `BETTER_AUTH_SECRET` fallback) — see [Secrets Management](#secrets)
242
+ - [ ] `AUTH_SKIP_EMAIL_VERIFICATION` is **not** set in production (or set only on QA preview deploys)
243
+
244
+ ### Webhook secrets (set the ones for integrations you use)
245
+
246
+ - [ ] Signing secret set for each enabled inbound integration — see [Inbound Webhooks](#webhooks) and [Messaging](/docs/messaging#env-vars) for the per-integration list
247
+ - [ ] `AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS` is **not** set in prod
248
+
249
+ ### Schema
250
+
251
+ - [ ] Every user-facing table has `owner_email`, multi-user tables also `org_id` — see [Data Scoping](#data-scoping)
252
+ - [ ] Ownable-table reads/writes go through the [access guards](#access-guards)
253
+ - [ ] All actions use `defineAction` with Zod `schema:` — see [Input Validation](#input-validation)
254
+ - [ ] Server-side fetches of user/agent URLs go through `ssrfSafeFetch` — see [SSRF](#ssrf)
255
+ - [ ] No `dangerouslySetInnerHTML` with user content (or output is run through DOMPurify)
256
+ - [ ] No string-concatenated SQL
257
+ - [ ] `pnpm guards` is clean (`guard-no-unscoped-queries`, `guard-no-env-credentials`, `guard-no-env-mutation`, `guard-no-localhost-fallback`, `guard-no-unscoped-credentials`, `guard-no-drizzle-push`)
258
+ - [ ] Tested with two user accounts to verify data isolation
259
+
260
+ ### Misc hardening
261
+
262
+ - [ ] `AGENT_NATIVE_DEBUG_ERRORS` is **not** set in real prod (only on debug previews)
263
+ - [ ] `AGENT_NATIVE_KEYS_WORKSPACE_FALLBACK` is **not** set unless your org actually shares workspace keys — see [Cross-User Tooling Secrets](#tooling-secrets)
264
+ - [ ] In multi-tenant deployments, **users bring their own `ANTHROPIC_API_KEY`** — the framework refuses to fall back to the deploy-level env var
265
+
266
+ ---
267
+
268
+ The sections below cover niche environment flags you only reach for in specific deployments. Most apps never touch them.
216
269
 
217
270
  ## OAuth State Signing {#oauth-state}
218
271
 
@@ -237,36 +290,3 @@ AGENT_NATIVE_KEYS_WORKSPACE_FALLBACK=1
237
290
  ```
238
291
 
239
292
  Workspace-scope secret writes still require org owner/admin role regardless of this flag.
240
-
241
- ## Production Checklist {#production-checklist}
242
-
243
- ### Auth & secrets
244
-
245
- - [ ] `BETTER_AUTH_SECRET` set to a random 32+ char string (`openssl rand -hex 32`), unless this is a hosted workspace deploy deriving it from `A2A_SECRET`
246
- - [ ] `OAUTH_STATE_SECRET` set to a separate random 32+ char string (don't reuse `BETTER_AUTH_SECRET`), unless this is a hosted workspace deploy deriving it from `A2A_SECRET`
247
- - [ ] `A2A_SECRET` set on every app that calls or receives A2A traffic
248
- - [ ] `SECRETS_ENCRYPTION_KEY` set (or rely on the `BETTER_AUTH_SECRET` fallback)
249
- - [ ] `AUTH_SKIP_EMAIL_VERIFICATION` is **not** set in production (or set only on QA preview deploys)
250
-
251
- ### Webhook secrets (set the ones for integrations you use)
252
-
253
- - [ ] `EMAIL_INBOUND_WEBHOOK_SECRET` if Resend / SendGrid inbound is enabled
254
- - [ ] `SLACK_SIGNING_SECRET` if Slack is enabled
255
- - [ ] `TELEGRAM_WEBHOOK_SECRET` / `WHATSAPP_APP_SECRET` for those integrations
256
- - [ ] `AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS` is **not** set in prod
257
-
258
- ### Schema
259
-
260
- - [ ] Every user-facing table has `owner_email`
261
- - [ ] Multi-user tables also have `org_id`
262
- - [ ] All actions use `defineAction` with Zod `schema:`
263
- - [ ] No `dangerouslySetInnerHTML` with user content (or output is run through DOMPurify)
264
- - [ ] No string-concatenated SQL
265
- - [ ] `pnpm guards` is clean (`guard-no-unscoped-queries`, `guard-no-env-credentials`, `guard-no-env-mutation`, `guard-no-localhost-fallback`, `guard-no-unscoped-credentials`, `guard-no-drizzle-push`)
266
- - [ ] Tested with two user accounts to verify data isolation
267
-
268
- ### Misc hardening
269
-
270
- - [ ] `AGENT_NATIVE_DEBUG_ERRORS` is **not** set in real prod (only on debug previews)
271
- - [ ] `AGENT_NATIVE_KEYS_WORKSPACE_FALLBACK` is **not** set unless your org actually shares workspace keys
272
- - [ ] In multi-tenant deployments, **users bring their own `ANTHROPIC_API_KEY`** — the framework refuses to fall back to the deploy-level env var