Reel Coach
Reel Coach generates production-ready short-form video scripts (TikTok / Reels / YouTube Shorts) from your note library. The AI retrieves relevant notes, produces a shot-by-shot script with timing, then annotates the draft with "Coach Notes" that explain why each section works and cite the exact source-note sentences that informed them. After generation, you can refine the draft inline and persist it as a Filmwork project.
Flow overview
| Step | Action | Cost | Endpoint |
|---|---|---|---|
| 1 | Generate script | 1-2 credits | POST /api/chat/stream with activeTool: "reel_coach" |
| 2a | Get refine suggestions (optional) | 1 credit | POST /api/filmwork/coach/refine-suggestions |
| 2b | Refine draft (optional) | 1 credit | POST /api/filmwork/coach/refine (SSE stream) |
| 3 | Persist as Filmwork project | 0 credits | POST /api/filmwork/director/persist |
Step 1: Generate script
Send a chat stream request with activeTool: "reel_coach". The backend runs two parallel Qdrant searches (breakdown notes + supporting notes), merges with pinned notes, then streams a JSON draft followed by Coach Notes annotations.
curl -N https://narrativelion.com/api/chat/stream \
-H "Authorization: Bearer nlk_your_key" \
-H "Content-Type: application/json" \
-d '{
"threadId": "your-thread-uuid",
"actionId": "unique-action-uuid",
"event": {
"type": "user_text",
"payload": {
"text": "Create a reel about productivity tips",
"activeTool": "reel_coach",
"reelCoachTopic": "Productivity tips from my notes",
"reelCoachTargetDurationSec": 30,
"reelCoachPinnedNoteIds": ["note-uuid-1", "note-uuid-2"],
"reelCoachAutoRetrieve": true
}
}
}'Payload fields
| Name | Type | Required | Description |
|---|---|---|---|
activeTool | "reel_coach" | Required | Must be "reel_coach" to trigger the Reel Coach pipeline. |
reelCoachTopic | string | Optional | Topic / creative brief (max 2000 chars). Falls back to the text field if omitted. |
reelCoachTargetDurationSec | number | Optional | Target video duration in seconds. Max 120, default 30. |
reelCoachPinnedNoteIds | string[] | Optional | Note IDs to always include as sources (max 20). Breakdown notes are prioritized. |
reelCoachAutoRetrieve | boolean | Optional | Whether to auto-retrieve relevant notes via semantic search. Default true. |
SSE response
The stream emits token events with the draft content, then a complete event containing the structured artifacts.
event: complete
data: {
"finalMessage": "...",
"artifacts": {
"reelCoachSetup": {
"topic": "Productivity tips from my notes",
"targetDurationSec": 30,
"pinnedNoteIds": ["note-uuid-1", "note-uuid-2"],
"autoRetrieve": true
},
"reelCoachAnnotations": [
{
"draftExcerpt": "Start with the hardest task...",
"rationale": "Opens with a counterintuitive hook that challenges common advice",
"confidence": 0.85,
"references": [
{
"noteId": "note-uuid-1",
"noteTitle": "Deep Work Summary",
"confidence": 0.9,
"mode": "quote",
"quotedSentences": ["The key to productivity is starting with your hardest task."]
}
]
}
],
"reelCoachStats": {
"totalBreakdownCount": 5,
"usedSourceCount": 3,
"validatedQuoteCount": 7
}
}
}Artifact fields
| Artifact | Description |
|---|---|
reelCoachSetup | The resolved setup parameters used for generation. Pass this back for refine/persist calls. |
reelCoachAnnotations | Coach Notes: annotation items with draft excerpts, rationale, and validated source quotes. Items below 0.65 confidence are filtered out. |
reelCoachStats | Stats: total breakdown notes in library, notes actually used, and validated quote count. |
Draft structure
The streamed draft content (from token events) is a JSON object with the following structure. Parse it from finalMessage in the complete event.
{
"shots": [
{
"title": "Hook — Start with the hardest task",
"durationSec": 5,
"script": "You've been doing productivity wrong. Here's why."
},
{
"title": "Core insight — Deep work blocks",
"durationSec": 10,
"script": "Block your first 2 hours for deep work. No meetings, no email."
},
{
"title": "CTA — Try it tomorrow",
"durationSec": 5,
"script": "Try this tomorrow morning. Save this for the reminder."
}
],
"coachOverview": "A punchy 20s reel using the eat-the-frog framework...",
"sourceRelevance": [
{ "noteTitle": "Deep Work Summary", "relevanceScore": 0.92 },
{ "noteTitle": "Morning Routine", "relevanceScore": 0.75 }
]
}Draft fields
| Name | Type | Required | Description |
|---|---|---|---|
shots | Shot[] | Required | Array of shots. Each has title (string), durationSec (number), and script (string). |
coachOverview | string | Required | AI summary of the draft strategy and how sources were used. |
sourceRelevance | array | Required | Per-source relevance scores: { noteTitle, relevanceScore (0-1) }. |
Step 2a: Get refine suggestions (optional)
Generate AI suggestions for improving the draft. Returns 2 suggestion chips the user can pick from.
curl -X POST https://narrativelion.com/api/filmwork/coach/refine-suggestions \
-H "Authorization: Bearer nlk_your_key" \
-H "Content-Type: application/json" \
-d '{
"draft": "<the streamed draft text>",
"setup": {
"topic": "Productivity tips from my notes",
"targetDurationSec": 30,
"pinnedNoteIds": [],
"autoRetrieve": true
}
}'| Name | Type | Required | Description |
|---|---|---|---|
draft | string | Required | Current draft text (max 50,000 chars). |
setup | object | Required | The reelCoachSetup object from the generate step. |
{
"suggestions": [
{ "label": "Add emotional hook", "prompt": "Add a personal story opening..." },
{ "label": "Tighten pacing", "prompt": "Cut each shot to under 5 seconds..." }
]
}Step 2b: Refine draft (optional)
Stream a revised draft based on a refinement instruction. Returns SSE token events with the revised content. Does not persist anything.
curl -N -X POST https://narrativelion.com/api/filmwork/coach/refine \
-H "Authorization: Bearer nlk_your_key" \
-H "Content-Type: application/json" \
-d '{
"currentDraft": "<the current draft text>",
"setup": {
"topic": "Productivity tips from my notes",
"targetDurationSec": 30,
"pinnedNoteIds": [],
"autoRetrieve": true
},
"refinementPrompt": "Make the hook more dramatic and shorten to 20 seconds",
"pinnedNoteIds": ["note-uuid-1"]
}'| Name | Type | Required | Description |
|---|---|---|---|
currentDraft | string | Required | Current draft text. |
setup | object | Required | The reelCoachSetup object from the generate step. |
refinementPrompt | string | Required | What to change about the draft. |
pinnedNoteIds | string[] | Optional | Note IDs to include as context for the refinement. |
event: token
data: {"content":"Revised draft content..."}
event: complete
data: {}Step 3: Persist as Filmwork project
Save the finalized draft as a Filmwork note with shot records. Uses the same /api/filmwork/director/persist endpoint as Film Director, but with shots[] + setup instead of draftMarkdown.
curl -X POST https://narrativelion.com/api/filmwork/director/persist \
-H "Authorization: Bearer nlk_your_key" \
-H "Content-Type: application/json" \
-d '{
"shots": [
{ "title": "Hook", "durationSec": 5, "script": "You've been doing it wrong." },
{ "title": "Core insight", "durationSec": 10, "script": "Block your first 2 hours." },
{ "title": "CTA", "durationSec": 5, "script": "Try this tomorrow." }
],
"setup": {
"topic": "Productivity tips",
"targetDurationSec": 20,
"pinnedNoteIds": [],
"autoRetrieve": true
},
"coachOverview": "A punchy 20s reel using the eat-the-frog framework."
}'| Name | Type | Required | Description |
|---|---|---|---|
shots | Shot[] | Required | Array of shots (min 1). Each has title, durationSec, and script. |
setup | object | Required | The reelCoachSetup object from the generate step. |
coachOverview | string | Optional | Coach overview text from the draft. |
{
"noteId": "new-filmwork-note-uuid",
"title": "Productivity tips"
}The response returns the new Filmwork note ID. Use Filmwork GraphQL operations (see Filmwork docs) to manage shots, upload assets, and generate rolls.
Coach Notes (annotations)
After the draft streams, a second LLM pass produces annotation items that explain why specific draft excerpts work and cite exact source-note sentences. All quoted sentences are validated as exact substrings of the source note text. Items below 0.65 confidence are dropped.
AnnotationItem
| Name | Type | Required | Description |
|---|---|---|---|
draftExcerpt | string | Required | The part of the draft this annotation refers to. |
rationale | string | Required | Why this section works or how it uses the source material. |
confidence | number | Required | Confidence score (0-1). Only items >= 0.65 are included. |
references | Reference[] | Required | Source notes cited by this annotation. |
Reference
| Name | Type | Required | Description |
|---|---|---|---|
noteId | string | Required | Source note ID. |
noteTitle | string | Required | Source note title. |
confidence | number | Required | Confidence that this note informed the excerpt (0-1). |
mode | "quote" | Required | Always "quote". |
quotedSentences | string[] | Required | Exact sentences from the source note. Validated as substrings. |
Important notes
- Reel Coach uses the
chatscope for generation andnotes:readfor refine/suggestions. - Persist uses
notes:write(same as Film Director persist). - The generate step auto-retrieves notes via semantic search when
autoRetrieveis true (default). Pinned notes are always included regardless of this setting. - Breakdown notes (notes with structured breakdowns) are prioritized in retrieval and receive a higher source budget.
- Each source note is capped at 5,000 characters with a 70/30 head/tail split. Total source budget is 30,000 characters (25,000 on Starter plan).
- After persisting, the Filmwork note stores
metadata.reelCoachwith the topic, duration, pinned note IDs, and coach overview for later hydration.