@agent-native/core 0.63.2 → 0.63.4
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.
- package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
- package/dist/client/blocks/library/AnnotatedCodeBlock.js +23 -19
- package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
- package/dist/client/blocks/library/diagram.d.ts.map +1 -1
- package/dist/client/blocks/library/diagram.js +10 -11
- package/dist/client/blocks/library/diagram.js.map +1 -1
- package/dist/client/blocks/library/wireframe.d.ts.map +1 -1
- package/dist/client/blocks/library/wireframe.js +2 -1
- package/dist/client/blocks/library/wireframe.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +5 -1
- package/dist/server/auth.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +50 -5
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/styles/blocks.css +25 -3
- package/docs/content/a2a-protocol.md +48 -10
- package/docs/content/actions.md +35 -16
- package/docs/content/agent-mentions.md +25 -32
- package/docs/content/agent-surfaces.md +31 -0
- package/docs/content/agent-teams.md +17 -14
- package/docs/content/agent-web-surfaces.md +24 -15
- package/docs/content/authentication.md +21 -0
- package/docs/content/automations.md +37 -21
- package/docs/content/blueprint-installer.md +7 -0
- package/docs/content/cli-adapters.md +7 -0
- package/docs/content/client.md +14 -0
- package/docs/content/cloneable-saas.md +14 -0
- package/docs/content/code-agents-ui.md +27 -0
- package/docs/content/components.md +21 -0
- package/docs/content/context-awareness.md +33 -48
- package/docs/content/creating-templates.md +43 -52
- package/docs/content/cross-app-sso.md +41 -0
- package/docs/content/database.md +41 -21
- package/docs/content/deployment.md +23 -6
- package/docs/content/dispatch.md +27 -0
- package/docs/content/drop-in-agent.md +26 -27
- package/docs/content/durable-resume.md +13 -1
- package/docs/content/embedding-sdk.md +14 -0
- package/docs/content/evals.md +14 -0
- package/docs/content/extensions.md +19 -0
- package/docs/content/external-agents.md +38 -1
- package/docs/content/faq.md +14 -0
- package/docs/content/file-uploads.md +20 -0
- package/docs/content/frames.md +14 -0
- package/docs/content/getting-started.md +34 -16
- package/docs/content/harness-agents.md +14 -0
- package/docs/content/human-approval.md +15 -30
- package/docs/content/key-concepts.md +37 -0
- package/docs/content/local-file-mode.md +26 -19
- package/docs/content/mcp-apps.md +36 -1
- package/docs/content/mcp-clients.md +49 -0
- package/docs/content/mcp-protocol.md +36 -0
- package/docs/content/messaging.md +34 -8
- package/docs/content/migration-workbench.md +7 -0
- package/docs/content/multi-app-workspace.md +29 -16
- package/docs/content/multi-tenancy.md +14 -0
- package/docs/content/native-chat-ui.md +20 -3
- package/docs/content/notifications.md +30 -0
- package/docs/content/observability.md +20 -1
- package/docs/content/observational-memory.md +14 -0
- package/docs/content/onboarding.md +32 -41
- package/docs/content/plan-plugin.md +14 -0
- package/docs/content/pr-visual-recap.md +14 -0
- package/docs/content/processors.md +7 -0
- package/docs/content/progress.md +23 -0
- package/docs/content/pure-agent-apps.md +7 -0
- package/docs/content/real-time-collaboration.md +19 -18
- package/docs/content/recurring-jobs.md +22 -19
- package/docs/content/routing.md +8 -0
- package/docs/content/sandbox-adapters.md +19 -0
- package/docs/content/security.md +38 -0
- package/docs/content/server.md +47 -25
- package/docs/content/sharing.md +50 -0
- package/docs/content/skills-guide.md +27 -42
- package/docs/content/template-analytics.md +71 -41
- package/docs/content/template-assets.md +76 -3
- package/docs/content/template-brain.md +89 -1
- package/docs/content/template-calendar.md +86 -58
- package/docs/content/template-chat.md +25 -9
- package/docs/content/template-clips.md +124 -16
- package/docs/content/template-content.md +146 -47
- package/docs/content/template-design.md +62 -2
- package/docs/content/template-dispatch.md +56 -9
- package/docs/content/template-forms.md +69 -13
- package/docs/content/template-mail.md +73 -26
- package/docs/content/template-plan.md +80 -1
- package/docs/content/template-slides.md +95 -74
- package/docs/content/template-videos.md +73 -52
- package/docs/content/tracking.md +21 -0
- package/docs/content/using-your-agent.md +14 -0
- package/docs/content/voice-input.md +31 -10
- package/docs/content/what-is-agent-native.md +25 -13
- package/docs/content/workspace-connections.md +49 -0
- package/docs/content/workspace-management.md +24 -0
- package/docs/content/workspace.md +50 -19
- package/docs/content/writing-agent-instructions.md +7 -0
- package/package.json +1 -1
package/docs/content/tracking.md
CHANGED
|
@@ -19,6 +19,13 @@ track(
|
|
|
19
19
|
);
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
+
```an-diagram title="One track() call, every provider" summary="Server and client callers hit the same registry, which fans every event out to all active providers in parallel."
|
|
23
|
+
{
|
|
24
|
+
"html": "<div class=\"trk\"><div class=\"diagram-col\"><div class=\"diagram-node\">Server code<br><small class=\"diagram-muted\">actions · plugins · routes</small></div><div class=\"diagram-node\">Browser code<br><small class=\"diagram-muted\">POST /_agent-native/track</small></div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-panel center\"><span class=\"diagram-pill accent\">Provider registry</span><small class=\"diagram-muted\">fan-out, fire-and-forget</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-col\"><div class=\"diagram-box\">PostHog</div><div class=\"diagram-box\">Mixpanel</div><div class=\"diagram-box\">Amplitude</div><div class=\"diagram-box\">Webhook</div></div></div>",
|
|
25
|
+
"css": ".trk{display:flex;align-items:center;gap:14px;flex-wrap:wrap}.trk .diagram-col{display:flex;flex-direction:column;gap:8px}.trk .diagram-arrow{font-size:22px;line-height:1}.trk .center{display:flex;flex-direction:column;align-items:center;gap:4px}"
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
22
29
|
## Built-in providers {#built-in}
|
|
23
30
|
|
|
24
31
|
Set an env var and the provider auto-registers at server startup. No code changes required.
|
|
@@ -95,6 +102,20 @@ Track calls are fire-and-forget — they return immediately and never block the
|
|
|
95
102
|
|
|
96
103
|
`track()` also works from browser/app code. Import the client twin from `@agent-native/core/client` and call it the same way — it POSTs the event to the framework route at `POST /_agent-native/track`, which forwards it to the **same** registered server-side providers (PostHog, Mixpanel, Amplitude, webhook). No analytics SDK ships to the browser and no provider keys are exposed client-side.
|
|
97
104
|
|
|
105
|
+
```an-api title="The client tracking route"
|
|
106
|
+
{
|
|
107
|
+
"method": "POST",
|
|
108
|
+
"path": "/_agent-native/track",
|
|
109
|
+
"summary": "Forward a browser event to the registered server-side providers",
|
|
110
|
+
"auth": "Session required + same-origin/CSRF marker (set automatically by the client helper). Not an open analytics relay.",
|
|
111
|
+
"params": [
|
|
112
|
+
{ "name": "name", "in": "body", "type": "string", "required": true, "description": "Event name. Capped at 200 characters." },
|
|
113
|
+
{ "name": "properties", "in": "body", "type": "object", "description": "Event properties (~16KB cap). `source: \"client\"` and the active `org_id` are added server-side." }
|
|
114
|
+
],
|
|
115
|
+
"description": "Identity is resolved **server-side** from the session — browser code never passes a `userId`. Fire-and-forget: never blocks the UI, never throws, swallows network errors. Oversized or malformed payloads are rejected."
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
98
119
|
```ts
|
|
99
120
|
import { track } from "@agent-native/core/client";
|
|
100
121
|
|
|
@@ -9,12 +9,26 @@ The defining idea behind agent-native is that the agent and the UI are **equal p
|
|
|
9
9
|
|
|
10
10
|
There's a simple through-line. The agent **sees** what you're looking at, you **direct** it toward what you want, you can **embed** it anywhere, you can go fully **UI-light** when that's the better fit, and you can **co-edit** the same documents at the same time. Each of those is a page in this section.
|
|
11
11
|
|
|
12
|
+
```an-diagram title="The day-to-day loop" summary="Five ways of working with a docked agent — each is a page in this section."
|
|
13
|
+
{
|
|
14
|
+
"html": "<div class=\"diagram-loop\"><div class=\"diagram-card\"><strong>Sees</strong><small class=\"diagram-muted\">your view & selection</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-card\"><strong>Direct</strong><small class=\"diagram-muted\">@-mentions & voice</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-card\"><strong>Embed</strong><small class=\"diagram-muted\">drop into any app</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-card\"><strong>UI-light</strong><small class=\"diagram-muted\">chat is the product</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-card accent-card\"><span class=\"diagram-pill accent\">Co-edit</span><small class=\"diagram-muted\">live, side by side</small></div></div>",
|
|
15
|
+
"css": ".diagram-loop{display:flex;align-items:stretch;gap:10px;flex-wrap:wrap}.diagram-loop .diagram-card{display:flex;flex-direction:column;gap:6px;padding:14px 16px;min-width:130px;flex:1}.diagram-loop .diagram-arrow{align-self:center;font-size:22px;line-height:1}"
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
12
19
|
## It sees what you're looking at {#it-sees}
|
|
13
20
|
|
|
14
21
|
The agent isn't blind to your screen. Open an email and it knows which thread. Select a chart and it knows which chart. Highlight a paragraph and it can act on just that range. That shared awareness is what lets you say "reply to this" or "summarize the selection" without spelling out the context every time.
|
|
15
22
|
|
|
16
23
|
This works because the current navigation and selection live in `application_state` SQL, which the agent reads as part of its context. The agent can also drive that same state back — opening a view, selecting a row — so you watch it work in the real UI rather than in a transcript.
|
|
17
24
|
|
|
25
|
+
```an-callout
|
|
26
|
+
{
|
|
27
|
+
"tone": "info",
|
|
28
|
+
"body": "**Shared awareness is two-way.** You and the agent both read and write `application_state`, so \"reply to this\" or \"summarize the selection\" just works — and when the agent navigates, the real UI moves with it."
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
18
32
|
→ [**Context Awareness**](/docs/context-awareness) — navigation state, view-screen, navigate commands, and how the agent stays in sync with your screen.
|
|
19
33
|
|
|
20
34
|
## You direct it {#you-direct-it}
|
|
@@ -19,6 +19,13 @@ The composer's voice button records audio in the browser, then picks a provider:
|
|
|
19
19
|
|
|
20
20
|
Provider choice is stored in application state under `voice-transcription-prefs` so the user can force `"auto"` (default — picks the best available provider), `"builder-gemini"`, `"builder"`, `"gemini"`, `"groq"`, `"openai"`, or `"browser"` in the sidebar settings.
|
|
21
21
|
|
|
22
|
+
```an-diagram title="Voice transcription provider fallback" summary="The composer records audio, then walks server providers in order, dropping to the browser Web Speech API only when no server provider is available."
|
|
23
|
+
{
|
|
24
|
+
"html": "<div class=\"diagram-voice\"><div class=\"diagram-node\">Mic button<br><small class=\"diagram-muted\">records webm/opus</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-card col\"><div class=\"diagram-pill accent\">1 · Builder Gemini</div><small class=\"diagram-muted\">default when Builder connected</small><div class=\"diagram-pill\">2 · BYOK cloud</div><small class=\"diagram-muted\">Gemini · Groq · OpenAI Whisper</small></div><div class=\"diagram-arrow diagram-warn\" aria-hidden=\"true\">↓</div><div class=\"diagram-box diagram-warn\" data-rough>3 · Browser Web Speech<br><small class=\"diagram-muted\">fallback on 400 · streams live</small></div></div>",
|
|
25
|
+
"css": ".diagram-voice{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.diagram-voice .col{display:flex;flex-direction:column;gap:6px;padding:14px}.diagram-voice .diagram-arrow{font-size:22px;line-height:1}"
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
22
29
|
The route is **same-origin only** — cross-site POSTs are rejected so an attacker can't burn transcription credits from an external page.
|
|
23
30
|
|
|
24
31
|
## Enabling Providers {#enabling-providers}
|
|
@@ -33,19 +40,33 @@ The user sets their own key via the agent sidebar settings UI. It's stored as a
|
|
|
33
40
|
|
|
34
41
|
Set `GEMINI_API_KEY`, `GROQ_API_KEY`, or `OPENAI_API_KEY` as an environment variable or in the `settings` table. Every user's transcription hits the shared key.
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
43
|
+
```an-callout
|
|
44
|
+
{
|
|
45
|
+
"tone": "info",
|
|
46
|
+
"body": "**Credential resolution order:** the route checks the user's own encrypted secret first, then the shared deployment key. A power user with their own key always overrides the shared one. If neither exists, the route returns a 400 the composer recognizes and silently falls back to browser Web Speech."
|
|
47
|
+
}
|
|
48
|
+
```
|
|
39
49
|
|
|
40
50
|
## The route {#route}
|
|
41
51
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
```an-api title="Voice transcription route"
|
|
53
|
+
{
|
|
54
|
+
"method": "POST",
|
|
55
|
+
"path": "/_agent-native/transcribe-voice",
|
|
56
|
+
"summary": "Transcribe a recorded audio clip into prompt text",
|
|
57
|
+
"auth": "Active session (Better Auth cookie). Same-origin only.",
|
|
58
|
+
"description": "The composer POSTs the recorded clip here; the route resolves a provider and returns the transcribed text. You should not call this directly.",
|
|
59
|
+
"params": [
|
|
60
|
+
{ "name": "audio", "in": "body", "type": "file", "required": true, "description": "The recorded clip, webm/opus by default. Max 25 MB." },
|
|
61
|
+
{ "name": "provider", "in": "body", "type": "string", "required": false, "description": "Optional override, e.g. gemini, groq, openai, builder." }
|
|
62
|
+
],
|
|
63
|
+
"request": { "contentType": "multipart/form-data" },
|
|
64
|
+
"responses": [
|
|
65
|
+
{ "status": "200", "description": "Transcription succeeded", "example": "{ \"text\": \"reply to Sara that I'll be there by 3\" }" },
|
|
66
|
+
{ "status": "400", "description": "No server provider configured — the composer recognizes this and falls back to Web Speech", "example": "{ \"error\": \"no_provider\" }" }
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
```
|
|
49
70
|
|
|
50
71
|
You don't need to call this directly — the composer does. If you're building a custom input surface, first reuse the shared composer/voice client pieces from `@agent-native/core/client`. Treat this route as the low-level transport boundary for custom helpers that need to send multipart audio.
|
|
51
72
|
|
|
@@ -50,6 +50,13 @@ Three things change when you reach rung 3:
|
|
|
50
50
|
|
|
51
51
|
That's rung 3. That's agent-native.
|
|
52
52
|
|
|
53
|
+
```an-diagram title="The Ladder Principle" summary="Most teams stop at rung 1 or 2. Agent-native is rung 3 — a real app and a real agent over one shared action surface."
|
|
54
|
+
{
|
|
55
|
+
"html": "<div class=\"diagram-ladder\"><div class=\"diagram-card rung rung-3\"><span class=\"diagram-pill accent\">Rung 3 · agent-native</span><strong>Agent + UI as equal partners</strong><small class=\"diagram-muted\">One action surface. Every agent tool is also a button; every button runs the same logic the agent uses.</small></div><div class=\"diagram-card rung rung-2\"><span class=\"diagram-pill\">Rung 2</span><strong>A chat with tools</strong><small class=\"diagram-muted\">The agent can act — but it is still just a chat window. No dashboards, lists, or shortcuts.</small></div><div class=\"diagram-card rung rung-1\"><span class=\"diagram-pill warn\">Rung 1</span><strong>A single LLM call</strong><small class=\"diagram-muted\">Prompt in, string out. Impressive in a demo; breaks the moment reality gets messy.</small></div></div>",
|
|
56
|
+
"css": ".diagram-ladder{display:flex;flex-direction:column;gap:14px}.diagram-ladder .rung{display:flex;flex-direction:column;gap:6px;padding:16px 18px}.diagram-ladder .rung-2{margin-inline-end:48px}.diagram-ladder .rung-1{margin-inline-end:96px}"
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
53
60
|
See [Key Concepts — Protocols](/docs/key-concepts#protocols) for how all of this hangs off the same action definition.
|
|
54
61
|
|
|
55
62
|
## Why every agent needs a UI {#why-every-agent-needs-a-ui}
|
|
@@ -82,6 +89,13 @@ This is the defining principle.
|
|
|
82
89
|
>
|
|
83
90
|
> **From the agent** — natural language, other agents via A2A, Slack, Telegram. The agent writes to the database; the UI updates automatically.
|
|
84
91
|
|
|
92
|
+
```an-diagram title="One system, two ways in" summary="The agent and the UI write to the same actions and the same database. Whatever one does, the other sees."
|
|
93
|
+
{
|
|
94
|
+
"html": "<div class=\"diagram-parity\"><div class=\"diagram-col\"><div class=\"diagram-node\">Human<br><small class=\"diagram-muted\">clicks, forms, shortcuts</small></div><div class=\"diagram-node\">Agent<br><small class=\"diagram-muted\">natural language · A2A · Slack</small></div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-panel center\"><span class=\"diagram-pill accent\">Actions</span><small class=\"diagram-muted\">defined once</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-box\">SQL database</div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">↻</div><div class=\"diagram-box\">UI updates live</div></div>",
|
|
95
|
+
"css": ".diagram-parity{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.diagram-parity .diagram-col{display:flex;flex-direction:column;gap:10px}.diagram-parity .diagram-arrow{font-size:22px;line-height:1}.diagram-parity .center{display:flex;flex-direction:column;align-items:center;gap:4px}"
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
85
99
|
When the agent creates a draft email, it appears in the UI. When you click "Send," the agent knows it was sent. There's no separate "agent world" and "UI world" — it's one system. See [Key Concepts](/docs/key-concepts) for the architecture that makes this work.
|
|
86
100
|
|
|
87
101
|
## Customization usually reserved for power tools {#workspace-customization}
|
|
@@ -145,19 +159,17 @@ This is powered by [A2A](/docs/a2a-protocol) and [MCP](/docs/mcp-protocol) under
|
|
|
145
159
|
|
|
146
160
|
If you're building or extending an agent-native app, here's the central pattern: every operation in the app is an **action** — defined once, available to both the agent and the UI.
|
|
147
161
|
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
},
|
|
160
|
-
});
|
|
162
|
+
```an-annotated-code title="One action, defined once"
|
|
163
|
+
{
|
|
164
|
+
"filename": "actions/reply-to-email.ts",
|
|
165
|
+
"language": "ts",
|
|
166
|
+
"code": "import { defineAction } from \"@agent-native/core/action\";\nimport { z } from \"zod\";\n\nexport default defineAction({\n description: \"Reply to an email thread\",\n schema: z.object({ emailId: z.string(), body: z.string() }),\n run: async ({ emailId, body }) => {\n // db and schema come from your app's server/db setup\n await db.insert(schema.replies).values({ emailId, body });\n },\n});",
|
|
167
|
+
"annotations": [
|
|
168
|
+
{ "lines": "5", "label": "Tool surface", "note": "The `description` is what the agent reads to decide when to call this as a tool." },
|
|
169
|
+
{ "lines": "6", "label": "Typed contract", "note": "One zod `schema` validates input from **every** surface — agent, UI, HTTP, MCP, and A2A." },
|
|
170
|
+
{ "lines": "7-10", "label": "One implementation", "note": "The `run` body is the single source of truth. The UI button and the agent tool both execute exactly this." }
|
|
171
|
+
]
|
|
172
|
+
}
|
|
161
173
|
```
|
|
162
174
|
|
|
163
175
|
```tsx
|
|
@@ -16,6 +16,13 @@ Workspace connections are the framework primitive for reusable integration metad
|
|
|
16
16
|
- **credentialRef** — a pointer to a vault secret (`{ key: "SLACK_BOT_TOKEN", scope: "org" }`). The connection says where the token lives; the vault holds the value.
|
|
17
17
|
- **Readiness** — the combined status an app sees: `connected` (granted + credentials present), `needs_grant`, `needs_credentials`, `needs_attention`, or `not_configured`.
|
|
18
18
|
|
|
19
|
+
```an-diagram title="Connect once, grant apps, reuse credentials" summary="A Connection holds provider metadata (never secrets) and credentialRefs that point at the vault. Per-app Grants unlock it. Apps read a single Readiness status."
|
|
20
|
+
{
|
|
21
|
+
"html": "<div class=\"diagram-conn\"><div class=\"diagram-panel col\" data-rough><span class=\"diagram-pill accent\">Connection</span><div class=\"diagram-box\" data-rough>named provider account<br><small class=\"diagram-muted\">provider, label, status, scopes, config · never stores secret values</small></div><div class=\"diagram-muted\">credentialRef → pointer to a vault secret</div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-panel col\" data-rough><span class=\"diagram-pill\">Grant</span><div class=\"diagram-box\" data-rough>per-app permission<br><small class=\"diagram-muted\">no grant = no credential access</small></div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-panel col\" data-rough><span class=\"diagram-pill ok\">Readiness</span><small class=\"diagram-muted\">what the app sees</small><div class=\"sev-row\"><span class=\"diagram-pill ok\">connected</span><span class=\"diagram-pill warn\">needs_grant</span></div><div class=\"sev-row\"><span class=\"diagram-pill warn\">needs_credentials</span><span class=\"diagram-pill warn\">needs_attention</span></div><div class=\"sev-row\"><span class=\"diagram-pill\">not_configured</span></div></div></div>",
|
|
22
|
+
"css": ".diagram-conn{display:flex;align-items:center;gap:14px;flex-wrap:wrap}.diagram-conn .col{display:flex;flex-direction:column;gap:8px;padding:14px;min-width:220px}.diagram-conn .diagram-arrow{font-size:22px;line-height:1}.diagram-conn .sev-row{display:flex;gap:8px;flex-wrap:wrap}"
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
19
26
|
### Worked example: Slack
|
|
20
27
|
|
|
21
28
|
Connect Slack once and grant it to Brain and Analytics:
|
|
@@ -51,6 +58,41 @@ await upsertWorkspaceConnectionGrant({
|
|
|
51
58
|
});
|
|
52
59
|
```
|
|
53
60
|
|
|
61
|
+
```an-schema title="The connection model" summary="A connection records safe provider metadata and credentialRefs (pointers, not secrets). Each grant unlocks one app — one connection, many grants."
|
|
62
|
+
{
|
|
63
|
+
"entities": [
|
|
64
|
+
{
|
|
65
|
+
"id": "conn",
|
|
66
|
+
"name": "workspace_connections",
|
|
67
|
+
"note": "Named provider account. Never stores secret values.",
|
|
68
|
+
"fields": [
|
|
69
|
+
{ "name": "id", "type": "string", "pk": true, "note": "e.g. acme-slack" },
|
|
70
|
+
{ "name": "provider", "type": "string", "note": "stable provider id, e.g. slack" },
|
|
71
|
+
{ "name": "label", "type": "string" },
|
|
72
|
+
{ "name": "accountId", "type": "string", "nullable": true },
|
|
73
|
+
{ "name": "accountLabel", "type": "string", "nullable": true },
|
|
74
|
+
{ "name": "status", "type": "string", "note": "e.g. connected" },
|
|
75
|
+
{ "name": "scopes", "type": "string[]", "nullable": true },
|
|
76
|
+
{ "name": "config", "type": "json", "nullable": true, "note": "safe, non-secret config" },
|
|
77
|
+
{ "name": "credentialRefs", "type": "json", "nullable": true, "note": "pointers to vault keys, e.g. { key, scope }" }
|
|
78
|
+
]
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "grant",
|
|
82
|
+
"name": "workspace_connection_grants",
|
|
83
|
+
"note": "Per-app permission to use a connection.",
|
|
84
|
+
"fields": [
|
|
85
|
+
{ "name": "connectionId", "type": "string", "fk": "conn.id" },
|
|
86
|
+
{ "name": "appId", "type": "string", "note": "e.g. brain, analytics" }
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"relations": [
|
|
91
|
+
{ "from": "conn", "to": "grant", "kind": "1-n", "label": "grants apps" }
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
54
96
|
### What apps call
|
|
55
97
|
|
|
56
98
|
Before asking a user to paste a new key, check readiness first:
|
|
@@ -164,6 +206,13 @@ The credential vault answers: "Where is the secret stored, who can access it, an
|
|
|
164
206
|
|
|
165
207
|
Workspace connection provider metadata answers: "Which provider is this, what can it do, what credential keys might it need, and which templates should offer it?"
|
|
166
208
|
|
|
209
|
+
```an-diagram title="Connection store vs. vault" summary="The vault owns the secret value. The connection owns provider metadata plus credentialRefs (pointers). At execution time the app resolves the ref through a granted connection and reads the value from the vault."
|
|
210
|
+
{
|
|
211
|
+
"html": "<div class=\"diagram-vault\"><div class=\"diagram-panel col\" data-rough><span class=\"diagram-pill accent\">Connection store</span><div class=\"diagram-box\" data-rough>provider account + metadata<br><small class=\"diagram-muted\">status, scopes, config</small></div><div class=\"diagram-box\" data-rough>credentialRef<br><small class=\"diagram-muted\">{ key: SLACK_BOT_TOKEN, scope: org }</small></div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-card\"><span class=\"diagram-pill\">App action</span><small class=\"diagram-muted\">resolves at execution time through a granted ref</small><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">↓</div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-panel col\" data-rough><span class=\"diagram-pill ok\">Vault</span><div class=\"diagram-box\" data-rough>secret value<br><small class=\"diagram-muted\">never returned to the agent or UI</small></div></div></div>",
|
|
212
|
+
"css": ".diagram-vault{display:flex;align-items:center;gap:14px;flex-wrap:wrap}.diagram-vault .col{display:flex;flex-direction:column;gap:8px;padding:14px;min-width:220px}.diagram-vault .diagram-card{display:flex;flex-direction:column;gap:6px;padding:12px 14px}.diagram-vault .diagram-arrow{font-size:22px;line-height:1}"
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
167
216
|
Use both together:
|
|
168
217
|
|
|
169
218
|
1. Dispatch (or another workspace setup flow) creates the underlying vault secret or OAuth credential reference.
|
|
@@ -9,6 +9,13 @@ description: "Branching, CODEOWNERS, PR review, and how Dispatch handles runtime
|
|
|
9
9
|
|
|
10
10
|
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.
|
|
11
11
|
|
|
12
|
+
```an-diagram title="Two governance planes" summary="Git governs code; Dispatch governs runtime. They are complementary — don't replicate one inside the other."
|
|
13
|
+
{
|
|
14
|
+
"html": "<div class=\"gov\"><div class=\"diagram-card\"><span class=\"diagram-pill accent\">Git / GitHub</span><strong>Code governance</strong><div class=\"gov-list\"><span class=\"diagram-pill\">CODEOWNERS</span><span class=\"diagram-pill\">branch protection</span><span class=\"diagram-pill\">PR review</span><span class=\"diagram-pill\">git log / blame</span></div></div><div class=\"diagram-pill diagram-muted\">+</div><div class=\"diagram-card\"><span class=\"diagram-pill accent\">Dispatch</span><strong>Runtime governance</strong><div class=\"gov-list\"><span class=\"diagram-pill\">vault secrets & grants</span><span class=\"diagram-pill\">workspace resources</span><span class=\"diagram-pill\">agent profiles</span><span class=\"diagram-pill\">approvals & audit</span></div></div></div>",
|
|
15
|
+
"css": ".gov{display:flex;align-items:center;gap:16px;flex-wrap:wrap}.gov .diagram-card{display:flex;flex-direction:column;gap:8px;padding:16px 18px;flex:1;min-width:240px}.gov .gov-list{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}"
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
12
19
|
## Branching
|
|
13
20
|
|
|
14
21
|
### Feature Branches
|
|
@@ -38,6 +45,19 @@ Not everyone who needs to make changes is comfortable with git. [Builder.io](htt
|
|
|
38
45
|
|
|
39
46
|
## Code Ownership
|
|
40
47
|
|
|
48
|
+
Code governance is configured by a handful of files at the repo root:
|
|
49
|
+
|
|
50
|
+
```an-file-tree title="Governance config in the repo"
|
|
51
|
+
{
|
|
52
|
+
"entries": [
|
|
53
|
+
{ "path": ".github/CODEOWNERS", "note": "Auto-assigns reviewers per changed path" },
|
|
54
|
+
{ "path": ".github/labeler.yml", "note": "Auto-labels PRs by app" },
|
|
55
|
+
{ "path": "pnpm-workspace.yaml", "note": "Workspace-level — broad review" },
|
|
56
|
+
{ "path": "package.json", "note": "Workspace-level — platform team owns" }
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
41
61
|
GitHub's CODEOWNERS file auto-assigns reviewers to PRs based on which files changed. Create `.github/CODEOWNERS` at the repo root:
|
|
42
62
|
|
|
43
63
|
```
|
|
@@ -96,6 +116,10 @@ Then add the [actions/labeler](https://github.com/actions/labeler) action — se
|
|
|
96
116
|
|
|
97
117
|
Agent-native workspaces often have multiple AI agents working on the same branch simultaneously. This is by design — the agents share a branch and push independently.
|
|
98
118
|
|
|
119
|
+
```an-callout
|
|
120
|
+
{ "tone": "warning", "body": "**The later commit wins.** Two agents touching the same file won't conflict at commit time — the conflict surfaces at review. Run `pnpm run prep` (typecheck + test + format) before pushing, and don't revert changes you didn't make unless they're clearly broken." }
|
|
121
|
+
```
|
|
122
|
+
|
|
99
123
|
When reviewing PRs in this environment:
|
|
100
124
|
|
|
101
125
|
- **Don't revert changes you didn't make** unless they're clearly broken
|
|
@@ -11,6 +11,13 @@ Every agent-native app ships with a **workspace**: the customization layer that
|
|
|
11
11
|
|
|
12
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.
|
|
13
13
|
|
|
14
|
+
```an-diagram title="A Claude-Code workspace, but stored in SQL" summary="The same customization layer — instructions, skills, memory, agents, jobs, MCP — except every file is a row in a shared multi-tenant database."
|
|
15
|
+
{
|
|
16
|
+
"html": "<div class=\"ws-map\"><div class=\"diagram-card cc\"><span class=\"diagram-pill warn\">Claude Code / Codex</span><small class=\"diagram-muted\">~/.claude/ on a local disk</small><div class=\"ws-files\"><span class=\"diagram-box\">CLAUDE.md</span><span class=\"diagram-box\">skills/</span><span class=\"diagram-box\">memory</span><span class=\"diagram-box\">mcp.json</span></div><small class=\"diagram-muted\">one codebase per developer</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-card an\"><span class=\"diagram-pill accent\">Agent-native workspace</span><small class=\"diagram-muted\">rows in one SQL database</small><div class=\"ws-rows\"><span class=\"diagram-pill\">AGENTS.md</span><span class=\"diagram-pill\">skills/…</span><span class=\"diagram-pill\">memory/…</span><span class=\"diagram-pill\">mcp-servers/…</span></div><small class=\"diagram-muted\">one codebase, many users, scoped <code>u:<email>:…</code></small></div></div>",
|
|
17
|
+
"css": ".ws-map{display:flex;align-items:center;gap:16px;flex-wrap:wrap}.ws-map .diagram-card{display:flex;flex-direction:column;gap:8px;padding:16px 18px;flex:1;min-width:220px}.ws-map .ws-files,.ws-map .ws-rows{display:flex;flex-wrap:wrap;gap:6px;margin:4px 0}.ws-map .diagram-arrow{font-size:24px}"
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
14
21
|
| Claude Code / Codex | Agent-native workspace |
|
|
15
22
|
| -------------------------------- | -------------------------------------------------- |
|
|
16
23
|
| Files on your local disk | Rows in a shared SQL database |
|
|
@@ -44,6 +51,13 @@ The canonical paths that control how the agent uses each resource:
|
|
|
44
51
|
|
|
45
52
|
These paths apply across all three scopes — workspace, organization/app, and personal. The later scope wins when the same path exists at multiple levels.
|
|
46
53
|
|
|
54
|
+
```an-diagram title="Three scopes, one effective file" summary="The runtime resolves the same path across workspace, app, and personal scopes on read — the most specific scope wins."
|
|
55
|
+
{
|
|
56
|
+
"html": "<div class=\"ws-stack\"><div class=\"diagram-card\"><span class=\"diagram-pill\">Workspace</span><small class=\"diagram-muted\">company-wide defaults from Dispatch</small><code>context/brand.md</code></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">↓</div><div class=\"diagram-card\"><span class=\"diagram-pill\">Organization / app</span><small class=\"diagram-muted\">team override for one app</small><code>context/brand.md</code></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">↓</div><div class=\"diagram-card\"><span class=\"diagram-pill accent\">Personal</span><small class=\"diagram-muted\">per-user override — wins</small><code>context/brand.md</code></div><div class=\"diagram-arrow diagram-accent\" aria-hidden=\"true\">→</div><div class=\"diagram-box ok\">Effective <code>context/brand.md</code></div></div>",
|
|
57
|
+
"css": ".ws-stack{display:flex;flex-direction:column;align-items:flex-start;gap:8px}.ws-stack .diagram-card{display:flex;flex-direction:column;gap:4px;padding:12px 16px;min-width:280px}.ws-stack .diagram-arrow{font-size:20px;align-self:center}.ws-stack code{font-size:.85em}.ws-stack .diagram-box{align-self:center;margin-top:4px}"
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
47
61
|
## Getting Started: a 1-minute walkthrough {#getting-started}
|
|
48
62
|
|
|
49
63
|
Change how the agent behaves, in 60 seconds.
|
|
@@ -59,6 +73,10 @@ Change how the agent behaves, in 60 seconds.
|
|
|
59
73
|
|
|
60
74
|
3. Save, switch to **Chat**, ask anything — the agent follows the new rule immediately.
|
|
61
75
|
|
|
76
|
+
```an-callout
|
|
77
|
+
{ "tone": "info", "body": "No restart, no redeploy. `AGENTS.md` is read at the start of every turn, so an edit you save now changes the agent's behavior on the very next message." }
|
|
78
|
+
```
|
|
79
|
+
|
|
62
80
|
**Next steps, when you want them:**
|
|
63
81
|
|
|
64
82
|
- **Skills** (`+` → **Skill**) — focused how-to files invoked in chat with `/skill-name`.
|
|
@@ -163,6 +181,26 @@ The resource system also seeds a personal `LEARNINGS.md` for compatibility with
|
|
|
163
181
|
|
|
164
182
|
Users can edit these memory files directly in the Workspace tab — they're regular resources. Delete lines the agent got wrong, keep personal preferences in `memory/MEMORY.md`, or promote team-wide rules into `AGENTS.md`.
|
|
165
183
|
|
|
184
|
+
Every one of these surfaces — `AGENTS.md`, skills, memory, custom agents, MCP servers — is the same underlying resource shape: a `path` + `scope` + `content`, addressed and resolved the same way.
|
|
185
|
+
|
|
186
|
+
```an-schema title="The workspace resource model" summary="One resource shape backs every workspace file. The runtime keys it by path and scope and resolves the effective value on read."
|
|
187
|
+
{
|
|
188
|
+
"entities": [
|
|
189
|
+
{
|
|
190
|
+
"id": "resource",
|
|
191
|
+
"name": "workspace resource",
|
|
192
|
+
"note": "A single file in a user's workspace — instructions, skill, memory, agent, MCP config, or job.",
|
|
193
|
+
"fields": [
|
|
194
|
+
{ "name": "path", "type": "string", "note": "Canonical path, e.g. AGENTS.md, skills/<slug>/SKILL.md" },
|
|
195
|
+
{ "name": "scope", "type": "workspace | shared | personal", "note": "Which level this row lives at" },
|
|
196
|
+
{ "name": "owner", "type": "string", "nullable": true, "note": "u:<email> for personal scope" },
|
|
197
|
+
{ "name": "content", "type": "text", "note": "Markdown / JSON / YAML body" }
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
166
204
|
## Skills {#skills}
|
|
167
205
|
|
|
168
206
|
Skills are Markdown resource files under the `skills/` path (preferably `skills/<name>/SKILL.md`) that give the agent on-demand domain knowledge, invoked in chat with `/skill-name`. Add them from the Workspace tab or, in Code mode, from `.agents/skills/`.
|
|
@@ -179,25 +217,18 @@ Use them when you want a focused delegate with its own name, description, model
|
|
|
179
217
|
|
|
180
218
|
Custom agents use YAML frontmatter plus Markdown instructions:
|
|
181
219
|
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
Reviews layouts, interaction patterns, and product UX decisions
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
You are a focused design agent.
|
|
195
|
-
|
|
196
|
-
## Responsibilities
|
|
197
|
-
|
|
198
|
-
- Review layouts and interaction flows
|
|
199
|
-
- Suggest stronger visual direction
|
|
200
|
-
- Be concise and opinionated
|
|
220
|
+
```an-annotated-code title="A custom agent profile"
|
|
221
|
+
{
|
|
222
|
+
"filename": "agents/design.md",
|
|
223
|
+
"language": "markdown",
|
|
224
|
+
"code": "---\nname: Design\ndescription: >-\n Reviews layouts, interaction patterns, and product UX decisions.\nmodel: inherit\ntools: inherit\ndelegate-default: false\n---\n\n# Role\n\nYou are a focused design agent.\n\n## Responsibilities\n\n- Review layouts and interaction flows\n- Suggest stronger visual direction\n- Be concise and opinionated",
|
|
225
|
+
"annotations": [
|
|
226
|
+
{ "lines": "2", "label": "@mention handle", "note": "`name` is what appears in the `@`-dropdown and what the main agent delegates to." },
|
|
227
|
+
{ "lines": "3-4", "label": "When to delegate", "note": "The `description` is what the orchestrator reads to decide this profile fits a task." },
|
|
228
|
+
{ "lines": "5", "label": "Model", "note": "`inherit` reuses the main agent's model. Override only when the profile clearly needs a different one." },
|
|
229
|
+
{ "lines": "6", "note": "`tools: inherit` for now — the field is reserved for future per-agent tool policies." }
|
|
230
|
+
]
|
|
231
|
+
}
|
|
201
232
|
```
|
|
202
233
|
|
|
203
234
|
Recommended conventions:
|
|
@@ -7,6 +7,13 @@ description: "How to write great agent instructions for an agent-native app or t
|
|
|
7
7
|
|
|
8
8
|
The agent's behavior in an agent-native app is only as good as the instructions you give it. Three surfaces carry that guidance: `AGENTS.md` (the map), skills (the deep dives), and action/tool descriptions (how the agent picks the right tool). Write each one for fast retrieval, not for prose.
|
|
9
9
|
|
|
10
|
+
```an-diagram title="Three authored surfaces + one runtime surface" summary="AGENTS.md and tool descriptions load every turn; skills load on demand; application_state is written live by your UI."
|
|
11
|
+
{
|
|
12
|
+
"html": "<div class=\"diagram-surfaces\"><div class=\"diagram-card always\" data-rough><span class=\"diagram-pill accent\">Every turn</span><strong>AGENTS.md</strong><small class=\"diagram-muted\">the map: purpose, core rules, state keys, action + skills index</small></div><div class=\"diagram-card always\" data-rough><span class=\"diagram-pill accent\">Every turn</span><strong>Tool descriptions</strong><small class=\"diagram-muted\">drive tool selection — one precise sentence each</small></div><div class=\"diagram-card ondemand\" data-rough><span class=\"diagram-pill\">On demand</span><strong>Skills</strong><small class=\"diagram-muted\">deep how-to, loaded when the description fires</small></div><div class=\"diagram-card runtime\" data-rough><span class=\"diagram-pill ok\">Live</span><strong>application_state</strong><small class=\"diagram-muted\">written by your UI: navigation, selection, focus</small></div></div>",
|
|
13
|
+
"css": ".diagram-surfaces{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}.diagram-surfaces .diagram-card{display:flex;flex-direction:column;gap:6px;padding:14px 16px}"
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
10
17
|
## Keep AGENTS.md small and skimmable {#small-agents-md}
|
|
11
18
|
|
|
12
19
|
`AGENTS.md` is loaded as orientation. It should be the smallest thing that lets the agent act correctly, with everything deep pushed into skills. Aim for these sections and little else:
|