gooseworks 0.4.1 → 0.4.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/README.md +43 -11
- package/dist/commands/doctor.d.ts +29 -5
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +107 -63
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/fetch.d.ts +1 -0
- package/dist/commands/fetch.d.ts.map +1 -1
- package/dist/commands/fetch.js +64 -29
- package/dist/commands/fetch.js.map +1 -1
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +37 -4
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +8 -3
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/skills.d.ts +34 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +109 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +17 -6
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/video-local.d.ts +9 -0
- package/dist/commands/video-local.d.ts.map +1 -0
- package/dist/commands/video-local.js +83 -0
- package/dist/commands/video-local.js.map +1 -0
- package/dist/commands/video-save.d.ts +3 -0
- package/dist/commands/video-save.d.ts.map +1 -0
- package/dist/commands/video-save.js +83 -0
- package/dist/commands/video-save.js.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/video-local-captions.d.ts +83 -0
- package/dist/lib/video-local-captions.d.ts.map +1 -0
- package/dist/lib/video-local-captions.js +261 -0
- package/dist/lib/video-local-captions.js.map +1 -0
- package/dist/lib/video-local-runtime.d.ts +8 -0
- package/dist/lib/video-local-runtime.d.ts.map +1 -0
- package/dist/lib/video-local-runtime.js +201 -0
- package/dist/lib/video-local-runtime.js.map +1 -0
- package/dist/lib/video-save-mcp.d.ts +9 -0
- package/dist/lib/video-save-mcp.d.ts.map +1 -0
- package/dist/lib/video-save-mcp.js +162 -0
- package/dist/lib/video-save-mcp.js.map +1 -0
- package/dist/lib/video-save.d.ts +77 -0
- package/dist/lib/video-save.d.ts.map +1 -0
- package/dist/lib/video-save.js +440 -0
- package/dist/lib/video-save.js.map +1 -0
- package/dist/skills/custom-video-skill.d.ts +3 -0
- package/dist/skills/custom-video-skill.d.ts.map +1 -0
- package/dist/skills/custom-video-skill.js +6 -0
- package/dist/skills/custom-video-skill.js.map +1 -0
- package/dist/skills/installer.d.ts +12 -6
- package/dist/skills/installer.d.ts.map +1 -1
- package/dist/skills/installer.js +41 -15
- package/dist/skills/installer.js.map +1 -1
- package/dist/skills/master-skill.d.ts +26 -10
- package/dist/skills/master-skill.d.ts.map +1 -1
- package/dist/skills/master-skill.js +1534 -286
- package/dist/skills/master-skill.js.map +1 -1
- package/dist/skills/package-freshness.d.ts +16 -0
- package/dist/skills/package-freshness.d.ts.map +1 -0
- package/dist/skills/package-freshness.js +36 -0
- package/dist/skills/package-freshness.js.map +1 -0
- package/dist/skills/releases.d.ts +12 -0
- package/dist/skills/releases.d.ts.map +1 -0
- package/dist/skills/releases.js +152 -0
- package/dist/skills/releases.js.map +1 -0
- package/dist/skills/routes.d.ts.map +1 -1
- package/dist/skills/routes.js +13 -1
- package/dist/skills/routes.js.map +1 -1
- package/dist/utils/browser-preflight.d.ts +29 -0
- package/dist/utils/browser-preflight.d.ts.map +1 -0
- package/dist/utils/browser-preflight.js +338 -0
- package/dist/utils/browser-preflight.js.map +1 -0
- package/package.json +2 -2
- package/skills/goose-ads/SKILL.md +124 -16
- package/skills/goose-product-photos/SKILL.md +55 -3
- package/skills/goose-video/SKILL.md +369 -433
- package/skills/goose-video-local/SKILL.md +1405 -0
- package/skills/gooseworks/SKILL.md +200 -13
- package/skills/make-custom-video/SKILL.md +490 -0
- package/skills/manifest.json +12 -0
- package/skills/routes.json +15 -1
|
@@ -2,440 +2,376 @@
|
|
|
2
2
|
name: goose-video
|
|
3
3
|
slug: goose-video
|
|
4
4
|
description: >
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
video ad project/batch or template, or asks to remix a video ad. Unlike goose-ads (static images,
|
|
10
|
-
generated server-side), video renders locally and reports progress + the result back through the
|
|
11
|
-
gooseworks MCP tools.
|
|
5
|
+
Start a video ad in the same chat. Resolve the brand and suggest supported formats with a
|
|
6
|
+
picker or the returned text choices. An agent with a verified shell makes the video with
|
|
7
|
+
goose-video-local; a chat host hands the same project to the GooseWorks coworker. Review
|
|
8
|
+
one complete template plan and total credits before production. Custom videos retain two authenticated review gates in this chat.
|
|
12
9
|
category: ads
|
|
13
|
-
version:
|
|
10
|
+
version: 3.0.0
|
|
14
11
|
author: GooseWorks
|
|
15
|
-
tags: [gooseworks, ads, video,
|
|
12
|
+
tags: [gooseworks, ads, video, local-render, coworker, chat]
|
|
16
13
|
---
|
|
17
14
|
|
|
18
|
-
# GooseWorks Video Ads —
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
**
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
Save
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
**
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
if agent: p["agent_id"] = agent
|
|
382
|
-
if project_id: p["project_id"] = project_id # attributes the spend to this ad project
|
|
383
|
-
return p
|
|
384
|
-
|
|
385
|
-
def fal_generate(model_path, payload, project_id=None, timeout_s=180, poll_s=3):
|
|
386
|
-
"""model_path e.g. 'fal-ai/nano-banana-2/edit' (the recipe names the model).
|
|
387
|
-
Pass project_id = the ad project you're rendering so credits attribute to it.
|
|
388
|
-
Returns the result image URL (a public *.fal.media CDN URL)."""
|
|
389
|
-
api_base, tok, agent = _cfg()
|
|
390
|
-
base = api_base + "/api/internal/fal-proxy"
|
|
391
|
-
sub = requests.post(f"{base}/{model_path}", params=_params(tok, agent, project_id), json=payload).json()
|
|
392
|
-
to_proxy = lambda u: base + urlparse(u).path
|
|
393
|
-
status_url, response_url = to_proxy(sub["status_url"]), to_proxy(sub["response_url"])
|
|
394
|
-
deadline = time.time() + timeout_s
|
|
395
|
-
while time.time() < deadline:
|
|
396
|
-
st = requests.get(status_url, params=_params(tok, agent, project_id)).json()
|
|
397
|
-
if st.get("status") == "COMPLETED":
|
|
398
|
-
return requests.get(response_url, params=_params(tok, agent, project_id)).json()["images"][0]["url"]
|
|
399
|
-
if st.get("status") in ("FAILED", "ERROR"):
|
|
400
|
-
raise RuntimeError(f"FAL failed: {st}")
|
|
401
|
-
time.sleep(poll_s)
|
|
402
|
-
raise TimeoutError("FAL polling exceeded timeout")
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
ElevenLabs (VO / music) is the same shape against `<api_base>/api/internal/elevenlabs-proxy`
|
|
406
|
-
with `?token=&agent_id=&project_id=`. Feed FAL a local image by storing it (`get_upload_url`) and passing its
|
|
407
|
-
`get_download_url` presigned URL as an `image_urls` / `audio_url` entry — this is the reliable
|
|
408
|
-
path. (`fal-storage-proxy` may 404 depending on the install; don't block on it — prefer the
|
|
409
|
-
`get_download_url` presigned URL.)
|
|
410
|
-
|
|
411
|
-
## Rules
|
|
412
|
-
|
|
413
|
-
- **MCP + ffmpeg + Playwright required** — run `gooseworks doctor` in Phase 0; stop with the
|
|
414
|
-
exact fix it prints if anything is ✗.
|
|
415
|
-
- **Assemble the whole review set first**, mirror it with `update_ad_project_script`, and get the
|
|
416
|
-
user's approval **in the app's review panel** (the "Approve & render" button) BEFORE the expensive
|
|
417
|
-
render — never ask for a thumbs-up in this chat (review-once, in-app).
|
|
418
|
-
- **Show the REAL cheap pieces; PROMPT only the expensive render.** Generate the FREE + CHEAP-paid
|
|
419
|
-
pieces (≤ ~100 credits — stills, creator frame, end card, short VO/music) and mirror the real
|
|
420
|
-
assets; put ONLY the expensive video take/render in the panel as its exact prompt. That prompt
|
|
421
|
-
must be in the panel before you ask to approve, so a single "go" runs the render + any remaining
|
|
422
|
-
paid work (→ QC → publish) with no re-pausing.
|
|
423
|
-
- **Costs in CREDITS, never dollars.** credits ≈ round-up(provider-$ × 120) per generation + a flat
|
|
424
|
-
200-credit base per video; never show a "$…" figure to the user.
|
|
425
|
-
- **Never assemble the full video before approval.** The review shows the
|
|
426
|
-
individual PIECES, never the finished cut (or their prompts) — not a
|
|
427
|
-
stitched/composited cut; do not add a "full cascade" / finished-video clip
|
|
428
|
-
as a review ingredient (GOOSE-2542). The assembled video is produced only in
|
|
429
|
-
Step 4.
|
|
430
|
-
- **submit_render only after the master is rendered** (Step 4.2), never on a guess; `output_url` =
|
|
431
|
-
the durable render-file URL, never a CDN URL.
|
|
432
|
-
- **Always pass `project_id` on media-proxy calls** (fal / ElevenLabs) so the credits attribute
|
|
433
|
-
to this ad project — that's what lets the user see per-project spend in the app.
|
|
434
|
-
- **Verify a real, non-empty MP4** (watch it) before marking the render complete.
|
|
435
|
-
- **Reuse the brand** when its research is complete; never re-research.
|
|
436
|
-
- On a hard error (auth/quota/model/timeout) set the render `failed` with a short
|
|
437
|
-
`error_message` and stop — don't ship the source unchanged. **Also `log` it** (`gooseworks log`
|
|
438
|
-
/ `log_cli_event`, `--event-type api_failure|error`) so we can see + fix it (see "Report problems").
|
|
439
|
-
- **Report blockers/bugs/confusing instructions via telemetry** (`gooseworks log` or the
|
|
440
|
-
`log_cli_event` MCP tool) — not just to the user. Set `GW_RUN_ID` once so events group.
|
|
441
|
-
- Always end a successful run with `app_url` + `brand_url`, verbatim.
|
|
15
|
+
# GooseWorks Video Ads — choose, review, make
|
|
16
|
+
|
|
17
|
+
## How to talk to the customer (applies to every message you send them)
|
|
18
|
+
|
|
19
|
+
The customer is a marketer or founder, not an engineer. Everything in this skill about tools,
|
|
20
|
+
fields, files, polling, models and pipeline steps is for YOU. Never pass it on to them.
|
|
21
|
+
|
|
22
|
+
- **Say what they get and what they need to decide, never how it's made.**
|
|
23
|
+
Bad: "Checking the media-proxy helpers for voiceover timestamps and lipsync." / "Generated with
|
|
24
|
+
gpt-image-2 at high quality, mouth closed, passes QC."
|
|
25
|
+
Good: "Recording the voices now." / "Here are your two hosts."
|
|
26
|
+
- **Never mention** tool, file or field names, ids, JSON, commands, scripts, installed software,
|
|
27
|
+
uploads, model or vendor names, timings in seconds or frames, retries, polling, internal statuses
|
|
28
|
+
or your own quality checks. Fix what you can quietly. If they ask how something works, explain it
|
|
29
|
+
simply.
|
|
30
|
+
- **Update them only at milestones they care about**: choices confirmed, script and voices done,
|
|
31
|
+
visuals done, ready to review, finished. One short line each, then stay quiet until the next
|
|
32
|
+
milestone. No update for setup, downloads, uploads or saving.
|
|
33
|
+
- **Money is in credits, with a number**: "the full video uses about N credits". Never "the cheap
|
|
34
|
+
pieces" or "the expensive render".
|
|
35
|
+
- **Problems:** say what it means for them and what they can do, in one or two sentences. No error
|
|
36
|
+
codes or stack traces. Only raise a problem that changes something for them.
|
|
37
|
+
- **Use their words**: script, voice, hook, scene, host, ending, logo, the product shot.
|
|
38
|
+
- **No filler**: no "Great question!", "Certainly!", "I hope this helps!", no restating what they
|
|
39
|
+
just said at length.
|
|
40
|
+
|
|
41
|
+
Example. Instead of a dozen lines about render tools, scripts, uploads and portraits, send:
|
|
42
|
+
"Got it: warm tone, home podcast studio, Brielle as the skeptic and Mark as the believer." then
|
|
43
|
+
"Script and voices are done (about 34 seconds)." then "Ready for you to review: the script, voices,
|
|
44
|
+
both hosts and the ending. You can also review your recipe ingredients in the app: <link>. Say go
|
|
45
|
+
here and I'll make the full video (about N credits)."
|
|
46
|
+
|
|
47
|
+
## Use current instructions for new work
|
|
48
|
+
|
|
49
|
+
Before a new task in a terminal host, run `gooseworks skills status` once. It compares the
|
|
50
|
+
installed entry files, running CLI and published npm release. An older CLI needs a package
|
|
51
|
+
upgrade before `gooseworks update`; update alone only uses that CLI's bundled instructions.
|
|
52
|
+
Preserve local edits or unknown install provenance. Review/back up before explicitly replacing
|
|
53
|
+
modified files; never quietly reinstall over them. If the release check is unavailable, report
|
|
54
|
+
that freshness is unknown rather than claiming the local copy is latest.
|
|
55
|
+
|
|
56
|
+
For a new recipe run, fetch its package from the connected catalog. Retain the returned
|
|
57
|
+
`version` / `contentHash` and every dependency's hash with the saved package. When reusing a
|
|
58
|
+
saved fetch JSON, `gooseworks fetch <slug> --saved-package <file>` returns the current package
|
|
59
|
+
and a hash comparison without changing that file. With MCP, if the advertised `catalog_fetch`
|
|
60
|
+
schema accepts them, send `saved_content_hash` and `saved_dependency_hashes`; otherwise fetch
|
|
61
|
+
normally and compare the returned hashes yourself. Missing hashes mean unknown, not current.
|
|
62
|
+
The server cannot inspect a client's saved files; hash metadata does not certify later edits.
|
|
63
|
+
Fetch current packages into a new run directory and report stale saved instructions. Preserve
|
|
64
|
+
an existing approved run's recorded package; changing that harness requires a reviewed change
|
|
65
|
+
and approval before spending. Hosted installed snapshots use the existing Skills Update action.
|
|
66
|
+
Skill content and a host's cached MCP tool schemas are separate: refreshing one does not refresh
|
|
67
|
+
the other. Check the actual advertised tools before using new fields.
|
|
68
|
+
|
|
69
|
+
## Purpose
|
|
70
|
+
|
|
71
|
+
Resolve the brand, show supported formats and create one saved project. An agent with a verified
|
|
72
|
+
shell follows **`goose-video-local`**. A chat host delegates that same project to the GooseWorks
|
|
73
|
+
coworker, which renders in its sandbox. This is agent execution, not a recipe server-order API.
|
|
74
|
+
|
|
75
|
+
**Cards and execution are separate capabilities.** A terminal may render without drawing a
|
|
76
|
+
picker; a chat host may draw a picker while the coworker renders. Follow `card.display_hint`
|
|
77
|
+
and `available_here`, never a guess from the host's name. Template-remix review stays in this
|
|
78
|
+
chat. Custom videos use separate authenticated script and ingredient approvals in this same chat.
|
|
79
|
+
Studio is an optional review surface.
|
|
80
|
+
|
|
81
|
+
## Custom videos: route before formats
|
|
82
|
+
|
|
83
|
+
For an original brief without a reference template, an Instagram reel/post URL or a direct video URL to study, fetch `catalog_fetch { type: "skill", slug: "make-custom-video" }` and follow it in this same session. It creates format:"custom", custom_mode:"generate" with the brief and optional reference_url. Growth executes in its managed sandbox; connected agents use their shell. Script and actual ingredients are reviewed and separately approved in the same chat before paid production; Studio is optional. Do not force a template choice or import the reference as a finished video.
|
|
84
|
+
|
|
85
|
+
## Route first: is this a new video?
|
|
86
|
+
|
|
87
|
+
Hand off to **`goose-video-local`** now, and stop following this skill, for:
|
|
88
|
+
|
|
89
|
+
- an existing **project** id or a **video batch** id;
|
|
90
|
+
- the app's copy-for-Claude command (it names `goose-video-local`);
|
|
91
|
+
- "remix this video ad template" for a specific app template.
|
|
92
|
+
|
|
93
|
+
Use `goose-video-local` if it is installed; otherwise load it with
|
|
94
|
+
`catalog_fetch { type: "skill", slug: "goose-video-local" }` on the GooseWorks MCP (older clients:
|
|
95
|
+
`fetch_skill("goose-video-local")`). It reads the project first and says what to do with it.
|
|
96
|
+
|
|
97
|
+
When they ask **what** to make ("give me video ad ideas", "what angles should I use?", "what's
|
|
98
|
+
working for my competitors?"), fetch **`ad-angle-miner`** (`catalog_fetch { type: "skill", slug: "ad-angle-miner" }`,
|
|
99
|
+
using its advertised tools) and run it with the **video** output. It returns ranked
|
|
100
|
+
video ideas mapped to formats and hands the picked ones to `goose-video-local`.
|
|
101
|
+
|
|
102
|
+
Everything else, including "make me a video ad for <brand>", starts at step 1 below.
|
|
103
|
+
|
|
104
|
+
## Keep the selected connection for the whole run
|
|
105
|
+
|
|
106
|
+
Call `account_whoami` on the connection that owns the brand/project before the first write.
|
|
107
|
+
Keep `environment.name` and the public `environment.api_origin` with this run. Respect the
|
|
108
|
+
user's selected production or staging connection. If multiple connections are available and
|
|
109
|
+
none was selected, resolve that once. Missing or unknown identity is uncertainty, not
|
|
110
|
+
permission to switch. Never infer the environment from credits, billing links or Node mode.
|
|
111
|
+
|
|
112
|
+
Reads, project creation, uploads, generation, polling and final updates all use that same
|
|
113
|
+
connection. If a production request fails, resume or report the failure on production;
|
|
114
|
+
never retry it on staging or recreate the project there. Before retrying a timed-out write,
|
|
115
|
+
read back the existing project or paid request on the selected connection.
|
|
116
|
+
|
|
117
|
+
Local/CLI proxy origin must match `environment.api_origin`. If it differs, use the MCP
|
|
118
|
+
relay on the selected connection (`GW_MEDIA_VIA=mcp`) before paid calls. Do not change
|
|
119
|
+
credentials or API origins to recover a failed write. An explicit user-requested move is
|
|
120
|
+
a separate operation, with the existing project and paid requests reconciled first.
|
|
121
|
+
|
|
122
|
+
## Check assets for the selected format before spending
|
|
123
|
+
|
|
124
|
+
For a template, read its structured `asset_readiness` from
|
|
125
|
+
`video_catalog_list { kind: "formats", brand_id }`. `missing` names gaps;
|
|
126
|
+
`needs_review` means suitability is unverified, including older recipes without
|
|
127
|
+
structured requirements. `ready` describes assets only, not script or budget approval.
|
|
128
|
+
For a custom video, derive requirements from its actual approved scenes.
|
|
129
|
+
|
|
130
|
+
Inspect candidate files for the chosen product and format. A catalog photo can contain
|
|
131
|
+
multiple objects, other products or a person; its existence or approved status does not
|
|
132
|
+
make it a standalone image of the selected product. Check object count, framing, readable
|
|
133
|
+
print and real image bytes. A service conversation has no automatic packshot requirement.
|
|
134
|
+
|
|
135
|
+
Reuse a suitable approved image first. A free crop or cutout is a new file: keep the
|
|
136
|
+
original, inspect the result and include it in the normal ingredient review. When no
|
|
137
|
+
usable input exists, explain the gap before generation. Estimate any paid preparation
|
|
138
|
+
separately before spending. Record the selected asset and inspection in the project
|
|
139
|
+
review set; do not add a separate approval round.
|
|
140
|
+
|
|
141
|
+
## Inputs
|
|
142
|
+
|
|
143
|
+
- A brand, usually named in the request. Resolve it from the accessible brands; one brand needs no question.
|
|
144
|
+
- The customer's goal, occasion, audience, selected angle and constraints when supplied; otherwise propose defaults from the verified kit.
|
|
145
|
+
- The selected format's required assets. Presence does not prove suitability; uncertain assets remain “needs review.”
|
|
146
|
+
|
|
147
|
+
## Save durable brand answers, then verify them
|
|
148
|
+
|
|
149
|
+
Read the selected brand with `brand_read { brand_id, sections: ["summary", "kit", "products", "learnings", "onboarding"] }`
|
|
150
|
+
(fallback: `brand_get_context` with the same sections). Keep founder answers, user corrections,
|
|
151
|
+
research and your own hypotheses distinct. Reuse matching saved answers; ask only about gaps.
|
|
152
|
+
|
|
153
|
+
When the user asks to remember a rule, answers a brand interview, or explicitly corrects a
|
|
154
|
+
standing fact, save that answer in the same turn. The capture request authorizes those answers;
|
|
155
|
+
do not ask for approval again. A direction for this one video stays in its brief. If the scope
|
|
156
|
+
is genuinely ambiguous, ask whether it applies to future videos before saving a standing rule.
|
|
157
|
+
|
|
158
|
+
Use the **live registered schema**. Where supported, call `brand_update` with
|
|
159
|
+
`knowledge_intent: "user_correction"` and `user_statement` containing the user's exact,
|
|
160
|
+
verbatim answer, not your paraphrase or researched text.
|
|
161
|
+
For an inference or suggested improvement, use `knowledge_intent: "agent_proposal"`. Show the
|
|
162
|
+
before/after change from your prior read and proposed value; retain the returned proposal IDs
|
|
163
|
+
and say the user must accept it in the app. Link only a review surface actually returned by a
|
|
164
|
+
tool; the compact `knowledge_updates` response does not itself contain a diff or URL.
|
|
165
|
+
A pending proposal is not a saved fact. Never call an unavailable
|
|
166
|
+
tool or silently relabel research or your inference as something the user said.
|
|
167
|
+
|
|
168
|
+
The safe structured shape is `patch: { knowledge: { positioning?, audience?, voice?,
|
|
169
|
+
instructions?, brandType?, tagline?, valueProps? } }`, using only fields present in the live
|
|
170
|
+
schema. Inferred rules/taste go in an `instructions` proposal with a rationale, never in
|
|
171
|
+
`patch.facts`. Prefix every video-only preference in that proposed text with "Video preference:"
|
|
172
|
+
so it remains production direction after acceptance. Preserve unrelated instructions when
|
|
173
|
+
proposing a merged replacement.
|
|
174
|
+
|
|
175
|
+
| User answer | Canonical write |
|
|
176
|
+
| --- | --- |
|
|
177
|
+
| Primary audience, positioning or voice correction | `patch.knowledge: { audience/positioning/voice: <answer> }` (one actual key). During onboarding, `brand_onboarding { action: "review_research", review: { action: "correct", field, value } }` writes these existing corrections with provenance. |
|
|
178
|
+
| Founder story, customer pains, objections, buying trigger or useful audience detail without a structured field | `patch.facts: [{ kind: "insight", text }]`; retain attribution such as "Founder reports: …" rather than turn a belief into a verified result. |
|
|
179
|
+
| Required wording or pronunciation | `patch.facts: [{ kind: "must", text }]`; pronunciation is exactly `Pronounce "<term>" as "<say_as>"`. |
|
|
180
|
+
| Forbidden claim, word or visual | `patch.facts: [{ kind: "dont", text }]`. |
|
|
181
|
+
| Durable visual, voice or pacing preference | `patch.facts: [{ kind: "do", text }]` for a preference; `dont` for an avoidance; `template_hint` for a preferred format. Prefix video-only preferences with "Video preference:". |
|
|
182
|
+
|
|
183
|
+
Facts are existing `ad_brand_learning` rows with user provenance; they are not a second profile.
|
|
184
|
+
Update a matching rule by its returned `id` instead of adding duplicates. Preserve unrelated
|
|
185
|
+
rules and the user's exact meaning. Only use the legacy facts shape for explicitly user-authored
|
|
186
|
+
answers when the live schema lacks intent fields; agent suggestions still need a proposal path.
|
|
187
|
+
|
|
188
|
+
**Claims and plans have separate gates.** A founder assertion or proof point is not an approved,
|
|
189
|
+
evidence-backed claim or consent to quote a customer. Use the existing evidence/claims and
|
|
190
|
+
operating-plan tools only if registered, following their proposal, evidence and confirmation
|
|
191
|
+
requirements. Never encode a spend cap, approver or emergency stop as a learning. If that write
|
|
192
|
+
path is missing, report the specific unsaved item and keep it pending for the supported review
|
|
193
|
+
surface; do not claim it was saved or create a parallel local profile.
|
|
194
|
+
|
|
195
|
+
After every write, **read back before saying saved**: use `brand_read` with `kit`, `learnings`
|
|
196
|
+
or `onboarding` as appropriate, or `brand_onboarding { action: "status", brand_id }` after an
|
|
197
|
+
onboarding answer. Verify the intended field/rule, its source and the absence of a conflicting
|
|
198
|
+
duplicate. A generic success response, pending proposal, ignored key or truncated result is not
|
|
199
|
+
proof. Report partial saves honestly. Carry the verified rules into the current task and the
|
|
200
|
+
routed skill; claims still pass their own safety gate.
|
|
201
|
+
|
|
202
|
+
## Video taste — reuse examples and preferences
|
|
203
|
+
|
|
204
|
+
When asked to capture video taste, or when the user volunteers a durable video preference,
|
|
205
|
+
first read the saved learnings and `media_list { brand_id, scope: "brand", scope_id: brand_id,
|
|
206
|
+
tags: ["video-taste"], limit: 100 }`. Follow `next_cursor` before deciding an example is absent.
|
|
207
|
+
Do not force a taste interview before an unrelated task or ask again for an existing preference.
|
|
208
|
+
|
|
209
|
+
Save what the user has already supplied first. Then ask only the missing useful question, for
|
|
210
|
+
example: "What do you like about this video—its pace, voice, captions, or look?" An inaccessible
|
|
211
|
+
link can still be saved as a link with the user's explanation; do not pretend you watched it.
|
|
212
|
+
|
|
213
|
+
- **Direct clip or video file:** register with `media_upload { brand_id, scope: "brand",
|
|
214
|
+
scope_id: brand_id, kind: "video", source: { type: "url", url }, tags: ["video-taste", "reference-only"],
|
|
215
|
+
metadata: { purpose: "video_taste", source_url: url, provenance: "user", captured_at: <ISO timestamp>,
|
|
216
|
+
preference: <the user's explanation> } }`. For a file use the live file/bytes upload flow and
|
|
217
|
+
`media_confirm` after a presigned upload. Registration of a URL does not copy or inspect it.
|
|
218
|
+
- **Instagram/post/page link:** the same registration with `kind: "document"`; it is a link
|
|
219
|
+
bookmark, not downloadable footage or an indexed transcript. Do not fabricate a direct clip URL.
|
|
220
|
+
- **Preferences:** save the user's reasons, likes and dislikes through the facts mapping above.
|
|
221
|
+
Read and preserve existing facts before updating one. Do not invent `video_preferences` or
|
|
222
|
+
new `video_lab` keys; the live kit patch accepts only its documented asset fields.
|
|
223
|
+
- **Deduplicate:** reuse a matching returned media row, then `media_update` its title/tags/metadata
|
|
224
|
+
if needed; preserve existing metadata and tags. Do not create another row for the same example.
|
|
225
|
+
Read back with `media_list` and `brand_read` learnings before claiming it was saved.
|
|
226
|
+
Check the returned row belongs to this brand: URL deduplication may return another brand's
|
|
227
|
+
existing row. Do not relabel that row or claim success unless the current brand's scoped read
|
|
228
|
+
actually returns it. Report an unsaved association if no supported attach path is available.
|
|
229
|
+
|
|
230
|
+
Never put third-party taste examples into kit reference images: `kind: "reference"` at brand
|
|
231
|
+
scope writes there. The tags and metadata above record purpose and provenance; **they do not
|
|
232
|
+
grant or enforce usage rights**. Study the structure, pacing and look only. Never use the example's
|
|
233
|
+
footage, face, product, testimonial or claims in a new ad without independently verified permission.
|
|
234
|
+
|
|
235
|
+
Read video-only entries prefixed `Video preference:` from both saved learnings and
|
|
236
|
+
`kit.instructions`, including accepted proposals. Keep them out of required or forbidden
|
|
237
|
+
dialogue. Build a brief from the verified readback: preferred pace, voice, caption treatment, visual style,
|
|
238
|
+
formats to favour/avoid, reference links and the user's reasons. Say what is still unknown.
|
|
239
|
+
Pass it with the brand rules into the existing video workflow. A one-video request overrides a
|
|
240
|
+
default for that project; it does not silently rewrite the brand's standing preference.
|
|
241
|
+
|
|
242
|
+
## Composed Atoms
|
|
243
|
+
|
|
244
|
+
Use the live canonical schemas: brand_read, brand_create, video_catalog_list,
|
|
245
|
+
video_project_upsert, video_project_read, catalog_fetch, goose_run_task and job_cancel.
|
|
246
|
+
An old tool name in a recipe is not grounds for terminal-update advice in a chat host.
|
|
247
|
+
|
|
248
|
+
## Paid media: images, clips, voice
|
|
249
|
+
|
|
250
|
+
**No FAL_KEY, ElevenLabs key or `fal_client` is ever needed.** Use
|
|
251
|
+
`data_post_provider { provider: "fal", path: <model id, e.g. "fal-ai/nano-banana/edit">, body: <model input>, project_id }`
|
|
252
|
+
then `job_get { job_id }`; voice/music use provider:"elevenlabs". Upload local inputs through
|
|
253
|
+
media_upload first. **A missing key is never a blocker.** `photos_generate` is **not** a general
|
|
254
|
+
image tool: it photographs physical catalog products only. Use goose-video-local for the
|
|
255
|
+
runtime, paid approval, asset saving and quality checks.
|
|
256
|
+
|
|
257
|
+
## Workflow
|
|
258
|
+
|
|
259
|
+
### 1. Resolve the brand, quietly when you can
|
|
260
|
+
|
|
261
|
+
Call brand_read without brand_id to list accessible brands. Resolve the customer's name from
|
|
262
|
+
actual returned names. One brand, or exactly one match: state it and continue. Several possible
|
|
263
|
+
brands: show names and websites and ask once. No match: show accessible brands and offer to add
|
|
264
|
+
one only when the customer asks and supplies its website; never guess the URL.
|
|
265
|
+
|
|
266
|
+
Read `brand_read { brand_id, sections: ["summary","kit","products","learnings"] }` before
|
|
267
|
+
choosing a format. Reconcile explicit brand corrections through the durable capture rules.
|
|
268
|
+
A direct video request does not require first-campaign acceptance. Follow any returned
|
|
269
|
+
request-specific setup requirement; never mark research complete or accept a campaign to
|
|
270
|
+
bypass setup. Keep the original request.
|
|
271
|
+
|
|
272
|
+
### 2. Keep the goal and propose defaults
|
|
273
|
+
|
|
274
|
+
Never ask what the ad is for before showing formats. Keep the customer's exact direction.
|
|
275
|
+
Otherwise propose defaults from the verified kit's products, audience, offer and voice. Show
|
|
276
|
+
those defaults in the saved plan so any can be changed. Never invent proof or product facts.
|
|
277
|
+
Idea requests still follow ad-angle-miner with the video output.
|
|
278
|
+
|
|
279
|
+
### 3. Show the picker or its text fallback
|
|
280
|
+
|
|
281
|
+
Call `video_catalog_list { kind: "formats", brand_id }`. On the customer's computer, when you
|
|
282
|
+
can actually execute shell commands, include `client: { shell: true }`; in a chat host omit
|
|
283
|
+
that claim. Inside a coworker sandbox follow its reported capabilities, never claim to be the
|
|
284
|
+
customer's computer. Respect requested limit and next_cursor for more item pages; the card may
|
|
285
|
+
contain a full picker independently of the item page.
|
|
286
|
+
|
|
287
|
+
- **card.display_hint:"widget"**: the picker replaces a format table. Write at most one short
|
|
288
|
+
acknowledgement, print no table or list of the formats, and wait for the selection.
|
|
289
|
+
- **Otherwise**: print card.text_summary as returned. Without a card, show returned rows with
|
|
290
|
+
names, faithful descriptions, needs and demo links, respecting the requested page size.
|
|
291
|
+
Write "no demo yet" when absent. Never put links only in a question control.
|
|
292
|
+
- A format whose card contradicts what they asked for is never Suggested. Never offer
|
|
293
|
+
available_here:false as an executable choice. Relay not_available_here in one short line.
|
|
294
|
+
- Missing required assets are missing; unknown suitability is “needs review.” Inspect the
|
|
295
|
+
selected format's candidates before spending. Never promise an unverified asset is ready.
|
|
296
|
+
- Template formats use **one plan, one approval with the total in credits**, not approval for
|
|
297
|
+
each paid step. Custom videos retain separate authenticated script/ingredient/budget gates in this chat.
|
|
298
|
+
|
|
299
|
+
### 4. Check this machine can render it
|
|
300
|
+
|
|
301
|
+
- **Chat host without a shell:** skip local checks and delegate an available format in Step 5.
|
|
302
|
+
Never tell a chat host it needs Claude Code to start. Browser-only formats remain unavailable
|
|
303
|
+
here; give computer setup guidance only if asked how to make one.
|
|
304
|
+
- **Local shell:** run `gooseworks doctor --no-browser` for common setup (auth/MCP, Node 18+,
|
|
305
|
+
ffmpeg with libx264 + libass, ffprobe). Then fetch the selected template and its capabilities,
|
|
306
|
+
and install documented dependencies in its fetched folder. Do not guess a renderer from a
|
|
307
|
+
format name. For each Node renderer using default Playwright Chromium, run
|
|
308
|
+
`gooseworks doctor --renderer-script "/absolute/path/to/the/fetched/scripts/record.js"` with
|
|
309
|
+
the exact environment used to render, including NODE_PATH and PLAYWRIGHT_BROWSERS_PATH.
|
|
310
|
+
Use the actual script path. Custom browser launch settings need their equivalent exact-runtime
|
|
311
|
+
check. Non-browser capabilities need only their documented runtime checks.
|
|
312
|
+
Never create paid ingredients before the selected renderer passes. Repair and recheck under
|
|
313
|
+
existing setup permissions. If it cannot be fixed, re-list with client:{shell:false} and
|
|
314
|
+
delegate only a format available to the coworker; never silently change the selected format.
|
|
315
|
+
- **Coworker sandbox:** you are the renderer. Follow goose-video-local's sandbox checks; never
|
|
316
|
+
hand off recursively or claim browser capability that the sandbox lacks.
|
|
317
|
+
|
|
318
|
+
### 5. Create the project and hand it off, in this session
|
|
319
|
+
|
|
320
|
+
1. `video_project_upsert { brand_id, name, format: <template_id> }` with no brief (a brief creates
|
|
321
|
+
a concept batch). Include client:{shell:true} only for real local execution. Default
|
|
322
|
+
creation_intent:"format" keeps the style with this brand's content; source_remix requires an
|
|
323
|
+
explicit choice to use source content.
|
|
324
|
+
If they already chose a campaign/concept, include its verified campaign_id and optional
|
|
325
|
+
campaign_concept_id. Read the IDs from that brand's saved campaign; the concept must belong
|
|
326
|
+
to it. Omit unknown IDs and never infer a link or create a campaign solely to file a video.
|
|
327
|
+
2. **Verified local shell or coworker sandbox:** load
|
|
328
|
+
`catalog_fetch { type: "skill", slug: "goose-video-local" }` and follow it on the same project_id.
|
|
329
|
+
Carry the customer's words, verified defaults, campaign and selected angle into its brief.
|
|
330
|
+
3. **Chat host:** `goose_run_task { brand_id, project_id, message }` with the request, selected
|
|
331
|
+
format and defaults. Keep task_id. Continue questions/edits with the same task and project.
|
|
332
|
+
A saved free draft is not a started worker or a complete plan. Follow actual saved state.
|
|
333
|
+
4. When follow.card_follows is true, the card follows progress: do not re-read it in a loop.
|
|
334
|
+
Read again on a customer reply, card action or requested update. A failure or missing saved
|
|
335
|
+
plan needs the returned recovery action; never claim completion or approve an empty plan.
|
|
336
|
+
Approval requires the current complete plan and total. Insufficient balance: offer a shorter
|
|
337
|
+
video or top-up. “Not now” keeps the saved plan.
|
|
338
|
+
|
|
339
|
+
Do not hand the customer a command to paste somewhere else.
|
|
340
|
+
|
|
341
|
+
## Decision Rules
|
|
342
|
+
|
|
343
|
+
- One sentence is a complete request. Resolve the brand and show formats without a goal interview.
|
|
344
|
+
- One brand in the org: never ask which brand. Cards decide presentation; checks decide execution.
|
|
345
|
+
- Use canonical tools. Preserve campaign context, selected script angles and custom authenticated review gates.
|
|
346
|
+
- Never fabricate readiness, completion, approval or a second project.
|
|
347
|
+
|
|
348
|
+
## Output
|
|
349
|
+
|
|
350
|
+
One project, one current saved plan in this chat, then the finished video. With a widget write one
|
|
351
|
+
line and do not add app_url, brand_url or duplicate video links. A text host gets text_summary
|
|
352
|
+
and its usable delivery link.
|
|
353
|
+
|
|
354
|
+
## Quality Checks
|
|
355
|
+
|
|
356
|
+
- No forced goal question, duplicate table or unsupported shell claim.
|
|
357
|
+
- The exact renderer passed before local paid ingredients; uncertain assets stay uncertain.
|
|
358
|
+
- Selected campaign and angle survive; a single template project has no brief.
|
|
359
|
+
- Current complete plan and total precede approval. Custom script and ingredient gates remain independent; Studio is optional.
|
|
360
|
+
|
|
361
|
+
## Failure Modes
|
|
362
|
+
|
|
363
|
+
| Symptom | Cause | Fix |
|
|
364
|
+
| --- | --- | --- |
|
|
365
|
+
| Picker plus table | Ignored display_hint | Widget: one line; otherwise text_summary |
|
|
366
|
+
| Terminal loses formats | Confused cards with execution | Declare real shell capability and check renderer |
|
|
367
|
+
| Chat told it cannot start | Only local execution considered | Create once and delegate to coworker |
|
|
368
|
+
| Worker ends without a plan | Assumed completion means ready | Follow actual failure/recovery state |
|
|
369
|
+
| Two projects for one video | Recreated instead of resuming | Continue same project and task |
|
|
370
|
+
|
|
371
|
+
## Use uploaded footage
|
|
372
|
+
|
|
373
|
+
When the customer asks to use existing footage, check the actual advertised schemas. Use `media_search` with purpose `production`, kind `video`, the brand and current project when needed. Omit query spend for free retrieval. Read facts/scenes with `media_analyze`, then use `media_excerpt` action `inspect` to review actual bounded frames and timed transcript before selecting. A description or thumbnail URL alone is not visual review.
|
|
374
|
+
|
|
375
|
+
Freeze `source_excerpt:{asset_id,analysis_revision,scene_id,start_ms,end_ms,audio_mode}`. Revision is the original-byte SHA, scene may be null for a known user trim, bounds use integer milliseconds, and audio is original or muted. Call `media_excerpt` action `attach` with that exact selection and a stable idempotency key. The returned project remains unfinished and unapproved. Open its existing Studio review; preserve user locks and requested format, and keep footage separate from image packshot indexes. An incompatible format requires an explicit choice before changing it.
|
|
376
|
+
|
|
377
|
+
For custom production, fetch the current shared `video-production-harness` and follow script/ingredient gates. Download the verified original and trim its exact selected window at normal speed with the approved audio. Recheck current revision and production permission before consumption and final upload/completion. Save excerpt lineage in plan and ingredient readback. Missing optional semantics does not require another upload; known user-selected stored footage remains usable. Research and competitor references never become production footage. Selected originals require no paid generation; only newly generated/replaced ingredients consume the approved budget.
|