GooseWorks Product Photos — branded product photography
The GooseWorks Product Photos skill. You pick a brand + product and submit one generation;
the backend runs the whole pipeline (compose the shot prompt → generate on gpt_image_2 →
judge for product fidelity → auto-retry a few times for free) and stores the results. You do NOT
generate images, call a model, or manage files — this is the exact same workflow the Product
Photos studio uses, so the skill and the app can never drift. The point is to enrich a brand's
usable product imagery — approved photos join the brand kit and can then feed the ad workflow
(goose-ads).
Prerequisite — the GooseWorks MCP server is REQUIRED
Everything goes through the mcp__gooseworks__* tools. If they are not available, stop and
tell the user to run gooseworks install --claude --mcp (and restart Claude Code). There is no
HTTP/file fallback.
Start from the brand context — don't re-ask what it already answers
If the gooseworks router handed you brand context, USE IT. If you were invoked directly, call
brand_get_context yourself first. It answers most of the setup questions below, so do not ask
the user for them:
- Which product? — the context's
products[] are the real catalog entries. Offer them; never
invent a product or ask the user to describe one you can already see.
- What does it look like / what is it made of? — grounded in the product's stored images and
description. Never guess a material, colorway, or silhouette.
- What vibe / who is it for? — the context's voice, positioning, and audience already say. Let
them shape the scene and styling instead of asking "what mood do you want?".
- Brand look — logo, colors, and fonts are owned by the backend research pass. Read them, never
re-derive them.
Ask only for the genuinely open choices: the shot category, how many photos, quality, and
whether a human model is wanted (which needs explicit consent — see the rules).
Identity & credits
- One agent-scoped token authenticates the tools; they resolve your org automatically. Never
print the token. (You may pass an optional
target to operate on a specific agent/org, exactly
as the other GooseWorks tools; omit it to use your pinned scope.)
- Credits are handled by the backend.
generate_product_photos reserves the estimated cost up
front and bills only the photos that pass the judge — automatic retries are free, and a photo
the judge can't get right (flagged) is shown but never billed. Call
estimate_product_photos first to quote the cost; get_ad_credits shows the balance.
The tools
Pick the brand + product
list_ad_brands — the user's ad brands (get a brand_id; also carries slug).
list_brand_products { brand_id, search?, page?, page_size? } — the brand's imported products.
Pick a product_id to shoot. search matches name / type / variant / SKU.
import_product { brand_id, kind, url, product_name? } — import a product if it isn't in the
catalog yet. kind is product_url (a single product page), shopify_store (a store URL →
imports the catalog), or image_url (a direct image; requires product_name). Returns an import
row with an id; if its status isn't complete, poll get_product_import until it is, then
list_brand_products to find the new product. (File uploads aren't available over MCP — use a URL.)
get_product_import { import_id } — poll an import until status is complete or failed.
Generate
estimate_product_photos { count, quality? } — cost preview (per-photo + total credits). count
is 1, 2, 4, or 8; quality is low | medium | high (default medium). Reserves nothing.
generate_product_photos { brand_id, product_id, variant_id?, category, controls?, prompt?, count?, quality?, reference_image_urls?, attestation_accepted? } — the one call that makes
photos. category is apparel | beauty | cpg (seeds sensible scene/framing defaults).
Omit controls to use the category preset; pass prompt as free-text steering added on top of
the settings (it doesn't replace them). Returns a generation with an id immediately — poll
get_product_photo_generation until done, then read each outputs[].final_image_url.
If you request a human model (controls.model.presence is not none) you MUST pass
attestation_accepted: true to confirm the user has the rights for model imagery.
get_product_photo_generation { generation_id } — poll until status is complete,
partial_failure, or failed. Each outputs[] entry has its own status and, once ready, a
final_image_url. A flagged output is the best attempt but wasn't billed.
Use the results
list_product_photos { brand_id, archived? } — the brand's generated photos (archived: false
= active, true = archived).
approve_product_photo { output_id } — approve a photo: links it to the product and makes it
available in the brand kit, so goose-ads can use it. Photos are not used anywhere until
approved.
archive_product_photo { output_id, reason? } — archive a photo; archived photos are excluded
from ad generation.
Workflow — shoot a product
- Load the brand context (
brand_get_context, or reuse what the router passed you) and
resolve the brand + product. list_ad_brands → brand_id. list_brand_products → pick a
product_id from the catalog you already know about. If the product genuinely isn't there,
import_product (poll get_product_import).
- Quote the cost.
estimate_product_photos { count, quality } → tell the user credits.
- Generate.
generate_product_photos { brand_id, product_id, category, count, quality, prompt? }.
Build prompt from the brand's voice/positioning you already have — don't interview the user for it.
Returns a generation id right away.
- Poll.
get_product_photo_generation { generation_id } until terminal; hand back each
final_image_url.
- Approve the keepers. Show the results and let the user pick;
approve_product_photo the ones
they'd publish (that's what puts them in the brand kit for ads), archive_product_photo the rest.
Rules
- Never invent product facts. The backend grounds the shot on the product's real images; don't
describe a product you can't see.
- Use the brand context instead of interviewing the user. Product, audience, voice, positioning,
logo/colors/fonts all come from
brand_get_context / the brand kit. Ask only for the shot
category, count, quality, and model consent.
- Ask before spending. Quote the estimate and confirm
count / quality before
generate_product_photos — it reserves credits.
- Poll, don't re-submit. A generation that's still
running is not stuck; re-submitting
double-bills. Only a failed generation should be retried.
- Model imagery needs consent. Only set a human model when the user asks, and pass
attestation_accepted: true.
- Approval is the hand-off to ads. Remind the user that only approved photos reach the brand
kit / ad workflow; archived ones never do.
1---2name: goose-product-photos3description: GooseWorks Product Photos — turn a brand's product images into publish-ready photography (clean studio shots, lifestyle scenes, on-model looks) while keeping the product faithful (silhouette, materials, logo, colorway). You pick a brand + product and submit; the GooseWorks backend runs the SAME server-side pipeline the Product Photos studio uses (compose → generate → judge → auto-retry) and bills credits. Use when the user says "make product photos", "shoot my product", "studio/lifestyle/on-model photo of <product>", "generate product photography", or references a product to photograph. Unlike goose-ads (ad creative) this produces clean PRODUCT photos that can then feed the ad workflow.4---56# GooseWorks Product Photos — branded product photography78The GooseWorks Product Photos skill. You **pick a brand + product and submit one generation**;9the **backend** runs the whole pipeline (compose the shot prompt → generate on `gpt_image_2` →10judge for product fidelity → auto-retry a few times for free) and stores the results. You do NOT11generate images, call a model, or manage files — this is the exact same workflow the Product12Photos studio uses, so the skill and the app can never drift. The point is to **enrich a brand's13usable product imagery** — approved photos join the brand kit and can then feed the ad workflow14(`goose-ads`).1516## Prerequisite — the GooseWorks MCP server is REQUIRED1718Everything goes through the `mcp__gooseworks__*` tools. If they are not available, **stop and19tell the user to run `gooseworks install --claude --mcp`** (and restart Claude Code). There is no20HTTP/file fallback.2122## Start from the brand context — don't re-ask what it already answers2324If the `gooseworks` router handed you brand context, USE IT. If you were invoked directly, call25`brand_get_context` yourself first. It answers most of the setup questions below, so **do not ask26the user for them**:2728- **Which product?** — the context's `products[]` are the real catalog entries. Offer them; never29 invent a product or ask the user to describe one you can already see.30- **What does it look like / what is it made of?** — grounded in the product's stored images and31 description. Never guess a material, colorway, or silhouette.32- **What vibe / who is it for?** — the context's voice, positioning, and audience already say. Let33 them shape the scene and styling instead of asking "what mood do you want?".34- **Brand look** — logo, colors, and fonts are owned by the backend research pass. Read them, never35 re-derive them.3637Ask only for the genuinely open choices: the shot `category`, how many photos, quality, and38whether a human model is wanted (which needs explicit consent — see the rules).3940## Identity & credits4142- One agent-scoped token authenticates the tools; they resolve your org automatically. Never43 print the token. (You may pass an optional `target` to operate on a specific agent/org, exactly44 as the other GooseWorks tools; omit it to use your pinned scope.)45- **Credits are handled by the backend.** `generate_product_photos` reserves the estimated cost up46 front and bills only the photos that pass the judge — **automatic retries are free**, and a photo47 the judge can't get right (`flagged`) is shown but **never billed**. Call48 `estimate_product_photos` first to quote the cost; `get_ad_credits` shows the balance.4950## The tools5152**Pick the brand + product**53- `list_ad_brands` — the user's ad brands (get a `brand_id`; also carries `slug`).54- `list_brand_products { brand_id, search?, page?, page_size? }` — the brand's imported products.55 Pick a `product_id` to shoot. `search` matches name / type / variant / SKU.56- `import_product { brand_id, kind, url, product_name? }` — import a product if it isn't in the57 catalog yet. `kind` is `product_url` (a single product page), `shopify_store` (a store URL →58 imports the catalog), or `image_url` (a direct image; requires `product_name`). Returns an import59 row with an `id`; if its `status` isn't `complete`, poll `get_product_import` until it is, then60 `list_brand_products` to find the new product. (File uploads aren't available over MCP — use a URL.)61- `get_product_import { import_id }` — poll an import until `status` is `complete` or `failed`.6263**Generate**64- `estimate_product_photos { count, quality? }` — cost preview (per-photo + total credits). `count`65 is 1, 2, 4, or 8; `quality` is `low` | `medium` | `high` (default `medium`). Reserves nothing.66- `generate_product_photos { brand_id, product_id, variant_id?, category, controls?, prompt?,67 count?, quality?, reference_image_urls?, attestation_accepted? }` — **the one call that makes68 photos.** `category` is `apparel` | `beauty` | `cpg` (seeds sensible scene/framing defaults).69 Omit `controls` to use the category preset; pass `prompt` as free-text steering **added on top of**70 the settings (it doesn't replace them). Returns a generation with an `id` **immediately** — poll71 `get_product_photo_generation` until done, then read each `outputs[].final_image_url`.72 **If you request a human model** (`controls.model.presence` is not `none`) you MUST pass73 `attestation_accepted: true` to confirm the user has the rights for model imagery.74- `get_product_photo_generation { generation_id }` — poll until `status` is `complete`,75 `partial_failure`, or `failed`. Each `outputs[]` entry has its own `status` and, once ready, a76 `final_image_url`. A `flagged` output is the best attempt but wasn't billed.7778**Use the results**79- `list_product_photos { brand_id, archived? }` — the brand's generated photos (`archived: false`80 = active, `true` = archived).81- `approve_product_photo { output_id }` — approve a photo: links it to the product and makes it82 available in the **brand kit**, so `goose-ads` can use it. **Photos are not used anywhere until83 approved.**84- `archive_product_photo { output_id, reason? }` — archive a photo; archived photos are **excluded**85 from ad generation.8687## Workflow — shoot a product88891. **Load the brand context** (`brand_get_context`, or reuse what the router passed you) and90 **resolve the brand + product.** `list_ad_brands` → `brand_id`. `list_brand_products` → pick a91 `product_id` from the catalog you already know about. If the product genuinely isn't there,92 `import_product` (poll `get_product_import`).932. **Quote the cost.** `estimate_product_photos { count, quality }` → tell the user credits.943. **Generate.** `generate_product_photos { brand_id, product_id, category, count, quality, prompt? }`.95 Build `prompt` from the brand's voice/positioning you already have — don't interview the user for it.96 Returns a generation `id` right away.974. **Poll.** `get_product_photo_generation { generation_id }` until terminal; hand back each98 `final_image_url`.995. **Approve the keepers.** Show the results and let the user pick; `approve_product_photo` the ones100 they'd publish (that's what puts them in the brand kit for ads), `archive_product_photo` the rest.101102## Rules103104- **Never invent product facts.** The backend grounds the shot on the product's real images; don't105 describe a product you can't see.106- **Use the brand context instead of interviewing the user.** Product, audience, voice, positioning,107 logo/colors/fonts all come from `brand_get_context` / the brand kit. Ask only for the shot108 category, count, quality, and model consent.109- **Ask before spending.** Quote the estimate and confirm `count` / `quality` before110 `generate_product_photos` — it reserves credits.111- **Poll, don't re-submit.** A generation that's still `running` is not stuck; re-submitting112 double-bills. Only a `failed` generation should be retried.113- **Model imagery needs consent.** Only set a human model when the user asks, and pass114 `attestation_accepted: true`.115- **Approval is the hand-off to ads.** Remind the user that only **approved** photos reach the brand116 kit / ad workflow; archived ones never do.