@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.
Files changed (98) hide show
  1. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  2. package/dist/client/blocks/library/AnnotatedCodeBlock.js +23 -19
  3. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  4. package/dist/client/blocks/library/diagram.d.ts.map +1 -1
  5. package/dist/client/blocks/library/diagram.js +10 -11
  6. package/dist/client/blocks/library/diagram.js.map +1 -1
  7. package/dist/client/blocks/library/wireframe.d.ts.map +1 -1
  8. package/dist/client/blocks/library/wireframe.js +2 -1
  9. package/dist/client/blocks/library/wireframe.js.map +1 -1
  10. package/dist/server/auth.d.ts.map +1 -1
  11. package/dist/server/auth.js +5 -1
  12. package/dist/server/auth.js.map +1 -1
  13. package/dist/server/onboarding-html.d.ts.map +1 -1
  14. package/dist/server/onboarding-html.js +50 -5
  15. package/dist/server/onboarding-html.js.map +1 -1
  16. package/dist/styles/blocks.css +25 -3
  17. package/docs/content/a2a-protocol.md +48 -10
  18. package/docs/content/actions.md +35 -16
  19. package/docs/content/agent-mentions.md +25 -32
  20. package/docs/content/agent-surfaces.md +31 -0
  21. package/docs/content/agent-teams.md +17 -14
  22. package/docs/content/agent-web-surfaces.md +24 -15
  23. package/docs/content/authentication.md +21 -0
  24. package/docs/content/automations.md +37 -21
  25. package/docs/content/blueprint-installer.md +7 -0
  26. package/docs/content/cli-adapters.md +7 -0
  27. package/docs/content/client.md +14 -0
  28. package/docs/content/cloneable-saas.md +14 -0
  29. package/docs/content/code-agents-ui.md +27 -0
  30. package/docs/content/components.md +21 -0
  31. package/docs/content/context-awareness.md +33 -48
  32. package/docs/content/creating-templates.md +43 -52
  33. package/docs/content/cross-app-sso.md +41 -0
  34. package/docs/content/database.md +41 -21
  35. package/docs/content/deployment.md +23 -6
  36. package/docs/content/dispatch.md +27 -0
  37. package/docs/content/drop-in-agent.md +26 -27
  38. package/docs/content/durable-resume.md +13 -1
  39. package/docs/content/embedding-sdk.md +14 -0
  40. package/docs/content/evals.md +14 -0
  41. package/docs/content/extensions.md +19 -0
  42. package/docs/content/external-agents.md +38 -1
  43. package/docs/content/faq.md +14 -0
  44. package/docs/content/file-uploads.md +20 -0
  45. package/docs/content/frames.md +14 -0
  46. package/docs/content/getting-started.md +34 -16
  47. package/docs/content/harness-agents.md +14 -0
  48. package/docs/content/human-approval.md +15 -30
  49. package/docs/content/key-concepts.md +37 -0
  50. package/docs/content/local-file-mode.md +26 -19
  51. package/docs/content/mcp-apps.md +36 -1
  52. package/docs/content/mcp-clients.md +49 -0
  53. package/docs/content/mcp-protocol.md +36 -0
  54. package/docs/content/messaging.md +34 -8
  55. package/docs/content/migration-workbench.md +7 -0
  56. package/docs/content/multi-app-workspace.md +29 -16
  57. package/docs/content/multi-tenancy.md +14 -0
  58. package/docs/content/native-chat-ui.md +20 -3
  59. package/docs/content/notifications.md +30 -0
  60. package/docs/content/observability.md +20 -1
  61. package/docs/content/observational-memory.md +14 -0
  62. package/docs/content/onboarding.md +32 -41
  63. package/docs/content/plan-plugin.md +14 -0
  64. package/docs/content/pr-visual-recap.md +14 -0
  65. package/docs/content/processors.md +7 -0
  66. package/docs/content/progress.md +23 -0
  67. package/docs/content/pure-agent-apps.md +7 -0
  68. package/docs/content/real-time-collaboration.md +19 -18
  69. package/docs/content/recurring-jobs.md +22 -19
  70. package/docs/content/routing.md +8 -0
  71. package/docs/content/sandbox-adapters.md +19 -0
  72. package/docs/content/security.md +38 -0
  73. package/docs/content/server.md +47 -25
  74. package/docs/content/sharing.md +50 -0
  75. package/docs/content/skills-guide.md +27 -42
  76. package/docs/content/template-analytics.md +71 -41
  77. package/docs/content/template-assets.md +76 -3
  78. package/docs/content/template-brain.md +89 -1
  79. package/docs/content/template-calendar.md +86 -58
  80. package/docs/content/template-chat.md +25 -9
  81. package/docs/content/template-clips.md +124 -16
  82. package/docs/content/template-content.md +146 -47
  83. package/docs/content/template-design.md +62 -2
  84. package/docs/content/template-dispatch.md +56 -9
  85. package/docs/content/template-forms.md +69 -13
  86. package/docs/content/template-mail.md +73 -26
  87. package/docs/content/template-plan.md +80 -1
  88. package/docs/content/template-slides.md +95 -74
  89. package/docs/content/template-videos.md +73 -52
  90. package/docs/content/tracking.md +21 -0
  91. package/docs/content/using-your-agent.md +14 -0
  92. package/docs/content/voice-input.md +31 -10
  93. package/docs/content/what-is-agent-native.md +25 -13
  94. package/docs/content/workspace-connections.md +49 -0
  95. package/docs/content/workspace-management.md +24 -0
  96. package/docs/content/workspace.md +50 -19
  97. package/docs/content/writing-agent-instructions.md +7 -0
  98. package/package.json +1 -1
@@ -7,17 +7,21 @@ description: "An agent-powered email client. Connect your Gmail and the agent ca
7
7
 
8
8
  An agent-powered email client. Connect your Gmail account and the agent can read, draft, send, and organize email for you — alongside a fast, keyboard-first inbox you can drive yourself. Think Superhuman, but the agent is a first-class citizen and the codebase is yours to own.
9
9
 
10
- <!-- screenshot:
11
- app: mail
12
- view: /inbox
13
- shows: Inbox listing (Priya Mehta, Acme Billing, Marcus Tang, GitHub, Sasha Park, Linear, Hannah Reyes, Acme Recruiting, Notion, Stripe, Vercel, Calendly, Olivia Brennan, AWS Billing, Dan Kim, Figma) with the agent sidebar open and suggestion chips visible
14
- account: screenshot-account (seeded with the email set above via the standard inbound flow)
15
- capture: 1400x800 viewport, cropped 90px from bottom (final 1400x710)
16
- -->
10
+ ```an-wireframe
11
+ {
12
+ "surface": "desktop",
13
+ "html": "<div style='display:flex;flex-direction:column;min-height:500px;box-sizing:border-box'><div style='display:flex;align-items:center;gap:12px;padding:12px 16px;border-bottom:1.4px solid var(--wf-line)'><strong>Inbox 16</strong><div style='flex:1'></div><span data-icon='search' aria-label='Search'></span><span data-icon='edit' aria-label='Compose'></span><span data-icon='bell' aria-label='Notify'></span></div><div style='display:flex;flex-direction:column;padding:8px 14px;gap:6px'><div class='wf-box' style='display:grid;grid-template-columns:155px 1fr auto;gap:12px;align-items:center'><strong>Priya Mehta</strong><span><strong>Q3 launch</strong> — final assets ready for review</span><span>★</span></div><div class='wf-box' style='display:grid;grid-template-columns:155px 1fr auto;gap:12px;align-items:center'><strong>Acme Billing</strong><span>Your monthly invoice is ready</span><span>11:10 AM</span></div><div class='wf-box' style='display:grid;grid-template-columns:155px 1fr auto;gap:12px;align-items:center'><span>Marcus Tang</span><span>Onboarding flow research findings</span><span>Yesterday</span></div><div class='wf-box' style='display:grid;grid-template-columns:155px 1fr auto;gap:12px;align-items:center'><span>GitHub</span><span>[framework] PR ready for review</span><span>Yesterday</span></div><div class='wf-box' style='display:grid;grid-template-columns:155px 1fr auto;gap:12px;align-items:center'><span>Linear</span><span>Issue ENG-1287 assigned to you</span><span>May 2</span></div><div class='wf-box' style='display:grid;grid-template-columns:155px 1fr auto;gap:12px;align-items:center'><span>Stripe</span><span>Weekly payments summary</span><span>Apr 29</span></div><div class='wf-box' style='display:grid;grid-template-columns:155px 1fr auto;gap:12px;align-items:center'><span>Calendly</span><span>New booking confirmed</span><span>Apr 28</span></div></div></div>"
14
+ }
15
+ ```
17
16
 
18
- ![Mail inbox with the agent sidebar](/screenshots/mail.png)
17
+ When you open the app, the keyboard-first inbox and thread view stay focused on the mail itself. The agent always knows which view you're in and which thread you have open, so you can say "archive this" or "draft a friendly decline" without explaining what "this" is.
19
18
 
20
- When you open the app, you'll see your inbox on the left, the open thread in the middle, and the agent in the sidebar on the right. The agent always knows which view you're in and which thread you have open, so you can say "archive this" or "draft a friendly decline" without explaining what "this" is.
19
+ ```an-diagram title="How a mail request flows" summary="Keyboard shortcuts and agent prompts run the same actions. Email lives in Gmail; drafts, automations, and tracking live in SQL and application_state."
20
+ {
21
+ "html": "<div class=\"diagram-flow\"><div class=\"diagram-col\"><div class=\"diagram-node\">You drive<br><small class=\"diagram-muted\">J/K/E/R shortcuts</small></div><div class=\"diagram-node\">You ask the agent<br><small class=\"diagram-muted\">\"draft a friendly decline\"</small></div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-panel center\"><span class=\"diagram-pill accent\">Actions</span><small class=\"diagram-muted\">list-emails · get-thread · manage-draft · send</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-col\"><div class=\"diagram-box\">Gmail<br><small class=\"diagram-muted\">multi-account, via OAuth</small></div><div class=\"diagram-box\">SQL + application_state<br><small class=\"diagram-muted\">drafts · automations · tracking</small></div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&#8635;</div><div class=\"diagram-box\">Inbox refreshes live</div></div>",
22
+ "css": ".diagram-flow{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.diagram-flow .diagram-col{display:flex;flex-direction:column;gap:10px}.diagram-flow .diagram-arrow{font-size:22px;line-height:1}.diagram-flow .center{display:flex;flex-direction:column;align-items:center;gap:4px}"
23
+ }
24
+ ```
21
25
 
22
26
  ## What you can do with it
23
27
 
@@ -112,27 +116,15 @@ To connect Gmail in dev, you need a Google OAuth client:
112
116
 
113
117
  Tokens are stored in the `oauth_tokens` SQL table and refresh automatically. You can connect multiple Gmail accounts once the first is set up.
114
118
 
115
- ### Key features (technical)
116
-
117
- **Gmail sync (multi-account).** Connect one or many Google accounts via OAuth. List and search actions query all connected inboxes by default; results carry an `accountEmail` field so you can tell which inbox each thread came from. Scope to a single account with `--account=user@example.com`. OAuth tokens are stored via `@agent-native/core/oauth-tokens` under the `"google"` provider.
118
-
119
- **Multiple compose drafts.** The compose panel supports multiple draft tabs at once. Each draft is stored as an `application_state` entry at `compose-{id}` and syncs live between the agent and the UI. The agent can create a new draft with `manage-draft --action=create`, edit your in-progress draft with `--action=update`, or close tabs with `--action=delete`. Drafts use markdown in the body field; the TipTap editor renders it as rich text and converts to HTML on send.
120
-
121
- **Queued draft review.** Drafts requested by teammates or Slack are durable SQL rows in `queued_email_drafts`. The agent uses `queue-email-draft` to assign a draft to an org member, returns a review URL such as `/draft-queue/<id>`, and waits for the owner to review or explicitly send. The queue supports listing assigned drafts, editing them, opening one in the compose panel, dismissing it, and sending one or all reviewed drafts.
119
+ ### Key features
122
120
 
123
- **AI triage via automations.** Mail supports automation rules that run against new inbox email using AI. A rule has a natural-language condition (for example, `"from a newsletter"` or `"subject contains invoice"`) and a list of actions (`label`, `archive`, `mark_read`, `star`, `trash`). Manage them via `pnpm action manage-automations --action=create|list|update|delete|enable|disable`, or through the Settings page. Rules fire automatically and can be triggered manually with `pnpm action trigger-automations`.
121
+ **Multi-account Gmail.** Connect one or more Google accounts, then list, search, draft, send, label, archive, star, or trash across connected inboxes.
124
122
 
125
- **Send tracking.** Sent messages get open-pixel and link-click tracking injected automatically. Settings live under `mail-settings.tracking` with `tracking.opens` and `tracking.clicks` (both default `true`). Only links in the new portion of a reply or forward are rewritten quoted content is left alone. Pull stats for any sent message with `pnpm action get-tracking --id=<message-id>`, or from `GET /api/emails/:id/tracking`. Open and click events are stored in the `email_tracking` and `email_link_tracking` tables.
123
+ **Draft workflows.** Multiple compose drafts sync through application state, and queued SQL drafts let teammates or Slack users request mail for the owner to review and send.
126
124
 
127
- **Search.** `pnpm action search-emails --q=<term>` searches across all views and all connected accounts. The UI search bar maps to the same action. Both `search-emails` and `list-emails` take `--compact` for shorter output and `--fields=from,subject,date` to limit returned fields.
125
+ **Automations and tracking.** Natural-language triage rules can label, archive, mark read, star, trash, or trigger manually; sent messages can track opens and clicks.
128
126
 
129
- **Bulk operations and export.**
130
-
131
- - `pnpm action bulk-archive --older-than=30` archives everything older than N days.
132
- - `pnpm action export-emails --view=inbox --output=file.json` dumps a view to JSON.
133
- - Archive, trash, mark-read, and star all accept comma-separated IDs (`--id=id1,id2,id3`) for bulk changes.
134
-
135
- **Inline thread previews in agent chat.** When the agent answers a question about a specific thread, it can embed a live preview of the thread directly in the chat message via an `embed` code fence. The preview is a sandboxed iframe that shows the full conversation without leaving the chat, with an "Open in app" button that navigates the main window to that thread.
127
+ **Search, bulk actions, and previews.** Shared actions power inbox search, bulk archive/export, and inline thread previews the agent can embed in chat.
136
128
 
137
129
  ### How the agent sees your context
138
130
 
@@ -164,6 +156,61 @@ When a Google account is connected, email lives in Gmail — the app is a view o
164
156
 
165
157
  Emails flowing through the API have the shape `{ id, threadId, from, to, cc, subject, snippet, body, date, isRead, isStarred, isArchived, isTrashed, labelIds, accountEmail, attachments }`.
166
158
 
159
+ ```an-schema title="Mail SQL tables" summary="Email itself lives in Gmail. The SQL tables hold what Gmail doesn't: queued drafts, send-tracking events, and OAuth tokens. Settings and ephemeral state live in the settings and application_state stores."
160
+ {
161
+ "entities": [
162
+ {
163
+ "id": "queued_email_drafts",
164
+ "name": "queued_email_drafts",
165
+ "note": "Teammate/Slack-requested drafts awaiting owner review",
166
+ "fields": [
167
+ { "name": "id", "type": "id", "pk": true },
168
+ { "name": "assignedTo", "type": "string", "note": "org member who reviews/sends" },
169
+ { "name": "subject", "type": "string" },
170
+ { "name": "body", "type": "markdown" },
171
+ { "name": "status", "type": "enum", "note": "review at /draft-queue/<id>" }
172
+ ]
173
+ },
174
+ {
175
+ "id": "email_tracking",
176
+ "name": "email_tracking",
177
+ "note": "Open-pixel events for sent messages",
178
+ "fields": [
179
+ { "name": "id", "type": "id", "pk": true },
180
+ { "name": "messageId", "type": "string" },
181
+ { "name": "openedAt", "type": "datetime" }
182
+ ]
183
+ },
184
+ {
185
+ "id": "email_link_tracking",
186
+ "name": "email_link_tracking",
187
+ "note": "Link-click events for sent messages",
188
+ "fields": [
189
+ { "name": "id", "type": "id", "pk": true },
190
+ { "name": "messageId", "type": "string", "fk": "email_tracking.messageId" },
191
+ { "name": "url", "type": "string" },
192
+ { "name": "clickedAt", "type": "datetime" }
193
+ ]
194
+ },
195
+ {
196
+ "id": "oauth_tokens",
197
+ "name": "oauth_tokens",
198
+ "note": "Framework table — one row per connected Google account",
199
+ "fields": [
200
+ { "name": "id", "type": "id", "pk": true },
201
+ { "name": "provider", "type": "string", "note": "\"google\"" },
202
+ { "name": "accountEmail", "type": "string" },
203
+ { "name": "accessToken", "type": "string" },
204
+ { "name": "refreshToken", "type": "string" }
205
+ ]
206
+ }
207
+ ],
208
+ "relations": [
209
+ { "from": "email_tracking", "to": "email_link_tracking", "kind": "1-n", "label": "click events" }
210
+ ]
211
+ }
212
+ ```
213
+
167
214
  Routes in the UI:
168
215
 
169
216
  - `/_index.tsx` — redirects to the default inbox view.
@@ -23,7 +23,19 @@ commit, branch, or git diff — into a high-altitude visual code review. Both op
23
23
  the same review surface, so you annotate, comment, and hand feedback back to the
24
24
  agent the same way.
25
25
 
26
- ![Agent-Native Plans review surface](https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2Fdd73f749f8c54dbcb577420ab1a18788)
26
+ ```an-diagram title="Two commands, one review surface" summary="Both commands publish through the hosted Plan MCP connector into the same annotate-and-comment surface."
27
+ {
28
+ "html": "<div class=\"diagram-plan\"><div class=\"diagram-col\"><div class=\"diagram-node\"><span class=\"diagram-pill accent\">/visual-plan</span><small class=\"diagram-muted\">before code — architecture, UI, refactor</small></div><div class=\"diagram-node\"><span class=\"diagram-pill\">/visual-recap</span><small class=\"diagram-muted\">after code — PR, commit, branch, diff</small></div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-panel center\">Plan MCP connector<br><small class=\"diagram-muted\">plan.agent-native.com</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-box\">Review surface<br><small class=\"diagram-muted\">diagrams · wireframes · annotated code · comments</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&harr;</div><div class=\"diagram-node\">Coding agent<br><small class=\"diagram-muted\">feedback handed back</small></div></div>",
29
+ "css": ".diagram-plan{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.diagram-plan .diagram-col{display:flex;flex-direction:column;gap:10px}.diagram-plan .diagram-arrow{font-size:22px;line-height:1}.diagram-plan .center{display:flex;flex-direction:column;align-items:center;gap:4px;text-align:center}"
30
+ }
31
+ ```
32
+
33
+ ```an-wireframe
34
+ {
35
+ "surface": "desktop",
36
+ "html": "<div style='display:grid;grid-template-columns:1fr 250px;gap:14px;padding:16px;min-height:520px;box-sizing:border-box'><main style='display:flex;flex-direction:column;gap:12px;min-width:0'><div style='display:flex;align-items:center;gap:10px'><h1 style='margin:0'>Checkout redesign plan</h1><div style='flex:1'></div><button>Share</button><button class='primary'>Approve</button></div><div class='wf-card' style='display:grid;grid-template-columns:1fr 1fr;gap:10px;min-height:150px'><div class='wf-box'>Current wireframe</div><div class='wf-box'>Proposed wireframe</div></div><div class='wf-card' style='flex:1;display:flex;flex-direction:column;gap:10px'><strong>Implementation plan</strong><div class='wf-box'>Decision: keep existing checkout shell</div><div class='wf-box'>Annotated code walkthrough</div><div class='wf-box'>Open questions</div></div></main><aside class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Comments</strong><div class='wf-box'>Pin on primary CTA</div><div class='wf-box'>Question for agent</div><div class='wf-box'>Resolved copy note</div><button class='primary'>Hand back feedback</button></aside></div>"
37
+ }
38
+ ```
27
39
 
28
40
  There are two ways into Plans:
29
41
 
@@ -384,6 +396,73 @@ Schema lives in `templates/plan/server/db/schema.ts`. Core tables:
384
396
  | `plan_guest_mints` | Rate-limit records for guest session issuance |
385
397
  | `plan_assets` | Inline image assets stored as base64 (fallback when no upload provider) |
386
398
 
399
+ ```an-schema title="Plan data model" summary="One plan row owns ordered sections plus comments, events, versions, shares, and inline assets."
400
+ {
401
+ "entities": [
402
+ { "id": "plans", "name": "plans", "note": "each plan or recap", "fields": [
403
+ { "name": "id", "type": "text", "pk": true },
404
+ { "name": "title", "type": "text" },
405
+ { "name": "brief", "type": "text", "nullable": true },
406
+ { "name": "kind", "type": "enum", "note": "plan | recap" },
407
+ { "name": "status", "type": "text" },
408
+ { "name": "source", "type": "text", "nullable": true },
409
+ { "name": "hosted_plan_id", "type": "text", "nullable": true, "note": "hosted_plan_url paired" },
410
+ { "name": "source_url", "type": "text", "nullable": true },
411
+ { "name": "deleted_at", "type": "timestamp", "nullable": true, "note": "soft delete; deleted_by paired" }
412
+ ] },
413
+ { "id": "plan_sections", "name": "plan_sections", "note": "ordered sections within a plan", "fields": [
414
+ { "name": "id", "type": "text", "pk": true },
415
+ { "name": "plan_id", "type": "text", "fk": "plans.id" },
416
+ { "name": "type", "type": "text" },
417
+ { "name": "title", "type": "text", "nullable": true },
418
+ { "name": "body", "type": "text", "nullable": true },
419
+ { "name": "html", "type": "text", "nullable": true },
420
+ { "name": "sort_order", "type": "integer" },
421
+ { "name": "created_by", "type": "text", "nullable": true }
422
+ ] },
423
+ { "id": "plan_comments", "name": "plan_comments", "note": "threaded comments", "fields": [
424
+ { "name": "id", "type": "text", "pk": true },
425
+ { "name": "plan_id", "type": "text", "fk": "plans.id" },
426
+ { "name": "kind", "type": "text" },
427
+ { "name": "status", "type": "text" },
428
+ { "name": "anchor", "type": "json", "nullable": true },
429
+ { "name": "message", "type": "text" },
430
+ { "name": "resolution_target", "type": "text", "nullable": true, "note": "agent | human | null" },
431
+ { "name": "mentions_json", "type": "json", "nullable": true },
432
+ { "name": "resolved_by", "type": "text", "nullable": true }
433
+ ] },
434
+ { "id": "plan_events", "name": "plan_events", "note": "audit log of agent/human events", "fields": [
435
+ { "name": "id", "type": "text", "pk": true },
436
+ { "name": "plan_id", "type": "text", "fk": "plans.id" }
437
+ ] },
438
+ { "id": "plan_versions", "name": "plan_versions", "note": "point-in-time snapshots", "fields": [
439
+ { "name": "id", "type": "text", "pk": true },
440
+ { "name": "plan_id", "type": "text", "fk": "plans.id" }
441
+ ] },
442
+ { "id": "plan_shares", "name": "plan_shares", "note": "per-principal grants", "fields": [
443
+ { "name": "id", "type": "text", "pk": true },
444
+ { "name": "plan_id", "type": "text", "fk": "plans.id" },
445
+ { "name": "role", "type": "enum", "note": "viewer | editor | admin" }
446
+ ] },
447
+ { "id": "plan_guest_mints", "name": "plan_guest_mints", "note": "rate-limit records for guest session issuance", "fields": [
448
+ { "name": "id", "type": "text", "pk": true }
449
+ ] },
450
+ { "id": "plan_assets", "name": "plan_assets", "note": "inline image assets as base64", "fields": [
451
+ { "name": "id", "type": "text", "pk": true },
452
+ { "name": "plan_id", "type": "text", "fk": "plans.id" }
453
+ ] }
454
+ ],
455
+ "relations": [
456
+ { "from": "plans", "to": "plan_sections", "kind": "1-n", "label": "has sections" },
457
+ { "from": "plans", "to": "plan_comments", "kind": "1-n", "label": "has comments" },
458
+ { "from": "plans", "to": "plan_events", "kind": "1-n", "label": "has events" },
459
+ { "from": "plans", "to": "plan_versions", "kind": "1-n", "label": "has versions" },
460
+ { "from": "plans", "to": "plan_shares", "kind": "1-n", "label": "has shares" },
461
+ { "from": "plans", "to": "plan_assets", "kind": "1-n", "label": "has assets" }
462
+ ]
463
+ }
464
+ ```
465
+
387
466
  ### Key actions
388
467
 
389
468
  Actions in `templates/plan/actions/`:
@@ -7,17 +7,21 @@ description: "Generate decks from a prompt, edit visually, and present full-scre
7
7
 
8
8
  Generate full presentation decks from a prompt, edit slides visually, and present full-screen. Ask the agent for "a 10-slide pitch deck for a coffee subscription service" and watch it stream slide-by-slide into the editor in seconds. An open-source replacement for Google Slides, Pitch, and PowerPoint.
9
9
 
10
- <!-- screenshot:
11
- app: slides
12
- view: /deck/<id>
13
- shows: Deck editor with a "Q3 Board Update" deck open collapsed left icon rail (Decks / Design Systems / Team), slides thumbnail strip (6 slides title, agenda, metrics, what we shipped, what we're watching), main slide preview showing the title slide by Maya Chen CEO, speaker notes pane, and the agent chat sidebar with deck-aware suggestions
14
- account: screenshot-account (deck authored on this account via the standard create-deck + add-slide flow)
15
- capture: 1400x800 viewport, cropped 90px from bottom (final 1400x710); collapse the left rail before capture
16
- -->
10
+ ```an-wireframe
11
+ {
12
+ "surface": "desktop",
13
+ "html": "<div style='display:flex;flex-direction:column;gap:12px;padding:16px;min-height:530px;box-sizing:border-box'><div style='display:flex;align-items:center;gap:10px'><h1 style='margin:0'>Q3 Board Update</h1><span class='wf-pill accent'>Title slide</span><div style='flex:1'></div><button>Preview</button><button>Present</button><button class='primary'>Share</button></div><main style='display:grid;grid-template-columns:1fr 220px;gap:12px;flex:1;min-height:0'><section class='wf-card' style='display:flex;align-items:center;justify-content:center;text-align:center;padding:36px'><div><strong style='font-size:28px'>Q3 Board Update</strong><br/><small>Maya Chen · CEO</small><div style='height:46px'></div><span class='wf-pill'>Product momentum</span></div></section><section style='display:flex;flex-direction:column;gap:10px'><div class='wf-card'><strong>Slide outline</strong><div class='wf-box'>1 Title</div><div class='wf-box'>2 Agenda</div><div class='wf-box'>3 Metrics</div><div class='wf-box'>4 Shipped</div></div><div class='wf-card' style='flex:1'><strong>Speaker notes</strong><p class='wf-muted' style='margin:8px 0 0'>Open with launch progress and retention story.</p></div></section></main><div style='display:grid;grid-template-columns:repeat(5,1fr);gap:8px'><div class='wf-box'>1 Title</div><div class='wf-box'>2 Agenda</div><div class='wf-box'>3 Metrics</div><div class='wf-box'>4 Shipped</div><div class='wf-box'>5 Risks</div></div></div>"
14
+ }
15
+ ```
17
16
 
18
- ![Slides deck editor with a deck open and slide thumbnails on the left](/screenshots/slides.png)
17
+ When you open a deck, the slide canvas, outline, notes, and filmstrip stay in one editor surface while the agent can still create, revise, and navigate slides through actions.
19
18
 
20
- When you open a deck, you get a slide editor in the middle, a sidebar of slides on the left, and the agent on the right.
19
+ ```an-diagram title="Prompt to deck" summary="Ask for a deck and the agent streams slides in one at a time through the same actions you could call from the CLI."
20
+ {
21
+ "html": "<div class=\"diagram-flow\"><div class=\"diagram-node\">Prompt<br><small class=\"diagram-muted\">\"10-slide pitch deck\"</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-panel center\"><span class=\"diagram-pill accent\">Agent</span><small class=\"diagram-muted\">picks layouts</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-col\"><div class=\"diagram-pill\">create-deck</div><div class=\"diagram-pill\">add-slide &#215; n</div><small class=\"diagram-muted\">parallel, streaming</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-box\" data-rough>decks (SQL)</div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&#8635;</div><div class=\"diagram-box\">Editor renders live</div></div>",
22
+ "css": ".diagram-flow{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.diagram-flow .diagram-col{display:flex;flex-direction:column;gap:6px;align-items:center}.diagram-flow .center{display:flex;flex-direction:column;align-items:center;gap:4px}.diagram-flow .diagram-arrow{font-size:22px;line-height:1}"
23
+ }
24
+ ```
21
25
 
22
26
  ## What you can do with it
23
27
 
@@ -39,7 +43,7 @@ Live demo: [slides.agent-native.com](https://slides.agent-native.com).
39
43
  When you open the app:
40
44
 
41
45
  1. Click **New deck**.
42
- 2. In the agent sidebar, ask: "Generate a 10-slide pitch deck for a coffee subscription service, audience is investors."
46
+ 2. Ask the agent: "Generate a 10-slide pitch deck for a coffee subscription service, audience is investors."
43
47
  3. Watch slides stream in. Click any slide to edit, or keep asking the agent to refine.
44
48
 
45
49
  ### Useful prompts
@@ -69,75 +73,17 @@ pnpm install
69
73
  pnpm dev
70
74
  ```
71
75
 
72
- ### Key features (technical) {#key-features}
73
-
74
- #### Import and export
75
-
76
- The template can pull content in from PPTX (`import-pptx`), DOCX (`import-docx`), Google Docs (`import-google-doc`), arbitrary URLs (`import-from-url`), and GitHub repos (`import-github`). Export paths cover PPTX (`export-pptx`), Google Slides (`export-google-slides`), and HTML (`export-html`). Importing uses the same action surface as the rest of the template — no separate pipeline.
77
-
78
- #### Design systems
79
-
80
- Reusable brand tokens are stored in the `design_systems` table (colors, typography, spacing, assets, custom instructions, and an `is_default` flag). Sharing is managed via `design_system_shares`. Actions: `create-design-system`, `update-design-system`, `get-design-system`, `list-design-systems`, `set-default-design-system`, `apply-design-system`, and `analyze-brand-assets` (collects brand data before analysis). See the `design-systems` and `image-generation-via-a2a` skills for the full pattern.
81
-
82
- #### Deck versions
83
-
84
- Every significant deck change is snapshotted in the `deck_versions` table (stores a full copy of title and deck data with an optional `changeLabel`). Actions: `list-deck-versions`, `restore-deck-version`, `get-deck-version`.
85
-
86
- #### Prompt-to-deck generation
87
-
88
- Ask the agent for a deck and it builds one slide at a time. Slides stream into the editor live as each one is generated — the agent fires parallel `add-slide` calls so you see the deck assemble in seconds.
89
-
90
- Under the hood, this is powered by the `add-slide` and `create-deck` actions in `templates/slides/actions/`.
91
-
92
- #### Seven slide layouts
93
-
94
- Built-in layouts: title, section divider, content with bullets, two-column, statement or quote, metrics or stats, and closing or CTA. Each layout is a pure HTML template with inline styles — the agent picks the right one based on slide purpose. The exact templates live inside `templates/slides/.agents/skills/create-deck/SKILL.md` so the agent can reference them without exploring the codebase.
95
-
96
- #### Visual and code editing
97
-
98
- - Double-click any text to edit inline.
99
- - Click a block to open the bubble menu for styles, alignment, and layout.
100
- - Switch to the code editor (`app/components/editor/CodeEditor.tsx`) to edit raw slide HTML.
101
- - Use the slash menu (`SlideSlashMenu.tsx`) to insert blocks by typing `/`.
76
+ ### Key features {#key-features}
102
77
 
103
- #### AI image generation
78
+ **Prompt-to-deck generation.** Ask for a deck and the agent streams slides into the editor using the same create and edit actions you can run yourself.
104
79
 
105
- Generate images through the Assets app when brand libraries matter; once the managed backend is deployed, that path can use Builder-managed image generation and keep the audit trail with the source library. Direct provider-key generation remains the fallback for standalone decks.
80
+ **Editable slide canvas.** Inline text editing, slash inserts, code editing, drag-and-drop ordering, undo/redo, comments, and presentation mode all live in the deck surface.
106
81
 
107
- Actions: `generate-image`, `edit-image`, `image-search`, `logo-lookup`. UI panels: `ImageGenPanel.tsx`, `ImageSearchPanel.tsx`, `LogoSearchPanel.tsx`.
82
+ **Import and export.** Bring in PPTX, DOCX, Google Docs, PDFs, URLs, and GitHub repos; export to PPTX, Google Slides, HTML, or a share link.
108
83
 
109
- #### Logo and stock image search
84
+ **Design systems and media.** Saved brand systems, image generation, stock search, and logo lookup keep decks closer to the intended visual direction.
110
85
 
111
- - `logo-lookup --domain acme.com` fetches a company logo via Logo.dev or Brandfetch.
112
- - `image-search --query "mountain landscape"` searches Google Images for stock photos.
113
-
114
- #### Comments and threads
115
-
116
- Leave comments on specific slides, quote selected text, and reply in threads. Stored in the `slide_comments` table. Actions: `add-slide-comment`, `list-slide-comments`.
117
-
118
- #### Drag and drop reordering
119
-
120
- Reorder slides in the sidebar, duplicate, or delete with hover controls. The sidebar lives in `app/components/editor/EditorSidebar.tsx`.
121
-
122
- #### Presentation mode
123
-
124
- Full-screen presentation at `/deck/:id/present` with keyboard navigation (arrow keys, space, escape), auto-hiding controls, and speaker notes. See `app/routes/deck.$id_.present.tsx` and `app/components/presentation/PresentationView.tsx`.
125
-
126
- #### Share links
127
-
128
- Generate a public read-only URL for a deck so reviewers can view without an account. The share page is `app/routes/share.$token.tsx`. Fine-grained sharing (viewer, editor, admin roles, per-user or org-wide) is also available via the framework's `share-resource` action.
129
-
130
- #### Real-time collaboration
131
-
132
- Multiple people can edit the same deck simultaneously. Text edits sync through Yjs CRDT so there are no conflicts, and the agent sees and edits the same live document via the `update-slide --find/--replace` action.
133
-
134
- #### Undo and redo
135
-
136
- Cmd+Z and Cmd+Shift+Z work across the whole deck, with a labeled history panel (`HistoryPanel.tsx`) you can scrub through.
137
-
138
- #### Extract from PDF
139
-
140
- Turn a PDF into a starter deck. The `extract-pdf` action parses the file and hands the content to the agent for layout.
86
+ **Collaboration and history.** Real-time Yjs editing, threaded comments, share roles, and deck version snapshots are built in.
141
87
 
142
88
  ### Working with the agent
143
89
 
@@ -165,6 +111,81 @@ The agent can embed a live slide preview directly in a chat reply using the fram
165
111
 
166
112
  All deck data lives in SQL via Drizzle ORM. Schema: `templates/slides/server/db/schema.ts`.
167
113
 
114
+ ```an-schema title="Slides data model" summary="A deck owns its slides as JSON in decks.data; comments, versions, shares, and design systems hang off it."
115
+ {
116
+ "entities": [
117
+ {
118
+ "id": "decks",
119
+ "name": "decks",
120
+ "note": "Slides live as JSON in data; carries ownableColumns",
121
+ "fields": [
122
+ { "name": "id", "type": "text", "pk": true, "note": "e.g. deck-1712345-abc" },
123
+ { "name": "title", "type": "text" },
124
+ { "name": "data", "type": "text", "note": "JSON: { title, slides: [{ id, content, layout }] }" },
125
+ { "name": "created_at", "type": "text" },
126
+ { "name": "updated_at", "type": "text" }
127
+ ]
128
+ },
129
+ {
130
+ "id": "slide_comments",
131
+ "name": "slide_comments",
132
+ "fields": [
133
+ { "name": "id", "type": "text", "pk": true },
134
+ { "name": "deck_id", "type": "text", "fk": "decks.id" },
135
+ { "name": "slide_id", "type": "text", "note": "Slide the comment lives on" },
136
+ { "name": "thread_id", "type": "text", "note": "Threading" },
137
+ { "name": "parent_id", "type": "text", "nullable": true },
138
+ { "name": "content", "type": "text" },
139
+ { "name": "quoted_text", "type": "text", "nullable": true },
140
+ { "name": "author_email", "type": "text" },
141
+ { "name": "author_name", "type": "text" },
142
+ { "name": "resolved", "type": "boolean" }
143
+ ]
144
+ },
145
+ {
146
+ "id": "deck_versions",
147
+ "name": "deck_versions",
148
+ "note": "Point-in-time snapshots for restore",
149
+ "fields": [
150
+ { "name": "deck_id", "type": "text", "fk": "decks.id" },
151
+ { "name": "title", "type": "text" },
152
+ { "name": "data", "type": "text", "note": "Full deck JSON" },
153
+ { "name": "change_label", "type": "text", "nullable": true }
154
+ ]
155
+ },
156
+ {
157
+ "id": "design_systems",
158
+ "name": "design_systems",
159
+ "note": "Reusable brand tokens; ownableColumns",
160
+ "fields": [
161
+ { "name": "data", "type": "text", "note": "colors / typography / spacing" },
162
+ { "name": "assets", "type": "text", "nullable": true },
163
+ { "name": "custom_instructions", "type": "text", "nullable": true },
164
+ { "name": "is_default", "type": "boolean" }
165
+ ]
166
+ },
167
+ {
168
+ "id": "deck_share_links",
169
+ "name": "deck_share_links",
170
+ "note": "Persisted public share-link snapshots",
171
+ "fields": [
172
+ { "name": "token", "type": "text", "pk": true },
173
+ { "name": "title", "type": "text" },
174
+ { "name": "slides", "type": "text", "note": "JSON slides snapshot" },
175
+ { "name": "aspect_ratio", "type": "text", "nullable": true },
176
+ { "name": "created_at", "type": "text" }
177
+ ]
178
+ }
179
+ ],
180
+ "relations": [
181
+ { "from": "decks", "to": "slide_comments", "kind": "1-n", "label": "comments" },
182
+ { "from": "decks", "to": "deck_versions", "kind": "1-n", "label": "snapshots" }
183
+ ]
184
+ }
185
+ ```
186
+
187
+ Framework shares tables (`deck_shares`, `design_system_shares`) map principals to viewer / editor / admin roles per resource.
188
+
168
189
  #### decks
169
190
 
170
191
  | Column | Type | Notes |
@@ -7,18 +7,22 @@ description: "A programmatic video studio for motion graphics, product demos, an
7
7
 
8
8
  A programmatic video studio for the kind of motion graphics, product demos, and kinetic-text videos that are a pain to keyframe by hand. Ask the agent for "a 6-second logo reveal that fades in at 2 seconds" and it builds the animation. Tune timing, easing, and camera moves on a timeline, then render to MP4 or WebM.
9
9
 
10
- <!-- screenshot:
11
- app: video
12
- view: /c/<composition-id>
13
- shows: Video studio with 4 compositions (Logo reveal, Q3 product demo, Pricing animation, Onboarding walkthrough) in the sidebar; Logo reveal loaded with timeline + Remotion preview + camera tools and the agent chat sidebar
14
- account: screenshot-account (compositions authored on this account)
15
- capture: 1400x800 viewport, cropped 90px from bottom (final 1400x710)
16
- -->
17
-
18
- ![Video studio with timeline, composition, and agent sidebar](/screenshots/videos.png)
10
+ ```an-wireframe
11
+ {
12
+ "surface": "desktop",
13
+ "html": "<div style='display:flex;flex-direction:column;gap:12px;padding:16px;min-height:530px;box-sizing:border-box'><div style='display:flex;align-items:center;gap:10px'><h1 style='margin:0'>Logo reveal</h1><span class='wf-pill accent'>6 seconds</span><div style='flex:1'></div><button>Preview</button><button class='primary'>Render</button></div><div class='wf-card' style='flex:1;display:flex;align-items:center;justify-content:center;min-height:250px'><div style='text-align:center'><strong>Remotion preview</strong><br/><small class='wf-muted'>logo scales in as the title fades</small></div></div><div class='wf-card' style='display:flex;flex-direction:column;gap:10px'><div style='display:flex;gap:8px;align-items:center'><span class='wf-pill'>0s</span><span class='wf-pill'>2s</span><span class='wf-pill'>4s</span><span class='wf-pill'>6s</span><div style='flex:1'></div><button>New track</button></div><div class='wf-box'>Title fade · 0-48 frames</div><div class='wf-box'>Logo scale · 48-120 frames</div><div class='wf-box'>Camera push · 72-144 frames</div></div></div>"
14
+ }
15
+ ```
19
16
 
20
17
  When you open the studio, you'll see a list of compositions on the home screen. Click into one and you get a player on top, a timeline at the bottom, and a properties panel on the right. The agent always knows which composition you have open.
21
18
 
19
+ ```an-diagram title="Animation as data" summary="A composition is a React component; every animation reads from a track so the agent and the timeline edit the same data."
20
+ {
21
+ "html": "<div class=\"diagram-flow\"><div class=\"diagram-col\"><div class=\"diagram-node\">Timeline<br><small class=\"diagram-muted\">drag, resize, scrub</small></div><div class=\"diagram-node\">Agent<br><small class=\"diagram-muted\">\"fade in at 2s\"</small></div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-panel center\"><span class=\"diagram-pill accent\">AnimationTrack</span><small class=\"diagram-muted\">startFrame / easing / animatedProps</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-box\" data-rough>React composition<br><small class=\"diagram-muted\">Remotion &lt;Player&gt;</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">&rarr;</div><div class=\"diagram-box\">MP4 / WebM</div></div>",
22
+ "css": ".diagram-flow{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.diagram-flow .diagram-col{display:flex;flex-direction:column;gap:10px}.diagram-flow .center{display:flex;flex-direction:column;align-items:center;gap:4px}.diagram-flow .diagram-arrow{font-size:22px;line-height:1}"
23
+ }
24
+ ```
25
+
22
26
  ## What you can do with it
23
27
 
24
28
  - **Generate animations from a prompt.** "Add a title card that fades in at 2 seconds and holds until 5." The agent edits the composition.
@@ -75,53 +79,15 @@ pnpm dev
75
79
 
76
80
  Open the studio in your browser, create a composition, and start from blank. Ask the agent something like "add a logo reveal that fades in at 2 seconds" and it will edit the composition for you.
77
81
 
78
- ### Key features (technical)
79
-
80
- #### React-based compositions
81
-
82
- Every video is a React component built on Remotion primitives (`AbsoluteFill`, `useCurrentFrame`, `useVideoConfig`). The template ships one in-code composition — `BlankComposition` in `app/remotion/compositions/BlankComposition.tsx` — and `app/remotion/registry.ts` exports an empty `compositions` array by default. User and example compositions (kinetic text, logo reveals, particle bursts, interactive UI demos, slideshows) live in SQL and load through `app/hooks/use-database-compositions.ts`. You can still add a code composition by dropping a `.tsx` file in `app/remotion/compositions/` and registering it in `app/remotion/registry.ts`.
83
-
84
- #### Timeline tracks
85
-
86
- Animations are tracks, not hardcoded frame checks. A track has `startFrame`, `endFrame`, `easing`, and a list of `animatedProps` (`opacity`, `translateY`, `scale`, rotation, colors, etc.). Three track shapes:
87
-
88
- - **Duration tracks** — bars you can drag and resize in the timeline.
89
- - **Keyframe tracks** — diamond markers at specific frames for instant state changes (`startFrame === endFrame`).
90
- - **Expression tracks** — programmatic animations (typing reveals, particle bursts) flagged with `programmatic: true` and shown with a purple `fx` badge.
91
-
92
- Helper utilities in `app/remotion/trackAnimation.ts` (`findTrack`, `trackProgress`, `getPropValue`) wire a track's values into a component's render.
93
-
94
- #### Easing curves
95
-
96
- 30+ easing curves ship in `app/types.ts` — linear, power1-4 in/out/inOut, back, bounce, circ, elastic, expo, sine, and Remotion's `spring`. The Properties panel shows a visual preview of the curve shape for each one.
97
-
98
- #### Camera controls
82
+ ### Key features
99
83
 
100
- Each composition has a dedicated `camera` track with six animatable properties: `translateX`, `translateY`, `scale`, `rotateX`, `rotateY`, `perspective`. The camera toolbar above the player has pan, zoom, and tilt tools click a tool, drag on the preview, and a keyframe is auto-created at the current frame. `CameraHost` (in `app/remotion/CameraHost.tsx`) applies the chained CSS 3D transform to everything inside.
84
+ **React-based compositions.** Videos are Remotion-backed React components, with SQL-backed user compositions and an optional code registry for local defaults.
101
85
 
102
- #### Multi-keyframe editing
86
+ **Timeline-first animation.** Duration tracks, keyframes, easing curves, camera moves, and programmatic expression tracks all edit the same composition data.
103
87
 
104
- Every animated property supports an optional `keyframes` array. Interpolation is linear between keyframes, with hold-at-first and hold-at-last at the edges. In the timeline you can box-select keyframes, shift-click to add or remove, and drag groups while keeping relative timing.
88
+ **Adjustable motion systems.** Parameters, cursor tracks, interactive hover zones, range navigation, and repeat playback make generated animations tunable without code.
105
89
 
106
- #### Adjustable parameters
107
-
108
- Programmatic animations expose internal magic numbers as user-editable `parameters` — character width, drift distance, particle count, stagger delay. Inputs appear in the Properties panel with min/max/step bounds and save to localStorage automatically.
109
-
110
- #### Interactive cursor system
111
-
112
- The `cursor` track drives a visible cursor that moves across the composition. Hover zones on interactive elements (buttons, tabs, inputs, cards) change the cursor appearance — arrow, pointer, or I-beam. See `app/remotion/hooks/useInteractiveComponent.ts` and `app/remotion/ui-components/InteractiveCard.tsx`.
113
-
114
- #### View range and repeat playback
115
-
116
- The timeline has a range navigator at the bottom (AE-style triangular handles). Drag to zoom and pan the visible time window. Playback in the player is constrained to that range, with a repeat toggle that loops inside it.
117
-
118
- #### Render output
119
-
120
- Composition size, fps, and render quality are per-composition in the Properties panel. Render quality is supersampling — 1x, 2x, or 3x internal resolution to keep text and vectors crisp during camera zoom. Final render happens via the Remotion CLI to MP4 or WebM.
121
-
122
- #### Composition persistence
123
-
124
- User edits (track values, parameter values, prop overrides, composition settings) persist to localStorage per composition. The **Save** button in the top-right of the composition view can write the current state back to `app/remotion/registry.ts` as TypeScript — so new users and sessions pick up the changes. That source-write path runs through `POST /api/save-composition-defaults`, which is gated to local development only; in production it returns a 403, and durable composition state lives in SQL instead.
90
+ **Render and persistence.** Composition settings, quality, fps, track values, and overrides persist per composition and render to MP4 or WebM through Remotion.
125
91
 
126
92
  ### Working with the agent
127
93
 
@@ -133,6 +99,61 @@ Under the hood the agent calls actions like `navigate`, `save-composition`, and
133
99
 
134
100
  Server-side schema is in `templates/videos/server/db/schema.ts`:
135
101
 
102
+ ```an-schema title="Video data model" summary="SQL-backed compositions plus design systems and nestable folders, each with a framework shares table."
103
+ {
104
+ "entities": [
105
+ {
106
+ "id": "compositions",
107
+ "name": "compositions",
108
+ "note": "User-created compositions and overrides; ownableColumns",
109
+ "fields": [
110
+ { "name": "id", "type": "text", "pk": true },
111
+ { "name": "title", "type": "text" },
112
+ { "name": "type", "type": "text" },
113
+ { "name": "data", "type": "text", "note": "Full composition JSON blob" },
114
+ { "name": "created_at", "type": "text" },
115
+ { "name": "updated_at", "type": "text" }
116
+ ]
117
+ },
118
+ {
119
+ "id": "design_systems",
120
+ "name": "design_systems",
121
+ "note": "Reusable brand tokens; ownableColumns",
122
+ "fields": [
123
+ { "name": "data", "type": "text", "note": "colors / typography / spacing" },
124
+ { "name": "assets", "type": "text", "nullable": true },
125
+ { "name": "custom_instructions", "type": "text", "nullable": true },
126
+ { "name": "is_default", "type": "boolean" }
127
+ ]
128
+ },
129
+ {
130
+ "id": "folders",
131
+ "name": "folders",
132
+ "note": "Nestable folders; ownableColumns",
133
+ "fields": [
134
+ { "name": "id", "type": "text", "pk": true },
135
+ { "name": "name", "type": "text" }
136
+ ]
137
+ },
138
+ {
139
+ "id": "folder_memberships",
140
+ "name": "folder_memberships",
141
+ "note": "Many-to-many join",
142
+ "fields": [
143
+ { "name": "folder_id", "type": "text", "fk": "folders.id" },
144
+ { "name": "composition_id", "type": "text", "fk": "compositions.id" }
145
+ ]
146
+ }
147
+ ],
148
+ "relations": [
149
+ { "from": "folders", "to": "folder_memberships", "kind": "1-n", "label": "members" },
150
+ { "from": "compositions", "to": "folder_memberships", "kind": "1-n", "label": "in folders" }
151
+ ]
152
+ }
153
+ ```
154
+
155
+ Each table also has a matching framework shares table (`composition_shares`, `design_system_shares`, `folder_shares`) produced by `createSharesTable()`.
156
+
136
157
  - `compositions` — id, title, type, `data` (full composition JSON blob), ownership columns, timestamps.
137
158
  - `composition_shares` — standard share grants produced by `createSharesTable()`.
138
159
  - `design_systems` — reusable brand tokens (colors, typography, spacing, assets, custom instructions, `is_default` flag) with `ownableColumns`.