gooseworks 0.4.2 → 0.4.5-dev.15.facf60fb

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 (156) hide show
  1. package/README.md +84 -22
  2. package/dist/agents/staging.d.ts +38 -0
  3. package/dist/agents/staging.d.ts.map +1 -0
  4. package/dist/agents/staging.js +309 -0
  5. package/dist/agents/staging.js.map +1 -0
  6. package/dist/auth/credentials.d.ts +1 -0
  7. package/dist/auth/credentials.d.ts.map +1 -1
  8. package/dist/auth/credentials.js +26 -8
  9. package/dist/auth/credentials.js.map +1 -1
  10. package/dist/auth/device-flow.d.ts +79 -0
  11. package/dist/auth/device-flow.d.ts.map +1 -0
  12. package/dist/auth/device-flow.js +411 -0
  13. package/dist/auth/device-flow.js.map +1 -0
  14. package/dist/auth/login-mode.d.ts +25 -0
  15. package/dist/auth/login-mode.d.ts.map +1 -0
  16. package/dist/auth/login-mode.js +87 -0
  17. package/dist/auth/login-mode.js.map +1 -0
  18. package/dist/auth/oauth-server.d.ts +2 -2
  19. package/dist/auth/oauth-server.d.ts.map +1 -1
  20. package/dist/auth/oauth-server.js +28 -5
  21. package/dist/auth/oauth-server.js.map +1 -1
  22. package/dist/auth/paste-login.d.ts +27 -0
  23. package/dist/auth/paste-login.d.ts.map +1 -0
  24. package/dist/auth/paste-login.js +203 -0
  25. package/dist/auth/paste-login.js.map +1 -0
  26. package/dist/commands/doctor.d.ts +29 -5
  27. package/dist/commands/doctor.d.ts.map +1 -1
  28. package/dist/commands/doctor.js +116 -63
  29. package/dist/commands/doctor.js.map +1 -1
  30. package/dist/commands/fetch.d.ts +1 -0
  31. package/dist/commands/fetch.d.ts.map +1 -1
  32. package/dist/commands/fetch.js +64 -29
  33. package/dist/commands/fetch.js.map +1 -1
  34. package/dist/commands/formats.js +2 -2
  35. package/dist/commands/formats.js.map +1 -1
  36. package/dist/commands/graphics/publish-flow.js +1 -1
  37. package/dist/commands/graphics/publish-flow.js.map +1 -1
  38. package/dist/commands/install.d.ts.map +1 -1
  39. package/dist/commands/install.js +126 -26
  40. package/dist/commands/install.js.map +1 -1
  41. package/dist/commands/launch.d.ts +3 -0
  42. package/dist/commands/launch.d.ts.map +1 -0
  43. package/dist/commands/launch.js +35 -0
  44. package/dist/commands/launch.js.map +1 -0
  45. package/dist/commands/login.d.ts +21 -1
  46. package/dist/commands/login.d.ts.map +1 -1
  47. package/dist/commands/login.js +112 -30
  48. package/dist/commands/login.js.map +1 -1
  49. package/dist/commands/logout.d.ts.map +1 -1
  50. package/dist/commands/logout.js +7 -1
  51. package/dist/commands/logout.js.map +1 -1
  52. package/dist/commands/skills.d.ts +50 -0
  53. package/dist/commands/skills.d.ts.map +1 -0
  54. package/dist/commands/skills.js +160 -0
  55. package/dist/commands/skills.js.map +1 -0
  56. package/dist/commands/styles.js +2 -2
  57. package/dist/commands/styles.js.map +1 -1
  58. package/dist/commands/tool.d.ts +17 -0
  59. package/dist/commands/tool.d.ts.map +1 -0
  60. package/dist/commands/tool.js +239 -0
  61. package/dist/commands/tool.js.map +1 -0
  62. package/dist/commands/update.d.ts.map +1 -1
  63. package/dist/commands/update.js +37 -6
  64. package/dist/commands/update.js.map +1 -1
  65. package/dist/commands/video-local.d.ts +9 -0
  66. package/dist/commands/video-local.d.ts.map +1 -0
  67. package/dist/commands/video-local.js +83 -0
  68. package/dist/commands/video-local.js.map +1 -0
  69. package/dist/commands/video-save.d.ts +3 -0
  70. package/dist/commands/video-save.d.ts.map +1 -0
  71. package/dist/commands/video-save.js +83 -0
  72. package/dist/commands/video-save.js.map +1 -0
  73. package/dist/config.d.ts.map +1 -1
  74. package/dist/config.js +14 -3
  75. package/dist/config.js.map +1 -1
  76. package/dist/environment.d.ts +9 -0
  77. package/dist/environment.d.ts.map +1 -0
  78. package/dist/environment.js +105 -0
  79. package/dist/environment.js.map +1 -0
  80. package/dist/index.js +12 -38
  81. package/dist/index.js.map +1 -1
  82. package/dist/lib/graphics-cache.d.ts.map +1 -1
  83. package/dist/lib/graphics-cache.js +2 -2
  84. package/dist/lib/graphics-cache.js.map +1 -1
  85. package/dist/lib/mcp-client.d.ts +53 -0
  86. package/dist/lib/mcp-client.d.ts.map +1 -0
  87. package/dist/lib/mcp-client.js +196 -0
  88. package/dist/lib/mcp-client.js.map +1 -0
  89. package/dist/lib/video-local-captions.d.ts +83 -0
  90. package/dist/lib/video-local-captions.d.ts.map +1 -0
  91. package/dist/lib/video-local-captions.js +261 -0
  92. package/dist/lib/video-local-captions.js.map +1 -0
  93. package/dist/lib/video-local-runtime.d.ts +8 -0
  94. package/dist/lib/video-local-runtime.d.ts.map +1 -0
  95. package/dist/lib/video-local-runtime.js +201 -0
  96. package/dist/lib/video-local-runtime.js.map +1 -0
  97. package/dist/lib/video-save-mcp.d.ts +9 -0
  98. package/dist/lib/video-save-mcp.d.ts.map +1 -0
  99. package/dist/lib/video-save-mcp.js +162 -0
  100. package/dist/lib/video-save-mcp.js.map +1 -0
  101. package/dist/lib/video-save.d.ts +77 -0
  102. package/dist/lib/video-save.d.ts.map +1 -0
  103. package/dist/lib/video-save.js +440 -0
  104. package/dist/lib/video-save.js.map +1 -0
  105. package/dist/program.d.ts +2 -0
  106. package/dist/program.d.ts.map +1 -0
  107. package/dist/program.js +56 -0
  108. package/dist/program.js.map +1 -0
  109. package/dist/skills/custom-video-skill.d.ts +3 -0
  110. package/dist/skills/custom-video-skill.d.ts.map +1 -0
  111. package/dist/skills/custom-video-skill.js +6 -0
  112. package/dist/skills/custom-video-skill.js.map +1 -0
  113. package/dist/skills/installer.d.ts +12 -6
  114. package/dist/skills/installer.d.ts.map +1 -1
  115. package/dist/skills/installer.js +82 -38
  116. package/dist/skills/installer.js.map +1 -1
  117. package/dist/skills/master-skill.d.ts +34 -28
  118. package/dist/skills/master-skill.d.ts.map +1 -1
  119. package/dist/skills/master-skill.js +2264 -858
  120. package/dist/skills/master-skill.js.map +1 -1
  121. package/dist/skills/package-freshness.d.ts +16 -0
  122. package/dist/skills/package-freshness.d.ts.map +1 -0
  123. package/dist/skills/package-freshness.js +36 -0
  124. package/dist/skills/package-freshness.js.map +1 -0
  125. package/dist/skills/releases.d.ts +12 -0
  126. package/dist/skills/releases.d.ts.map +1 -0
  127. package/dist/skills/releases.js +155 -0
  128. package/dist/skills/releases.js.map +1 -0
  129. package/dist/skills/routes.d.ts.map +1 -1
  130. package/dist/skills/routes.js +12 -6
  131. package/dist/skills/routes.js.map +1 -1
  132. package/dist/skills/staging-content.d.ts +3 -0
  133. package/dist/skills/staging-content.d.ts.map +1 -0
  134. package/dist/skills/staging-content.js +12 -0
  135. package/dist/skills/staging-content.js.map +1 -0
  136. package/dist/utils/browser-preflight.d.ts +29 -0
  137. package/dist/utils/browser-preflight.d.ts.map +1 -0
  138. package/dist/utils/browser-preflight.js +338 -0
  139. package/dist/utils/browser-preflight.js.map +1 -0
  140. package/dist/utils/http.d.ts +7 -1
  141. package/dist/utils/http.d.ts.map +1 -1
  142. package/dist/utils/http.js +5 -1
  143. package/dist/utils/http.js.map +1 -1
  144. package/package.json +11 -3
  145. package/skills/goose-ads/SKILL.md +509 -239
  146. package/skills/goose-product-photos/SKILL.md +161 -60
  147. package/skills/goose-video/SKILL.md +592 -259
  148. package/skills/goose-video-local/SKILL.md +1409 -236
  149. package/skills/gooseworks/SKILL.md +327 -34
  150. package/skills/make-custom-video/SKILL.md +735 -0
  151. package/skills/manifest.json +12 -0
  152. package/skills/routes.json +13 -6
  153. package/dist/skills/fetcher.d.ts +0 -18
  154. package/dist/skills/fetcher.d.ts.map +0 -1
  155. package/dist/skills/fetcher.js +0 -118
  156. package/dist/skills/fetcher.js.map +0 -1
@@ -11,7 +11,7 @@ description: >
11
11
  references a product to photograph. Unlike goose-ads (ad creative) this produces clean PRODUCT
12
12
  photos that can then feed the ad workflow.
13
13
  category: ads
14
- version: 0.2.0
14
+ version: 0.3.0
15
15
  author: GooseWorks
16
16
  tags: [gooseworks, ads, product-photos, photoshoot, product, ecommerce, studio, lifestyle, on-model]
17
17
  ---
@@ -19,26 +19,116 @@ tags: [gooseworks, ads, product-photos, photoshoot, product, ecommerce, studio,
19
19
  # GooseWorks Product Photos — branded product photography
20
20
 
21
21
  The GooseWorks Product Photos skill. You **pick a brand + product and submit one generation**;
22
- the **backend** runs the whole pipeline (compose the shot prompt → generate on `gpt_image_2` →
23
- judge for product fidelity → auto-retry a few times for free) and stores the results. You do NOT
22
+ the **backend** runs the whole pipeline (compose the shot prompt → generate → judge for product
23
+ fidelity → auto-retry a few times for free) and stores the results. You do NOT
24
24
  generate images, call a model, or manage files — this is the exact same workflow the Product
25
25
  Photos studio uses, so the skill and the app can never drift. The point is to **enrich a brand's
26
26
  usable product imagery** — approved photos join the brand kit and can then feed the ad workflow
27
27
  (`goose-ads`).
28
28
 
29
- ## Prerequisite — the GooseWorks MCP server is REQUIRED
30
-
31
- Everything goes through the `mcp__gooseworks__*` tools. If they are not available, **stop and
32
- tell the user to run `gooseworks install --claude --mcp`** (and restart Claude Code). There is no
33
- HTTP/file fallback.
29
+ It shoots a **physical catalog product** (apparel, beauty, consumer goods). A software
30
+ screenshot or an app mockup is not a product photo: that is an image edit, not this skill.
31
+
32
+ ## How to talk to the customer (applies to every message you send them)
33
+
34
+ The customer is a marketer or founder, not an engineer. Everything in this skill about tools,
35
+ fields, files, polling, models and pipeline steps is for YOU. Never pass it on to them.
36
+
37
+ - **Say what they get and what they need to decide, never how it's made.**
38
+ Bad: "Checking the media-proxy helpers for voiceover timestamps and lipsync." / "Generated with
39
+ gpt-image-2 at high quality, mouth closed, passes QC."
40
+ Good: "Recording the voices now." / "Here are your two hosts."
41
+ - **Never mention** tool, file or field names, ids, JSON, commands, scripts, installed software,
42
+ uploads, model or vendor names, timings in seconds or frames, retries, polling, internal statuses
43
+ or your own quality checks. Fix what you can quietly. If they ask how something works, explain it
44
+ simply.
45
+ - **Update them only at milestones they care about**: choices confirmed, script and voices done,
46
+ visuals done, ready to review, finished. One short line each, then stay quiet until the next
47
+ milestone. No update for setup, downloads, uploads or saving.
48
+ - **Money is in credits, with a number**: "the full video uses about N credits". Never "the cheap
49
+ pieces" or "the expensive render".
50
+ - **Problems:** say what it means for them and what they can do, in one or two sentences. No error
51
+ codes or stack traces. Only raise a problem that changes something for them.
52
+ - **Use their words**: script, voice, hook, scene, host, ending, logo, the product shot.
53
+ - **No filler**: no "Great question!", "Certainly!", "I hope this helps!", no restating what they
54
+ just said at length.
55
+
56
+ Example. Instead of a dozen lines about render tools, scripts, uploads and portraits, send:
57
+ "Got it: warm tone, home podcast studio, Brielle as the skeptic and Mark as the believer." then
58
+ "Script and voices are done (about 34 seconds)." then "Ready for you to review: the script, voices,
59
+ both hosts and the ending. You can also review your recipe ingredients in the app: <link>. Say go
60
+ here and I'll make the full video (about N credits)."
61
+
62
+ ## Use current instructions for new work
63
+
64
+ Before a new task in a terminal host, run `gooseworks skills status` once. It compares the
65
+ installed entry files, running CLI and published npm release. An older CLI needs a package
66
+ upgrade before `gooseworks update`; update alone only uses that CLI's bundled instructions.
67
+ Preserve local edits or unknown install provenance. Review/back up before explicitly replacing
68
+ modified files; never quietly reinstall over them. If the release check is unavailable, report
69
+ that freshness is unknown rather than claiming the local copy is latest.
70
+
71
+ For a new recipe run, fetch its package from the connected catalog. Retain the returned
72
+ `version` / `contentHash` and every dependency's hash with the saved package. When reusing a
73
+ saved fetch JSON, `gooseworks fetch <slug> --saved-package <file>` returns the current package
74
+ and a hash comparison without changing that file. With MCP, if the advertised `catalog_fetch`
75
+ schema accepts them, send `saved_content_hash` and `saved_dependency_hashes`; otherwise fetch
76
+ normally and compare the returned hashes yourself. Missing hashes mean unknown, not current.
77
+ The server cannot inspect a client's saved files; hash metadata does not certify later edits.
78
+ Fetch current packages into a new run directory and report stale saved instructions. Preserve
79
+ an existing approved run's recorded package; changing that harness requires a reviewed change
80
+ and approval before spending. Hosted installed snapshots use the existing Skills Update action.
81
+ Skill content and a host's cached MCP tool schemas are separate: refreshing one does not refresh
82
+ the other. Check the actual advertised tools before using new fields.
83
+
84
+ ## No GooseWorks tools in this session? Call them through the CLI
85
+
86
+ The GooseWorks tools named here (for example `account_whoami`, `brand_onboarding`,
87
+ `brand_read`) normally come from the GooseWorks connector. If they are not registered in this
88
+ session but you have a shell with the `gooseworks` CLI signed in (a cloud sandbox such as
89
+ ChatGPT agent, Meta AI or Grok), call the same tool from the shell:
90
+
91
+ ```bash
92
+ npx gooseworks tool <name> '<arguments as a JSON object>'
93
+ ```
94
+
95
+ - Run `npx gooseworks tool --list` once first. It prints the server's rules for using the tools
96
+ and every tool name; `npx gooseworks tool <name> --schema` shows one tool's arguments.
97
+ - The result prints as JSON. When a tool answers with a one-line summary, the fields you act on
98
+ (such as `next_step` and ids) follow under "Data:". It exits 1 when the tool reports an error.
99
+ - Nothing renders as a widget here, so tell the user the result in plain words.
100
+ - The same rules apply as over the connector: state the credit total and get the user's yes
101
+ before paid work.
102
+ - If it says you are not logged in, run `npx gooseworks login --device --no-wait`, show the
103
+ user the link and code it prints, and run `npx gooseworks login --device` once they approve.
104
+
105
+ When the tools are registered in this session, call them directly instead.
106
+
107
+ ## Prerequisite — the GooseWorks connector tools
108
+
109
+ Everything below runs through the GooseWorks connector's tools, by the names this skill uses.
110
+ Match on the tool name: a coding agent may show a server prefix (for example
111
+ `mcp__gooseworks__photos_generate`), a chat app may not.
112
+
113
+ If a tool named here is missing, the GooseWorks connection or its tool list is stale: ask the
114
+ user to reconnect or refresh GooseWorks in their app's connector settings. Installing or
115
+ updating the `gooseworks` CLI never fixes a missing connector tool, so never send a chat-app
116
+ user to a terminal for it. Only a terminal coding agent (Claude Code, Codex, Cursor) that has no
117
+ GooseWorks tools at all connects them, in that terminal, with `gooseworks install --mcp` plus
118
+ `--claude`, `--codex` or `--cursor`, then a restart.
119
+
120
+ Older notes or skill copies may name tools the connector no longer lists. Use the tool this skill
121
+ names instead; `catalog_fetch { type: "skill", slug: "gooseworks-guide" }` maps every old name.
34
122
 
35
123
  ## Start from the brand context — don't re-ask what it already answers
36
124
 
37
125
  If the `gooseworks` router handed you brand context, USE IT. If you were invoked directly, call
38
- `brand_get_context` yourself first. It answers most of the setup questions below, so **do not ask
39
- the user for them**:
126
+ `brand_read { brand_id, sections: ["summary","kit","products","learnings"] }` yourself first, then
127
+ `knowledge_search { brand_id, query: "<the shoot, in the user's words>" }` for saved rules and past
128
+ feedback (an archived photo's reason is saved as a `dont` rule). They answer most of the setup
129
+ questions below, so **do not ask the user for them**:
40
130
 
41
- - **Which product?** — the context's `products[]` are the real catalog entries. Offer them; never
131
+ - **Which product?** — the context's `products` are the real catalog entries. Offer them; never
42
132
  invent a product or ask the user to describe one you can already see.
43
133
  - **What does it look like / what is it made of?** — grounded in the product's stored images and
44
134
  description. Never guess a material, colorway, or silhouette.
@@ -50,79 +140,90 @@ the user for them**:
50
140
  Ask only for the genuinely open choices: the shot `category`, how many photos, quality, and
51
141
  whether a human model is wanted (which needs explicit consent — see the rules).
52
142
 
53
- ## Identity & credits
143
+ ## Credits — state the total, then get a yes
54
144
 
55
- - One agent-scoped token authenticates the tools; they resolve your org automatically. Never
56
- print the token. (You may pass an optional `target` to operate on a specific agent/org, exactly
57
- as the other GooseWorks tools; omit it to use your pinned scope.)
58
- - **Credits are handled by the backend.** `generate_product_photos` reserves the estimated cost up
59
- front and bills only the photos that pass the judge — **automatic retries are free**, and a photo
60
- the judge can't get right (`flagged`) is shown but **never billed**. Call
61
- `estimate_product_photos` first to quote the cost; `get_ad_credits` shows the balance.
145
+ - One token authenticates the tools and resolves your org; never print it. Omit `target`.
146
+ - **Quote first.** Call `photos_generate` with the exact arguments you will submit plus
147
+ `dry_run: true`. It reserves nothing and returns `creditsPerOutput` and `totalCredits`. Pass
148
+ `count` and `quality` explicitly in both calls so the quote matches the run.
149
+ - **Nothing paid runs without the user's explicit yes in this chat, given after you state that
150
+ credit total.** Then submit the same call without `dry_run`.
151
+ - The submit reserves the quoted credits and bills only the photos that pass the judge:
152
+ **automatic retries are free**, and a photo the judge can't get right (`flagged`) is shown but
153
+ **never billed**. The balance is `credits.available_credits` from `account_whoami`. If the
154
+ wallet is short, say so plainly with the total and the balance, and stop.
62
155
 
63
156
  ## The tools
64
157
 
65
158
  **Pick the brand + product**
66
- - `list_ad_brands` — the user's ad brands (get a `brand_id`; also carries `slug`).
67
- - `list_brand_products { brand_id, search?, page?, page_size? }` — the brand's imported products.
68
- Pick a `product_id` to shoot. `search` matches name / type / variant / SKU.
69
- - `import_product { brand_id, kind, url, product_name? }` — import a product if it isn't in the
70
- catalog yet. `kind` is `product_url` (a single product page), `shopify_store` (a store URL →
71
- imports the catalog), or `image_url` (a direct image; requires `product_name`). Returns an import
72
- row with an `id`; if its `status` isn't `complete`, poll `get_product_import` until it is, then
73
- `list_brand_products` to find the new product. (File uploads aren't available over MCP — use a URL.)
74
- - `get_product_import { import_id }` — poll an import until `status` is `complete` or `failed`.
159
+ - `brand_read` with no `brand_id` — the user's brands (each row's `id` is the `brand_id`).
160
+ - `brand_read { brand_id, sections: ["products"], products_query: "<name>" }` — the brand's
161
+ imported products in `products.items`; a product's `id` is the `product_id` to shoot.
162
+ `products_query` matches name / type / variant / SKU / description.
163
+ - Import a product that isn't in the catalog yet (free):
164
+ `brand_update { brand_id, patch: { products: [{ import_url, import_kind, name? }] } }`.
165
+ `import_kind` is `product_url` (a single product page), `shopify_store` (a store URL → imports
166
+ the catalog), or `image_url` (a direct image; also needs `name`). It returns `jobs[]`: poll
167
+ `job_get { job_id, kind: "product_import" }` until it finishes, then read the products again.
168
+ To add a photo the user attached to an existing product:
169
+ `media_upload { brand_id, scope: "product", scope_id: <product_id>, kind: "reference", source: { type: "bytes", filename, content_base64 } }`.
75
170
 
76
171
  **Generate**
77
- - `estimate_product_photos { count, quality? }` — cost preview (per-photo + total credits). `count`
78
- is 1, 2, 4, or 8; `quality` is `low` | `medium` | `high` (default `medium`). Reserves nothing.
79
- - `generate_product_photos { brand_id, product_id, variant_id?, category, controls?, prompt?,
80
- count?, quality?, reference_image_urls?, attestation_accepted? }` — **the one call that makes
81
- photos.** `category` is `apparel` | `beauty` | `cpg` (seeds sensible scene/framing defaults).
82
- Omit `controls` to use the category preset; pass `prompt` as free-text steering **added on top of**
83
- the settings (it doesn't replace them). Returns a generation with an `id` **immediately** — poll
84
- `get_product_photo_generation` until done, then read each `outputs[].final_image_url`.
172
+ - `photos_generate { brand_id, product_id, variant_id?, category, controls?, prompt?, count,
173
+ quality, reference_image_urls?, attestation_accepted?, dry_run? }` — **the one call that makes
174
+ photos** (and, with `dry_run: true`, its free quote). `category` is `apparel` | `beauty` |
175
+ `cpg` (seeds sensible scene/framing defaults). `count` is 1, 2, 4, or 8; `quality` is
176
+ `low` | `medium` | `high`. Omit `controls` to use the category preset; pass `prompt` as
177
+ free-text steering **added on top of** the settings (it doesn't replace them). Returns the
178
+ generation with its `id` **immediately**.
85
179
  **If you request a human model** (`controls.model.presence` is not `none`) you MUST pass
86
180
  `attestation_accepted: true` to confirm the user has the rights for model imagery.
87
- - `get_product_photo_generation { generation_id }` — poll until `status` is `complete`,
88
- `partial_failure`, or `failed`. Each `outputs[]` entry has its own `status` and, once ready, a
181
+ - `photos_read { brand_id, generation_id }` — poll until `status` is `complete`,
182
+ `partial_failure`, or `failed` (`job_get { job_id: <generation id>, kind: "photo_generation" }`
183
+ works too). Each `outputs[]` entry has its own `id`, `status` and, once ready, a
89
184
  `final_image_url`. A `flagged` output is the best attempt but wasn't billed.
90
185
 
91
186
  **Use the results**
92
- - `list_product_photos { brand_id, archived? }` — the brand's generated photos (`archived: false`
93
- = active, `true` = archived).
94
- - `approve_product_photo { output_id }` — approve a photo: links it to the product and makes it
95
- available in the **brand kit**, so `goose-ads` can use it. **Photos are not used anywhere until
96
- approved.**
97
- - `archive_product_photo { output_id, reason? }` — archive a photo; archived photos are **excluded**
98
- from ad generation.
187
+ - `photos_read { brand_id, archived?, product_id?, status? }` — the brand's generated photos
188
+ (`archived: false` = active, `true` = archived).
189
+ - `photos_update { brand_id, output_id, action: "approve" }` — approve a photo: links it to the
190
+ product and makes it available in the **brand kit**, so `goose-ads` can use it. **Photos are
191
+ not used anywhere until approved.**
192
+ - `photos_update { brand_id, output_id, action: "archive", reason? }` — archive a photo; archived
193
+ photos are **excluded** from ad generation, and the reason is saved as a `dont` rule.
99
194
 
100
195
  ## Workflow — shoot a product
101
196
 
102
- 1. **Load the brand context** (`brand_get_context`, or reuse what the router passed you) and
103
- **resolve the brand + product.** `list_ad_brands` → `brand_id`. `list_brand_products` → pick a
104
- `product_id` from the catalog you already know about. If the product genuinely isn't there,
105
- `import_product` (poll `get_product_import`).
106
- 2. **Quote the cost.** `estimate_product_photos { count, quality }` → tell the user credits.
107
- 3. **Generate.** `generate_product_photos { brand_id, product_id, category, count, quality, prompt? }`.
108
- Build `prompt` from the brand's voice/positioning you already have — don't interview the user for it.
109
- Returns a generation `id` right away.
110
- 4. **Poll.** `get_product_photo_generation { generation_id }` until terminal; hand back each
197
+ 1. **Load the brand context** (`brand_read` + `knowledge_search`, or reuse what the router passed
198
+ you) and **resolve the brand + product.** Pick a `product_id` from the catalog you already
199
+ know about. If the product genuinely isn't there, import it and poll the import.
200
+ 2. **Quote the cost.** `photos_generate` with `dry_run: true` and the exact `brand_id`,
201
+ `product_id`, `category`, `count` and `quality` → tell the user the credit total and wait
202
+ for their explicit yes.
203
+ 3. **Generate.** The same `photos_generate` call without `dry_run` (add `prompt` built from the
204
+ brand's voice/positioning you already have — don't interview the user for it). Returns a
205
+ generation `id` right away.
206
+ 4. **Poll.** `photos_read { brand_id, generation_id }` every ~20-30s until terminal; show each
111
207
  `final_image_url`.
112
- 5. **Approve the keepers.** Show the results and let the user pick; `approve_product_photo` the ones
113
- they'd publish (that's what puts them in the brand kit for ads), `archive_product_photo` the rest.
208
+ 5. **Approve the keepers.** Show the results and let the user pick; `photos_update` with
209
+ `action: "approve"` the ones they'd publish (that's what puts them in the brand kit for ads),
210
+ `action: "archive"` the rest.
114
211
 
115
212
  ## Rules
116
213
 
214
+ - **Connector tools only** — a missing tool means the GooseWorks connection is stale: ask the
215
+ user to reconnect or refresh GooseWorks. Never send a chat-app user to a terminal or a CLI
216
+ install.
117
217
  - **Never invent product facts.** The backend grounds the shot on the product's real images; don't
118
218
  describe a product you can't see.
119
219
  - **Use the brand context instead of interviewing the user.** Product, audience, voice, positioning,
120
- logo/colors/fonts all come from `brand_get_context` / the brand kit. Ask only for the shot
220
+ logo/colors/fonts all come from `brand_read` / the brand kit. Ask only for the shot
121
221
  category, count, quality, and model consent.
122
- - **Ask before spending.** Quote the estimate and confirm `count` / `quality` before
123
- `generate_product_photos` — it reserves credits.
222
+ - **Ask before spending.** State the dry-run credit total and get the user's explicit yes before
223
+ the real `photos_generate` — it reserves credits.
124
224
  - **Poll, don't re-submit.** A generation that's still `running` is not stuck; re-submitting
125
- double-bills. Only a `failed` generation should be retried.
225
+ double-bills. A `failed` generation may still hold `flagged` photos (shown, never billed):
226
+ show those first, and run again only after a new quote and the user's yes.
126
227
  - **Model imagery needs consent.** Only set a human model when the user asks, and pass
127
228
  `attestation_accepted: true`.
128
229
  - **Approval is the hand-off to ads.** Remind the user that only **approved** photos reach the brand