@mevdragon/vidfarm-devcli 0.2.7 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/.env.example +9 -0
  2. package/GETTING_STARTED.developers.md +1 -30
  3. package/README.md +22 -5
  4. package/SKILL.developer.md +464 -12
  5. package/auto-create-templates/AUTO_CREATE_TEMPLATES.md +475 -0
  6. package/auto-create-templates/extractor-system-prompt.md +113 -0
  7. package/auto-create-templates/production-graph.schema.json +276 -0
  8. package/auto-create-templates/runbook.md +140 -0
  9. package/auto-create-templates/template-plan.schema.json +230 -0
  10. package/auto-create-templates/template-planner-prompt.md +75 -0
  11. package/dist/src/account-pages-legacy.js +9064 -0
  12. package/dist/src/account-pages.js +41 -620
  13. package/dist/src/app.js +7173 -494
  14. package/dist/src/cli.js +525 -29
  15. package/dist/src/config.js +14 -7
  16. package/dist/src/context.js +51 -35
  17. package/dist/src/db.js +1049 -55
  18. package/dist/src/dev-app-legacy.js +693 -0
  19. package/dist/src/dev-app.js +4 -904
  20. package/dist/src/domain.js +1 -1
  21. package/dist/src/editor-chat-history.js +72 -0
  22. package/dist/src/editor-chat.js +202 -0
  23. package/dist/src/frontend/flockposter-cache-store.js +116 -0
  24. package/dist/src/frontend/homepage-client.js +114 -0
  25. package/dist/src/frontend/homepage-shared.js +3 -0
  26. package/dist/src/frontend/homepage-store.js +27 -0
  27. package/dist/src/frontend/homepage-view.js +147 -0
  28. package/dist/src/frontend/page-runtime-client.js +100 -0
  29. package/dist/src/frontend/page-runtime-store.js +8 -0
  30. package/dist/src/frontend/template-editor-chat.js +2261 -0
  31. package/dist/src/homepage.js +695 -339
  32. package/dist/src/lib/template-paths.js +10 -4
  33. package/dist/src/lib/template-style-options.js +95 -15
  34. package/dist/src/page-runtime.js +1 -0
  35. package/dist/src/page-shell.js +941 -0
  36. package/dist/src/primitive-context.js +163 -0
  37. package/dist/src/primitive-registry.js +340 -0
  38. package/dist/src/primitive-sdk.js +3 -0
  39. package/dist/src/primitives/remotion/html-image.js +28 -0
  40. package/dist/src/react-page-shell.js +34 -0
  41. package/dist/src/ready-post-schedule-component.js +1514 -0
  42. package/dist/src/registry.js +44 -18
  43. package/dist/src/runtime.js +6 -1
  44. package/dist/src/services/api-call-history.js +245 -0
  45. package/dist/src/services/auth.js +27 -9
  46. package/dist/src/services/billing.js +248 -9
  47. package/dist/src/services/chat-threads.js +88 -0
  48. package/dist/src/services/job-logs.js +10 -3
  49. package/dist/src/services/jobs.js +13 -2
  50. package/dist/src/services/providers.js +944 -55
  51. package/dist/src/services/rate-limits.js +236 -0
  52. package/dist/src/services/remotion.js +143 -16
  53. package/dist/src/services/storage.js +23 -8
  54. package/dist/src/services/template-certification.js +26 -3
  55. package/dist/src/services/template-loader.js +19 -1
  56. package/dist/src/services/template-sources.js +316 -7
  57. package/dist/src/template-editor-pages.js +2309 -0
  58. package/dist/src/template-editor-shell.js +1507 -0
  59. package/dist/src/worker.js +120 -22
  60. package/package.json +30 -6
  61. package/public/assets/homepage-app.js +54 -0
  62. package/public/assets/homepage-client-app.js +54 -0
  63. package/public/assets/page-runtime-client-app.js +68 -0
  64. package/dist/templates/template_0000/src/lib/images.js +0 -202
  65. package/dist/templates/template_0000/src/remotion/Root.js +0 -33
  66. package/dist/templates/template_0000/src/remotion/index.js +0 -3
  67. package/dist/templates/template_0000/src/sdk.js +0 -3
  68. package/dist/templates/template_0000/src/style-options.js +0 -51
  69. package/dist/templates/template_0000/src/template-dna.js +0 -9
  70. package/dist/templates/template_0000/src/template.js +0 -1441
  71. package/templates/template_0000/README.md +0 -77
  72. package/templates/template_0000/SKILL.md +0 -225
  73. package/templates/template_0000/assets/Abel-Regular.ttf +0 -0
  74. package/templates/template_0000/assets/DMSerifDisplay-Regular.ttf +0 -0
  75. package/templates/template_0000/assets/Montserrat[wght].ttf +0 -0
  76. package/templates/template_0000/assets/SourceCodePro[wght].ttf +0 -0
  77. package/templates/template_0000/assets/TikTokSans-SemiBold.ttf +0 -0
  78. package/templates/template_0000/assets/Yesteryear-Regular.ttf +0 -0
  79. package/templates/template_0000/composition.json +0 -11
  80. package/templates/template_0000/package.json +0 -28
  81. package/templates/template_0000/research/preview/.gitkeep +0 -1
  82. package/templates/template_0000/research/source_notes.md +0 -7
  83. package/templates/template_0000/src/lib/images.js +0 -202
  84. package/templates/template_0000/src/lib/images.ts +0 -241
  85. package/templates/template_0000/src/remotion/Root.js +0 -33
  86. package/templates/template_0000/src/remotion/Root.tsx +0 -75
  87. package/templates/template_0000/src/remotion/index.js +0 -3
  88. package/templates/template_0000/src/remotion/index.tsx +0 -4
  89. package/templates/template_0000/src/sdk.js +0 -3
  90. package/templates/template_0000/src/sdk.ts +0 -122
  91. package/templates/template_0000/src/style-options.js +0 -51
  92. package/templates/template_0000/src/style-options.ts +0 -60
  93. package/templates/template_0000/src/template-dna.js +0 -9
  94. package/templates/template_0000/src/template-dna.ts +0 -15
  95. package/templates/template_0000/src/template.js +0 -1441
  96. package/templates/template_0000/src/template.ts +0 -2042
  97. package/templates/template_0000/template.config.json +0 -21
  98. package/templates/template_0000/tsconfig.json +0 -19
@@ -26,17 +26,84 @@ Do not use this skill for:
26
26
  - production deploys, release admin, or shared cloud infrastructure
27
27
  - asking for AWS, S3, Remotion cloud, or other platform secrets
28
28
 
29
+ ## Hosted Remotion Cost Reporting
30
+
31
+ When a template runs a hosted Remotion Lambda render, template code should report the base render cost back to platform billing.
32
+
33
+ Use the template job context billing helper:
34
+
35
+ ```ts
36
+ await ctx.billing.record({
37
+ type: "render",
38
+ costUsd: 0.35,
39
+ costCenterSlug: "remotion_lambda",
40
+ idempotencyKey: `remotion_lambda:${render.renderId}`,
41
+ occurredAtMs: Date.now(),
42
+ metadata: {
43
+ render_id: render.renderId,
44
+ ...render.metadata
45
+ }
46
+ });
47
+ ```
48
+
49
+ Rules:
50
+
51
+ - only report the raw base Remotion cost in `costUsd`
52
+ - always use `costCenterSlug: "remotion_lambda"` for hosted Remotion Lambda usage
53
+ - always provide a stable `idempotencyKey`, typically derived from `render.renderId`
54
+ - include useful diagnostics in `metadata`, such as `render_id`, composition ID, mode, and output details
55
+ - do not compute customer wallet debits in template code
56
+ - do not set platform pricing policy in template code
57
+
58
+ The platform billing service applies wallet mutations and pricing centrally. The default customer charge currently uses an approximately `20%` safety-buffer markup over reported base cost.
59
+
60
+ Job-status billing response fields are also platform-managed. Template developers do not need to shape the API response; they only need to keep reporting real usage through existing helpers where applicable. The customer-facing job response exposes `billing.consumed_usd` and does not expose internal `base_cost_usd`.
61
+
29
62
  ## Third-Party Publish Rule
30
63
 
31
64
  Third-party template developers publish template code by pushing git commits to GitHub. That is the only code-distribution step they own.
32
65
 
66
+ Default hosted update rule:
67
+
68
+ - for an already-registered template, the default hosted handoff is `publish-update-hosted --commit-sha <sha>`
69
+ - do not default to prod-side branch-head import for normal template updates
70
+ - if the source repo is private, treat artifact publish as the normal path, not as a fallback
71
+ - if `gh` is available, prefer an authenticated local clone such as `gh repo clone <owner>/<repo>` before publishing a hosted update
72
+ - checked-in `about/preview-*` files only become live hosted preview media after platform import and activation sync them into `templates/:template_id/about/*`
73
+
74
+ Important nuance:
75
+
76
+ - GitHub is relevant for the hosted handoff, not for normal local template authoring
77
+ - do not make GitHub setup or GitHub debugging a blocker for local template creation, testing, iteration, or validation
78
+ - if the user is only building or revising a template locally, they should not need to worry about GitHub at all
79
+
33
80
  The third-party developer responsibility is:
34
81
 
35
82
  - build and validate the template locally
36
83
  - commit and push the template folder to GitHub
37
84
  - register or update the hosted template source metadata with `register-source-hosted` so Vidfarm knows which repo, branch, and template folder to import from
85
+ - for an already-registered template update, publish the exact GitHub commit SHA with `publish-update-hosted`
38
86
  - stop there and hand off to the platform team
39
87
 
88
+ Preferred private-repo publish pattern:
89
+
90
+ ```bash
91
+ gh repo clone mevdragon/vidfarm_templates ./vidfarm_templates
92
+ git -C ./vidfarm_templates rev-parse HEAD
93
+ node dist/src/cli.js publish-update-hosted \
94
+ --env-file .env \
95
+ --repo-dir ./vidfarm_templates \
96
+ --template-id <template-id> \
97
+ --slug-id <template-slug> \
98
+ --repo-url https://github.com/mevdragon/vidfarm_templates.git \
99
+ --branch main \
100
+ --template-module-path src/<template-folder>/src/template.ts \
101
+ --skill-path src/<template-folder>/SKILL.md \
102
+ --install-command "npm install --prefix src/<template-folder>" \
103
+ --build-command "npm run build --prefix src/<template-folder>" \
104
+ --commit-sha <exact-github-commit>
105
+ ```
106
+
40
107
  The third-party developer should not:
41
108
 
42
109
  - run `import-source-prod`
@@ -46,8 +113,32 @@ The third-party developer should not:
46
113
 
47
114
  `import-source-prod` and `deploy-template-cycle` are platform-operator commands. They are for internal admin flow, not for external template authors.
48
115
 
116
+ Private repo rule:
117
+
118
+ - if the registered source repo is private, do not treat prod-side `git ls-remote` or raw GitHub import as the primary publish mechanism
119
+ - for private repos, the reliable default is: authenticated local clone -> `publish-update-hosted --commit-sha ...` -> platform review -> admin approve/activate
120
+ - if the registered source repo is private, assume the intended hosted setup is that Vidfarm has already been granted access to it
121
+ - when repo sharing is needed, the repo should be shared with GitHub username `mevdragon`
122
+ - do not treat a private repo itself as a problem if that access assumption is already stated
123
+
49
124
  For third-party developers, Remotion is local and storage should be accessed through Vidfarm helpers. Do not require cloud Remotion setup or hand-written S3 integration for normal template work.
50
125
 
126
+ ## Media Storage Boundary
127
+
128
+ Template job results must keep binary media out of JSON. If a workflow produces, fetches, or accepts image/audio/video bytes, write those bytes through `ctx.storage.putBuffer(...)` and put the returned URL in the job output, manifest, and render inputs.
129
+
130
+ Rules:
131
+
132
+ - use `ctx.storage.putBuffer(...)`, `ctx.storage.putJson(...)`, and `ctx.storage.putText(...)` for artifacts
133
+ - return artifact URLs in fields like `imageUrl`, `thumbnailUrl`, `audioUrl`, `videoUrl`, `files`, `manifest`, and render input objects
134
+ - do not persist `data:image/...;base64,...`, raw base64 strings, Buffers, or large inline SVG/image strings in `result.output`
135
+ - accepting a `data:image/*` input is allowed, but decode it and store it as an artifact before including it in any durable output
136
+ - generated provider media should be stored immediately; never use `Buffer.from(bytes).toString("base64")` as a durable result value
137
+ - Remotion render props may reference artifact URLs; use short-lived inline data only inside a private render helper if it is not returned, logged, or written to a manifest
138
+ - keep manifests lightweight enough to inspect in job history and webhooks; they should describe artifacts by URL, not embed artifact bytes
139
+
140
+ This boundary matters because job results are saved in SQLite, returned by REST APIs, included in webhooks, and surfaced in editor history. Embedding base64 media can turn one small job result into multi-megabyte JSON and break UI history views.
141
+
51
142
  ## Agent Operating Rule
52
143
 
53
144
  If the user gives you a media file, a screenshot, a folder of source assets, or a link to an original viral post and says some variant of "turn this into a template", you should default to this workflow:
@@ -115,40 +206,79 @@ Notes:
115
206
  - at least one runtime AI provider key is usually enough
116
207
  - `GEMINI_API_KEY` is the key used by the built-in DNA analysis commands
117
208
  - `VIDFARM_API_KEY` is needed when calling a hosted Vidfarm API directly, including when minting presigned preview-media uploads through `vidfarm-devcli presign-preview-media`
118
- - `VIDFARM_API_KEY` is also what `vidfarm-devcli register-source-hosted` uses for hosted source registration
209
+ - `VIDFARM_API_KEY` is also what `vidfarm-devcli register-source-hosted` and `vidfarm-devcli publish-update-hosted` use for hosted handoff
119
210
  - local `vidfarm-devcli session` already gives you a seeded local API key for the local runtime
120
211
  - when calling the hosted API directly, include both `vidfarm-user-id` and `vidfarm-api-key` headers
121
212
  - for local `vidfarm-devcli` sessions, you usually do not need to supply `VIDFARM_USER_ID` manually
122
213
  - template authoring is TypeScript-first; create and edit template source as `src/template.ts`, not `src/template.js`
123
214
  - keep exploratory scripts, one-off test runners, scratch validation files, and temporary job-driving code out of `src/`; place them in a repo-local tmp folder that is a sibling to `src` instead, for example `templates/vidfarm_template_0007/tmp/`
124
215
  - when registering a hosted template source, set `template_module_path` to the repo-relative TypeScript entrypoint inside the template folder, for example `templates/vidfarm_template_example/src/template.ts`; the platform build/import flow resolves the compiled `src/template.js` sibling after `npm run build`
125
- - hosted template registration is git metadata only: repo URL, branch, template entrypoint path, and optionally an explicit commit SHA for a specific import
216
+ - hosted template registration is git metadata only: repo URL, branch, and template entrypoint path
126
217
  - if a template moves folders or switches branches, update the registration metadata; if the template code changed but the location stayed the same, just push a new Git commit
127
- - the platform determines whether an update exists by comparing the registered branch head against the latest imported release commit
218
+ - for an already-registered template, submit the exact commit you want reviewed with `publish-update-hosted --commit-sha <sha>`; that command packages the commit locally and uploads a review artifact to platform-controlled S3
219
+ - a local shell GitHub auth failure does not prove the hosted Vidfarm platform lacks repo access
220
+ - if `git ls-remote` fails locally, interpret that as local credential state unless the hosted import flow itself reports a GitHub access error
128
221
  - do not ask for platform secrets like `ENCRYPTION_SECRET`, `API_KEY_SALT`, `WEBHOOK_SECRET`, admin emails, S3 config, or generic AWS credentials
129
222
  - do not ask for `REMOTION_AWS_ACCESS_KEY_ID` or `REMOTION_AWS_SECRET_ACCESS_KEY`
130
223
 
224
+ Current first-class speech model allowlists in the platform runtime:
225
+
226
+ - text-to-speech
227
+ - `openrouter`: `google/gemini-3.1-flash-tts-preview`
228
+ - `gemini`: `gemini-3.1-flash-tts-preview`
229
+ - `openai`: `gpt-4o-mini-tts-2025-12-15`
230
+
231
+ - speech-to-text
232
+ - `openrouter`: `openai/gpt-4o-mini-transcribe`
233
+ - `gemini`: `gemini-3.1-flash-lite-preview`, `gemini-2.5-flash-lite`
234
+ - `openai`: `gpt-4o-mini-transcribe-2025-12-15`
235
+
131
236
  ## Hosted Registration Flow
132
237
 
133
238
  For a third-party developer, the hosted publish handoff is:
134
239
 
135
240
  1. push the repo changes that contain the target template folder
136
241
  2. register the source location if it is new, or update the existing registration if the repo, branch, or template path changed
137
- 3. stop there, then tell the platform operator which branch head or commit SHA should be imported if they ask
242
+ 3. if the template is already registered and the location did not change, publish the exact GitHub commit SHA with `publish-update-hosted`; that command uploads a signed artifact for that commit
243
+ 4. stop there, then tell the platform operator which commit was submitted if they ask
244
+
245
+ If the repo is private or prod-side GitHub access is uncertain, use the exact same `publish-update-hosted` flow anyway. It packages the commit locally and avoids relying on hosted `git ls-remote` or hosted branch-head import as the update path.
138
246
 
139
247
  Registration data should be treated like this:
140
248
 
141
249
  - `repo_url`: the GitHub repo that contains the template code
142
250
  - `branch`: the branch Vidfarm should watch for the latest version, usually `main`
143
251
  - `template_module_path`: the repo-relative path to the template TypeScript entrypoint, for example `src/vidfarm_template_funnychat/src/template.ts`
144
- - `commit_sha`: optional and only needed when you want to import a specific commit instead of the current branch head
252
+ - `install_command`: the exact command that installs dependencies for the registered template source
253
+ - `build_command`: the exact command that leaves the compiled JavaScript entrypoint beside the declared TypeScript entrypoint, or `:` when the compiled `.js` files are already committed and no build step is needed
254
+ - `commit_sha`: for developer publish flow, the exact GitHub commit to package locally and submit for review on an already-registered source
255
+
256
+ Registration command rule:
145
257
 
146
- Do not tell third-party developers to run AWS-backed operator commands just to publish template code. If the task is only "make my updated template available to Vidfarm", the correct answer is GitHub push plus source registration metadata.
258
+ - do not guess `install_command` and `build_command`
259
+ - for a standalone template repo rooted at the template itself, root-level commands like `npm install` and `npm run build` are usually correct
260
+ - for a multi-template repo, the commands must match the registered template folder, usually with `--prefix <template-folder>`
261
+ - if the declared `template_module_path` is `src/vidfarm_template_chadvirgin/src/template.ts`, then a typical install command is `npm install --prefix src/vidfarm_template_chadvirgin`
262
+ - if that template folder already commits `src/template.js`, a typical build command is `:`
263
+ - if that template folder requires compilation, a typical build command is `npm run build --prefix src/vidfarm_template_chadvirgin`
264
+ - a broken `build_command` will block hosted import even if the source registration itself succeeded
265
+ - before telling a user to register or update hosted source metadata, inspect the repo's actual `package.json` files and choose commands that match the template's real location
266
+
267
+ Do not tell third-party developers to run AWS-backed operator commands just to publish template code. If the task is only "make my updated template available to Vidfarm", the correct answer is GitHub push plus source registration metadata for new sources, or GitHub push plus `publish-update-hosted --commit-sha ...` for existing sources.
268
+
269
+ When reasoning about hosted visibility:
270
+
271
+ - the required developer-side outcome is that the intended commit is pushed to the registered branch
272
+ - do not infer hosted GitHub access failure from a local CLI auth error
273
+ - for hosted template updates, the review artifact is uploaded from the developer machine and prod later imports it from S3, so server-side GitHub access is not part of the normal publish path
274
+ - if prod-side import fails on `git ls-remote`, GitHub username/password prompts, or private-repo access, the correct fix is usually to publish the exact commit as an artifact from a locally authenticated checkout, not to keep retrying branch-head import
147
275
 
148
276
  If a developer can register a source but receives `403 Admin access required` when trying to import or activate it, that is the expected boundary, not a blocker they are supposed to solve. It means the handoff point was reached correctly.
149
277
 
150
278
  Hosted registration should use `register-source-hosted`, not a local DB-backed command. That command calls the Vidfarm REST API so the source appears in the production review queue with `pending_review` status.
151
279
 
280
+ For updates to an already-registered template, use `publish-update-hosted` so the exact GitHub commit is packaged locally, uploaded as a signed artifact, and enters review as a pending release without granting approval or activation rights.
281
+
152
282
  ## Template Deploy Cycle
153
283
 
154
284
  If the user explicitly says "template deploy cycle", interpret that as the internal platform-operator sequence:
@@ -157,6 +287,12 @@ If the user explicitly says "template deploy cycle", interpret that as the inter
157
287
  2. approve and activate the new release
158
288
  3. run the prod deploy script if platform code changed, or reuse the current prod image for a formal restart if the change was template-only
159
289
 
290
+ Operator preference rule:
291
+
292
+ - if a pending artifact-backed release already exists for the intended commit, prefer approving and activating that release instead of asking prod to resolve branch head from GitHub
293
+ - activation is the step that syncs checked-in template `about/` preview assets into hosted storage under `templates/:template_id/about/*`
294
+ - if a hosted template exists in the catalog but its preview media redirects to missing S3 keys, re-activating the intended release on a platform build that contains the sync logic is the correct fix
295
+
160
296
  Do not assume "template deploy cycle" means "deploy the entire dirty root repo". If the root worktree has unrelated changes and the release is template-only, prefer reusing the current prod image with:
161
297
 
162
298
  ```bash
@@ -169,8 +305,8 @@ Read these files first when doing template work:
169
305
 
170
306
  1. [GETTING_STARTED.developers.md](/Users/localghost/Projects/OfficeX/OfficeX/ZoomGTM/vidfarm/GETTING_STARTED.developers.md)
171
307
  2. [README.md](/Users/localghost/Projects/OfficeX/OfficeX/ZoomGTM/vidfarm/README.md)
172
- 3. [templates/template_0000/SKILL.md](/Users/localghost/Projects/OfficeX/OfficeX/ZoomGTM/vidfarm/templates/template_0000/SKILL.md)
173
- 4. [templates/template_0000/src/template.ts](/Users/localghost/Projects/OfficeX/OfficeX/ZoomGTM/vidfarm/templates/template_0000/src/template.ts)
308
+ 3. [templates/vidfarm_template_0000/SKILL.md](/Users/localghost/Projects/OfficeX/OfficeX/ZoomGTM/vidfarm/templates/vidfarm_template_0000/SKILL.md)
309
+ 4. [templates/vidfarm_template_0000/src/template.ts](/Users/localghost/Projects/OfficeX/OfficeX/ZoomGTM/vidfarm/templates/vidfarm_template_0000/src/template.ts)
174
310
  5. [src/template-sdk.ts](/Users/localghost/Projects/OfficeX/OfficeX/ZoomGTM/vidfarm/src/template-sdk.ts)
175
311
  6. [src/cli.ts](/Users/localghost/Projects/OfficeX/OfficeX/ZoomGTM/vidfarm/src/cli.ts)
176
312
 
@@ -187,11 +323,33 @@ The contract is:
187
323
  - `jobs` implement the actual work
188
324
  - `configSchema` defines editable per-user template config
189
325
  - `about.viral_dna` and `about.visual_dna` explain why the format wins
326
+ - `about.proposal_generator` tells directors and agents how to turn product/about context into template-native post ideas
327
+ - `about.skeleton_prompt` gives directors and agents a fill-in-the-blanks prompt scaffold for the template
328
+ - `about.sample_prompts` shows future users and agents how to prompt the template well
190
329
  - `SKILL.md` teaches humans and agents how to call the template correctly
191
330
  - the canonical template entrypoint is `src/template.ts`
192
331
 
332
+ The platform-owned helper surface on `ctx.providers` currently includes:
333
+
334
+ - `generateText(...)`
335
+ - `generateImage(...)`
336
+ - `analyzeImageLayout(...)`
337
+ - `generateSpeech(...)`
338
+ - `transcribeSpeech(...)`
339
+
193
340
  Every public template action should remain async and job-based. Prefer one or more named operations behind `POST /api/v1/templates/:templateId/operations/:operationName` instead of inventing custom synchronous endpoints.
194
341
 
342
+ Keep operation design reasonably coarse-grained. These routes are customer-facing, usage-limited API calls, so avoid exploding one user action into a large number of tiny operations unless the workflow genuinely needs that split.
343
+
344
+ Vidfarm already has native queueing for template jobs. When a task needs multiple runs, do not invent a custom batch manager, worker pool, queue coordinator, or other fancy orchestration layer in the template or in temporary validation code. The default pattern is:
345
+
346
+ - submit jobs in a reasonable loop
347
+ - record the returned job IDs
348
+ - poll those jobs through the standard job endpoints
349
+ - if completion will take a while, tell the user to check back later instead of overengineering lifecycle control
350
+
351
+ Use extra job-management code only when the user explicitly asks for it and there is a concrete platform requirement that the built-in queue cannot satisfy.
352
+
195
353
  Templates are expected to evolve through multiple revisions. One-shot generation is not the standard. The standard is:
196
354
 
197
355
  - create a working first pass
@@ -213,7 +371,7 @@ That documentation should describe:
213
371
 
214
372
  - supported provider names
215
373
  - allowed model IDs per provider
216
- - which capability each model is intended for, such as `text`, `image`, `layout_analysis`, or `video`
374
+ - which capability each model is intended for, such as `text`, `image`, `layout_analysis`, `tts`, `stt`, or `video`
217
375
  - whether the list is strict, preferred, or just known-good defaults
218
376
  - any runtime caveats, especially when a provider is only partially supported by the current platform adapter
219
377
 
@@ -238,6 +396,42 @@ const TEMPLATE_PROVIDER_REQUIREMENTS = {
238
396
  } as const;
239
397
  ```
240
398
 
399
+ Recommended baseline model set, matching the current repo examples unless a template has a specific reason to differ:
400
+
401
+ ```ts
402
+ const TEMPLATE_PROVIDER_RECOMMENDATIONS = {
403
+ text: {
404
+ openai: "gpt-5.4",
405
+ gemini: "gemini-3.1-flash-lite",
406
+ openrouter: "qwen/qwen3.6-flash"
407
+ },
408
+ layout_analysis: {
409
+ openai: "gpt-5.4",
410
+ gemini: "gemini-3.1-flash-lite",
411
+ openrouter: "qwen/qwen3.6-flash"
412
+ },
413
+ image: {
414
+ openai: "gpt-image-1",
415
+ gemini: "gemini-3.1-flash-image-preview",
416
+ openrouter: "google/gemini-3.1-flash-image-preview"
417
+ },
418
+ video: {
419
+ openai: "sora-2",
420
+ gemini: "veo-3.0-generate-001"
421
+ },
422
+ tts: {
423
+ openai: "gpt-4o-mini-tts-2025-12-15",
424
+ gemini: "gemini-3.1-flash-tts-preview",
425
+ openrouter: "google/gemini-3.1-flash-tts-preview"
426
+ },
427
+ stt: {
428
+ openai: "gpt-4o-mini-transcribe-2025-12-15",
429
+ gemini: "gemini-3.1-flash-lite-preview",
430
+ openrouter: "openai/gpt-4o-mini-transcribe"
431
+ }
432
+ } as const;
433
+ ```
434
+
241
435
  Important:
242
436
 
243
437
  - this is documentation for humans and agents, not a framework-consumed schema field
@@ -273,7 +467,9 @@ npx @mevdragon/vidfarm-devcli presign-preview-media \
273
467
  --directory drafts/preview
274
468
  ```
275
469
 
276
- That command calls the hosted Vidfarm API with the user's `VIDFARM_API_KEY`, mints a presigned PUT URL scoped under `developer/<user_id>/*`, stores each uploaded file under a UUID path segment while preserving the original filename, uploads the file automatically when `--file` is provided, and returns both the `storage_key` and a public-read `preview_media_url`. Public readability for `developer/<user_id>/*` comes from Vidfarm bucket policy, not from public write access, so objects may be read directly by URL but should not be treated as listable or writable without authenticated API access. Agents should prefer that path for hosted preview uploads whenever the input is a local media file path.
470
+ That command calls the hosted Vidfarm API with the user's `VIDFARM_API_KEY`, mints a presigned PUT URL scoped under `developer/<user_id>/*`, stores each uploaded file under a UUID path segment while preserving the original filename, uploads the file automatically when `--file` is provided, and returns both the `storage_key` and a public-read `preview_media_url`. Public readability for `developer/<user_id>/*` comes from Vidfarm bucket policy, not from public write access, so objects may be read directly by URL but should not be treated as listable or writable without authenticated API access. Agents should prefer that path for hosted preview uploads whenever the input is a local media file path, and should paste the returned absolute `preview_media_url` directly into `about.preview_media` when the template needs to work immediately in the hosted catalog.
471
+
472
+ Do not assume a checked-in repo asset like `about/preview-01.png` already exists at `templates/:template_id/about/*` in hosted S3. That stable template namespace is populated by the platform import and activation flow, not by the developer presign command. Before admin import/activation, the immediately valid hosted preview URL is the returned `developer/<user_id>/*` public URL.
277
473
 
278
474
  ### 2. Start local runtime
279
475
 
@@ -288,6 +484,13 @@ This boots the local API, worker, SQLite state, provider-key seeding, and local
288
484
 
289
485
  Use a folder name that starts with `vidfarm_template_`, such as `templates/vidfarm_template_<nnnn>/`.
290
486
 
487
+ Keep the identifiers separate:
488
+
489
+ - the folder / package name should keep the `vidfarm_template_` prefix
490
+ - the `slugId` should stay clean and human-meaningful, for example `ugc_hooks_v1`
491
+ - `about.title` is the user-facing display title and should not be prefixed with `Vidfarm Template` unless that phrase is genuinely part of the brand or concept
492
+ - avoid redundant titles like `Vidfarm Template UGC Hooks V1` when `UGC Hooks V1` is the actual display name
493
+
291
494
  Example:
292
495
 
293
496
  ```bash
@@ -352,11 +555,19 @@ These commands:
352
555
  - sync the generated DNA module back into the template
353
556
  - populate the strings consumed by `about.viral_dna`, `about.visual_dna`, and `about.link_to_original`
354
557
 
558
+ After DNA analysis, add `about.proposal_generator`, `about.skeleton_prompt`, and `about.sample_prompts` manually. The standard now requires all three. `proposal_generator` should help a director combine product/about information with the template's format to invent many post proposals. `skeleton_prompt` should provide the default fill-in-the-blanks structure a director can instantiate quickly. `sample_prompts` should show what strong final prompts look like. Do not leave any of them as optional polish.
559
+
560
+ Required-field rule:
561
+
562
+ - treat missing required fields as a blocking bug, not as follow-up polish
563
+ - before calling a template "ready", verify every required field in `defineTemplate(...)` is present and populated with real values
564
+ - if a scaffold or older repo shape omits any current required field, update the template to the current contract in the same pass
565
+
355
566
  Do not hand-write these summaries if the CLI can generate them from the source media.
356
567
 
357
568
  ### 6. Implement the actual repeatable workflow
358
569
 
359
- Use [templates/template_0000/src/template.ts](/Users/localghost/Projects/OfficeX/OfficeX/ZoomGTM/vidfarm/templates/template_0000/src/template.ts) as the baseline pattern.
570
+ Use [templates/vidfarm_template_0000/src/template.ts](/Users/localghost/Projects/OfficeX/OfficeX/ZoomGTM/vidfarm/templates/vidfarm_template_0000/src/template.ts) as the baseline pattern.
360
571
 
361
572
  For a new template, make sure it has:
362
573
 
@@ -364,6 +575,15 @@ For a new template, make sure it has:
364
575
  - `slugId`
365
576
  - `version`
366
577
  - `about`
578
+ - `about.title`
579
+ - `about.description`
580
+ - `about.viral_dna`
581
+ - `about.visual_dna`
582
+ - `about.preview_media`
583
+ - `about.link_to_original`
584
+ - `about.proposal_generator` with a reusable instruction for proposal generation
585
+ - `about.skeleton_prompt` with a reusable fill-in-the-blanks prompt scaffold
586
+ - `about.sample_prompts` with multiple concrete examples
367
587
  - `configSchema`
368
588
  - `operations`
369
589
  - `jobs`
@@ -387,6 +607,7 @@ The platform route shape is fixed. A template should work behind:
387
607
 
388
608
  - `GET /api/v1/templates/:templateId`
389
609
  - `GET /api/v1/templates/:templateId/skill`
610
+ - `GET /api/v1/rate-limit-status`
390
611
  - `POST /api/v1/templates/:templateId/config`
391
612
  - `POST /api/v1/templates/:templateId/operations/:operationName`
392
613
  - `GET /api/v1/templates/:templateId/jobs/:jobId`
@@ -395,6 +616,65 @@ The platform route shape is fixed. A template should work behind:
395
616
 
396
617
  Do not invent one-off REST endpoints for template behavior that already fits an operation workflow.
397
618
 
619
+ Template-local docs do not need to restate platform plan names or operation quota numbers unless a template adds stricter limits of its own.
620
+
621
+ Every template-local `SKILL.md` must also include TypeScript route templates for those routes. Treat this as part of the template standard, not optional documentation. The type block must name the concrete template slug, list every operation as a string-literal union, define each operation payload, and show the standard wrapper bodies.
622
+
623
+ Minimum block to adapt per template:
624
+
625
+ ```ts
626
+ type TemplateSlug = "vidfarm_template_example";
627
+ type TemplateOperation = "create_asset" | "render_video";
628
+
629
+ type TemplateConfigRequest = {
630
+ config: {
631
+ defaultProvider?: "openai" | "gemini" | "openrouter" | "perplexity";
632
+ [key: string]: unknown;
633
+ };
634
+ };
635
+
636
+ type SubmitTemplateOperation<TPayload> = {
637
+ tracer?: string;
638
+ payload: TPayload;
639
+ webhook_url?: string;
640
+ };
641
+
642
+ type QueuedJobResponse = {
643
+ job_id: string;
644
+ tracer?: string;
645
+ status: "queued";
646
+ };
647
+
648
+ type JobStatusResponse<TOutput = unknown> = {
649
+ job_id: string;
650
+ template_id: TemplateSlug;
651
+ operation_name: TemplateOperation;
652
+ tracer?: string;
653
+ status: "queued" | "running" | "succeeded" | "failed" | "cancelled";
654
+ progress?: number;
655
+ output?: TOutput;
656
+ error?: string;
657
+ };
658
+
659
+ type TemplateRoute =
660
+ | `GET /api/v1/templates/${TemplateSlug}`
661
+ | `GET /api/v1/templates/${TemplateSlug}/skill`
662
+ | `POST /api/v1/templates/${TemplateSlug}/config`
663
+ | `POST /api/v1/templates/${TemplateSlug}/operations/${TemplateOperation}`
664
+ | `GET /api/v1/templates/${TemplateSlug}/jobs`
665
+ | `GET /api/v1/templates/${TemplateSlug}/jobs/${string}`
666
+ | `GET /api/v1/templates/${TemplateSlug}/jobs/${string}/logs`
667
+ | `POST /api/v1/templates/${TemplateSlug}/jobs/${string}/cancel`;
668
+ ```
669
+
670
+ For collection-style REST reads, use cursor pagination instead of assuming a single unbounded response:
671
+
672
+ - send `limit`
673
+ - if the response returns `next_cursor`, request the next page with `cursor=<that value>`
674
+ - this applies to template job lists, structured logs, artifacts, and the admin source/release queues
675
+
676
+ If the template accepts custom HTML, attachment URLs, generated image prompts, render-slide manifests, provider/model choices, or template-specific output artifacts, include those fields in the route types instead of leaving them as `Record<string, unknown>`.
677
+
398
678
  ### 8. Validate end to end
399
679
 
400
680
  Run:
@@ -418,6 +698,8 @@ Minimum bar:
418
698
  - inspect produced artifacts
419
699
  - if you need ad hoc scripts or test-run inputs to drive this validation, keep them under a sibling `tmp/` folder and not inside `src/`
420
700
 
701
+ For multi-job validation, keep it simple: create the jobs in a loop, wait or poll, inspect the finished results, and move on. Do not turn local validation into a custom batch-processing subsystem.
702
+
421
703
  The expected result is that another agent can rerun the template without reverse-engineering the workflow.
422
704
 
423
705
  ## Golden Path: Natural-Language Revisions
@@ -471,6 +753,7 @@ A revision is not complete just because the code compiles. It is complete when:
471
753
  - the requested change is visible in the output
472
754
  - the change does not obviously regress the core format
473
755
  - the template can still be rerun by another user or agent
756
+ - `about.proposal_generator`, `about.skeleton_prompt`, and `about.sample_prompts` still reflect the best current way to ideate and prompt the template
474
757
  - the usage instructions still match the implementation
475
758
 
476
759
  ## Template Contract
@@ -488,7 +771,16 @@ export const myTemplate = defineTemplate({
488
771
  viral_dna: "Fast creator-style hooks with simple repeatable structure.",
489
772
  visual_dna: "Presentation-led mobile layouts with recognizable creator-native framing.",
490
773
  preview_media: ["templates/ugc_hooks_v1/about/preview-01.jpg"],
491
- link_to_original: "https://www.tiktok.com/@example/video/1234567890"
774
+ link_to_original: "https://www.tiktok.com/@example/video/1234567890",
775
+ proposal_generator:
776
+ "Given the director's product, audience, and positioning, propose multiple UGC hook post ideas that fit this template. Return ideas that can either be used directly as prompts or expanded into a larger series of related prompts.",
777
+ skeleton_prompt:
778
+ "Create a [number]-slide UGC hook post for [audience] about [topic or product]. Hook: [opening]. Middle beats: [proof, story, objection, or comparison]. Ending: [CTA or payoff]. Tone: [voice].",
779
+ sample_prompts: [
780
+ "Create a 3-slide UGC hook sequence for a sleep supplement targeting new parents.",
781
+ "Make a creator-style launch teaser for a skincare serum with one hook, one proof point, and one CTA.",
782
+ "Generate a short product explainer slideshow for a budgeting app aimed at freelancers."
783
+ ]
492
784
  },
493
785
  configSchema: z.object({
494
786
  defaultProvider: z.enum(["openai", "openrouter", "gemini", "perplexity"]).default("openai")
@@ -522,25 +814,177 @@ Keep these roles clear:
522
814
 
523
815
  - `id` is the UUID-style template identifier
524
816
  - `slugId` is the stable human-readable identifier
817
+ - `version` is required and should be an explicit template version string such as `1.0.0`
818
+ - `about.title` is the customer-facing display name; it does not need the folder prefix and should usually read like a normal product/template title
819
+ - `about.description` is required and should explain the reusable output format, not just restate the folder name
820
+ - `about.viral_dna` is required and should describe the repeatable distribution mechanics that make the format work
821
+ - `about.visual_dna` is required and should describe the repeatable visual system, framing, pacing, and composition cues
822
+ - `about.preview_media` is required and should contain checked-in preview asset paths that represent the template well
823
+ - `about.link_to_original` is required and should point to the original inspiration post or source reference when one exists
824
+ - `about.proposal_generator` is required and should help directors turn product/about context into a list of strong post proposals for that template
825
+ - `about.skeleton_prompt` is required and should give directors a template-native fill-in-the-blanks prompt scaffold they can instantiate quickly
826
+ - `about.sample_prompts` is required and should contain realistic, high-signal examples that teach users how to get good results
525
827
  - `operations` define the public API
526
828
  - `jobs` implement the actual work
527
829
  - `smokeTestPayload` is required for each operation
528
830
 
831
+ Required fields checklist:
832
+
833
+ - `id`
834
+ - `slugId`
835
+ - `version`
836
+ - `about.title`
837
+ - `about.description`
838
+ - `about.viral_dna`
839
+ - `about.visual_dna`
840
+ - `about.preview_media`
841
+ - `about.link_to_original`
842
+ - `about.proposal_generator`
843
+ - `about.skeleton_prompt`
844
+ - `about.sample_prompts`
845
+ - `configSchema`
846
+ - at least one operation
847
+ - a valid workflow function for every operation
848
+ - `smokeTestPayload` for every operation
849
+ - template-local `SKILL.md`
850
+
851
+ ## Caption Style Standard
852
+
853
+ For TikTok-native captions, use the platform caption standard exposed by `vidfarm-devcli session` under `starter_style_options`.
854
+
855
+ Canonical font IDs:
856
+
857
+ - `tiktok_sans_semibold`: default native TikTok caption font, backed by `@fontsource/tiktok-sans` or the bundled `TikTokSans-SemiBold.ttf` starter asset
858
+ - `montserrat_semibold`: rounded modern caption style
859
+ - `source_code_pro_bold`: bold monospace caption style
860
+ - `yesteryear`: script caption style
861
+ - `georgia_bold`: bundled Georgia-style bold serif caption, backed by Libre Baskerville from Fontsource
862
+ - `abel`: condensed caption style
863
+
864
+ Legacy aliases remain accepted for older starters:
865
+
866
+ - `montserrat` -> `montserrat_semibold`
867
+ - `source_code_pro` -> `source_code_pro_bold`
868
+
869
+ Canonical text background color IDs:
870
+
871
+ - `black`: `#000000`
872
+ - `red`: `#EA403F`
873
+ - `orange`: `#FF933D`
874
+ - `yellow`: `#F2CD46`
875
+ - `lime_green`: `#78C25E`
876
+ - `teal`: `#77C8A6`
877
+ - `light_blue`: `#3496F0`
878
+ - `dark_blue`: `#3496F0`
879
+ - `violet`: `#5756D4`
880
+ - `pink`: `#F7D7E9`
881
+ - `brown`: `#A3895B`
882
+ - `dark_green`: `#32523B`
883
+ - `blue_gray`: `#2F688C`
884
+ - `light_gray`: `#92979E`
885
+ - `dark_gray`: `#333333`
886
+
887
+ Templates that expose caption styling should use these IDs in `configSchema`, operation payloads, manifests, and docs instead of inventing local names or hardcoding unrelated font stacks. If a template intentionally uses a format-specific typography system, document the exception in the template-local `SKILL.md`.
888
+
889
+ The caption standard is a default, not a hard lock. Templates may support `captionFont: "custom"` or template-specific text rendering when the user explicitly needs typography outside the standard. In that case, keep the standard options available, document the custom fields, and prefer bundled or template-local font assets over system fonts or remote Google Fonts URLs.
890
+
891
+ Best-practice rule:
892
+
893
+ - when creating a new template, the agent should author `about.proposal_generator`, `about.skeleton_prompt`, `about.sample_prompts`, and the template-local `SKILL.md` in the same pass without waiting for a separate follow-up request
894
+ - every template should ship with sample prompts
895
+ - every template should ship with a proposal generator prompt
896
+ - every template should ship with a skeleton prompt that captures the default prompt structure
897
+ - proposal generation should support a workflow of proposal -> prompts -> posts
898
+ - proposal generation should use the skeleton prompt as a quality harness, so the ideas it emits can be instantiated cleanly without inventing a brand-new structure every time
899
+ - proposal outputs should be useful either as direct one-off prompts or as seeds for a whole series
900
+ - sample prompts should feel like strong filled-out versions of the skeleton prompt, not disconnected examples
901
+ - include more than one example so users can see the range of valid requests
902
+ - prefer prompts that are specific enough to be reusable exemplars, not vague one-liners
903
+ - refresh `about.proposal_generator`, `about.skeleton_prompt`, and `about.sample_prompts` when the template's prompting strategy or supported use cases change
904
+
905
+ ## Typical Template Patterns
906
+
907
+ When a developer says "use typical template patterns", interpret that as the default template-authoring contract below unless the template has a strong reason to differ.
908
+
909
+ Authoring defaults:
910
+
911
+ - when creating a new template, automatically write `about.proposal_generator`, `about.skeleton_prompt`, `about.sample_prompts`, and the template-local `SKILL.md`
912
+ - the template-local `SKILL.md` should explain the template's operations, expected payloads, sample requests, provider caveats, and any format-specific guidance future agents need
913
+ - if the template intentionally does not follow one of these patterns, call that out explicitly in the template-local `SKILL.md`
914
+
915
+ Asset-input defaults:
916
+
917
+ - image-generating or slide-generating operations should usually accept either an AI image prompt or an exact image source supplied by the director
918
+ - video-aware operations should usually accept either an AI video prompt or an exact video source supplied by the director when the format benefits from source footage
919
+ - exact media sources should accept either direct URLs or raw prompt text in the same high-level input family when practical
920
+ - URL detection should be robust enough to handle normal query strings and signed URLs; do not assume a media URL has a clean extension with no params
921
+ - media-type detection should prefer explicit user fields first, then MIME type or fetch metadata when available, then conservative URL/path heuristics as a fallback
922
+ - if a template supports file uploads or attachment arrays, document whether it expects a single asset, multiple assets, or either
923
+
924
+ Operation-pattern defaults:
925
+
926
+ - for most image-generation or slide-generation capabilities, provide two operations or two clearly documented modes of one operation
927
+ - one mode should be an explicit director-controlled path where the caller can provide exact copy, exact media, or exact slide instructions
928
+ - one mode should be a full-auto AI path where the caller provides a higher-level prompt or brief and the template decides the detailed text, imagery, and slide plan
929
+ - name these modes clearly in the template-local `SKILL.md` so future agents and developers can tell which route is deterministic versus generative
930
+
931
+ Slideshow-to-video defaults:
932
+
933
+ - any operation that turns slideshow media into a video should, by default, accept `[{ media_url: string, duration_ms: number }]`
934
+ - `media_url` may point to either an image or a video, and the slideshow renderer should handle both
935
+ - when video clips are supplied in slideshow media, preserve the clip visually for the requested slot duration using a documented strategy such as trim, loop, freeze-last-frame, or fit-to-slot
936
+ - when the template needs richer control than this default shape, extend it rather than replacing it with an unrelated format
937
+
938
+ Remotion arbitrary-slide default:
939
+
940
+ - include an arbitrary slide operation when it fits the template family, backed by Remotion rendering
941
+ - that operation should accept either an AI image prompt or custom HTML as the slide source
942
+ - the intended use is arbitrary inserts such as outro call-to-action slides, sponsor cards, transitions, or other one-off slides that do not need a dedicated template-specific generator
943
+ - if custom HTML is accepted, document the styling, sanitization, and asset-loading constraints in the template-local `SKILL.md`
944
+
945
+ Recommended input-shape convention:
946
+
947
+ ```ts
948
+ const TYPICAL_MEDIA_SOURCE = z.object({
949
+ media_url: z.string().url().optional(),
950
+ image_url: z.string().url().optional(),
951
+ video_url: z.string().url().optional(),
952
+ image_prompt: z.string().optional(),
953
+ video_prompt: z.string().optional(),
954
+ html: z.string().optional(),
955
+ duration_ms: z.number().int().positive().optional()
956
+ });
957
+ ```
958
+
959
+ Notes:
960
+
961
+ - templates may expose clearer, narrower schemas than this when that improves usability
962
+ - prefer explicit fields like `image_prompt`, `image_url`, `video_prompt`, and `video_url` over guessing from one overloaded string when designing a new schema
963
+ - if you still accept a single overloaded field for convenience, document the precedence rules clearly
964
+
529
965
  ## Provider Rules
530
966
 
531
967
  Templates should use the provider abstractions already available on `ctx.providers`.
532
968
 
533
969
  Rules:
534
970
 
971
+ - templates do not need to support all of `openai`, `gemini`, and `openrouter`; supporting at least one real provider path is usually enough unless the template explicitly promises broader portability
535
972
  - use the configured provider path instead of hardcoding one provider everywhere
536
973
  - let templates work with whichever supported provider key the developer actually has
537
974
  - keep prompts and model choices configurable when useful
538
975
  - use image attachments when the format depends on source references
539
976
  - avoid requiring multiple provider accounts unless the template genuinely needs them
540
977
 
978
+ Recommended defaults when a template supports these providers:
979
+
980
+ - `openai`: `gpt-5.4` for `text` and `layout_analysis`, `gpt-image-1` for `image`, `sora-2` for `video`, `gpt-4o-mini-tts-2025-12-15` for `tts`, `gpt-4o-mini-transcribe-2025-12-15` for `stt`
981
+ - `gemini`: `gemini-3.1-flash-lite` for `text` and `layout_analysis`, `gemini-3.1-flash-image-preview` for `image`, `veo-3.0-generate-001` for `video`, `gemini-3.1-flash-tts-preview` for `tts`, `gemini-3.1-flash-lite-preview` for `stt`
982
+ - `openrouter`: `qwen/qwen3.6-flash` for `text` and `layout_analysis`, `google/gemini-3.1-flash-image-preview` as the recommended paid `image` default where runtime support exists, `google/gemini-3.1-flash-tts-preview` with PCM for `tts`, `openai/gpt-4o-mini-transcribe` for `stt`
983
+
541
984
  Important distinction:
542
985
 
543
986
  - runtime template generation can use OpenAI, OpenRouter, Gemini, or Perplexity according to template logic
987
+ - first-class speech helpers use a strict runtime allowlist per provider/model pair; if a template needs other speech models, document that it is using a custom provider path instead of the built-in helper
544
988
  - built-in DNA analysis commands currently depend on `GEMINI_API_KEY`
545
989
 
546
990
  ## Storage And Upload Rules
@@ -563,6 +1007,12 @@ Rules:
563
1007
  - prefer `putJson`, `putText`, `putBuffer`, and `getPublicUrl`
564
1008
  - do not scatter files across arbitrary top-level prefixes
565
1009
 
1010
+ Hosted preview-media rule for developers:
1011
+
1012
+ - if an agent uploads preview media with `presign-preview-media`, the resulting hosted `about.preview_media` entry should be the returned absolute `developer/<user_id>/*` URL
1013
+ - only use `templates/:template_id/about/*` in `about.preview_media` when that object already exists there, typically after platform import/activation sync or another platform-managed copy step
1014
+ - a repo-local file such as `about/preview-01.png` is fine for source control and for platform sync, but it is not by itself an immediately valid hosted catalog URL
1015
+
566
1016
  The runtime may back these writes with local filesystem storage or S3 depending on environment. The template should not care.
567
1017
 
568
1018
  ## API Usage
@@ -590,6 +1040,8 @@ After changes, validate with as many of these as apply:
590
1040
  7. poll the job and fetch logs
591
1041
  8. inspect produced artifacts
592
1042
 
1043
+ If you need several runs, submit them in a reasonable loop and poll the returned job IDs. Rely on Vidfarm's native queueing instead of adding bespoke batch scheduling or coordination logic.
1044
+
593
1045
  If you changed slideshow, overlay, or video output behavior, also validate:
594
1046
 
595
1047
  1. output images are the expected aspect ratio