@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
|
@@ -19,7 +19,19 @@ The product surface stays simple on purpose: **Ask** is the primary chat
|
|
|
19
19
|
experience, while **Sources**, **Review**, and **Knowledge** are admin/support
|
|
20
20
|
surfaces for connecting data, approving proposals, and inspecting cited memory.
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
```an-diagram title="From source to cited answer" summary="Brain ingests approved sources into raw captures, distills durable memory, gates it through review, and only then answers with citations."
|
|
23
|
+
{
|
|
24
|
+
"html": "<div class=\"diagram-flow\"><div class=\"diagram-card\"><span class=\"diagram-pill\">Sources</span><small class=\"diagram-muted\">Slack · Granola · GitHub · Clips · webhooks</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-box\" data-rough>Raw captures<br><small class=\"diagram-muted\">deduped, redacted</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-box\" data-rough>Distill<br><small class=\"diagram-muted\">facts · decisions · processes</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-card\"><span class=\"diagram-pill warn\">Review</span><small class=\"diagram-muted\">sensitive / low-confidence queue</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-box\" data-rough><span class=\"diagram-pill ok\">Knowledge</span><small class=\"diagram-muted\">approved, atomic</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-panel center\"><span class=\"diagram-pill accent\">Ask</span><small class=\"diagram-muted\">cited answer</small></div></div>",
|
|
25
|
+
"css": ".diagram-flow{display:flex;align-items:center;gap:10px;flex-wrap:wrap}.diagram-flow .diagram-card{display:flex;flex-direction:column;gap:4px;padding:10px 12px}.diagram-flow .diagram-box{display:flex;flex-direction:column;gap:4px}.diagram-flow .diagram-arrow{font-size:20px;line-height:1}.diagram-flow .center{display:flex;flex-direction:column;align-items:center;gap:4px}"
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
```an-wireframe
|
|
30
|
+
{
|
|
31
|
+
"surface": "desktop",
|
|
32
|
+
"html": "<div style='display:flex;flex-direction:column;gap:14px;padding:18px;min-height:520px;box-sizing:border-box'><div style='display:flex;align-items:center;gap:10px'><h1 style='margin:0'>Ask company memory</h1><span class='wf-pill accent'>42 approved memories</span><span class='wf-pill'>3 sources</span><div style='flex:1'></div><button>Sources</button><button>Review</button></div><div class='wf-card' style='display:flex;align-items:center;gap:10px'><span data-icon='search' aria-label='Search'></span><strong style='flex:1'>Why did we choose usage pricing?</strong><button class='primary'>Ask</button></div><div class='wf-card' style='display:flex;flex-direction:column;gap:10px'><strong>Answer</strong><p style='margin:0'>The team chose usage pricing after pilots showed seat counts undercounted automation value.</p><div style='display:flex;gap:8px;flex-wrap:wrap'><span class='wf-pill accent'>Pricing RFC</span><span class='wf-pill'>Launch retro</span><span class='wf-pill'>Sales notes</span></div></div><div class='wf-card' style='flex:1;display:flex;flex-direction:column;gap:8px'><strong>Source timeline</strong><div class='wf-box'>May 3 · Decision captured</div><div class='wf-box'>May 8 · Customer evidence added</div><div class='wf-box'>May 12 · Legal note approved</div></div></div>"
|
|
33
|
+
}
|
|
34
|
+
```
|
|
23
35
|
|
|
24
36
|
When you open the app, **Ask** is front and center — a clean chat over reviewed
|
|
25
37
|
company memory. **Sources**, **Review**, and **Knowledge** sit alongside it as
|
|
@@ -140,6 +152,65 @@ Brain's schema lives in `templates/brain/server/db/schema.ts`. Eight tables:
|
|
|
140
152
|
| `brain_sync_runs` | Sync audit log — provider, status, stats JSON, error, start/end timestamps |
|
|
141
153
|
| `brain_ingest_queue` | Background distillation queue — operation, status, priority, retry count, `run_after` |
|
|
142
154
|
|
|
155
|
+
```an-schema title="Brain data model" summary="Connectors produce raw captures; distillation turns captures into reviewable knowledge; proposals gate sensitive entries. Sync runs and the ingest queue track background work."
|
|
156
|
+
{
|
|
157
|
+
"entities": [
|
|
158
|
+
{ "id": "sources", "name": "brain_sources", "note": "Connector config", "fields": [
|
|
159
|
+
{ "name": "id", "type": "id", "pk": true },
|
|
160
|
+
{ "name": "provider", "type": "text", "note": "slack / granola / github / clips / webhook" },
|
|
161
|
+
{ "name": "ingest_token_hash", "type": "text" },
|
|
162
|
+
{ "name": "status", "type": "text" },
|
|
163
|
+
{ "name": "last_synced_at", "type": "timestamp", "nullable": true }
|
|
164
|
+
] },
|
|
165
|
+
{ "id": "source_shares", "name": "brain_source_shares", "note": "viewer / editor / admin", "fields": [
|
|
166
|
+
{ "name": "source_id", "type": "id", "fk": "brain_sources.id" }
|
|
167
|
+
] },
|
|
168
|
+
{ "id": "captures", "name": "brain_raw_captures", "note": "Ingested raw payloads", "fields": [
|
|
169
|
+
{ "name": "id", "type": "id", "pk": true },
|
|
170
|
+
{ "name": "source_id", "type": "id", "fk": "brain_sources.id" },
|
|
171
|
+
{ "name": "external_id", "type": "text", "note": "dedupe key" },
|
|
172
|
+
{ "name": "content_hash", "type": "text" },
|
|
173
|
+
{ "name": "kind", "type": "text" }
|
|
174
|
+
] },
|
|
175
|
+
{ "id": "knowledge", "name": "brain_knowledge", "note": "Distilled atomic entries", "fields": [
|
|
176
|
+
{ "name": "id", "type": "id", "pk": true },
|
|
177
|
+
{ "name": "kind", "type": "text", "note": "decision / fact / process" },
|
|
178
|
+
{ "name": "topic", "type": "text" },
|
|
179
|
+
{ "name": "entities", "type": "json" },
|
|
180
|
+
{ "name": "confidence", "type": "real" },
|
|
181
|
+
{ "name": "publish_tier", "type": "text" }
|
|
182
|
+
] },
|
|
183
|
+
{ "id": "knowledge_shares", "name": "brain_knowledge_shares", "fields": [
|
|
184
|
+
{ "name": "knowledge_id", "type": "id", "fk": "brain_knowledge.id" }
|
|
185
|
+
] },
|
|
186
|
+
{ "id": "proposals", "name": "brain_proposals", "note": "Pending review items", "fields": [
|
|
187
|
+
{ "name": "id", "type": "id", "pk": true },
|
|
188
|
+
{ "name": "op", "type": "text", "note": "create / update / archive" }
|
|
189
|
+
] },
|
|
190
|
+
{ "id": "proposal_shares", "name": "brain_proposal_shares", "fields": [
|
|
191
|
+
{ "name": "proposal_id", "type": "id", "fk": "brain_proposals.id" }
|
|
192
|
+
] },
|
|
193
|
+
{ "id": "sync_runs", "name": "brain_sync_runs", "note": "Sync audit log", "fields": [
|
|
194
|
+
{ "name": "source_id", "type": "id", "fk": "brain_sources.id" },
|
|
195
|
+
{ "name": "status", "type": "text" },
|
|
196
|
+
{ "name": "stats", "type": "json" }
|
|
197
|
+
] },
|
|
198
|
+
{ "id": "ingest_queue", "name": "brain_ingest_queue", "note": "Background distillation queue", "fields": [
|
|
199
|
+
{ "name": "operation", "type": "text" },
|
|
200
|
+
{ "name": "status", "type": "text" },
|
|
201
|
+
{ "name": "priority", "type": "int" },
|
|
202
|
+
{ "name": "run_after", "type": "timestamp", "nullable": true }
|
|
203
|
+
] }
|
|
204
|
+
],
|
|
205
|
+
"relations": [
|
|
206
|
+
{ "from": "sources", "to": "captures", "kind": "1-n", "label": "ingested into" },
|
|
207
|
+
{ "from": "knowledge", "to": "captures", "kind": "n-n", "label": "evidence" },
|
|
208
|
+
{ "from": "knowledge", "to": "proposals", "kind": "1-n", "label": "gated by" },
|
|
209
|
+
{ "from": "sources", "to": "sync_runs", "kind": "1-n", "label": "audited by" }
|
|
210
|
+
]
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
143
214
|
### Key actions
|
|
144
215
|
|
|
145
216
|
Grouped by area (`templates/brain/actions/`):
|
|
@@ -188,6 +259,23 @@ a source with a `sourceKey` to receive a bearer token, then send a
|
|
|
188
259
|
use the same payload shape for call transcripts, customer research, imported
|
|
189
260
|
notes, or any other source that can produce a bounded capture.
|
|
190
261
|
|
|
262
|
+
```an-api title="Signed ingest webhook" summary="Clips and generic transcript/capture imports post a RawCapturePayload with a per-source bearer token."
|
|
263
|
+
{
|
|
264
|
+
"method": "POST",
|
|
265
|
+
"path": "/api/_agent-native/brain/ingest",
|
|
266
|
+
"summary": "Import a raw capture from Clips or a generic source",
|
|
267
|
+
"auth": "Bearer <ingestToken> issued per source via its sourceKey",
|
|
268
|
+
"request": {
|
|
269
|
+
"contentType": "application/json",
|
|
270
|
+
"example": "RawCapturePayload — bounded transcript / capture body"
|
|
271
|
+
},
|
|
272
|
+
"responses": [
|
|
273
|
+
{ "status": "200", "description": "Capture accepted and queued for distillation" },
|
|
274
|
+
{ "status": "401", "description": "Missing or invalid ingest bearer token" }
|
|
275
|
+
]
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
191
279
|
Slack, Granola, and GitHub sources can opt into background `autoSync` with a
|
|
192
280
|
poll cadence once review quality is proven.
|
|
193
281
|
|
|
@@ -7,17 +7,21 @@ description: "An agent-powered calendar with Google Calendar sync and Calendly-s
|
|
|
7
7
|
|
|
8
8
|
An agent-powered calendar app. Connect your Google Calendar and the agent can read your schedule, find free slots, create events, and manage Calendly-style booking links — all in plain English. It replaces the Google Calendar + Calendly combo with one app you own.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-->
|
|
10
|
+
```an-wireframe
|
|
11
|
+
{
|
|
12
|
+
"surface": "desktop",
|
|
13
|
+
"html": "<div style='display:flex;flex-direction:column;min-height:530px;box-sizing:border-box'><div style='display:flex;align-items:center;gap:10px;padding:14px 18px;border-bottom:1.4px solid var(--wf-line)'><button>Week</button><button>Today</button><button>‹</button><button>›</button><div style='flex:1'></div><strong>May 3-9, 2026</strong><div style='flex:1'></div><button class='primary'>New Event</button></div><div style='display:grid;grid-template-columns:56px repeat(7,minmax(0,1fr));grid-template-rows:36px repeat(5,72px);gap:7px;padding:14px;flex:1'><div></div><strong>Sun 3</strong><strong>Mon 4</strong><strong>Tue 5</strong><strong>Wed 6</strong><strong>Thu 7</strong><strong>Fri 8</strong><strong>Sat 9</strong><small class='wf-muted'>7 AM</small><div class='wf-box' style='opacity:.45'></div><div></div><div></div><div></div><div></div><div></div><div></div><small class='wf-muted'>9 AM</small><div class='wf-box'>All-hands</div><div class='wf-box'>Eng standup</div><div class='wf-box'>Eng standup</div><div class='wf-box'>Eng standup</div><div></div><div class='wf-box'>Planning</div><div></div><small class='wf-muted'>11 AM</small><div class='wf-box'>Design review</div><div></div><div class='wf-box'>Design crit</div><div class='wf-box'>Roadmap</div><div class='wf-box'>Friday demo</div><div></div><div></div><small class='wf-muted'>1 PM</small><div></div><div class='wf-box'>1:1</div><div class='wf-box'>Focus block</div><div></div><div></div><div class='wf-box'>All-hands</div><div></div><small class='wf-muted'>3 PM</small><div></div><div></div><div></div><div class='wf-box'>Skip-level</div><div></div><div></div><div></div></div></div>"
|
|
14
|
+
}
|
|
15
|
+
```
|
|
17
16
|
|
|
18
|
-
|
|
17
|
+
When you open the app, the active calendar view is the primary surface. The agent still knows which day, week, or event you're looking at, so you can say "schedule a 30-minute call with Alex on this day" without spelling everything out.
|
|
19
18
|
|
|
20
|
-
|
|
19
|
+
```an-diagram title="How a scheduling request flows" summary="Whether you click in the calendar or ask the agent, the same actions read live from Google Calendar and write back to the same view."
|
|
20
|
+
{
|
|
21
|
+
"html": "<div class=\"diagram-flow\"><div class=\"diagram-col\"><div class=\"diagram-node\">You click<br><small class=\"diagram-muted\">drag, toolbar, shortcuts</small></div><div class=\"diagram-node\">You ask the agent<br><small class=\"diagram-muted\">\"find a 1-hour slot next week\"</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\">list-events · check-availability · create-event</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-col\"><div class=\"diagram-box\">Google Calendar<br><small class=\"diagram-muted\">live, multi-account</small></div><div class=\"diagram-box\">SQL<br><small class=\"diagram-muted\">bookings · availability</small></div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">↻</div><div class=\"diagram-box\">Calendar view updates 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
|
|
|
@@ -80,60 +84,17 @@ Open `http://localhost:8082` (the default Calendar dev port).
|
|
|
80
84
|
|
|
81
85
|
To connect Google Calendar in dev, open the Settings view, paste a `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` from [Google Cloud Console](https://console.cloud.google.com/), and click "Connect Google Calendar". The OAuth redirect URI is `http://localhost:8082/_agent-native/google/callback` in dev. Tokens are stored in the `oauth_tokens` SQL table and refresh automatically.
|
|
82
86
|
|
|
83
|
-
### Key features
|
|
87
|
+
### Key features
|
|
84
88
|
|
|
85
|
-
**
|
|
89
|
+
**Live calendar views.** Day, week, and month views read directly from connected Google accounts, with optional read-only ICS feeds layered into the same schedule.
|
|
86
90
|
|
|
87
|
-
**
|
|
88
|
-
|
|
89
|
-
**External calendars (ICS subscriptions).** Subscribe to read-only ICS or `webcal://` feeds — useful for HR time off, conference schedules, or shared team calendars. Feeds are added in Settings and stored per user. Relevant actions: `add-external-calendar`, `list-external-calendars`, `remove-external-calendar`, `update-external-calendars`.
|
|
90
|
-
|
|
91
|
-
**Availability rules.** Availability is a weekly schedule of time windows per day, plus a timezone. It is stored in the settings table under the key `calendar-availability`:
|
|
92
|
-
|
|
93
|
-
```json
|
|
94
|
-
{
|
|
95
|
-
"timezone": "America/Los_Angeles",
|
|
96
|
-
"schedule": {
|
|
97
|
-
"monday": [{ "start": "09:00", "end": "17:00" }],
|
|
98
|
-
"tuesday": [{ "start": "09:00", "end": "17:00" }],
|
|
99
|
-
"wednesday": [
|
|
100
|
-
{ "start": "09:00", "end": "12:00" },
|
|
101
|
-
{ "start": "13:00", "end": "17:00" }
|
|
102
|
-
],
|
|
103
|
-
"thursday": [{ "start": "09:00", "end": "17:00" }],
|
|
104
|
-
"friday": [{ "start": "09:00", "end": "16:00" }],
|
|
105
|
-
"saturday": [],
|
|
106
|
-
"sunday": []
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
```
|
|
91
|
+
**Availability and free-slot search.** Weekly availability rules, timezone support, and existing events all feed the same availability action the UI and agent use.
|
|
110
92
|
|
|
111
|
-
|
|
93
|
+
**Booking links.** Public `/book/{slug}` pages collect name, email, custom fields, conferencing preferences, and cancellation/reschedule tokens.
|
|
112
94
|
|
|
113
|
-
**
|
|
95
|
+
**Shareable management.** Booking links are private by default, but can be shared with teammates through the framework sharing actions.
|
|
114
96
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
- A URL slug, so the public page lives at `/book/{slug}`.
|
|
118
|
-
- A primary duration plus an optional list of alternative durations (for example 15, 30, or 60 minutes).
|
|
119
|
-
- Optional custom fields collected at booking time.
|
|
120
|
-
- A conferencing option (Google Meet, Zoom, or a custom meeting link).
|
|
121
|
-
- An `isActive` toggle to pause bookings without deleting the link.
|
|
122
|
-
|
|
123
|
-
Visitors land on the public page, pick a date and time from the available slots, fill in name, email, and any custom fields, and receive a confirmation. Bookings are stored in the `bookings` table with a `cancelToken`, which powers the public cancel/reschedule page at `/booking/manage/{token}`.
|
|
124
|
-
|
|
125
|
-
There is also a per-user public URL at `/meet/{username}/{slug}` for clean personal sharing.
|
|
126
|
-
|
|
127
|
-
**Sharing booking links with teammates.** Booking links are private by default — only the creator can edit or delete them. To let a teammate manage a link, either change the link's visibility or grant explicit access. The framework ships these actions, auto-mounted for any `booking-link` resource:
|
|
128
|
-
|
|
129
|
-
- `share-resource` — grant a user or org `viewer`, `editor`, or `admin` access.
|
|
130
|
-
- `unshare-resource` — revoke a grant.
|
|
131
|
-
- `list-resource-shares` — show current visibility plus all grants.
|
|
132
|
-
- `set-resource-visibility` — change the coarse visibility (`private`, `org`, or `public`).
|
|
133
|
-
|
|
134
|
-
Sharing only controls who can manage the link. The public booking URL always accepts bookings from unauthenticated visitors as long as `isActive` is true.
|
|
135
|
-
|
|
136
|
-
**Inline event previews in chat.** The `/event` route (`app/routes/event.tsx`) renders a compact, chromeless event card that the agent can embed in chat when you ask about a specific event. Title, time, location, attendees, and a description snippet are shown with a button to jump into the main calendar.
|
|
97
|
+
**Inline event previews.** The agent can embed compact event cards in chat with title, time, location, attendees, and a jump-back button.
|
|
137
98
|
|
|
138
99
|
### Working with the agent
|
|
139
100
|
|
|
@@ -150,6 +111,73 @@ Defined in `templates/calendar/server/db/schema.ts`. Only non-event data is stor
|
|
|
150
111
|
- `booking_slug_redirects` — remembers old slugs when a link is renamed so existing public URLs keep working.
|
|
151
112
|
- `booking_link_shares` — share grants for booking links.
|
|
152
113
|
|
|
114
|
+
```an-schema title="Calendar data model" summary="Only non-event data is stored locally — events live in Google Calendar. Booking links use ownableColumns so the sharing system applies."
|
|
115
|
+
{
|
|
116
|
+
"entities": [
|
|
117
|
+
{
|
|
118
|
+
"id": "booking_links",
|
|
119
|
+
"name": "booking_links",
|
|
120
|
+
"note": "Calendly-style link definitions (ownable)",
|
|
121
|
+
"fields": [
|
|
122
|
+
{ "name": "id", "type": "id", "pk": true },
|
|
123
|
+
{ "name": "slug", "type": "string", "note": "public page at /book/{slug}" },
|
|
124
|
+
{ "name": "title", "type": "string" },
|
|
125
|
+
{ "name": "description", "type": "string", "nullable": true },
|
|
126
|
+
{ "name": "duration", "type": "int", "note": "primary duration in minutes" },
|
|
127
|
+
{ "name": "durations", "type": "json", "nullable": true, "note": "alternative durations" },
|
|
128
|
+
{ "name": "customFields", "type": "json", "nullable": true },
|
|
129
|
+
{ "name": "conferencing", "type": "string", "note": "Google Meet / Zoom / custom" },
|
|
130
|
+
{ "name": "color", "type": "string", "nullable": true },
|
|
131
|
+
{ "name": "isActive", "type": "bool", "note": "pause without deleting" }
|
|
132
|
+
]
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
"id": "bookings",
|
|
136
|
+
"name": "bookings",
|
|
137
|
+
"note": "Confirmed appointments from public booking pages",
|
|
138
|
+
"fields": [
|
|
139
|
+
{ "name": "id", "type": "id", "pk": true },
|
|
140
|
+
{ "name": "slug", "type": "string", "fk": "booking_links.slug" },
|
|
141
|
+
{ "name": "name", "type": "string" },
|
|
142
|
+
{ "name": "email", "type": "string" },
|
|
143
|
+
{ "name": "start", "type": "datetime" },
|
|
144
|
+
{ "name": "end", "type": "datetime" },
|
|
145
|
+
{ "name": "notes", "type": "string", "nullable": true },
|
|
146
|
+
{ "name": "customFields", "type": "json", "nullable": true, "note": "custom field responses" },
|
|
147
|
+
{ "name": "meetingLink", "type": "string", "nullable": true },
|
|
148
|
+
{ "name": "cancelToken", "type": "string", "note": "powers /booking/manage/{token}" },
|
|
149
|
+
{ "name": "status", "type": "enum", "note": "confirmed | cancelled" }
|
|
150
|
+
]
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"id": "booking_slug_redirects",
|
|
154
|
+
"name": "booking_slug_redirects",
|
|
155
|
+
"note": "Keeps old public URLs working after a link is renamed",
|
|
156
|
+
"fields": [
|
|
157
|
+
{ "name": "oldSlug", "type": "string", "pk": true },
|
|
158
|
+
{ "name": "linkId", "type": "id", "fk": "booking_links.id" }
|
|
159
|
+
]
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"id": "booking_link_shares",
|
|
163
|
+
"name": "booking_link_shares",
|
|
164
|
+
"note": "Share grants for booking links",
|
|
165
|
+
"fields": [
|
|
166
|
+
{ "name": "id", "type": "id", "pk": true },
|
|
167
|
+
{ "name": "linkId", "type": "id", "fk": "booking_links.id" },
|
|
168
|
+
{ "name": "principal", "type": "string", "note": "user or org" },
|
|
169
|
+
{ "name": "role", "type": "enum", "note": "viewer | editor | admin" }
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
],
|
|
173
|
+
"relations": [
|
|
174
|
+
{ "from": "booking_links", "to": "bookings", "kind": "1-n", "label": "has bookings" },
|
|
175
|
+
{ "from": "booking_links", "to": "booking_slug_redirects", "kind": "1-n", "label": "has old slugs" },
|
|
176
|
+
{ "from": "booking_links", "to": "booking_link_shares", "kind": "1-n", "label": "has share grants" }
|
|
177
|
+
]
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
153
181
|
Availability rules and per-user configuration live in the settings table, keyed by `calendar-availability`. Google OAuth tokens live in the framework `oauth_tokens` table. Ephemeral UI state (current view, date, selected event) lives in `application_state` under the `navigation` key.
|
|
154
182
|
|
|
155
183
|
### Customizing it
|
|
@@ -9,15 +9,12 @@ Chat is the basic agent-native app starting point. It gives you a clean ChatGPT-
|
|
|
9
9
|
|
|
10
10
|
If you want the smallest action-only runtime with no browser UI, start with [Pure-Agent Apps](/docs/pure-agent-apps). If you want a finished domain product shape, start from [Calendar](/docs/template-calendar), [Mail](/docs/template-mail), [Content](/docs/template-content), [Forms](/docs/template-forms), [Analytics](/docs/template-analytics), or another domain template.
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-->
|
|
19
|
-
|
|
20
|
-

|
|
12
|
+
```an-wireframe
|
|
13
|
+
{
|
|
14
|
+
"surface": "desktop",
|
|
15
|
+
"html": "<div style='min-height:560px;box-sizing:border-box;display:flex;align-items:center;justify-content:center;padding:56px 40px'><div style='display:flex;flex-direction:column;align-items:center;justify-content:center;gap:28px;width:min(700px,92%);min-height:430px'><div style='height:34px'></div><div style='text-align:center'><h1 style='margin:0'>How can I help?</h1><p class='wf-muted' style='margin:10px 0 0'>Chat about anything. Add actions, components, pages, jobs, or your own backend.</p></div><div class='wf-card' style='width:100%;min-height:150px;display:flex;flex-direction:column;gap:18px'><span class='wf-muted'>Message the agent...</span><div style='flex:1'></div><div style='display:flex;align-items:center;gap:10px'><span data-icon='plus' aria-label='Attach'></span><div style='flex:1'></div><span class='wf-pill'>Sonnet 4.6 · Auto</span><span class='wf-pill'>Act</span><button class='primary'>↑</button></div></div><div style='height:34px'></div></div></div>"
|
|
16
|
+
}
|
|
17
|
+
```
|
|
21
18
|
|
|
22
19
|
## What's in it {#whats-in-it}
|
|
23
20
|
|
|
@@ -38,6 +35,13 @@ If you want the smallest action-only runtime with no browser UI, start with [Pur
|
|
|
38
35
|
|
|
39
36
|
That's the point. Chat is a thin, useful default shell for your own agent, not a domain product pretending to be generic.
|
|
40
37
|
|
|
38
|
+
```an-diagram title="What ships in the Chat shell" summary="A thin chat surface over the framework's standard runtime — actions, durable threads, live sync, and auth — with room to add your own UI."
|
|
39
|
+
{
|
|
40
|
+
"html": "<div class=\"diagram-chat\"><div class=\"diagram-col left\"><div class=\"diagram-node\">Thread list<br><small class=\"diagram-muted\">create · reopen · pin · archive</small></div><div class=\"diagram-node\">Full-page chat<br><small class=\"diagram-muted\">framework chat surface on /</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\">hello.ts · view-screen · navigate</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-col right\"><div class=\"diagram-box\">Core SQL tables<br><small class=\"diagram-muted\">threads · application_state · settings · sessions · runs</small></div><div class=\"diagram-pill ok\">Live sync ↻</div><div class=\"diagram-box\">Better Auth<br><small class=\"diagram-muted\">login · orgs · sessions</small></div></div></div>",
|
|
41
|
+
"css": ".diagram-chat{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.diagram-chat .diagram-col{display:flex;flex-direction:column;gap:10px}.diagram-chat .diagram-arrow{font-size:22px;line-height:1}.diagram-chat .center{display:flex;flex-direction:column;align-items:center;gap:4px}"
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
41
45
|
## When to pick it {#when-to-pick}
|
|
42
46
|
|
|
43
47
|
- **You want a basic app users can talk to immediately** and then extend with actions and UI.
|
|
@@ -70,6 +74,18 @@ From there, copy the Chat template's `/` route and sidebar thread list into your
|
|
|
70
74
|
suggestions, empty state, composer, or surrounding layout here.
|
|
71
75
|
- `AGENTS.md` tells the built-in agent how to work inside this app.
|
|
72
76
|
|
|
77
|
+
```an-file-tree title="Chat template layout"
|
|
78
|
+
{
|
|
79
|
+
"entries": [
|
|
80
|
+
{ "path": "actions/hello.ts", "note": "the one example action; replace or add actions beside it" },
|
|
81
|
+
{ "path": "actions/view-screen.ts", "note": "standard context action the agent reads" },
|
|
82
|
+
{ "path": "actions/navigate.ts", "note": "standard navigation action" },
|
|
83
|
+
{ "path": "app/routes/_index.tsx", "note": "renders the full-page chat surface; edit suggestions, empty state, composer" },
|
|
84
|
+
{ "path": "AGENTS.md", "note": "chat-first guidance the built-in agent reads" }
|
|
85
|
+
]
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
73
89
|
The chat page is intentionally thin:
|
|
74
90
|
|
|
75
91
|
```tsx
|
|
@@ -7,18 +7,22 @@ description: "Async screen recording, calendar-synced meeting notes, and push-to
|
|
|
7
7
|
|
|
8
8
|
A capture-everything app: screen recordings, meeting notes from your calendar, and Fn-hold voice dictation. The agent transcribes, titles, summarizes, and indexes all of it — then lets you ask "find the clip where we discussed the rollout plan" and searches across every transcript you've ever made.
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
-->
|
|
17
|
-
|
|
18
|
-

|
|
10
|
+
```an-wireframe
|
|
11
|
+
{
|
|
12
|
+
"surface": "desktop",
|
|
13
|
+
"html": "<div style='display:flex;flex-direction:column;gap:14px;padding:18px;min-height:520px;box-sizing:border-box'><div style='display:flex;align-items:center;gap:10px'><h1 style='margin:0'>Engineering clips</h1><span class='wf-pill accent'>Library</span><span class='wf-pill'>Meetings</span><span class='wf-pill'>Dictation</span><div style='flex:1'></div><button>Import</button><button class='primary'>Record</button></div><div style='display:grid;grid-template-columns:repeat(3,1fr);gap:12px'><div class='wf-card' style='height:120px;display:flex;flex-direction:column;justify-content:end'><strong>OKRs review</strong><small>35 min</small></div><div class='wf-card' style='height:120px;display:flex;flex-direction:column;justify-content:end'><strong>Onboarding flow</strong><small>12 min</small></div><div class='wf-card' style='height:120px;display:flex;flex-direction:column;justify-content:end'><strong>Bug repro</strong><small>4 min</small></div></div><div class='wf-card' style='display:flex;gap:10px;align-items:center'><span class='wf-pill accent'>Agent-readable</span><span>Transcript + frames ready for share links</span><div style='flex:1'></div><button>Share</button></div><div class='wf-card' style='flex:1;display:flex;flex-direction:column;gap:8px'><strong>Transcript search</strong><div class='wf-box'>Matched chapter 03:12 · rollout risks and owner handoff</div><div class='wf-box'>Meeting summary and action items</div></div></div>"
|
|
14
|
+
}
|
|
15
|
+
```
|
|
19
16
|
|
|
20
17
|
Think along the lines of Loom + Granola + Wispr Flow rolled into one app — but the agent is a first-class editor across every surface, and the recordings, meetings, and dictations are yours, not a SaaS vendor's. Clips also makes shared recordings agent-readable: paste a normal Clips share link into an agent, and it can "hear" the transcript and "see" timestamped frames even when the underlying model cannot ingest raw video or audio.
|
|
21
18
|
|
|
19
|
+
```an-diagram title="Capture, transcribe, reuse" summary="Three capture types land in one library; the agent transcribes, titles, and summarizes, then every transcript is searchable and shareable."
|
|
20
|
+
{
|
|
21
|
+
"html": "<div class=\"diagram-clips\"><div class=\"diagram-col\"><div class=\"diagram-node\">Screen recording</div><div class=\"diagram-node\">Calendar meeting</div><div class=\"diagram-node\">Fn-hold dictation</div></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-box\" data-rough>One library<br><small class=\"diagram-muted\">recordings + transcripts (SQL)</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-panel center\"><span class=\"diagram-pill accent\">Agent</span><small class=\"diagram-muted\">title · summary · chapters</small></div><div class=\"diagram-arrow diagram-muted\" aria-hidden=\"true\">→</div><div class=\"diagram-col\"><div class=\"diagram-pill\">Search</div><div class=\"diagram-pill\">Share</div><div class=\"diagram-pill\">Agent-readable links</div></div></div>",
|
|
22
|
+
"css": ".diagram-clips{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.diagram-clips .diagram-col{display:flex;flex-direction:column;gap:8px}.diagram-clips .center{display:flex;flex-direction:column;align-items:center;gap:4px}.diagram-clips .diagram-arrow{font-size:22px;line-height:1}"
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
22
26
|
## What you can do with it
|
|
23
27
|
|
|
24
28
|
- **Record your screen** with a built-in recorder, webcam overlay, audio capture, and pause/trim.
|
|
@@ -49,6 +53,51 @@ Password-protected clips require the password once; successful responses return
|
|
|
49
53
|
short-lived tokenized links so downstream agents do not need the plaintext
|
|
50
54
|
password.
|
|
51
55
|
|
|
56
|
+
```an-api title="Agent context entry point"
|
|
57
|
+
{
|
|
58
|
+
"method": "GET",
|
|
59
|
+
"path": "/api/agent-context.json",
|
|
60
|
+
"summary": "Compact, agent-readable description of a shared clip",
|
|
61
|
+
"description": "Returns clip metadata, transcript status, chapters, CTAs, recommended frames, and links to the transcript and frame APIs. Advertised by the public share page so a text- or image-only agent can understand a recording without ingesting raw video.",
|
|
62
|
+
"auth": "Same public / password / expiry rules as the share page",
|
|
63
|
+
"params": [
|
|
64
|
+
{ "name": "id", "in": "query", "type": "string", "required": true, "description": "Recording id" }
|
|
65
|
+
],
|
|
66
|
+
"responses": [
|
|
67
|
+
{ "status": "200", "description": "Clip metadata plus transcript and frame API links" }
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```an-api title="Timestamped transcript"
|
|
73
|
+
{
|
|
74
|
+
"method": "GET",
|
|
75
|
+
"path": "/api/agent-transcript.json",
|
|
76
|
+
"summary": "Timestamped transcript segments for a shared clip",
|
|
77
|
+
"params": [
|
|
78
|
+
{ "name": "id", "in": "query", "type": "string", "required": true, "description": "Recording id" }
|
|
79
|
+
],
|
|
80
|
+
"responses": [
|
|
81
|
+
{ "status": "200", "description": "Segments with startMs, endMs, readable timestamps, text, and optional source labels" }
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```an-api title="Frame at a timestamp"
|
|
87
|
+
{
|
|
88
|
+
"method": "GET",
|
|
89
|
+
"path": "/api/agent-frame.jpg",
|
|
90
|
+
"summary": "A JPEG frame extracted from the video at an original-video timestamp",
|
|
91
|
+
"params": [
|
|
92
|
+
{ "name": "id", "in": "query", "type": "string", "required": true, "description": "Recording id" },
|
|
93
|
+
{ "name": "atMs", "in": "query", "type": "integer", "required": true, "description": "Original-video timestamp in milliseconds" }
|
|
94
|
+
],
|
|
95
|
+
"responses": [
|
|
96
|
+
{ "status": "200", "description": "image/jpeg frame" }
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
52
101
|
## Getting started
|
|
53
102
|
|
|
54
103
|
Live demo: [clips.agent-native.com](https://clips.agent-native.com).
|
|
@@ -89,22 +138,81 @@ Clips is a larger template with a native recorder (it ships a desktop companion
|
|
|
89
138
|
2. **Google Calendar (optional).** To sync upcoming meetings, connect a Google Calendar account from Settings. The OAuth callback URL in dev is `http://localhost:8094/_agent-native/google/callback`. Set up a Google OAuth client in [Google Cloud Console](https://console.cloud.google.com/) with the Gmail and Google Calendar APIs enabled.
|
|
90
139
|
3. **Screen-capture permissions.** On macOS, grant Screen Recording permission to the browser (or the desktop companion app) in System Settings → Privacy & Security → Screen Recording.
|
|
91
140
|
|
|
92
|
-
### Key features
|
|
141
|
+
### Key features
|
|
93
142
|
|
|
94
|
-
**One library, three capture types.** Screen recordings, calendar
|
|
143
|
+
**One library, three capture types.** Screen recordings, calendar meetings, and push-to-talk dictations share one searchable library.
|
|
95
144
|
|
|
96
|
-
**Transcript and AI pipeline.**
|
|
145
|
+
**Transcript and AI pipeline.** Recordings get timestamped transcript segments, generated titles, summaries, and chapter markers.
|
|
97
146
|
|
|
98
|
-
**Non-destructive editing.** Trim, split, filler-word removal, silence removal, and stitching
|
|
147
|
+
**Non-destructive editing.** Trim, split, filler-word removal, silence removal, and stitching stay in `edits_json` so original media remains intact.
|
|
99
148
|
|
|
100
|
-
**Agent-readable share links.**
|
|
101
|
-
|
|
102
|
-
**Meetings compose with recordings.** A meeting owns the recording it captures, but the `recordings` row stays the source of truth for the video and per-segment transcript instead of duplicating media.
|
|
149
|
+
**Agent-readable share links.** Public share links expose transcript and frame APIs so agents can understand recordings without ingesting raw video.
|
|
103
150
|
|
|
104
151
|
### Data model
|
|
105
152
|
|
|
106
153
|
All data lives in SQL via Drizzle ORM. Schema: `templates/clips/server/db/schema.ts`. Recordings, meetings, dictations, calendar accounts, and vocabulary all carry the standard `ownableColumns` and have a matching framework shares table, so they slot into the per-user / per-org sharing model.
|
|
107
154
|
|
|
155
|
+
```an-schema title="Clips core data model" summary="recordings is the source of truth for media; transcripts, meetings, and dictations compose with it rather than duplicating video. (Engagement and org tables omitted for clarity — see the full table below.)"
|
|
156
|
+
{
|
|
157
|
+
"entities": [
|
|
158
|
+
{
|
|
159
|
+
"id": "recordings",
|
|
160
|
+
"name": "recordings",
|
|
161
|
+
"note": "Core resource; source of truth for media. ownableColumns",
|
|
162
|
+
"fields": [
|
|
163
|
+
{ "name": "id", "type": "text", "pk": true },
|
|
164
|
+
{ "name": "title", "type": "text" },
|
|
165
|
+
{ "name": "video_url", "type": "text", "note": "plus format / size / duration / thumbnails" },
|
|
166
|
+
{ "name": "status", "type": "text" },
|
|
167
|
+
{ "name": "edits_json", "type": "text", "note": "Non-destructive edits" },
|
|
168
|
+
{ "name": "chapters_json", "type": "text", "nullable": true },
|
|
169
|
+
{ "name": "password", "type": "text", "nullable": true, "note": "Privacy: password / expiry" }
|
|
170
|
+
]
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
"id": "recording_transcripts",
|
|
174
|
+
"name": "recording_transcripts",
|
|
175
|
+
"note": "Split out so the library and transcript views render fast",
|
|
176
|
+
"fields": [
|
|
177
|
+
{ "name": "recording_id", "type": "text", "fk": "recordings.id" },
|
|
178
|
+
{ "name": "segments_json", "type": "text", "note": "{ startMs, endMs, text }" },
|
|
179
|
+
{ "name": "full_text", "type": "text" },
|
|
180
|
+
{ "name": "language", "type": "text" },
|
|
181
|
+
{ "name": "status", "type": "text" }
|
|
182
|
+
]
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
"id": "clips_meetings",
|
|
186
|
+
"name": "clips_meetings",
|
|
187
|
+
"note": "Calendar-sourced or ad-hoc; owns a recording",
|
|
188
|
+
"fields": [
|
|
189
|
+
{ "name": "id", "type": "text", "pk": true },
|
|
190
|
+
{ "name": "recording_id", "type": "text", "fk": "recordings.id", "nullable": true },
|
|
191
|
+
{ "name": "summary_md", "type": "text", "nullable": true },
|
|
192
|
+
{ "name": "bullets_json", "type": "text", "nullable": true },
|
|
193
|
+
{ "name": "action_items_json", "type": "text", "nullable": true }
|
|
194
|
+
]
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
"id": "clips_dictations",
|
|
198
|
+
"name": "clips_dictations",
|
|
199
|
+
"note": "Push-to-talk dictation history; ownableColumns",
|
|
200
|
+
"fields": [
|
|
201
|
+
{ "name": "id", "type": "text", "pk": true },
|
|
202
|
+
{ "name": "full_text", "type": "text", "note": "Raw" },
|
|
203
|
+
{ "name": "cleaned_text", "type": "text", "nullable": true },
|
|
204
|
+
{ "name": "source", "type": "text", "note": "fn-hold, etc." },
|
|
205
|
+
{ "name": "target_app", "type": "text", "nullable": true }
|
|
206
|
+
]
|
|
207
|
+
}
|
|
208
|
+
],
|
|
209
|
+
"relations": [
|
|
210
|
+
{ "from": "recordings", "to": "recording_transcripts", "kind": "1-1", "label": "transcript" },
|
|
211
|
+
{ "from": "recordings", "to": "clips_meetings", "kind": "1-1", "label": "captured by" }
|
|
212
|
+
]
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
108
216
|
| Table | What it holds |
|
|
109
217
|
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
110
218
|
| `recordings` | The core resource — title, video URL/format/size, duration, thumbnails, status, non-destructive `edits_json`, `chapters_json`, privacy (password, expiry), and player toggles |
|