@mevdragon/vidfarm-devcli 0.2.14 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/README.md +11 -4
  2. package/SKILL.director.md +100 -0
  3. package/SKILL.platform.md +66 -6
  4. package/dist/src/cli.js +135 -1527
  5. package/package.json +5 -24
  6. package/.env.example +0 -60
  7. package/auto-create-hyperframe-templates/AUTO_CREATE_HYPERFRAME_TEMPLATES.md +0 -275
  8. package/auto-create-hyperframe-templates/extractor-system-prompt.md +0 -128
  9. package/auto-create-hyperframe-templates/input-manifest.schema.json +0 -56
  10. package/auto-create-hyperframe-templates/lambda-memory-estimator.md +0 -118
  11. package/auto-create-hyperframe-templates/production-graph.schema.json +0 -314
  12. package/auto-create-hyperframe-templates/runbook.md +0 -198
  13. package/auto-create-hyperframe-templates/scripts/create-hyperframe-template.mjs +0 -368
  14. package/auto-create-hyperframe-templates/template-plan.schema.json +0 -311
  15. package/auto-create-hyperframe-templates/template-planner-prompt.md +0 -144
  16. package/auto-create-templates/AUTO_CREATE_TEMPLATES.md +0 -599
  17. package/auto-create-templates/extractor-system-prompt.md +0 -119
  18. package/auto-create-templates/production-graph.schema.json +0 -276
  19. package/auto-create-templates/runbook.md +0 -140
  20. package/auto-create-templates/template-plan.schema.json +0 -301
  21. package/auto-create-templates/template-planner-prompt.md +0 -137
  22. package/dist/src/account-pages-legacy.js +0 -9338
  23. package/dist/src/account-pages-legacy.js.map +0 -1
  24. package/dist/src/account-pages.js +0 -52
  25. package/dist/src/account-pages.js.map +0 -1
  26. package/dist/src/app.js +0 -13711
  27. package/dist/src/app.js.map +0 -1
  28. package/dist/src/cli.js.map +0 -1
  29. package/dist/src/composition-runtime.js +0 -581
  30. package/dist/src/composition-runtime.js.map +0 -1
  31. package/dist/src/config.js +0 -140
  32. package/dist/src/config.js.map +0 -1
  33. package/dist/src/context.js +0 -492
  34. package/dist/src/context.js.map +0 -1
  35. package/dist/src/dev-app-legacy.js +0 -694
  36. package/dist/src/dev-app-legacy.js.map +0 -1
  37. package/dist/src/dev-app.js +0 -6
  38. package/dist/src/dev-app.js.map +0 -1
  39. package/dist/src/dev-serve.js.map +0 -1
  40. package/dist/src/domain.js +0 -2
  41. package/dist/src/domain.js.map +0 -1
  42. package/dist/src/editor-chat-history.js +0 -82
  43. package/dist/src/editor-chat-history.js.map +0 -1
  44. package/dist/src/editor-chat.js +0 -312
  45. package/dist/src/editor-chat.js.map +0 -1
  46. package/dist/src/editor-dark-theme.js +0 -1128
  47. package/dist/src/editor-dark-theme.js.map +0 -1
  48. package/dist/src/frontend/flockposter-cache-store.js +0 -124
  49. package/dist/src/frontend/flockposter-cache-store.js.map +0 -1
  50. package/dist/src/frontend/homepage-client.js +0 -117
  51. package/dist/src/frontend/homepage-client.js.map +0 -1
  52. package/dist/src/frontend/homepage-shared.js +0 -4
  53. package/dist/src/frontend/homepage-shared.js.map +0 -1
  54. package/dist/src/frontend/homepage-store.js +0 -28
  55. package/dist/src/frontend/homepage-store.js.map +0 -1
  56. package/dist/src/frontend/homepage-view.js +0 -260
  57. package/dist/src/frontend/homepage-view.js.map +0 -1
  58. package/dist/src/frontend/page-runtime-client.js +0 -124
  59. package/dist/src/frontend/page-runtime-client.js.map +0 -1
  60. package/dist/src/frontend/page-runtime-store.js +0 -9
  61. package/dist/src/frontend/page-runtime-store.js.map +0 -1
  62. package/dist/src/frontend/sentry.js +0 -42
  63. package/dist/src/frontend/sentry.js.map +0 -1
  64. package/dist/src/frontend/template-editor-chat.js +0 -3760
  65. package/dist/src/frontend/template-editor-chat.js.map +0 -1
  66. package/dist/src/help-page.js +0 -333
  67. package/dist/src/help-page.js.map +0 -1
  68. package/dist/src/homepage.js +0 -919
  69. package/dist/src/homepage.js.map +0 -1
  70. package/dist/src/hyperframes/composition.js +0 -180
  71. package/dist/src/hyperframes/composition.js.map +0 -1
  72. package/dist/src/index.js +0 -16
  73. package/dist/src/index.js.map +0 -1
  74. package/dist/src/instrument.js +0 -30
  75. package/dist/src/instrument.js.map +0 -1
  76. package/dist/src/lib/crypto.js +0 -45
  77. package/dist/src/lib/crypto.js.map +0 -1
  78. package/dist/src/lib/dev-log.js +0 -54
  79. package/dist/src/lib/dev-log.js.map +0 -1
  80. package/dist/src/lib/display-name.js +0 -11
  81. package/dist/src/lib/display-name.js.map +0 -1
  82. package/dist/src/lib/ids.js +0 -24
  83. package/dist/src/lib/ids.js.map +0 -1
  84. package/dist/src/lib/images.js +0 -19
  85. package/dist/src/lib/images.js.map +0 -1
  86. package/dist/src/lib/json.js +0 -15
  87. package/dist/src/lib/json.js.map +0 -1
  88. package/dist/src/lib/template-dna.js +0 -543
  89. package/dist/src/lib/template-dna.js.map +0 -1
  90. package/dist/src/lib/template-paths.js +0 -28
  91. package/dist/src/lib/template-paths.js.map +0 -1
  92. package/dist/src/lib/template-style-options.js +0 -203
  93. package/dist/src/lib/template-style-options.js.map +0 -1
  94. package/dist/src/lib/time.js +0 -7
  95. package/dist/src/lib/time.js.map +0 -1
  96. package/dist/src/lib/video-quality-harness.js +0 -60
  97. package/dist/src/lib/video-quality-harness.js.map +0 -1
  98. package/dist/src/page-runtime.js +0 -2
  99. package/dist/src/page-runtime.js.map +0 -1
  100. package/dist/src/page-shell.js +0 -1315
  101. package/dist/src/page-shell.js.map +0 -1
  102. package/dist/src/primitive-context.js +0 -299
  103. package/dist/src/primitive-context.js.map +0 -1
  104. package/dist/src/primitive-registry.js +0 -2181
  105. package/dist/src/primitive-registry.js.map +0 -1
  106. package/dist/src/primitive-sdk.js +0 -4
  107. package/dist/src/primitive-sdk.js.map +0 -1
  108. package/dist/src/primitives/remotion/html-image.js +0 -30
  109. package/dist/src/primitives/remotion/html-image.js.map +0 -1
  110. package/dist/src/primitives/remotion/media-slideshow.js +0 -60
  111. package/dist/src/primitives/remotion/media-slideshow.js.map +0 -1
  112. package/dist/src/react-page-shell.js +0 -35
  113. package/dist/src/react-page-shell.js.map +0 -1
  114. package/dist/src/ready-post-schedule-component.js +0 -1515
  115. package/dist/src/ready-post-schedule-component.js.map +0 -1
  116. package/dist/src/registry.js +0 -296
  117. package/dist/src/registry.js.map +0 -1
  118. package/dist/src/runtime.js +0 -31
  119. package/dist/src/runtime.js.map +0 -1
  120. package/dist/src/services/api-call-history.js +0 -249
  121. package/dist/src/services/api-call-history.js.map +0 -1
  122. package/dist/src/services/auth.js +0 -152
  123. package/dist/src/services/auth.js.map +0 -1
  124. package/dist/src/services/billing.js +0 -231
  125. package/dist/src/services/billing.js.map +0 -1
  126. package/dist/src/services/chat-threads.js +0 -92
  127. package/dist/src/services/chat-threads.js.map +0 -1
  128. package/dist/src/services/fork-access.js +0 -93
  129. package/dist/src/services/fork-access.js.map +0 -1
  130. package/dist/src/services/fork-manifest.js +0 -43
  131. package/dist/src/services/fork-manifest.js.map +0 -1
  132. package/dist/src/services/ghostcut.js +0 -132
  133. package/dist/src/services/ghostcut.js.map +0 -1
  134. package/dist/src/services/hyperframes.js +0 -1014
  135. package/dist/src/services/hyperframes.js.map +0 -1
  136. package/dist/src/services/job-capacity.js +0 -14
  137. package/dist/src/services/job-capacity.js.map +0 -1
  138. package/dist/src/services/job-logs.js +0 -197
  139. package/dist/src/services/job-logs.js.map +0 -1
  140. package/dist/src/services/jobs.js +0 -136
  141. package/dist/src/services/jobs.js.map +0 -1
  142. package/dist/src/services/media-processing.js +0 -743
  143. package/dist/src/services/media-processing.js.map +0 -1
  144. package/dist/src/services/primitive-media-lambda.js +0 -280
  145. package/dist/src/services/primitive-media-lambda.js.map +0 -1
  146. package/dist/src/services/providers.js +0 -2870
  147. package/dist/src/services/providers.js.map +0 -1
  148. package/dist/src/services/rate-limits.js +0 -237
  149. package/dist/src/services/rate-limits.js.map +0 -1
  150. package/dist/src/services/remotion.js +0 -688
  151. package/dist/src/services/remotion.js.map +0 -1
  152. package/dist/src/services/serverless-auth.js +0 -374
  153. package/dist/src/services/serverless-auth.js.map +0 -1
  154. package/dist/src/services/serverless-jobs.js +0 -1074
  155. package/dist/src/services/serverless-jobs.js.map +0 -1
  156. package/dist/src/services/serverless-provider-keys.js +0 -401
  157. package/dist/src/services/serverless-provider-keys.js.map +0 -1
  158. package/dist/src/services/serverless-records.js +0 -1088
  159. package/dist/src/services/serverless-records.js.map +0 -1
  160. package/dist/src/services/serverless-template-configs.js +0 -67
  161. package/dist/src/services/serverless-template-configs.js.map +0 -1
  162. package/dist/src/services/storage.js +0 -383
  163. package/dist/src/services/storage.js.map +0 -1
  164. package/dist/src/services/template-certification.js +0 -475
  165. package/dist/src/services/template-certification.js.map +0 -1
  166. package/dist/src/services/template-loader.js +0 -99
  167. package/dist/src/services/template-loader.js.map +0 -1
  168. package/dist/src/services/template-runtime-bundles.js +0 -217
  169. package/dist/src/services/template-runtime-bundles.js.map +0 -1
  170. package/dist/src/services/template-sources.js +0 -1017
  171. package/dist/src/services/template-sources.js.map +0 -1
  172. package/dist/src/services/video-normalization.js +0 -2
  173. package/dist/src/services/video-normalization.js.map +0 -1
  174. package/dist/src/services/webhooks.js +0 -62
  175. package/dist/src/services/webhooks.js.map +0 -1
  176. package/dist/src/template-editor-pages.js +0 -2491
  177. package/dist/src/template-editor-pages.js.map +0 -1
  178. package/dist/src/template-editor-shell.js +0 -2702
  179. package/dist/src/template-editor-shell.js.map +0 -1
  180. package/dist/src/template-sdk.js +0 -4
  181. package/dist/src/template-sdk.js.map +0 -1
  182. package/dist/src/worker.js +0 -17
  183. package/dist/src/worker.js.map +0 -1
  184. package/public/assets/homepage-app.js +0 -54
  185. package/public/assets/homepage-client-app.js +0 -80
  186. package/public/assets/page-runtime-client-app.js +0 -94
  187. package/readme.secret.md +0 -89
  188. package/templates/vidfarm_template_0000/README.md +0 -106
  189. package/templates/vidfarm_template_0000/SKILL.md +0 -266
  190. package/templates/vidfarm_template_0000/assets/Abel-Regular.ttf +0 -0
  191. package/templates/vidfarm_template_0000/assets/DMSerifDisplay-Regular.ttf +0 -0
  192. package/templates/vidfarm_template_0000/assets/Montserrat[wght].ttf +0 -0
  193. package/templates/vidfarm_template_0000/assets/SourceCodePro[wght].ttf +0 -0
  194. package/templates/vidfarm_template_0000/assets/TikTokSans-SemiBold.ttf +0 -0
  195. package/templates/vidfarm_template_0000/assets/Yesteryear-Regular.ttf +0 -0
  196. package/templates/vidfarm_template_0000/composition.json +0 -11
  197. package/templates/vidfarm_template_0000/src/lib/images.js +0 -221
  198. package/templates/vidfarm_template_0000/src/remotion/Root.js +0 -33
  199. package/templates/vidfarm_template_0000/src/remotion/index.js +0 -3
  200. package/templates/vidfarm_template_0000/src/sdk.js +0 -3
  201. package/templates/vidfarm_template_0000/src/style-options.js +0 -200
  202. package/templates/vidfarm_template_0000/src/template-dna.js +0 -9
  203. package/templates/vidfarm_template_0000/src/template.js +0 -1566
  204. package/templates/vidfarm_template_0000/template.config.json +0 -21
package/README.md CHANGED
@@ -35,10 +35,17 @@ npm run cdk:deploy:prod-serverless
35
35
 
36
36
  Never call bare `cdk deploy` — the npm scripts load the correct `.env.<stage>` and select the right stack.
37
37
 
38
- ## Deprecated: `@mevdragon/vidfarm-devcli`
38
+ ## Local editor: `@mevdragon/vidfarm-devcli`
39
39
 
40
- The `vidfarm-devcli` CLI (`src/cli.ts`) is **deprecated and no longer maintained**. It was built around the old REST-API template model templates with `src/template.ts`, workflows, operations, viral DNA extraction, and the hosted publish/approve/activate flow. That entire paradigm has been superseded by the browser-based **Trackpad Editor** at `https://vidfarm.cc/editor/`.
40
+ Pair a local composition directory with the hosted Trackpad Editor so an AI agent (Claude Code, Codex, etc.) or a human can edit `composition.html` on disk and see live preview in the browser.
41
41
 
42
- The CLI still exists in the repo and may partially work, but it will print a deprecation banner on every invocation. No fixes will land. Do not build new tooling on it.
42
+ ```bash
43
+ npx -y @mevdragon/vidfarm-devcli <template_id>
44
+ # → downloads the current composition into .vidfarm/<template_id>/
45
+ # → starts dev-serve on localhost:4321
46
+ # → prints an https://vidfarm.cc/editor/<template_id>?fork=…&dev=… URL to open
47
+ ```
48
+
49
+ Flags: `--port`, `--dir`, `--host`, `--fork`, `--api-key` (or `VIDFARM_API_KEY`), `--share`, `--refetch`. Use `dev-serve` as an explicit subcommand to skip the fetch step and just serve an existing directory.
43
50
 
44
- See `SKILL.platform.md` for the current architecture.
51
+ See `SKILL.platform.md` § "Local editor dev loop" for the request-rewrite / SSE reload flow.
package/SKILL.director.md CHANGED
@@ -118,6 +118,14 @@ The editor persists to:
118
118
 
119
119
  Automation that needs to bypass the UI can call these endpoints directly.
120
120
 
121
+ Reads also work anonymously since the `compositions/forks/*` S3 prefix is public-read — clients that only need to fetch (not mutate) can bypass the API and hit S3 directly:
122
+
123
+ - `GET https://<bucket>.s3.<region>.amazonaws.com/compositions/forks/<forkId>/working/composition.html`
124
+ - `GET .../working/composition.json`
125
+ - `GET .../working/manifest.json` — fork identity + genealogy (`parent_fork_id`, `parent_version`, `latest_version`, direct URLs for html/json/parent manifest). Also served via `GET /api/v1/compositions/:forkId/manifest.json` and `.../versions/:v/manifest.json`.
126
+
127
+ Treat the `forkId` as an unguessable bearer token — anyone with it can view the composition.
128
+
121
129
  ## Auto-decompose
122
130
 
123
131
  If the fork's source is a raw video (not a pre-decomposed template), call auto-decompose to split it into scenes:
@@ -246,6 +254,23 @@ For agents that operate Vidfarm headlessly, the typical loop is:
246
254
 
247
255
  Always send a stable `tracer` on publish to make retries idempotent.
248
256
 
257
+ ## Local dev loop with `vidfarm-devcli`
258
+
259
+ For iterating on a composition on disk (e.g. Claude Code editing HTML directly), pair the hosted editor with a local composition directory:
260
+
261
+ ```bash
262
+ npx -y @mevdragon/vidfarm-devcli <template_id>
263
+ # → downloads composition.html/json + manifest.json into .vidfarm/<template_id>/
264
+ # → starts dev-serve on http://localhost:4321
265
+ # → prints https://vidfarm.cc/editor/<template_id>?fork=<forkId>&dev=http%3A%2F%2Flocalhost%3A4321
266
+ ```
267
+
268
+ Open the printed URL in your browser. An orange **LOCAL DEV MODE** banner pins to the top with an Exit button. All fork API fetches now route to your local dir instead of the deployed API; disk edits push an SSE reload event and the editor re-fetches automatically.
269
+
270
+ Flags: `--port`, `--dir`, `--host`, `--fork`, `--api-key` (or set `VIDFARM_API_KEY`), `--share`, `--refetch`. For a fork that already has composition files on disk (or that you've populated manually), use `vidfarm-devcli dev-serve --dir ./my-fork --port 4321` to skip the fetch step.
271
+
272
+ The dev source is persisted in `localStorage.VIDFARM_DEV_SOURCE`, so you don't need to keep the `?dev=` param in the URL after the first load.
273
+
249
274
  ## What NOT to do
250
275
 
251
276
  - Do **not** manipulate composition HTML by string concatenation. Always parse, edit, and re-serialize the DOM. The editor and runtime rely on `data-start`, `data-duration`, `data-track-index`, `data-hf-id`, `data-composition-id` attributes being well-formed.
@@ -291,3 +316,78 @@ curl -X POST "$VIDFARM_BASE/api/v1/primitives/images/remove-background" \
291
316
  -H "content-type: application/json" \
292
317
  -d '{"source_image_url": "https://cdn.example.com/photo.jpg"}'
293
318
  ```
319
+
320
+ ## Primitive: media_dedupe
321
+
322
+ Apply subtle camouflage transforms (zoom, tilt, rotate, saturation, playback speed, contrast, brightness, hue rotate, blur, horizontal flip, tint overlay) to any source **image or video** URL. Useful when reposting existing media and you want small perceptual differences to reduce duplicate-detection.
323
+
324
+ - `POST /api/v1/primitives/media/dedupe`
325
+ - Body: `{ "tracer": "...", "payload": { ...fields... }, "webhook_url"?: "..." }`
326
+ - Response: standard primitive job. Poll to completion, then read `primary_file_url` (also `video.file_url` for MP4 or `image.file_url` for stills)
327
+ - Billing: metered as a Remotion render (via `remotion_lambda` on prod, local fallback in dev)
328
+
329
+ Payload fields:
330
+
331
+ - `source_media_url` (required, URL) — the image or video to transform
332
+ - `media_type` (`"image" | "video"`, optional) — auto-detected from URL extension if omitted (`.mp4/.mov/.webm/.m4v` → video, else image)
333
+ - `effects` (optional object). All fields optional; defaults camouflage lightly:
334
+ - `zoom` (default `1.04`) — scale factor
335
+ - `tilt` (default `3`) — degrees of 3D X-axis tilt (perspective 1000px)
336
+ - `rotate` (default `3`) — degrees of 2D rotation
337
+ - `saturation` (default `1.05`)
338
+ - `speed` (default `1.05`, video only) — playback rate, also compresses output duration accordingly
339
+ - `horizontal_flip` (default `false`)
340
+ - `contrast` (default `1.05`)
341
+ - `brightness` (default `1.05`)
342
+ - `hue_rotate` (default `0`) — degrees
343
+ - `blur` (default `0`) — pixels
344
+ - `tint_color` (default `"#FF8C00"`), `tint_opacity` (default `0.08`) — subtle color overlay
345
+ - `width` (default `1080`), `height` (default `1920`) — output canvas
346
+ - `duration_ms` — output duration for video; if omitted, `fallback_duration_ms` (default `5000`) is used
347
+ - `object_fit` (`"cover" | "contain" | "fill" | "none" | "scale-down"`, default `"cover"`)
348
+ - `background_color` (default `"#000000"`) — visible when `object_fit` leaves letterboxing
349
+ - `muted` (default `false`), `volume` (default `1`) — audio pass-through on video
350
+ - `output_format` (`"png" | "jpeg" | "webp"`, default `"png"`) — image mode only; video mode always outputs MP4
351
+
352
+ Video example (camouflage a reused clip):
353
+
354
+ ```bash
355
+ curl -X POST "$VIDFARM_BASE/api/v1/primitives/media/dedupe" \
356
+ -H "authorization: Bearer $VIDFARM_API_KEY" \
357
+ -H "content-type: application/json" \
358
+ -d '{
359
+ "tracer": "dedupe-2026-07-01-abc",
360
+ "payload": {
361
+ "source_media_url": "https://cdn.example.com/reel.mp4",
362
+ "media_type": "video",
363
+ "duration_ms": 8500,
364
+ "effects": {
365
+ "zoom": 1.05,
366
+ "tilt": 2,
367
+ "rotate": -2,
368
+ "speed": 1.03,
369
+ "hue_rotate": 4,
370
+ "horizontal_flip": true
371
+ },
372
+ "tint_color": "#00A3FF",
373
+ "tint_opacity": 0.06
374
+ }
375
+ }'
376
+ ```
377
+
378
+ Image example:
379
+
380
+ ```bash
381
+ curl -X POST "$VIDFARM_BASE/api/v1/primitives/media/dedupe" \
382
+ -H "authorization: Bearer $VIDFARM_API_KEY" \
383
+ -H "content-type: application/json" \
384
+ -d '{
385
+ "tracer": "dedupe-still-01",
386
+ "payload": {
387
+ "source_media_url": "https://cdn.example.com/photo.jpg",
388
+ "media_type": "image",
389
+ "effects": { "zoom": 1.06, "rotate": -1, "hue_rotate": 8 },
390
+ "output_format": "webp"
391
+ }
392
+ }'
393
+ ```
package/SKILL.platform.md CHANGED
@@ -58,19 +58,23 @@ Query patterns use GSIs on `customerId`, `forkId`, `granteeId`, `slug`, and `sta
58
58
 
59
59
  ### S3 — composition storage
60
60
 
61
- Bucket per stage. Layout is **ownership-agnostic** — the customerId does not appear in the S3 key. Access control is enforced at the API layer via the DynamoDB permission records.
61
+ Bucket per stage. Layout is **ownership-agnostic** — the customerId does not appear in the S3 key.
62
62
 
63
63
  ```
64
64
  compositions/forks/<forkId>/
65
65
  ├── working/
66
66
  │ ├── composition.html # current editor state
67
67
  │ ├── composition.json # current metadata (scenes, captions, viral DNA)
68
+ │ ├── manifest.json # fork identity + genealogy pointer
68
69
  │ └── ghostcut.json # GhostCut subtitle-removal task state (optional)
69
70
  └── versions/<version>/
70
71
  ├── composition.html
71
- └── composition.json
72
+ ├── composition.json
73
+ └── manifest.json # frozen version manifest
72
74
  ```
73
75
 
76
+ The `compositions/forks/*` prefix is **public-read** in the bucket resource policy — any client with a `forkId` can fetch `composition.html` / `composition.json` / `manifest.json` directly from S3 without a Lambda proxy hop. The `forkId` is treated as an unguessable bearer token (revoking share = generating a new fork). Write access is still gated at the API by `assertForkAccess(..., "edit" | "publish" | "share" | "delete")`. See `isPublicStorageKey` in `src/services/storage.ts`.
77
+
74
78
  Additional prefixes:
75
79
 
76
80
  - `renders/vidfarm/<slug>/<render-id>/output.mp4` — published MP4s
@@ -78,7 +82,35 @@ Additional prefixes:
78
82
  - `template-assets/<slug>/...` — template media
79
83
  - `user-attachments/<customerId>/...` — chat panel uploads (only ownership-keyed area remaining)
80
84
 
81
- Old ownership-keyed composition paths (`compositions/users/<customerId>/forks/...`) were migrated away by `scripts/migrate-compositions-to-ownership-agnostic.ts`. Old `decomposition.json` was renamed to `composition.json` by `scripts/migrate-decomposition-to-composition.ts`.
85
+ Old ownership-keyed composition paths (`compositions/users/<customerId>/forks/...`) were migrated away by `scripts/migrate-compositions-to-ownership-agnostic.ts`. Old `decomposition.json` was renamed to `composition.json` by `scripts/migrate-decomposition-to-composition.ts`. Forks written before the manifest rollout won't have `manifest.json` until their next mutation — reads must tolerate 404.
86
+
87
+ ### manifest.json
88
+
89
+ Written next to `composition.html` / `composition.json` in both `working/` and `versions/<n>/`. Lets clients traverse fork genealogy and jump between versions without a DynamoDB round-trip.
90
+
91
+ ```json
92
+ {
93
+ "fork_id": "...",
94
+ "customer_id": "...",
95
+ "is_working": true,
96
+ "version": null,
97
+ "latest_version": 3,
98
+ "parent_fork_id": "fork_abc" | null,
99
+ "parent_version": 2 | null,
100
+ "source_slug_id": "...",
101
+ "source_video_id": "..." | null,
102
+ "visibility": "private" | "unlisted" | "public",
103
+ "title": "...",
104
+ "composition_url": "https://.../composition.html",
105
+ "composition_json_url": "https://.../composition.json",
106
+ "manifest_url": "https://.../manifest.json",
107
+ "parent_manifest_url": "https://.../versions/2/manifest.json" | null,
108
+ "created_at": "...",
109
+ "updated_at": "..."
110
+ }
111
+ ```
112
+
113
+ Writes are centralized in `writeForkManifest()` in `src/services/fork-manifest.ts`. `snapshotForkVersion()` writes both the version manifest AND refreshes the working manifest (so `latest_version` stays in sync). Every working-only mutation site (create, PUT html, PATCH json, visibility, decompose, ghostcut swap, export) also calls it.
82
114
 
83
115
  ## Composition model
84
116
 
@@ -119,7 +151,7 @@ A composition is a single HTML document plus a JSON sidecar.
119
151
  }
120
152
  ```
121
153
 
122
- Both files are treated as immutable per version. The working state is mutable.
154
+ All three files (`composition.html`, `composition.json`, `manifest.json`) are treated as immutable per version. The working state is mutable.
123
155
 
124
156
  ## Composition runtime
125
157
 
@@ -287,7 +319,7 @@ Top-level:
287
319
 
288
320
  Legacy but still active:
289
321
 
290
- - `auto-create-templates/` — extractor prompts for the older template creation flow. Still consumed by `src/cli.ts` (`autocreate-template` command) and `demo/scripts/dev.mjs`. Migrate the CLI before deleting.
322
+ - `auto-create-templates/` — extractor prompts for the older template creation flow. Only `extractor-system-prompt.md` and `production-graph.schema.json` are still live (loaded by `demo/scripts/dev.mjs`); the rest is inert docs kept for reference.
291
323
  - `src/account-pages-legacy.ts`, `src/dev-app-legacy.ts` — HTML-string page renderers wrapped by `.tsx` React shells (`account-pages.tsx`, `dev-app.tsx`). Still active.
292
324
 
293
325
  ## Common failure modes
@@ -302,11 +334,39 @@ Legacy but still active:
302
334
 
303
335
  - Composition endpoints — `src/app.ts` under `COMPOSITIONS_PREFIX` (~line 6970+)
304
336
  - Fork CRUD & permissions — `src/services/serverless-records.ts`, `src/services/fork-access.ts`
305
- - Storage keys — `src/services/storage.ts`
337
+ - Storage keys + public-read prefix list — `src/services/storage.ts`
338
+ - Fork manifest.json helper — `src/services/fork-manifest.ts`
306
339
  - Composition runtime script — `src/composition-runtime.ts`
307
340
  - Trackpad Editor — `demo/src/HyperframesStudioEditor.tsx`
341
+ - Editor local-mode bootstrap — `demo/src/dev-mode.ts`
342
+ - Devcli (`vidfarm-devcli`) — `src/cli.ts` (edit-mode fetch + banner), `src/dev-serve.ts` (raw HTTP shim)
308
343
  - Auto-decompose logic — `src/hyperframes/composition.ts` (time-slice), `src/services/hyperframes.ts` (smart)
309
344
  - Publish flow — `src/app.ts` `publishCompositionToRenderer()`
310
345
  - Ghostcut — `src/services/ghostcut.ts`
311
346
  - CDK stack — `infra/cdk/lib/vidfarm-serverless-staging-stack.ts`, `infra/cdk/lib/vidfarm-prod-stack.ts`
347
+
348
+ ## Local editor dev loop
349
+
350
+ `@mevdragon/vidfarm-devcli` (`src/cli.ts` + `src/dev-serve.ts`) pairs a local directory of composition files with the hosted Trackpad Editor so Claude Code, Codex, or a human can edit `composition.html` on disk and see instant preview reload in the browser.
351
+
352
+ ```bash
353
+ # One-shot: fetch composition, start dev-serve, print editor URL.
354
+ vidfarm-devcli <template_id>
355
+ # → downloads composition.html/json + manifest.json into .vidfarm/<template_id>/
356
+ # → listens on http://localhost:4321
357
+ # → prints https://vidfarm.cc/editor/<template_id>?fork=<forkId>&dev=http%3A%2F%2Flocalhost%3A4321
358
+
359
+ # Advanced: skip fetch, serve an existing directory.
360
+ vidfarm-devcli dev-serve --dir ./my-fork --port 4321
361
+ # Then open the editor with ?dev=1 (or ?dev=host:port / ?dev=<full-url>)
362
+ ```
363
+
364
+ Edit flags: `--port`, `--dir`, `--host`, `--fork`, `--api-key` (or `VIDFARM_API_KEY`), `--share`, `--refetch`.
365
+
366
+ `dev-serve` behavior:
367
+ - Serves `composition.html` / `composition.json` / `manifest.json` (and `/versions/{n}/…`) with CORS `*`.
368
+ - Accepts `PUT /composition.html` and `PATCH /composition.json`.
369
+ - Watches the dir with `fs.watch`, coalesces bursts, fans out reload events via `GET /_events` SSE.
370
+
371
+ The editor side lives in `demo/src/dev-mode.ts` — a self-installing module imported at the top of `demo/src/main.tsx`. It reads `?dev=<url>` (persisted to `localStorage.VIDFARM_DEV_SOURCE`), monkey-patches `window.fetch` to rewrite `/api/v1/compositions/{forkId}/*` → `${devSource}/*`, injects a persistent orange banner with an Exit button, and dispatches `vidfarm:dev-reload` on SSE reload events. `HyperframesStudioEditor.tsx` listens for that event and re-runs the composition fetch effect with `cache: "reload"`.
312
372
  - Lambdas — `infra/lambda/*.ts`