@agent-native/core 0.7.50 → 0.7.52

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 (121) hide show
  1. package/dist/a2a/agent-card.d.ts.map +1 -1
  2. package/dist/a2a/agent-card.js +21 -16
  3. package/dist/a2a/agent-card.js.map +1 -1
  4. package/dist/a2a/artifact-response.d.ts.map +1 -1
  5. package/dist/a2a/artifact-response.js +109 -5
  6. package/dist/a2a/artifact-response.js.map +1 -1
  7. package/dist/a2a/auth-policy.d.ts +10 -0
  8. package/dist/a2a/auth-policy.d.ts.map +1 -0
  9. package/dist/a2a/auth-policy.js +34 -0
  10. package/dist/a2a/auth-policy.js.map +1 -0
  11. package/dist/a2a/handlers.d.ts.map +1 -1
  12. package/dist/a2a/handlers.js +5 -4
  13. package/dist/a2a/handlers.js.map +1 -1
  14. package/dist/a2a/index.d.ts +1 -0
  15. package/dist/a2a/index.d.ts.map +1 -1
  16. package/dist/a2a/index.js +1 -0
  17. package/dist/a2a/index.js.map +1 -1
  18. package/dist/a2a/server.d.ts.map +1 -1
  19. package/dist/a2a/server.js +27 -14
  20. package/dist/a2a/server.js.map +1 -1
  21. package/dist/client/resources/ResourceEditor.d.ts.map +1 -1
  22. package/dist/client/resources/ResourceEditor.js +2 -4
  23. package/dist/client/resources/ResourceEditor.js.map +1 -1
  24. package/dist/client/settings/AgentsSection.d.ts.map +1 -1
  25. package/dist/client/settings/AgentsSection.js +4 -6
  26. package/dist/client/settings/AgentsSection.js.map +1 -1
  27. package/dist/deploy/build.d.ts.map +1 -1
  28. package/dist/deploy/build.js +8 -0
  29. package/dist/deploy/build.js.map +1 -1
  30. package/dist/deploy/route-discovery.d.ts.map +1 -1
  31. package/dist/deploy/route-discovery.js +11 -2
  32. package/dist/deploy/route-discovery.js.map +1 -1
  33. package/dist/deploy/workspace-deploy.js +32 -3
  34. package/dist/deploy/workspace-deploy.js.map +1 -1
  35. package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -1
  36. package/dist/integrations/a2a-continuation-processor.js +17 -11
  37. package/dist/integrations/a2a-continuation-processor.js.map +1 -1
  38. package/dist/integrations/a2a-continuations-store.d.ts +2 -1
  39. package/dist/integrations/a2a-continuations-store.d.ts.map +1 -1
  40. package/dist/integrations/a2a-continuations-store.js +33 -4
  41. package/dist/integrations/a2a-continuations-store.js.map +1 -1
  42. package/dist/integrations/plugin.d.ts.map +1 -1
  43. package/dist/integrations/plugin.js +2 -1
  44. package/dist/integrations/plugin.js.map +1 -1
  45. package/dist/integrations/webhook-handler.d.ts.map +1 -1
  46. package/dist/integrations/webhook-handler.js +11 -1
  47. package/dist/integrations/webhook-handler.js.map +1 -1
  48. package/dist/onboarding/plugin.d.ts.map +1 -1
  49. package/dist/onboarding/plugin.js +2 -1
  50. package/dist/onboarding/plugin.js.map +1 -1
  51. package/dist/org/plugin.d.ts.map +1 -1
  52. package/dist/org/plugin.js +2 -1
  53. package/dist/org/plugin.js.map +1 -1
  54. package/dist/resources/handlers.d.ts.map +1 -1
  55. package/dist/resources/handlers.js +2 -3
  56. package/dist/resources/handlers.js.map +1 -1
  57. package/dist/resources/metadata.d.ts +5 -0
  58. package/dist/resources/metadata.d.ts.map +1 -1
  59. package/dist/resources/metadata.js +17 -2
  60. package/dist/resources/metadata.js.map +1 -1
  61. package/dist/resources/store.d.ts.map +1 -1
  62. package/dist/resources/store.js +2 -1
  63. package/dist/resources/store.js.map +1 -1
  64. package/dist/scripts/call-agent.js +2 -2
  65. package/dist/scripts/call-agent.js.map +1 -1
  66. package/dist/server/action-routes.d.ts.map +1 -1
  67. package/dist/server/action-routes.js +5 -11
  68. package/dist/server/action-routes.js.map +1 -1
  69. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  70. package/dist/server/agent-chat-plugin.js +2 -1
  71. package/dist/server/agent-chat-plugin.js.map +1 -1
  72. package/dist/server/agent-discovery.d.ts.map +1 -1
  73. package/dist/server/agent-discovery.js +7 -4
  74. package/dist/server/agent-discovery.js.map +1 -1
  75. package/dist/server/auth-plugin.d.ts.map +1 -1
  76. package/dist/server/auth-plugin.js +2 -1
  77. package/dist/server/auth-plugin.js.map +1 -1
  78. package/dist/server/auth.d.ts.map +1 -1
  79. package/dist/server/auth.js +13 -12
  80. package/dist/server/auth.js.map +1 -1
  81. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  82. package/dist/server/core-routes-plugin.js +9 -29
  83. package/dist/server/core-routes-plugin.js.map +1 -1
  84. package/dist/server/cors-origins.d.ts +10 -0
  85. package/dist/server/cors-origins.d.ts.map +1 -0
  86. package/dist/server/cors-origins.js +34 -0
  87. package/dist/server/cors-origins.js.map +1 -0
  88. package/dist/server/create-server.d.ts.map +1 -1
  89. package/dist/server/create-server.js +10 -29
  90. package/dist/server/create-server.js.map +1 -1
  91. package/dist/server/framework-request-handler.d.ts +11 -0
  92. package/dist/server/framework-request-handler.d.ts.map +1 -1
  93. package/dist/server/framework-request-handler.js +24 -1
  94. package/dist/server/framework-request-handler.js.map +1 -1
  95. package/dist/server/resources-plugin.d.ts.map +1 -1
  96. package/dist/server/resources-plugin.js +2 -1
  97. package/dist/server/resources-plugin.js.map +1 -1
  98. package/dist/terminal/terminal-plugin.d.ts.map +1 -1
  99. package/dist/terminal/terminal-plugin.js +2 -1
  100. package/dist/terminal/terminal-plugin.js.map +1 -1
  101. package/dist/vite/index.d.ts +1 -1
  102. package/dist/vite/index.d.ts.map +1 -1
  103. package/dist/vite/index.js +1 -1
  104. package/dist/vite/index.js.map +1 -1
  105. package/docs/content/a2a-protocol.md +75 -6
  106. package/docs/content/creating-templates.md +10 -0
  107. package/docs/content/dispatch.md +94 -0
  108. package/docs/content/getting-started.md +8 -0
  109. package/docs/content/key-concepts.md +16 -0
  110. package/docs/content/messaging.md +45 -13
  111. package/docs/content/multi-app-workspace.md +10 -2
  112. package/docs/content/notifications.md +1 -1
  113. package/docs/content/observability.md +184 -0
  114. package/docs/content/onboarding.md +7 -2
  115. package/docs/content/template-dispatch.md +3 -1
  116. package/docs/content/tools.md +95 -1
  117. package/docs/content/tracking.md +1 -1
  118. package/docs/content/what-is-agent-native.md +3 -1
  119. package/docs/content/workspace-management.md +5 -5
  120. package/docs/content/workspace.md +2 -0
  121. package/package.json +1 -1
@@ -0,0 +1,184 @@
1
+ ---
2
+ title: "Observability"
3
+ description: "Agent traces, evals, feedback, A/B experiments, and the admin dashboard — all built-in with zero configuration."
4
+ ---
5
+
6
+ # Agent Observability
7
+
8
+ Every agent-native app gets observability out of the box. Traces, automated evals, user feedback, and A/B experiments work with zero configuration — all data lives in the app's own SQL database.
9
+
10
+ ## What's Captured Automatically
11
+
12
+ When a user sends a message, the framework automatically records:
13
+
14
+ - **Token usage** — input, output, cache read, cache write
15
+ - **Cost** — computed from token counts and model pricing
16
+ - **Latency** — total duration and time per tool call
17
+ - **Tool calls** — which actions were invoked, success/error status, duration
18
+ - **Automated evals** — 5 quality scores computed after every run
19
+
20
+ No code changes needed. The instrumentation hooks into `production-agent.ts` transparently.
21
+
22
+ ## The Dashboard
23
+
24
+ Add the dashboard to any template with a single route:
25
+
26
+ ```tsx
27
+ // app/routes/observability.tsx
28
+ import { ObservabilityDashboard } from "@agent-native/core/client";
29
+
30
+ export default function ObservabilityPage() {
31
+ return (
32
+ <div className="min-h-screen bg-background p-6">
33
+ <ObservabilityDashboard />
34
+ </div>
35
+ );
36
+ }
37
+ ```
38
+
39
+ The dashboard has 5 tabs:
40
+
41
+ | Tab | What it shows |
42
+ | ----------------- | ------------------------------------------------------------------------------- |
43
+ | **Overview** | Key metrics — runs, cost, latency, tool success rate, satisfaction, eval score |
44
+ | **Conversations** | Trace list with drill-down to individual spans (agent_run, llm_call, tool_call) |
45
+ | **Evals** | Automated eval scores by criteria, trends over time |
46
+ | **Experiments** | A/B test list with status badges, variant results with confidence intervals |
47
+ | **Feedback** | Thumbs up/down stream, category breakdown, frustration scores |
48
+
49
+ ## User Feedback
50
+
51
+ ### Explicit Feedback
52
+
53
+ Thumbs up/down buttons render inline on every agent message in the chat UI. Thumbs down opens a category popover (Inaccurate, Not helpful, Wrong tool, Too slow). This is wired into `AssistantChat.tsx` automatically.
54
+
55
+ ### Implicit Feedback (Frustration Index)
56
+
57
+ The framework computes a Frustration Index (0-100) from conversation signals:
58
+
59
+ | Signal | Weight | What it detects |
60
+ | -------------- | ------ | ----------------------------------- |
61
+ | Rephrasing | 30% | User repeats similar messages |
62
+ | Retry patterns | 20% | "Try again", "no that's wrong" |
63
+ | Abandonment | 20% | Session ends shortly after response |
64
+ | Sentiment | 15% | Negative language patterns |
65
+ | Length trend | 15% | Declining message lengths |
66
+
67
+ Score interpretation: 0-20 = healthy, 20-40 = friction, 40-60 = dissatisfied, 60+ = broken session.
68
+
69
+ ## Automated Evals
70
+
71
+ Five deterministic scorers run after every agent run:
72
+
73
+ | Criteria | What it measures | Score range |
74
+ | ------------------- | ------------------------------------------------------ | ----------- |
75
+ | `tool_success_rate` | % of tool calls without errors | 0-1 |
76
+ | `step_efficiency` | Penalizes excessive LLM iterations for tool-using runs | 0-1 |
77
+ | `latency_score` | Normalized against 10s/tool baseline | 0-1 |
78
+ | `cost_efficiency` | Normalized against cost baseline | 0-1 |
79
+ | `error_recovery` | Did the agent recover from tool errors? | 0 or 1 |
80
+
81
+ ### LLM-as-Judge (Optional)
82
+
83
+ Enable sampled LLM-based evaluation by setting `evalSampleRate`:
84
+
85
+ ```ts
86
+ import { putSetting } from "@agent-native/core/settings";
87
+
88
+ await putSetting("observability-config", {
89
+ enabled: true,
90
+ evalSampleRate: 0.05, // 5% of runs
91
+ });
92
+ ```
93
+
94
+ Custom criteria use natural language rubrics:
95
+
96
+ ```ts
97
+ const criteria = {
98
+ name: "helpfulness",
99
+ description: "Was the response helpful and complete?",
100
+ rubric: "0.0 = unhelpful, 0.5 = partially helpful, 1.0 = fully resolved",
101
+ };
102
+ ```
103
+
104
+ ## A/B Experiments
105
+
106
+ Test different models, temperatures, or agent configurations:
107
+
108
+ ```ts
109
+ // Create via API
110
+ POST /_agent-native/observability/experiments
111
+ {
112
+ "name": "sonnet-vs-haiku",
113
+ "variants": [
114
+ { "id": "control", "weight": 50, "config": { "model": "claude-sonnet-4-6" } },
115
+ { "id": "treatment", "weight": 50, "config": { "model": "claude-haiku-4-5-20251001" } }
116
+ ],
117
+ "metrics": ["cost", "latency", "satisfaction"]
118
+ }
119
+
120
+ // Start the experiment
121
+ PUT /_agent-native/observability/experiments/:id
122
+ { "status": "running" }
123
+ ```
124
+
125
+ The agent loop automatically resolves the user's variant and applies the config override. Assignment uses consistent hashing — same user always gets the same variant.
126
+
127
+ ## Configuration
128
+
129
+ All settings are stored in the `observability-config` key:
130
+
131
+ ```ts
132
+ {
133
+ enabled: true, // Master switch
134
+ capturePrompts: false, // Store prompt content in traces
135
+ captureToolArgs: false, // Store action input arguments
136
+ captureToolResults: false, // Store action results
137
+ evalSampleRate: 0, // 0-1, fraction of runs to LLM-judge
138
+ exporters: [] // OTLP export targets
139
+ }
140
+ ```
141
+
142
+ Content is **redacted by default** — only token counts, costs, and timing are stored. Opt in to content capture when needed for debugging.
143
+
144
+ ## API Endpoints
145
+
146
+ All auto-mounted at `/_agent-native/observability/`:
147
+
148
+ | Method | Path | Purpose |
149
+ | ------ | -------------------------- | ------------------------------ |
150
+ | GET | `/` | Overview stats |
151
+ | GET | `/traces` | List trace summaries |
152
+ | GET | `/traces/:runId` | Trace detail (summary + spans) |
153
+ | GET | `/traces/:runId/evals` | Evals for a run |
154
+ | POST | `/feedback` | Submit feedback |
155
+ | GET | `/feedback` | List feedback |
156
+ | GET | `/feedback/stats` | Feedback aggregation |
157
+ | GET | `/satisfaction` | Satisfaction scores |
158
+ | GET | `/evals/stats` | Eval statistics |
159
+ | POST | `/experiments` | Create experiment |
160
+ | GET | `/experiments` | List experiments |
161
+ | PUT | `/experiments/:id` | Update experiment |
162
+ | POST | `/experiments/:id/results` | Compute results |
163
+ | GET | `/experiments/:id/results` | Get results |
164
+
165
+ All endpoints support `?since=N` (ms timestamp) and `?limit=N` query params.
166
+
167
+ ## Export to External Platforms
168
+
169
+ Send traces to Langfuse, Datadog, Grafana, or any OTel-compatible backend:
170
+
171
+ ```ts
172
+ await putSetting("observability-config", {
173
+ enabled: true,
174
+ exporters: [
175
+ {
176
+ type: "otlp",
177
+ endpoint: "https://cloud.langfuse.com/api/public/otel",
178
+ headers: { Authorization: "Bearer sk-..." },
179
+ },
180
+ ],
181
+ });
182
+ ```
183
+
184
+ The framework emits `gen_ai.*` semantic convention spans compatible with the OpenTelemetry GenAI spec.
@@ -1,3 +1,8 @@
1
+ ---
2
+ title: "Onboarding & API Keys"
3
+ description: "Setup checklist for first-run configuration — API keys, OAuth, and provider connections"
4
+ ---
5
+
1
6
  # Onboarding
2
7
 
3
8
  When you first open an app built on the agent-native framework, you'll see a
@@ -33,7 +38,7 @@ behind a picker or disclosure when a step has several equivalent providers.
33
38
  OAuth provider, or email provider, paste the value(s), click **Save**.
34
39
  Secret fields use a password input so the value isn't shown on screen. Saved
35
40
  values go into your local `.env` (or workspace settings) — see
36
- [Secrets](/docs/secrets) for where they live.
41
+ [Security](/docs/security) for where they live.
37
42
  - **Open a link** — some steps point to a sign-in page or docs. Click
38
43
  **Continue** and finish the flow in the new tab.
39
44
  - **Ask the agent** — a few steps offer a "Let the agent set it up" option.
@@ -174,6 +179,6 @@ function MySidebar() {
174
179
  ```
175
180
 
176
181
  For background on where step values are stored and how secrets are handled,
177
- see [Secrets](/docs/secrets). For end-user messaging touchpoints (invitations,
182
+ see [Security](/docs/security). For end-user messaging touchpoints (invitations,
178
183
  password resets) that depend on the **Email delivery** step, see
179
184
  [Messaging](/docs/messaging).
@@ -5,6 +5,8 @@ description: "Dispatch is the workspace control plane — central inbox, cross-a
5
5
 
6
6
  # Dispatch
7
7
 
8
+ > **See also:** for the conceptual overview of what Dispatch does and when you want it, see [Dispatch](/docs/dispatch). This page is the template-specific reference.
9
+
8
10
  Dispatch is the **workspace control plane**. Where other templates are domain apps (Mail, Calendar, Analytics), Dispatch is the app you run _alongside_ them to coordinate everything: a central inbox, a secrets vault, scheduled jobs, Slack/Telegram integration, and an orchestrator agent that delegates domain work to the right specialist app over [A2A](/docs/a2a-protocol).
9
11
 
10
12
  If you're running an [multi-app workspace](/docs/multi-app-workspace) with many apps, Dispatch is the glue.
@@ -45,7 +47,7 @@ Day-to-day, Dispatch is the place admins and ops folks open to keep the workspac
45
47
  _How it works under the hood (for developers)._
46
48
 
47
49
  - **Orchestrator agent.** The chat is set up as a router: it reads `AGENTS.md`, `LEARNINGS.md`, and routes to specialist sub-agents or remote A2A agents.
48
- - **Remote agent registry.** A2A manifests live in `remote-agents/*.json` — one per app. Dispatch calls them using the `call-agent` action.
50
+ - **Remote agent registry.** A2A manifests live in `remote-agents/*.json` — one per app. Dispatch calls them using the `call-agent` action. In a multi-app workspace, sibling apps under `apps/` are auto-discovered as A2A peers — no manual registration needed.
49
51
  - **Vault schema.** Drizzle tables for secrets, grants, requests, approvals, and audit logs. See `server/db/schema.ts` in the template.
50
52
  - **Slack / Telegram plugins.** Server plugins that register webhooks and forward incoming messages to the orchestrator agent.
51
53
  - **MCP hub mode.** Dispatch can act as the workspace's [MCP hub](/docs/mcp-clients#hub) so every other app in the workspace pulls the same org-scope MCP server list.
@@ -26,6 +26,26 @@ Tools are different:
26
26
 
27
27
  Use app code for features that are core to the product. Use tools for everything else — one-off utilities, personal dashboards, quick integrations, monitors, and things you want to spin up in seconds.
28
28
 
29
+ ## When to build a tool vs. a template feature {#when-to-build}
30
+
31
+ A quick decision rubric:
32
+
33
+ **Build a tool when:**
34
+
35
+ - It's for one user or one team, not the whole product.
36
+ - It's a quick utility, dashboard, or widget you want now, not next sprint.
37
+ - No new database schema is needed (or per-tool key-value storage is enough).
38
+ - You want to ship it inside a single chat turn, no deploy.
39
+
40
+ **Add a template feature when:**
41
+
42
+ - Every user of the template should get it.
43
+ - It needs new SQL tables, migrations, or shared schema changes.
44
+ - The UI is complex enough to warrant React components, routes, and proper testing.
45
+ - It's part of the product surface — something you'd advertise on a landing page.
46
+
47
+ When in doubt, start as a tool. Promoting a tool to a template feature later is straightforward; rolling back a half-shipped product feature is not.
48
+
29
49
  ## Creating a tool {#creating}
30
50
 
31
51
  ### From the sidebar
@@ -58,16 +78,56 @@ Tools render with modest canvas padding by default so simple widgets and dashboa
58
78
 
59
79
  ## Persistent storage {#persistent-storage}
60
80
 
61
- Every tool has access to a built-in key-value store. Data is automatically scoped per tool and per user — your data stays yours.
81
+ Every tool has access to a built-in key-value store via the `toolData` helper. Data is automatically scoped per tool and per user — your data stays yours.
62
82
 
63
83
  When you ask the agent to "add persistence" or "remember state" in a tool, it uses this built-in storage. No database tables to create, no migrations to run.
64
84
 
85
+ ### Scopes
86
+
87
+ All `toolData` methods accept an optional `{ scope }` option:
88
+
89
+ - `'user'` (default) — private to the current user.
90
+ - `'org'` — shared across the user's organization.
91
+ - `'all'` — list/get only; returns both user-scoped and org-scoped items.
92
+
93
+ ```html
94
+ <script>
95
+ // Private to me
96
+ await toolData.set('notes', 'note-1', { title: 'My Note' });
97
+
98
+ // Shared with my org
99
+ await toolData.set('notes', 'team-note', { title: 'Team Note' }, { scope: 'org' });
100
+
101
+ // List my notes (default)
102
+ const mine = await toolData.list('notes');
103
+
104
+ // List both mine and the org's
105
+ const everything = await toolData.list('notes', { scope: 'all' });
106
+ </script>
107
+ ```
108
+
65
109
  ## API keys and secrets {#secrets}
66
110
 
67
111
  When a tool needs an API key (for GitHub, OpenAI, a weather service, etc.), the agent will tell you what's needed and where to get it. You add the key through the Settings UI in the agent sidebar.
68
112
 
69
113
  Keys are encrypted and stored securely. Each key is restricted to specific domains — a GitHub token can only be sent to `api.github.com`, never anywhere else.
70
114
 
115
+ ### Secrets in tools {#secrets-in-tools}
116
+
117
+ Tools reference secrets in `toolFetch()` calls using the `${keys.NAME}` template pattern. The proxy substitutes the encrypted value server-side; the actual key never reaches the browser.
118
+
119
+ ```html
120
+ <script>
121
+ const res = await toolFetch('https://api.github.com/user', {
122
+ headers: {
123
+ Authorization: 'Bearer ${keys.GITHUB_TOKEN}',
124
+ },
125
+ });
126
+ </script>
127
+ ```
128
+
129
+ When a tool needs a one-off key, the agent can register an ad-hoc secret via `POST /_agent-native/secrets/adhoc` with a `urlAllowlist` that pins which domains the secret may be sent to. A request to any other host is rejected before the proxy fires. Combined with SSRF and private-network protections, this means a leaked tool can't exfiltrate secrets to an attacker-controlled URL.
130
+
71
131
  ## Sharing {#sharing}
72
132
 
73
133
  Tools are **private by default** — only you can see and use a tool you create.
@@ -79,6 +139,8 @@ You can share tools with your team:
79
139
 
80
140
  Shared tools have their own URLs, so you can link to them directly.
81
141
 
142
+ Under the hood, tools use the same ownable-resource model as the rest of the framework — `ownableColumns()` on the `tools` table and a standard `createSharesTable()` for grants. That means tools plug into the same share dialog, access checks, and audit surfaces as documents, decks, dashboards, and any other shareable resource. See [Security](/docs/security) for the full access model.
143
+
82
144
  ## Security {#security}
83
145
 
84
146
  Tools run in a secure sandbox:
@@ -89,6 +151,38 @@ Tools run in a secure sandbox:
89
151
  - **Private network protection** — tools can't reach internal/private network addresses.
90
152
  - **Authentication required** — only logged-in users can use tools.
91
153
 
154
+ ## Tool API reference {#api-reference}
155
+
156
+ Every tool runs inside a sandboxed iframe with the following helpers injected on `window`. They are the complete surface area — anything else a tool needs has to go through one of these.
157
+
158
+ | Helper | Purpose | Example |
159
+ | ------------------------------------------- | ---------------------- | --------------------------------------------- |
160
+ | `toolData.set(collection, id, data, opts?)` | Persist data per-tool | `toolData.set('notes', id, { text: '...' })` |
161
+ | `toolData.list(collection, opts?)` | List persisted items | `toolData.list('notes', { scope: 'all' })` |
162
+ | `toolData.get(collection, id, opts?)` | Get a single item | `toolData.get('notes', 'note-1')` |
163
+ | `toolData.remove(collection, id, opts?)` | Delete persisted item | `toolData.remove('notes', 'note-1')` |
164
+ | `appAction(name, params)` | Call any app action | `appAction('list-emails', { view: 'inbox' })` |
165
+ | `dbQuery(sql, args)` | Read from SQL | `dbQuery('SELECT * FROM tools')` |
166
+ | `dbExec(sql, args)` | Write to SQL | `dbExec('INSERT INTO ...')` |
167
+ | `appFetch(path, options)` | Call any app endpoint | `appFetch('/api/settings')` |
168
+ | `toolFetch(url, options)` | External API via proxy | `toolFetch('https://api.github.com/...')` |
169
+
170
+ `appAction` is the preferred way to trigger app behavior — it routes through the same actions the agent and the frontend use, so authorization and access scoping happen automatically. Drop down to `dbQuery`/`dbExec` only when there's no action that fits.
171
+
172
+ ### Routes {#routes}
173
+
174
+ The framework mounts the following endpoints under `/_agent-native/tools/`. Tools themselves rarely call these directly — they're useful when integrating tools with external scripts or custom UI.
175
+
176
+ | Method | Path | Purpose |
177
+ | ------ | --------------------------------- | -------------------------------------------- |
178
+ | GET | `/_agent-native/tools` | List tools (filtered by ownership + sharing) |
179
+ | POST | `/_agent-native/tools` | Create a tool |
180
+ | GET | `/_agent-native/tools/:id` | Get a single tool |
181
+ | PUT | `/_agent-native/tools/:id` | Update (supports `patches` for diffing) |
182
+ | DELETE | `/_agent-native/tools/:id` | Delete a tool |
183
+ | GET | `/_agent-native/tools/:id/render` | Render the iframe HTML |
184
+ | POST | `/_agent-native/tools/proxy` | Authenticated proxy with secret injection |
185
+
92
186
  ## Examples {#examples}
93
187
 
94
188
  Here are some things people build as tools:
@@ -1,5 +1,5 @@
1
1
  ---
2
- title: "Analytics Tracking"
2
+ title: "Tracking & Analytics"
3
3
  description: "Server-side analytics with pluggable providers — PostHog, Mixpanel, Amplitude, or custom webhook"
4
4
  ---
5
5
 
@@ -177,5 +177,7 @@ One action, four surfaces: the agent calls it as a tool, the UI calls it as a ty
177
177
  - [**Getting Started**](/docs) — pick a template and run it
178
178
  - [**Key Concepts**](/docs/key-concepts) — the architecture: SQL, actions, polling sync, context awareness, portability
179
179
  - [**Cloneable SaaS**](/docs/cloneable-saas) — templates as complete products you own
180
- - [**Workspace**](/docs/workspace) — the per-user customization layer (skills, memory, instructions, MCP)
180
+ - [**Workspace**](/docs/workspace) — the per-user customization layer (skills, memory, instructions, MCP) backed by SQL, not files
181
+ - [**Dispatch**](/docs/dispatch) — the workspace control plane: secrets vault, Slack/email inbox, cross-app delegation
182
+ - [**Tools**](/docs/tools) — sandboxed mini-apps the agent creates instantly without code changes
181
183
  - [**Drop-in Agent**](/docs/drop-in-agent) — mount `<AgentPanel>` into any React app
@@ -1,13 +1,13 @@
1
1
  ---
2
- title: "Workspace Management"
3
- description: "Branching strategies, code ownership, PR review, and governance practices for agent-native workspaces."
2
+ title: "Workspace Governance"
3
+ description: "Branching, CODEOWNERS, PR review, and how Dispatch handles runtime governance alongside git-level governance."
4
4
  ---
5
5
 
6
- # Workspace Management
6
+ # Workspace Governance
7
7
 
8
8
  This guide covers the operational side of running an agent-native workspace — how to branch, who reviews what, how to set up code ownership, and how the dispatch control plane fits into your governance model.
9
9
 
10
- For workspace setup, shared auth, and deployment, see [Multi-App Workspace](/docs/multi-app-workspace).
10
+ For workspace setup, shared auth, and deployment, see [Multi-App Workspaces](/docs/multi-app-workspace).
11
11
 
12
12
  ## Branching
13
13
 
@@ -179,7 +179,7 @@ When reviewing PRs in this environment:
179
179
 
180
180
  ## Dispatch as Governance
181
181
 
182
- The dispatch app is the workspace's runtime control plane. It complements git-level governance with runtime governance:
182
+ The [Dispatch](/docs/dispatch) app is the workspace's runtime control plane. It complements git-level governance with runtime governance:
183
183
 
184
184
  | Concern | Git / GitHub | Dispatch |
185
185
  | ------------------------------- | ----------------------------- | ------------------------------------------ |
@@ -5,6 +5,8 @@ description: "Claude-Code-level customization per user — skills, memory, instr
5
5
 
6
6
  # Workspace
7
7
 
8
+ > **See also:** Deploying multiple apps as one workspace? See [Multi-App Workspaces](/docs/multi-app-workspace). Governance, branching, and CODEOWNERS? See [Workspace Governance](/docs/workspace-management).
9
+
8
10
  Every agent-native app ships with a **workspace**: the customization layer that makes the agent yours. It contains team instructions (`AGENTS.md`), per-user memory (`learnings.md`), skills the agent pulls in on demand, custom sub-agents, scheduled jobs, and connected MCP servers — everything you'd expect from a Claude Code / Codex setup.
9
11
 
10
12
  The twist: **it's SQL rows, not filesystem files.** Each user gets their own workspace stored in the database. There's no dev-box to spin up, no container per user, no files to mount. A multi-tenant SaaS can give every user a fully-customizable agent for essentially free, because all of it is rows — personal memory, personal MCP servers, personal skills, personal sub-agents — and the shared codebase hosts all of them at once.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.7.50",
3
+ "version": "0.7.52",
4
4
  "type": "module",
5
5
  "description": "Framework for agent-native application development — where AI agents and UI share state via files",
6
6
  "license": "MIT",