@cliangdev/conductor 0.27.1 → 0.28.0

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 (43) hide show
  1. package/assets/claude/agents/conductor-content-art-director.md +16 -4
  2. package/assets/claude/agents/conductor-content-scriptwriter.md +4 -0
  3. package/assets/claude/commands/conductor/creative.md +2 -1
  4. package/assets/claude/skills/conductor-content-studio/SKILL.md +39 -17
  5. package/assets/claude/skills/conductor-content-studio/references/capabilities.md +11 -2
  6. package/assets/claude/skills/conductor-content-studio/references/compliance-checklist.md +1 -0
  7. package/assets/claude/skills/conductor-content-studio/references/idea-template.md +6 -1
  8. package/assets/claude/skills/conductor-content-studio/references/publish-pack-template.md +3 -1
  9. package/assets/claude/skills/conductor-content-studio/references/script-template.md +1 -1
  10. package/assets/claude/skills/conductor-creative/SKILL.md +33 -8
  11. package/assets/cli-manifest.json +8 -0
  12. package/dist/commands/doctor.d.ts +5 -0
  13. package/dist/commands/doctor.d.ts.map +1 -1
  14. package/dist/commands/doctor.js +20 -0
  15. package/dist/commands/doctor.js.map +1 -1
  16. package/dist/lib/codex-image.d.ts +51 -0
  17. package/dist/lib/codex-image.d.ts.map +1 -0
  18. package/dist/lib/codex-image.js +329 -0
  19. package/dist/lib/codex-image.js.map +1 -0
  20. package/dist/lib/media-probe.d.ts +4 -0
  21. package/dist/lib/media-probe.d.ts.map +1 -1
  22. package/dist/lib/media-probe.js +5 -2
  23. package/dist/lib/media-probe.js.map +1 -1
  24. package/dist/lib/provenance-sidecar.d.ts +19 -0
  25. package/dist/lib/provenance-sidecar.d.ts.map +1 -0
  26. package/dist/lib/provenance-sidecar.js +39 -0
  27. package/dist/lib/provenance-sidecar.js.map +1 -0
  28. package/dist/mcp/index.d.ts +531 -0
  29. package/dist/mcp/index.d.ts.map +1 -1
  30. package/dist/mcp/index.js +34 -2
  31. package/dist/mcp/index.js.map +1 -1
  32. package/dist/mcp/tools/creative-drafts.d.ts +12 -0
  33. package/dist/mcp/tools/creative-drafts.d.ts.map +1 -1
  34. package/dist/mcp/tools/creative-drafts.js +31 -6
  35. package/dist/mcp/tools/creative-drafts.js.map +1 -1
  36. package/dist/mcp/tools/creative-images.d.ts +39 -0
  37. package/dist/mcp/tools/creative-images.d.ts.map +1 -0
  38. package/dist/mcp/tools/creative-images.js +89 -0
  39. package/dist/mcp/tools/creative-images.js.map +1 -0
  40. package/dist/mcp/tools/creatives.d.ts.map +1 -1
  41. package/dist/mcp/tools/creatives.js +7 -0
  42. package/dist/mcp/tools/creatives.js.map +1 -1
  43. package/package.json +1 -1
@@ -15,7 +15,7 @@ send to the draft renderer, so it has to be valid on the first try.
15
15
  - Read only the files you are given: `script.md`, `context/media.json`, `context/brand-kit.json`,
16
16
  `references/shotlist-template.md`, `references/platform-specs.md`, `references/capabilities.md` and
17
17
  `references/publish-pack-template.md` when given.
18
- - Write only your output files: `direction.md` and, for `RENDER`, `creative-spec.json`.
18
+ - Write only your output files: `direction.md` and, for `RENDER`, `creative-spec.json`, plus `image-prompts.json` when `media.json` has `generate: true`.
19
19
  - Never call Conductor or any MCP tool.
20
20
 
21
21
  ## direction.md
@@ -45,7 +45,9 @@ A single JSON object whose keys are exactly `preview_creative_draft` inputs, and
45
45
  - `photoId`: only an id that appears in `media.json`; or `photoPath` only for a local file the person
46
46
  supplied, given in the request or listed as `local` in `media.json`. Never invent an id or a path.
47
47
  Every STILL, carousel and story needs a photo, and a MOTION needs a photo or clip (see
48
- `references/capabilities.md`). If none is available, stop and say so in `direction.md` rather
48
+ `references/capabilities.md`). If `media.json` has `generate: true` and no library photo fits,
49
+ write `image-prompts.json` instead (below) and omit `photoPath`/`photoId` for those slots; the
50
+ orchestrator fills them. Otherwise, if none is available, stop and say so in `direction.md` rather
49
51
  than writing a spec the preview will refuse.
50
52
  - `typeOverrides` when text must read bigger or smaller on a placement, and `layoutOverrides` for
51
53
  photo height or focal point. Don't change layout just to resize text.
@@ -57,11 +59,21 @@ A single JSON object whose keys are exactly `preview_creative_draft` inputs, and
57
59
  - A story or carousel: `sequenceKind` (`story` 2 to 7 beats, `carousel` 2 to 10 cards, plus
58
60
  `carouselRatio` such as `4x5` or `1x1`) and a `sequence` array of beats, each with `headline`
59
61
  and optional `body`, `photoId` or `photoPath`, `cta`.
60
- - MOTION: `motion` (`preset`, `durationSec` 3 to 60, `background`, `endCard`) and optionally
61
- `audio`. A clip background uses `background.clipMediaId` from `media.json`, or `clipPath` for a
62
+ - MOTION: `motion.preset` (`fade-up`, `word-by-word`, `accent-pop` or `none`), `motion.durationSec`
63
+ (3 to 60), `motion.background` (`{source: "photo", motion: zoom-in|zoom-out|pan-left|pan-right|none}`
64
+ or `{source: "clip", clipMediaId}`), `motion.endCard`, and optionally top-level `audio`. A MOTION
65
+ renders one headline and one optional body plus an end card holding the final frame: no timed
66
+ multi-beat on-screen text (extra beats go in a story or carousel sequence, or the caption). A clip background uses `background.clipMediaId` from `media.json`, or `clipPath` for a
62
67
  user-supplied local file.
63
68
  - Omit any field you do not need. Do not add comments or fields the tool does not take.
64
69
 
70
+ ## image-prompts.json (only when `generate: true`)
71
+
72
+ `{"photo": "<scene prompt>", "beats": {"2": "<scene prompt>"}}` next to the spec: `photo` for the
73
+ main photo, `beats` keyed by sequence position for cards or beats that need their own. Each prompt
74
+ describes the scene, subject, light, framing and where the negative space for the headline sits. No
75
+ text in the image, and no product depiction unless a reference image is listed in `media.json`.
76
+
65
77
  ## Finish
66
78
 
67
79
  Return at most about 150 words: the layout and look in one sentence, any risk you see, and the
@@ -22,6 +22,10 @@ anything.
22
22
  1. Follow the script template exactly: hook, beats table, payoff, CTA, publish copy, copy-rule check.
23
23
  2. The hook lands within 3 seconds, spoken and on screen, and is what the winning idea promised.
24
24
  3. A new beat or pattern interrupt every 3 to 5 seconds. Everything works with the sound off.
25
+ Exception, a `MOTION` idea: Conductor renders exactly one headline and one optional body
26
+ (animated by preset) plus an end card that holds the final frame. Write one on-screen headline
27
+ and body, not timed beats of on-screen text; extra beats belong in a story or carousel sequence
28
+ or the caption.
25
29
  4. Respect the brief's must-say and must-avoid lists. Use approved lines verbatim. If the brand kit
26
30
  requires an accent phrase, mark exactly one `*phrase*` in on-screen headlines. Check every line
27
31
  against the copy rules and write the result in the final section.
@@ -48,7 +48,8 @@ Keep this light — one or two follow-up questions, not a form:
48
48
 
49
49
  - **Static ad / short video from a photo**: the headline (or let the skill draft one from the
50
50
  Knowledge page), and a photo. Call `list_creative_media({kind: "IMAGE"})` first and offer what's
51
- already on hand before asking for a new photo. A new photo is a local file path (a URL: download it
51
+ already on hand before asking for a new photo; no photo fits and none is offered? Offer to generate one with
52
+ `generate_creative_image` (needs Codex installed and `codex login`). A new photo is a local file path (a URL: download it
52
53
  to a local file first) — it is only uploaded after the person approves the preview.
53
54
  - **Video from a clip I have / Post an existing video as-is**: call
54
55
  `list_creative_media({kind: "VIDEO"})` first; if nothing fits, ask for a local path (a URL:
@@ -44,8 +44,9 @@ folder; give subagents absolute paths.
44
44
 
45
45
  ```
46
46
  request.md run.json brief.md script.md direction.md creative-spec.json decision.md
47
+ image-prompts.json (S5, only when generation is enabled)
47
48
  context/ brand-kit.json knowledge.md performance.md learning.md media.json
48
- ideas/ angle-1.md angle-2.md angle-3.md pool.md
49
+ ideas/ angle-1.md angle-2.md angle-3.md pool.md winner.md
49
50
  judging/ scores.md
50
51
  drafts/ finalist-<id>/ (contact sheets from the finalist renders)
51
52
  publish-pack.md publish-pack.json (S5b; see references/publish-pack-template.md)
@@ -124,8 +125,16 @@ Write `request.md` (the request verbatim, `--quick` if given, the platform if st
124
125
  6. Every renderable idea needs a photo (or, for MOTION, a clip); see `references/capabilities.md`. If
125
126
  `media.json` has no unblocked image and no clip, ask once with `AskUserQuestion` before ideating:
126
127
  **Give a photo or two** (local paths; record them in `context/media.json` as `local` entries the
127
- art director may use via `photoPath`) or **Plan for filming** (ideas will be `FILM`). Never let
128
- the team design a type-only still; the preview refuses it.
128
+ art director may use via `photoPath`), **Generate with Codex** (record `"generate": true` in
129
+ `context/media.json`; ideas can then be `RENDER` with no library photo, each giving an
130
+ `imagePrompt`, and photos are made with `generate_creative_image` from the person's local Codex CLI)
131
+ or **Plan for filming** (ideas will be `FILM`). Never let the team design a type-only still; the
132
+ preview refuses it.
133
+ When the library does have usable images, or the request itself asks for generated imagery, set
134
+ `"generate": true` without asking: ideas use a library photo when one fits and give an
135
+ `imagePrompt` only when none does. If `generate_creative_image` later fails (Codex missing, logged
136
+ out, or a plan without image generation), treat that finalist as unrenderable in S3b; at S6, say
137
+ why and ask for a photo instead of offering Approve & upload.
129
138
 
130
139
  ### S1 — Strategist -> `brief.md`
131
140
 
@@ -165,7 +174,9 @@ before each score, and names the top 3. Store the finalists in `run.json`.
165
174
 
166
175
  For each `RENDER` finalist, call `preview_creative_draft` with that idea's draft spec (map the
167
176
  draft-spec block to the tool's fields) and `draftDir` set to `<run>/drafts/finalist-<id>`. Use
168
- `full: false`. Record each draft dir in `run.json`.
177
+ `full: false`. Record each draft dir in `run.json`. For a finalist whose draft spec carries an
178
+ `imagePrompt`, call `generate_creative_image({prompt})` first, eye-check the result, and use its
179
+ path as `photoPath` (generate only for finalists, not the whole pool).
169
180
 
170
181
  - If the validator refuses the copy (accent phrase or a copy rule), fix the copy once yourself and
171
182
  retry. If it still fails, mark that finalist unrenderable in `run.json`, keep its text score, and
@@ -176,7 +187,7 @@ draft-spec block to the tool's fields) and `draftDir` set to `<run>/drafts/final
176
187
  shorter body) and re-preview; otherwise keep it and record the failure for the judge.
177
188
  - `FILM` finalists have no render.
178
189
 
179
- ### S3c — Creative director, visual round -> `decision.md`
190
+ ### S3c — Creative director, visual round (text-only with `--quick`) -> `decision.md`
180
191
 
181
192
  Same agent, mode `visual-round`. Inputs: `brief.md`, `judging/scores.md`, `ideas/pool.md`, the
182
193
  finalist image paths (`drafts/finalist-<id>/sheet.jpg`; the director views them with Read), the
@@ -194,11 +205,13 @@ which idea to take; show the decision at the gate.
194
205
 
195
206
  ### S4 — Scriptwriter -> `script.md`
196
207
 
197
- `Agent(subagent_type: "conductor-content-scriptwriter")` with `brief.md`, `decision.md`, the winning
198
- idea from `ideas/pool.md`, `references/script-template.md`, `references/platform-specs.md` and
208
+ First copy the winning idea's block from `ideas/pool.md` to `ideas/winner.md`. Then
209
+ `Agent(subagent_type: "conductor-content-scriptwriter")` with `brief.md`, `decision.md`, `ideas/winner.md`, `references/script-template.md`, `references/platform-specs.md` and
199
210
  `references/publish-pack-template.md`. Besides the script it writes the Publish copy section: a
200
211
  caption per platform, hashtags, a first comment and 2 to 3 alternate hooks with a hookType each.
201
- When merging into `publish-pack.json`, append each platform's hashtags to its `captionOverride`
212
+ For a `MOTION` winner tell it that the render shows one headline and one optional body, animated
213
+ by preset, then an end card that holds the final frame: no timed multi-beat on-screen text. Extra
214
+ beats belong in a story or carousel sequence, or in the caption. When merging into `publish-pack.json`, append each platform's hashtags to its `captionOverride`
202
215
  (caption, blank line, hashtags): that field is posted verbatim.
203
216
 
204
217
  ### S5 — Art director (`RENDER` only) -> `direction.md` + `creative-spec.json`
@@ -212,8 +225,12 @@ Tell it the supported options: the kit's enabled placements, and the layouts and
212
225
  the creative registry supports (at the time of writing `stacked`, `bleed`, `split` dark only, `card` dark or
213
226
  light; a refusal from the validator names the valid ones). The spec's keys must be exactly
214
227
  `preview_creative_draft` inputs. Give it `references/capabilities.md` too. The spec's `name` is the
215
- idea's title only: never include the internal `I<n>` ID, which means nothing outside this run. A
216
- `FILM` winner skips S5 and goes to the shoot script, below.
228
+ idea's title only: never include the internal `I<n>` ID, which means nothing outside this run. When
229
+ `media.json` has `generate: true`, the art director may also write `image-prompts.json`
230
+ (`{"photo": "...", "beats": {"2": "..."}}`) next to the spec. Before S6, call
231
+ `generate_creative_image` for each prompt, eye-check each image, and set `photoPath` (or
232
+ `sequence[i].photoPath`) in `creative-spec.json`. A `FILM` winner skips S5 and goes to the shoot
233
+ script, below.
217
234
 
218
235
  ### S5b — Publish pack and pre-publish checks (you; RENDER after S5, FILM after the shoot script)
219
236
 
@@ -253,18 +270,23 @@ does not apply is answered "not applicable".
253
270
  re-preview **before** showing anything, and never offer Approve & upload while one still fails.
254
271
  Revise at most twice beyond that; if it is still wrong, show it honestly and say what is off.
255
272
  3. Show the person: the draft image, the finalist sheets of the runners-up (view them from
256
- `drafts/finalist-<id>/sheet.jpg`; say when a runner-up could not be rendered), and a short decision
273
+ `drafts/finalist-<id>/sheet.jpg`; say when a runner-up could not be rendered; with `--quick` no
274
+ sheets exist, so show runners-up by title and tag only), and a short decision
257
275
  summary (the winner and why, the runners-up, what was cut and why), and a short pack summary: the
258
276
  disclosure setting (which toggle, or none), the AI-label setting, the sound and its licence, and
259
277
  the alternate hooks with their types.
260
278
  4. Ask with `AskUserQuestion`, header "Draft", with exactly these four options. `AskUserQuestion`
261
279
  allows at most four, so never add one per runner-up, and **Stop** must always be among them:
262
- - **Approve & upload**: if the spec used a local file (`photoPath`, `clipPath`, `audioPath`),
263
- first ask for its provenance (`source`, `licence`, and whether it is AI-generated) and pass
264
- them to `commit_creative_draft({draftDir, source, licence, aiGenerated})`. Then
265
- `get_creative` and read its `readiness`. If provenance or anything else blocking is missing,
266
- say exactly what and ask for it; never call a Creative done while `ready` is false. After the
267
- commit, write the Creative's id into `publish-pack.json` as `creativeId` (and into `run.json`).
280
+ - **Approve & upload**: the question says approving also confirms the photo carries no burned-in
281
+ text, logo or claim. Ask for provenance (`source`, `licence`, and whether it is AI-generated)
282
+ only for local files the preview lists in `provenance.needed` (a file from
283
+ `generate_creative_image` already carries it), then
284
+ `commit_creative_draft({draftDir, photoChecked: true, source, licence, aiGenerated})` (provenance
285
+ fields only when needed). Then `get_creative` and read its `readiness`. If `state` is the only
286
+ blocking item, `update_creative({creativeId, state: "READY"})` and verify with `get_creative`;
287
+ otherwise say exactly what is missing and ask for it. Never call a Creative done while `ready`
288
+ is false. After the commit, write the Creative's id into `publish-pack.json` as `creativeId` and
289
+ its state into `publish-pack.json` as `creativeState` (and both into `run.json`).
268
290
  - **Use a runner-up**: ask a second `AskUserQuestion` listing the runners-up by title (with
269
291
  their tag; label one that could not be rendered as such and say why, rather than offering it as
270
292
  if it would work). Then set the chosen idea as `winner` and re-run S4 onward for it (S5, S5b and S6,
@@ -26,7 +26,8 @@ needs changing until it fits.
26
26
 
27
27
  - **A photo.** Every STILL needs one, and so does a carousel or story, whose beats inherit the main
28
28
  photo. A MOTION needs a photo or a clip as its background. There are no type-only stills. If
29
- `media.json` has no usable (unblocked) image, a `RENDER` idea needs the person to supply a photo.
29
+ `media.json` has no usable (unblocked) image, a `RENDER` idea needs the person to supply a photo,
30
+ or `media.json` must have `generate: true` so the photo is made with `generate_creative_image`.
30
31
  - **A headline.** If the Brand Kit requires an accent phrase, the headline needs exactly one
31
32
  `*accent phrase*`.
32
33
  - **Copy rules and approved lines.** Every Brand Kit copy rule applies to the headline, body,
@@ -51,11 +52,19 @@ needs changing until it fits.
51
52
  text or a badge under the platform's buttons, is fixed before anyone is asked to approve.
52
53
  - **The caption is never drawn on the artwork.** It goes with the post.
53
54
 
55
+ ## Generated photos
56
+
57
+ When `media.json` has `generate: true`, one generated photo per card or beat (or as a MOTION
58
+ background) is renderable. It comes from `generate_creative_image` (the person's local Codex CLI):
59
+ photographic, no text, logos or screens in the picture, and no depiction of the product unless a real
60
+ reference image is supplied. It is `aiGenerated: true`. Collages, charts and text-in-image stay out.
61
+ Ask for a mid-tone scene: under `bleed`, a dark or night scene can render almost black. For a dark scene, use `card` or `stacked`.
62
+
54
63
  ## What it cannot do (so the idea needs filming or a rethink)
55
64
 
56
65
  - Footage of people, places, cooking or the product in use. Screen recordings of an app.
57
66
  - Voiceover or spoken dialogue: MOTION has music or clip sound, not speech.
58
- - Grids, charts, collages of several photos on one card, illustrations, or generated images.
67
+ - Grids, charts, collages of several photos on one card, illustrations, or text inside an image.
59
68
  Each card is one photo plus text.
60
69
  - Anything that relies on a product claim the brief can't confirm. That's a copy problem, not a
61
70
  rendering one: soften the claim or drop the idea.
@@ -41,6 +41,7 @@ disclose paid, gifted, employee and affiliate relationships; in video, disclose
41
41
  **Is any realistic imagery, video or voice AI-generated or AI-altered?** Check the Creative's and
42
42
  each media file's provenance (`aiGenerated` in `context/media.json`) and the script's visuals.
43
43
 
44
+ - A photo from `generate_creative_image` is `aiGenerated: true`, so this is a **Yes**: the AI label / `isAigc` applies.
44
45
  - **Yes**: set TikTok `isAigc: true` on a video post. Conductor does not send `isAigc` on a TikTok
45
46
  photo post, so for a photo post note "turn on TikTok's AI label by hand" as a manual step. Set
46
47
  YouTube `containsSyntheticMedia: true`. Meta has no option: note that Instagram's and Facebook's
@@ -28,10 +28,15 @@ Draft spec (RENDER only):
28
28
  - body: <max 20 words, or none>
29
29
  - caption: <the post caption, within the platform's limit>
30
30
  - photoId: <id from media.json, or none>
31
+ - imagePrompt: <only when media.json has `generate: true` and no library photo fits: the scene in one line, no text in the image, no product depiction>
31
32
  - sequence: <for a story or carousel only: one line per beat, "headline | body">
32
33
  - motion: <MOTION only: preset, durationSec, background>
33
34
  ```
34
35
 
36
+ The idea's format maps to the publish pack's `tags.format` as: still -> `still`; carousel ->
37
+ `carousel`; story sequence -> `story`; motion text over photo or clip -> `motion`; talking head,
38
+ demo, skit or other -> `film`.
39
+
35
40
  ## Sound
36
41
 
37
42
  An idea may not rely on a trending song. A business account cannot license most trending tracks, so
@@ -40,7 +45,7 @@ name original audio or a Commercial Music Library track, or leave sound out of t
40
45
  ## Tagging honestly
41
46
 
42
47
  - `RENDER` means Conductor can make it end to end: a still, a carousel, a story sequence, or motion
43
- text over photos or clips that exist in `media.json` (or need no photo at all). Nothing in it
48
+ text over photos or clips that exist in `media.json` (or a generated photo, via `imagePrompt`, when `media.json` has `generate: true`; there are no type-only renders). Nothing in it
44
49
  requires a person to be filmed or footage that is not on hand.
45
50
  - `FILM` means it needs real filming: a person speaking to camera, a demonstration, a skit, a
46
51
  product in use. A `FILM` idea has no draft spec; it gets a shoot-ready script instead.
@@ -60,6 +60,7 @@ Run: <runId> Creative: <display id, or "not yet committed"> Tags: hook <type
60
60
  ```json
61
61
  {
62
62
  "creativeId": null,
63
+ "creativeState": null,
63
64
  "platforms": [
64
65
  {
65
66
  "platform": "tiktok",
@@ -84,6 +85,7 @@ Rules:
84
85
 
85
86
  - `creativeId` is null until the person approves the commit (S6, On Approve), then it is the
86
87
  Creative's id. A `FILM` run leaves it null: the publisher is pointed at the pack by the person.
88
+ - `creativeState` is the Creative's state after S6 (`READY`, or `DRAFT` if something still blocks it).
87
89
  - `platforms[]` items are shaped to drop straight into `create_post` targets or
88
90
  `set_publish_targets` targets: `platform`, `format` (`feed`, `reel` or `story`, and only one the destination's `formats` offers: at the time
89
91
  of writing TikTok and YouTube are feed only, Facebook and Instagram offer all three),
@@ -117,5 +119,5 @@ Rules:
117
119
  - `alternateHooks` and `tags` are for learning and experiments, not for publishing. `tags` is also
118
120
  copied into `run.json`.
119
121
  - `tags.angle` is the ideator's angle: `story-emotion`, `utility-education` or `trend-humor`.
120
- `tags.format` is the idea's format (`still`, `carousel`, `story`, `motion`, `clip` or `film`).
122
+ `tags.format` is the idea's format (`still`, `carousel`, `story`, `motion`, `clip` or `film`; map the idea template's formats: story sequence -> `story`, motion text over photo or clip -> `motion`, talking head, demo, skit or other -> `film`; `clip` is for a finished video posted as-is).
121
123
  - Valid JSON, no comments.
@@ -48,6 +48,6 @@ curiosity-gap, story, social-proof.
48
48
  <each must-say / must-avoid item from brief.md, and ok or the fix>
49
49
  ```
50
50
 
51
- Rules: a beat every 3 to 5 seconds; no beat longer than 5 seconds without a visual or text change;
51
+ Rules: a beat every 3 to 5 seconds (a `MOTION` idea instead has one headline, one optional body and an end card, with no timed on-screen beats); no beat longer than 5 seconds without a visual or text change;
52
52
  caption limits are in `platform-specs.md`; alternates differ from the main hook in hook type, not just wording (check current platform guidance); approved lines run
53
53
  verbatim; leave out platforms the brief did not ask for.
@@ -83,7 +83,20 @@ to `commit_creative_draft`, which records them on every file it uploads. This cl
83
83
  exposure: an unattributed or unlicensed photo running as paid or organic media. A photo already in
84
84
  the library is used by its id (`photoId`) with no upload at all.
85
85
 
86
- **Open the photo and look at it before using it.** A picture can break every copy rule with text,
86
+ **Nothing in the library fits, or the person asks for a generated one?** Call
87
+ `generate_creative_image` with a scene prompt drawn from the brand's Knowledge page and the angle:
88
+ the scene, subject, light, framing and where the headline's negative space sits. The tool adds its own
89
+ fixed rules (photographic, no text, letters, logos, UI or phone screens) and runs the person's local
90
+ Codex CLI, so it needs `codex login` on a ChatGPT Plus (or higher) plan (`conductor doctor` reports the login), takes about 30-90 s and uses
91
+ their Codex quota. It returns the first image plus `files[].path`; pass a path as `photoPath` (or
92
+ `sequence[].photoPath`). When the real product must appear, list a real shot in
93
+ `referenceImagePaths` — never describe an invented product. Each file gets a provenance sidecar
94
+ (`aiGenerated: true`) that the preview and commit use automatically, so don't ask about it, and the
95
+ AI label applies. A 1024x1536 image cropped to 9:16 may draw the "soft, upscaled photo" warning:
96
+ mention it, don't fight it.
97
+
98
+ **Open the photo and look at it before using it** — a generated one most of all (pseudo-text, warped
99
+ hands or faces, a fake product or app screen). A picture can break every copy rule with text,
87
100
  a logo or a claim burned into its pixels, and no automated check can see that — this is the first
88
101
  of this skill's silent failure modes (the full list is below). A human or a prior pass marks a bad
89
102
  photo `blocked`; if you notice one that should be, say so rather than using it anyway.
@@ -155,15 +168,25 @@ Only once `passed` is true, show the image to the person and ask with `AskUserQu
155
168
  **Approve & upload**, **Request changes**, **Stop**. If `passed` is false you are not at this step
156
169
  yet: fix it and re-preview first (step 6). On changes, preview again with the edits (another draft; nothing was saved). On
157
170
  Stop, leave it: the draft stays on this machine under `.conductor/drafts/` and is cleaned up
158
- automatically once it is committed or two weeks old. Only on **Approve & upload**, call
159
- `commit_creative_draft({draftDir})` with the `draftDir` the approved preview returned.
171
+ automatically once it is committed or two weeks old. Say in the question that approving
172
+ also confirms the photo carries no burned-in text, logo or claim. Only on **Approve & upload**, call
173
+ `commit_creative_draft({draftDir, photoChecked: true})` with the `draftDir` the approved preview
174
+ returned, plus provenance (`source`, `licence`, `aiGenerated`) only for local files the preview
175
+ lists in `provenance.needed`. Pass `photoChecked` only after that approval, never on your own
176
+ judgement.
160
177
 
161
178
  ### 8. Check readiness before calling it done
162
179
 
163
- The preview already lists the readiness gaps, so fix what you can (caption, alt text, a checked
164
- photo) before asking for approval. After the commit, `get_creative` includes a `readiness` block: caption, alt text, the photo's checked/blocked state
165
- and provenance, and the Creative's own state (not `DRAFT`) are blocking; an AI-generation disclosure
166
- is informational only. Do not call a Creative done while `ready` is false.
180
+ The preview already lists the readiness gaps (including a local file's sidecar provenance), so fix
181
+ what you can (caption, alt text) before asking for approval; the photo check is cleared by the
182
+ approval itself (`photoChecked: true` on the commit, for files that commit uploads; a library photo
183
+ keeps its own verdict). After the commit, `get_creative` includes a `readiness` block: caption, alt
184
+ text, the photo's checked/blocked state and provenance, and the Creative's own state (not `DRAFT`)
185
+ are blocking; an AI-generation disclosure is informational only (when publishing, turn on the
186
+ platform's AI-generated label). If the only blocking item left is `state`, call
187
+ `update_creative({creativeId, state: "READY"})` and verify with `get_creative`; the backend refuses
188
+ READY while anything else blocking fails. Otherwise name exactly what is missing and ask. Do not
189
+ call a Creative done while `ready` is false.
167
190
 
168
191
  ### 9. Commit, then hand off
169
192
 
@@ -223,7 +246,7 @@ A MOTION Creative animates the same brand layout from steps 1-5 above into a sho
223
246
  of a static frame — no separate video tool needed. Use it when a still doesn't hold attention, or a
224
247
  destination rewards video over an image.
225
248
 
226
- 1. Pick a photo (step 5) or, for a moving background, a video — check `list_creative_media({kind:
249
+ 1. Pick a photo (step 5; a generated photo works here too) or, for a moving background, a video — check `list_creative_media({kind:
227
250
  "VIDEO"})` first and use its media id if something fits; otherwise pass the local file as
228
251
  `clipPath` (previewed from disk, uploaded on commit). For background music,
229
252
  `list_creative_media({kind: "AUDIO"})` the same way, else `audioPath`.
@@ -264,6 +287,8 @@ Automated checks are real but incomplete. These are the ones worth remembering t
264
287
  - **A photo with text, a logo or a claim burned into its pixels** passes every copy-rule and
265
288
  render check, because none of them look at pixels for meaning — only step 5's "open and look at
266
289
  it" catches this.
290
+ - **A generated image depicting a product, result or claim that isn't real** (a made-up app screen,
291
+ a before/after, an invented package) passes every check — only looking at it catches it.
267
292
  - **A structurally valid render is not necessarily a good one.** The render's own assertions check
268
293
  spill, safe zones, fonts and contrast — never whether the headline reads at a glance or the copy
269
294
  sits on the subject's face. Step 7 exists because of this gap.
@@ -832,6 +832,14 @@
832
832
  "creativeId"
833
833
  ]
834
834
  },
835
+ {
836
+ "name": "generate_creative_image",
837
+ "description": "Generate a photo locally with the Codex CLI (needs codex login): no text in the image, returns it with local paths and a provenance sidecar. Pass a path as photoPath to preview_creative_draft.",
838
+ "category": "marketing",
839
+ "requiredParams": [
840
+ "prompt"
841
+ ]
842
+ },
835
843
  {
836
844
  "name": "preview_creative_draft",
837
845
  "description": "Look at a Creative before anything is saved: renders a draft locally from the create_creative fields plus local files (photoPath, clipPath, audioPath) and returns the contact sheet as an image. Never writes to Conductor; commit only after the person approves.",
@@ -1,6 +1,11 @@
1
1
  import { Command } from 'commander';
2
+ import { type CodexStatus } from '../lib/codex-image.js';
2
3
  export declare function checkApiHealth(apiUrl: string): Promise<boolean>;
3
4
  export declare function checkMcpJson(workingDir: string): boolean;
4
5
  export declare function checkConfigFile(): boolean;
6
+ export declare function describeCodexStatus(status: CodexStatus): {
7
+ status: 'pass' | 'warn';
8
+ message: string;
9
+ };
5
10
  export declare function registerDoctor(program: Command): void;
6
11
  //# sourceMappingURL=doctor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAMnC,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOrE;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA+GrD"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAInC,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAGvE,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAOrE;AAED,wBAAgB,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAExD;AAED,wBAAgB,eAAe,IAAI,OAAO,CAEzC;AAID,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG;IAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAMrG;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA0HrD"}
@@ -4,6 +4,7 @@ import * as os from 'os';
4
4
  import chalk from 'chalk';
5
5
  import { readConfig, CONFIG_PATH } from '../lib/config.js';
6
6
  import { getAssetSrcDir, getPluginInstallStatus } from '../lib/plugin-assets.js';
7
+ import { checkCodexCli } from '../lib/codex-image.js';
7
8
  import { printNextSteps } from '../lib/next-steps.js';
8
9
  export async function checkApiHealth(apiUrl) {
9
10
  try {
@@ -20,6 +21,15 @@ export function checkMcpJson(workingDir) {
20
21
  export function checkConfigFile() {
21
22
  return fs.existsSync(CONFIG_PATH);
22
23
  }
24
+ const CODEX_CHECK_NAME = 'Codex CLI (image generation)';
25
+ export function describeCodexStatus(status) {
26
+ if (status.state === 'ready')
27
+ return { status: 'pass', message: `${CODEX_CHECK_NAME}: ${status.version}, logged in` };
28
+ if (status.state === 'logged-out') {
29
+ return { status: 'warn', message: `${CODEX_CHECK_NAME}: ${status.version} installed but not logged in — run \`codex login\`` };
30
+ }
31
+ return { status: 'warn', message: `${CODEX_CHECK_NAME}: not found — npm i -g @openai/codex, then \`codex login\` (optional; only needed to generate photos)` };
32
+ }
23
33
  export function registerDoctor(program) {
24
34
  program
25
35
  .command('doctor')
@@ -72,6 +82,8 @@ Examples:
72
82
  if (location !== 'none' && outdated) {
73
83
  checks.push({ name: 'plugin-version', status: 'warn', message: 'Claude plugin outdated — re-run conductor init to update' });
74
84
  }
85
+ const codex = describeCodexStatus(await checkCodexCli());
86
+ checks.push({ name: 'codex', status: codex.status, message: codex.message });
75
87
  const allPass = checks.every(c => c.status !== 'fail');
76
88
  process.stdout.write(JSON.stringify({ checks }, null, 2) + '\n');
77
89
  process.exit(allPass ? 0 : 1);
@@ -118,6 +130,14 @@ Examples:
118
130
  console.log(`${chalk.yellow('⚠')} Claude plugin outdated — re-run conductor init to update`);
119
131
  warnings++;
120
132
  }
133
+ const codex = describeCodexStatus(await checkCodexCli());
134
+ if (codex.status === 'pass') {
135
+ console.log(`${chalk.green('✓')} ${codex.message}`);
136
+ }
137
+ else {
138
+ console.log(`${chalk.yellow('⚠')} ${codex.message}`);
139
+ warnings++;
140
+ }
121
141
  if (failures === 0 && warnings === 0) {
122
142
  printNextSteps();
123
143
  }
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ export type ImageAspect = 'portrait' | 'square' | 'landscape';
2
+ export declare const ASPECT_SIZES: Record<ImageAspect, string>;
3
+ export declare const NO_CODEX_HINT = "Codex CLI not found \u2014 install it (npm i -g @openai/codex) and run `codex login`, or set CONDUCTOR_CODEX_PATH.";
4
+ export declare const NOT_LOGGED_IN_HINT = "Codex CLI is not logged in \u2014 run `codex login` (see `conductor doctor`).";
5
+ export interface GenerateImagesParams {
6
+ prompt: string;
7
+ aspect?: ImageAspect;
8
+ count?: number;
9
+ referenceImagePaths?: string[];
10
+ outDir: string;
11
+ onProgress?: (message: string) => void;
12
+ timeoutMs?: number;
13
+ }
14
+ export interface GeneratedImage {
15
+ path: string;
16
+ width: number;
17
+ height: number;
18
+ }
19
+ export interface GenerateImagesResult {
20
+ files: GeneratedImage[];
21
+ provenance: {
22
+ source: string;
23
+ licence: string;
24
+ aiGenerated: true;
25
+ };
26
+ revisedPrompt: string;
27
+ outDir: string;
28
+ /** JPEG (or small PNG) of the first image for inline display; absent when none fits ~1 MB. */
29
+ preview?: {
30
+ data: Buffer;
31
+ mimeType: string;
32
+ };
33
+ }
34
+ /** `CONDUCTOR_CODEX_PATH`, else `codex` on PATH. Cached for the process lifetime. */
35
+ export declare function resolveCodexPath(): Promise<string>;
36
+ /** Test-only: the resolved path is cached, so tests that vary availability reset it. */
37
+ export declare function resetCodexPathCache(): void;
38
+ export type CodexStatus = {
39
+ state: 'ready';
40
+ version: string;
41
+ } | {
42
+ state: 'logged-out';
43
+ version: string;
44
+ } | {
45
+ state: 'missing';
46
+ };
47
+ /** For `conductor doctor`: never throws. */
48
+ export declare function checkCodexCli(): Promise<CodexStatus>;
49
+ export declare function buildPrompt(scene: string, aspect: ImageAspect, count: number, hasReferences: boolean): string;
50
+ export declare function generateImages(params: GenerateImagesParams): Promise<GenerateImagesResult>;
51
+ //# sourceMappingURL=codex-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-image.d.ts","sourceRoot":"","sources":["../../src/lib/codex-image.ts"],"names":[],"mappings":"AAkBA,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAA;AAE7D,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,WAAW,EAAE,MAAM,CAIpD,CAAA;AAED,eAAO,MAAM,aAAa,uHACuF,CAAA;AACjH,eAAO,MAAM,kBAAkB,kFAA6E,CAAA;AAe5G,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,cAAc,EAAE,CAAA;IACvB,UAAU,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,IAAI,CAAA;KAAE,CAAA;IAClE,aAAa,EAAE,MAAM,CAAA;IACrB,MAAM,EAAE,MAAM,CAAA;IACd,8FAA8F;IAC9F,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAC7C;AAID,qFAAqF;AACrF,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAQxD;AAED,wFAAwF;AACxF,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AA4BD,MAAM,MAAM,WAAW,GACnB;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,KAAK,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,CAAA;AAExB,4CAA4C;AAC5C,wBAAsB,aAAa,IAAI,OAAO,CAAC,WAAW,CAAC,CAoB1D;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,GAAG,MAAM,CAa7G;AA0ID,wBAAsB,cAAc,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA+EhG"}