gooseworks 0.4.4 → 0.5.0-dev.5.1ff84a4f

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 (94) hide show
  1. package/README.md +27 -10
  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/oauth-server.d.ts.map +1 -1
  11. package/dist/auth/oauth-server.js +18 -2
  12. package/dist/auth/oauth-server.js.map +1 -1
  13. package/dist/commands/doctor.d.ts.map +1 -1
  14. package/dist/commands/doctor.js +17 -8
  15. package/dist/commands/doctor.js.map +1 -1
  16. package/dist/commands/formats.js +2 -2
  17. package/dist/commands/formats.js.map +1 -1
  18. package/dist/commands/graphics/publish-flow.js +1 -1
  19. package/dist/commands/graphics/publish-flow.js.map +1 -1
  20. package/dist/commands/install.d.ts.map +1 -1
  21. package/dist/commands/install.js +20 -0
  22. package/dist/commands/install.js.map +1 -1
  23. package/dist/commands/launch.d.ts +3 -0
  24. package/dist/commands/launch.d.ts.map +1 -0
  25. package/dist/commands/launch.js +35 -0
  26. package/dist/commands/launch.js.map +1 -0
  27. package/dist/commands/login.d.ts.map +1 -1
  28. package/dist/commands/login.js +7 -0
  29. package/dist/commands/login.js.map +1 -1
  30. package/dist/commands/logout.d.ts.map +1 -1
  31. package/dist/commands/logout.js +3 -1
  32. package/dist/commands/logout.js.map +1 -1
  33. package/dist/commands/skills.d.ts +16 -0
  34. package/dist/commands/skills.d.ts.map +1 -1
  35. package/dist/commands/skills.js +52 -1
  36. package/dist/commands/skills.js.map +1 -1
  37. package/dist/commands/styles.js +2 -2
  38. package/dist/commands/styles.js.map +1 -1
  39. package/dist/commands/update.d.ts.map +1 -1
  40. package/dist/commands/update.js +20 -0
  41. package/dist/commands/update.js.map +1 -1
  42. package/dist/commands/video-local.d.ts.map +1 -1
  43. package/dist/commands/video-local.js +2 -2
  44. package/dist/commands/video-local.js.map +1 -1
  45. package/dist/config.d.ts.map +1 -1
  46. package/dist/config.js +11 -3
  47. package/dist/config.js.map +1 -1
  48. package/dist/environment.d.ts +9 -0
  49. package/dist/environment.d.ts.map +1 -0
  50. package/dist/environment.js +103 -0
  51. package/dist/environment.js.map +1 -0
  52. package/dist/index.js +12 -45
  53. package/dist/index.js.map +1 -1
  54. package/dist/lib/graphics-cache.d.ts.map +1 -1
  55. package/dist/lib/graphics-cache.js +2 -2
  56. package/dist/lib/graphics-cache.js.map +1 -1
  57. package/dist/program.d.ts +2 -0
  58. package/dist/program.d.ts.map +1 -0
  59. package/dist/program.js +54 -0
  60. package/dist/program.js.map +1 -0
  61. package/dist/skills/custom-video-skill.d.ts +1 -1
  62. package/dist/skills/custom-video-skill.d.ts.map +1 -1
  63. package/dist/skills/custom-video-skill.js +1 -1
  64. package/dist/skills/custom-video-skill.js.map +1 -1
  65. package/dist/skills/installer.d.ts.map +1 -1
  66. package/dist/skills/installer.js +42 -24
  67. package/dist/skills/installer.js.map +1 -1
  68. package/dist/skills/master-skill.d.ts +12 -9
  69. package/dist/skills/master-skill.d.ts.map +1 -1
  70. package/dist/skills/master-skill.js +745 -343
  71. package/dist/skills/master-skill.js.map +1 -1
  72. package/dist/skills/releases.d.ts +1 -1
  73. package/dist/skills/releases.d.ts.map +1 -1
  74. package/dist/skills/releases.js +8 -5
  75. package/dist/skills/releases.js.map +1 -1
  76. package/dist/skills/routes.js +7 -7
  77. package/dist/skills/routes.js.map +1 -1
  78. package/dist/skills/staging-content.d.ts +3 -0
  79. package/dist/skills/staging-content.d.ts.map +1 -0
  80. package/dist/skills/staging-content.js +12 -0
  81. package/dist/skills/staging-content.js.map +1 -0
  82. package/package.json +12 -4
  83. package/skills/goose-ads/SKILL.md +363 -224
  84. package/skills/goose-product-photos/SKILL.md +84 -58
  85. package/skills/goose-video/SKILL.md +223 -14
  86. package/skills/goose-video-local/SKILL.md +195 -24
  87. package/skills/gooseworks/SKILL.md +106 -24
  88. package/skills/make-custom-video/SKILL.md +231 -10
  89. package/skills/manifest.json +7 -7
  90. package/skills/routes.json +7 -7
  91. package/dist/skills/fetcher.d.ts +0 -18
  92. package/dist/skills/fetcher.d.ts.map +0 -1
  93. package/dist/skills/fetcher.js +0 -118
  94. package/dist/skills/fetcher.js.map +0 -1
@@ -12,7 +12,7 @@ description: >
12
12
  app uses) — credits are reserved and billed server-side. Analytics recipes are fetched from
13
13
  goose-skills on demand.
14
14
  category: ads
15
- version: 2.4.0
15
+ version: 2.6.1
16
16
  author: GooseWorks
17
17
  tags: [gooseworks, ads, remix, static-ad, brand, creative, image, analytics, meta-ads, performance]
18
18
  ---
@@ -30,6 +30,9 @@ The GooseWorks ads skill. Two jobs:
30
30
  2. **Analyze ad performance** — fetch ad-analytics recipes from goose-skills on demand
31
31
  (these are unrelated to generation; see "Analyze / intelligence" below).
32
32
 
33
+ It works the same in a chat app (ChatGPT, claude.ai, Cowork) and in a terminal coding agent:
34
+ everything except the few steps labelled terminal-only goes through the connector's tools.
35
+
33
36
  ## How to talk to the customer (applies to every message you send them)
34
37
 
35
38
  The customer is a marketer or founder, not an engineer. Everything in this skill about tools,
@@ -82,39 +85,124 @@ and approval before spending. Hosted installed snapshots use the existing Skills
82
85
  Skill content and a host's cached MCP tool schemas are separate: refreshing one does not refresh
83
86
  the other. Check the actual advertised tools before using new fields.
84
87
 
85
- ## Prerequisite — the GooseWorks MCP server is REQUIRED
88
+ ## Prerequisite — the GooseWorks connector tools
89
+
90
+ Everything below runs through the GooseWorks connector's tools, by the names this skill uses.
91
+ Match on the tool name: a coding agent may show a server prefix (for example
92
+ `mcp__gooseworks__ads_generate`), a chat app may not. There is no HTTP or file fallback: the REST ad
93
+ endpoints are session-cookie-only and reject your token.
94
+
95
+ If a tool named here is missing, the GooseWorks connection or its tool list is stale: ask the
96
+ user to reconnect or refresh GooseWorks in their app's connector settings. Installing or
97
+ updating the `gooseworks` CLI never fixes a missing connector tool, so never send a chat-app
98
+ user to a terminal for it. Only a terminal coding agent (Claude Code, Codex, Cursor) that has no
99
+ GooseWorks tools at all connects them, in that terminal, with `gooseworks install --mcp` plus
100
+ `--claude`, `--codex` or `--cursor`, then a restart.
86
101
 
87
- Everything goes through the `mcp__gooseworks__*` tools. If they are not available, **stop and
88
- tell the user to run `gooseworks install --claude --mcp`** (and restart Claude Code). There is
89
- no HTTP/file fallback — the REST ad endpoints are session-cookie-only and reject your token.
102
+ Older notes or skill copies may name tools the connector no longer lists. Use the tool this skill
103
+ names instead; `catalog_fetch { type: "skill", slug: "gooseworks-guide" }` maps every old name.
90
104
 
91
105
  ## Start from the brand context — don't re-ask what it already answers
92
106
 
93
- If the `gooseworks` router handed you brand context, USE IT. If you were invoked directly, call
94
- `brand_read { brand_id, sections: ["summary","kit","products","learnings"] }` first. It already
95
- answers most of what the flows below would otherwise ask the user:
107
+ If the `gooseworks` router handed you brand context and an evidence brief, USE THEM. If you were
108
+ invoked directly, call `brand_read { brand_id, sections: ["summary","kit","products","learnings"] }`
109
+ first, then search the Brand Brain (next section). Together they answer most of what the flows
110
+ below would otherwise ask the user:
96
111
 
97
- - **Which product to feature** → `products[]`. Offer the real catalog entries; never guess a
112
+ - **Which product to feature** → `products.items`. Recommend one real catalog entry; never guess a
98
113
  product name and never ask the user to list their products.
99
114
  - **The vibe / tone of the copy** → the brand's **voice**. Use it; don't ask "what tone?".
100
115
  - **Who the ad is for** → the brand's **audience**. Don't ask "who's the target?".
101
- - **The angle, offer framing, and what to claim** → **positioning**, value props, proof points.
116
+ - **The angle and offer framing** → **positioning** and value props, sharpened by the Brain:
117
+ lead with an angle past approved creatives proved, and drop anything a saved rule forbids.
118
+ - **What to claim** → only claim-grade proof: a search result with `approved_ad_claim: true`, the
119
+ kit's approved claims, or its proof points as written. Other Kit text, documents and
120
+ performance numbers are context.
102
121
  - **Logo, colors, fonts** → owned by the backend research pass. **Never re-derive them.**
103
122
  - **Whether the facts are trustworthy yet** → **research status**. If it isn't complete, say so in
104
123
  one line and continue; the batch queues and runs when research finishes.
105
124
 
106
- Ask only for what the context genuinely doesn't answer: the specific campaign intent (season,
107
- promo, which of several angles), the source ad, and anything the user must consent to.
108
-
109
- ## Identity & credits
110
-
111
- - One agent-scoped token authenticates the `gooseworks` MCP tools. Never print it. The tools
112
- resolve your org automatically — you do NOT resolve an "Ads agent" or pass `target` for the
113
- generation tools.
114
- - **Credits are handled entirely by the backend.** `submit_remix_batch` reserves the estimated
115
- cost up front (it errors with `insufficient_credits` if the wallet is short — relay the
116
- message and stop) and bills only the images that actually complete. Call
117
- `estimate_remix_batch` first to tell the user the cost; `gooseworks credits` shows balance.
125
+ Don't ask for the angle, product or tone: recommend them with a one-line reason. Ask only for a
126
+ decision the brand read and the Brain search cannot settle (for example an offer or season the
127
+ user hasn't mentioned) and for anything the user must consent to (rights, spend).
128
+
129
+ ## Search the Brand Brain, then propose — before any creative choice or question
130
+
131
+ The Brand Kit is a summary. The brand's saved knowledge (its Brain) holds what the Kit does not:
132
+ rules from past feedback, approved and rejected creatives, customer evidence, approved claims,
133
+ reports and documents. **After `brand_read`, and before you choose an angle, claim, hook,
134
+ product emphasis, format or source ad — and before you ask the user for any brand fact — call
135
+ `knowledge_search { brand_id, query }`** when it is registered. It is free and read-only: no
136
+ approval, no announcement to the customer and no questionnaire.
137
+
138
+ 1. **Search for this task, not the whole Brain.** Run one short query (under 500 characters) in
139
+ the user's own words plus the product (for example "ads for <product>: what worked, what to
140
+ avoid") and one with
141
+ `source_types: ["evidence", "claim", "learning", "creative", "document"]` for proof and past
142
+ creative results. Add a query only for a specific open question. Reuse results from this run.
143
+ 2. **Keep these states distinct** and record which one each query returned:
144
+
145
+ | Result | Means | Do |
146
+ | --- | --- | --- |
147
+ | `status: "ok"` with matches | Saved knowledge exists | Use it; keep each fact's citation in your working brief |
148
+ | `status: "empty"` | Nothing saved matches this query | Say "no saved evidence for <topic>", never "the brand has no proof" |
149
+ | `refresh_required` | The results shown are current; some changed sources were left out | Use them; search again shortly for anything missing |
150
+ | `building` | The index is not ready | Retry once shortly, then continue with the gap stated |
151
+ | An error, or the tool is not registered | Retrieval failed or is unavailable | Retry an error once, then continue from `brand_read` and treat evidence as unchecked |
152
+ | An empty Kit field | Only that field is blank | Not a search result: still search before asking |
153
+
154
+ 3. **Let the findings change the plan.** A `dont`/`must` learning or a rejected creative rules
155
+ options out; an approved or well-rated past creative is a proven angle to lead with; a report
156
+ shows what worked. Claim-grade proof is a result with `approved_ad_claim: true` or the kit's
157
+ `approvedClaims` within their stated applicability; the kit's `proofPoints` are what the
158
+ backend allows an ad to state, used as written. Other Kit text, documents and performance
159
+ numbers are context, never public claims. Never invent an offer, price or result. Judge
160
+ relevance and skip results about another product or business.
161
+ 4. **Propose; don't interview.** Lead with one recommended direction (angle, product, source or
162
+ format) and a one-line reason naming what you found, with up to two alternatives. When several
163
+ directions fit (two audiences, products or campaigns), pick the one the evidence favours, such
164
+ as an active campaign or approved past creatives, and name the other as an alternative instead
165
+ of asking. Ask only for a decision the brand read and the search cannot settle, or for spend
166
+ approval. Never ask the user for a fact the Brain already answered.
167
+ Keep directions already chosen (the user's words, a project's creative brief, handed-off
168
+ defaults, approved plans): search only to fill empty fields and to apply saved rules. When a
169
+ returned card or picker presents the choice, your recommendation is its one acknowledgement
170
+ line and the saved plan's defaults, not a separate list.
171
+ 5. **Carry an evidence brief** into the routed skill, writer or plan: findings with citations,
172
+ the state of each query, what it ruled out and the open gaps. Tell the customer the findings
173
+ in plain words; the citations stay in the brief.
174
+
175
+ On an approved resume, keep the saved brief and evidence; search again only for a new decision.
176
+
177
+ ## Credits — state the total, then get a yes
178
+
179
+ - One token authenticates the GooseWorks tools and resolves your org; never print it. The
180
+ generation tools need no `target`.
181
+ - **Nothing paid runs without the user's explicit yes in this chat, given after you state the
182
+ credit total.** The paid calls are `ads_generate` (without `dry_run`), every
183
+ `ads_creative_edit` action, `ads_approval_decide` with `decision: "approve"`, and every
184
+ `data_call_provider` / `data_post_provider` call (the data calls an analysis recipe or brand
185
+ research makes; `gooseworks call` in a terminal). Reads, dry runs, `ads_creative_update` and
186
+ `request_campaign_generation` (it only composes plans) are free.
187
+ - The balance is `credits.available_credits` from `account_whoami`; a dry-run `estimate` also
188
+ carries `available_credits`.
189
+ - The backend reserves the quoted credits when a paid call starts and bills only the images
190
+ that complete. A rejection with `insufficient_credits` means the wallet is short: tell the
191
+ user the total and their balance in plain words, offer fewer images or a top-up, and stop.
192
+ Never retry blindly.
193
+
194
+ How to get the total for each paid call:
195
+
196
+ | Paid call | Credit total to state |
197
+ | --- | --- |
198
+ | `ads_generate` with `source.template_ids` | The same call with `dry_run: true` returns `estimate`: `total_credits` for `images` images (plus `credits_per_image`, `rates` and `unknown_template_ids`). |
199
+ | `ads_generate` with `source.community_ad_ids` or `source.creative_ids` | No dry run (it returns `not_available`; these are priced when submitted). Pass `quality` explicitly (the user's choice, else `high`, the app default) and quote the images (each source's `variants` × its `ratios`) × `estimate.rates.<quality>` as the most it will cost (an engine without quality tiers costs the lower `rates.low`). `rates` comes with any template dry run; with no template at hand, dry-run one Surprise-me pick. |
200
+ | `ads_creative_edit` `animate` | The same call with `dry_run: true` returns its `estimate`. |
201
+ | `ads_creative_edit` `regenerate` / `precision_edit` | No dry run. Pass `quality` in the action's payload (without it `precision_edit` copies the source render's tier) and quote the images × `estimate.rates.<quality>` as the most it will cost: `regenerate` with `mode: "variation"` makes one per ratio (omitted `ratios` make three); `edit`, `exact` and `precision_edit` make one. |
202
+ | `ads_creative_edit` `resize` | No dry run and no quality setting: it renders at the server's default tier (`high` today). Quote one image per placement × the larger of `estimate.rates.high` and `credits_per_image` from a template dry run without `quality` (that dry run uses the server's default tier) as the most it will cost. `platforms` expands to every placement: meta 4, google 4, tiktok 2, linkedin 3, reddit 3, x 2; pass `targets` for fewer. |
203
+ | `ads_creative_edit` `layerize` | No dry run. It holds about 80 credits while it runs and charges the actual cost of the split (usually less). Say so and get the yes before sending `layerize: { confirmed: true }`. |
204
+ | `ads_approval_decide` approve | The `credits` that `request_campaign_generation` and `ads_creative_read { brand_id, view: "approvals", batch_id }` return for those plans. |
205
+ | `data_call_provider` / `data_post_provider` | The calls a recipe will make × their price: a ScrapeCreators call costs 1 credit today, and each result reports what it charged. A fal or ElevenLabs POST quotes free with the same call plus `query: { quote_only: true }`. State the rough total for the whole recipe once, before its first paid call. |
118
206
 
119
207
  ## Live MCP contract — inspect it before asking
120
208
 
@@ -127,77 +215,82 @@ Before each tool call:
127
215
  2. Fill required inputs already known from the Brand Kit, selected source, or conversation.
128
216
  3. Ask the user only for required inputs that cannot be inferred and for choices that materially
129
217
  change the result. Do not turn every optional field into a questionnaire.
130
- 4. Omit unspecified optional settings so the backend applies its current app defaults.
218
+ 4. Omit unspecified optional settings so the backend applies its current app defaults. Two
219
+ exceptions: always pass `ratios` on every source (omitted ratios make three images per
220
+ variant), and keep the same `quality` setting in the quote and the paid call (both omitted
221
+ for a template dry run, or the explicit `quality` the credits table asks for).
131
222
  5. If the live schema conflicts with this workflow, follow the live schema and report the drift
132
- with `log_cli_event`.
133
-
134
- ## The generation tools (the new, single-workflow surface)
135
-
136
- - `submit_remix_batch` — **the one call that makes ads.** Inspect its live schema and supply
137
- the required brand/source inputs plus any choices the user explicitly made.
138
- Returns the batch with a `links` block (`brand_url` + per-creative `app_url`). If the brand's
139
- research isn't finished yet the batch comes back `status: "queued"` — it auto-runs the moment
140
- research completes; tell the user it'll appear shortly, don't error.
141
- - `estimate_remix_batch` — cost preview. Reserves nothing. Use it to quote the cost first and
142
- check whether every selected source resolved before submitting.
143
- - `get_remix_batch` — poll status. Returns each creative with its renders and
144
- `completed`/`failed`/`pending` counts, plus `links`. A creative is done when its `pending` is 0
145
- — NOT when `current_render_url` is set (during a regenerate that field still points at the prior
146
- image). Each render carries `age_seconds` (since queued) and `elapsed_seconds` (time generating):
147
- use them to tell a slow-but-healthy render from a stuck one. A render only failed when its
148
- `status` is `"failed"` — never assume a stall and re-submit, that double-bills.
149
- - `list_brand_creatives` — the brand's gallery feed (newest
150
- first) + `brand_url`. Alternative poll target; also use to show everything made for a brand.
151
- - `surprise_me_templates` — the **"Surprise me" recommender**. Picks
152
- remixable Community creations (SAME logic as the web /create "Surprise me" button), shuffled
153
- so picks stay fresh. It does not use the retired curated third-party catalog.
154
- Returns the picked templates (id, slug, title, image, ratio) AND a ready-to-open `create_url`
155
- (the /create page with `cli=true` and the picks pre-selected). This is how you recommend
156
- templates — do NOT hand-pick from the raw catalog yourself (see "Picking templates" below).
157
- - `regenerate_creative` — edit or re-roll one existing creative through the same pipeline.
158
- Inspect the live schema to select the supported mode and required source inputs. Returns a
159
- single-item batch; poll it with `get_remix_batch`.
160
- - `set_creative_feedback` — record the user's reaction to a generated image. Use it whenever
161
- the user reacts; inspect the schema for the current rating and reason choices.
162
-
163
- ### Plan mode — review the plan BEFORE generating (optional)
164
-
165
- For users who want to approve each ad's plan before spending credits (the app's "Plan it" flow):
166
-
167
- - Use the approval option exposed by `submit_remix_batch` — it composes each creative's plan and PAUSES.
168
- **No credits are reserved and no image renders** until you approve.
169
- - `list_ad_approvals` — poll this. While a creative is
170
- `composing`, wait; once `awaiting_approval`, show its `plan` (composed prompt + refs + quality)
171
- to the user.
172
- - `revise_ad_plan` — recompose from a chat steer, still
173
- free. Poll `list_ad_approvals` until it's `awaiting_approval` again.
174
- - `approve_ad_plan` — approve one creative or the whole batch using the live schema.
175
- **This is the step that reserves credits and renders.** Then poll
176
- `get_remix_batch` and hand back links as usual.
177
-
178
- Only offer plan mode when the user asks to review/approve first — the default path generates
179
- immediately.
180
-
181
- ## Reading the brand & picking inputs (still MCP, read-only)
182
-
183
- - `get_brand_kit` — read the canonical brand context and available products/assets.
184
- - `list_ad_brands` / `get_ad_brand` — find and fetch the active brand.
185
- - `list_user_ad_templates` — list the org's own uploads and
186
- imported ads. Prefer `relationship: "self"` when the user wants to reuse their own ads;
187
- `relationship: "competitor"` is research/inspiration, never proof that the user owns the ad.
188
- - `search_ad_templates` — search remixable Community generations. The
189
- retired curated third-party catalog is not returned.
190
- - `get_static_ad_template` — resolve a source already owned by
191
- the org, including an own upload or a snapshotted Community creative. It does not resolve the
192
- retired curated third-party catalog.
193
- - `remix_community_ad` — turn a selected Community creative into a private remix source before
194
- submitting it. A Community ad id is an `ad_project` id, not a
195
- template id. Call this FIRST to snapshot it into a private template, then use the returned
196
- template `id` in `items`.
197
- - `create_user_ad_template` — upload a source image as a private template. Answer any
198
- ownership/rights input only from the user's explicit confirmation. Never claim rights for a
199
- competitor ad or an image found online.
200
- - `get_ad_project` / `append_project_message` — inspect a creative / leave a note on its thread.
223
+ (see "Report problems" in the rules).
224
+
225
+ ## The ad tools
226
+
227
+ - `ads_generate` — **the one call that makes ads.** Needs `brand_id` and exactly one `source`:
228
+ `template_ids: [{ template_id, variants?, ratios }]` (the brand's own templates, Surprise-me
229
+ picks, Community rows whose `item_type` is `template`), `community_ad_ids: [{ community_id,
230
+ variants?, ratios }]` (Community rows whose `item_type` is `creative`; the backend snapshots
231
+ them), or `creative_ids: [{ project_id, render_id?, variants?, ratios }]` (remix the user's own
232
+ finished ads). Optional: `product_name` (a real product), `prompt` (a short steering note),
233
+ `reference_image_urls`, `quality`. `dry_run: true` quotes template sources and reserves
234
+ nothing. A real call GENERATES at once and returns `{ job_id }` (`kind: "ads_batch"`) and the
235
+ `batch`, which already carries its `links` (below). If the
236
+ brand's research is still running the batch is `queued` and starts on its own when research
237
+ finishes: tell the user it'll appear shortly, don't error.
238
+ - `job_get { job_id, kind: "ads_batch" }` — poll a batch. `status` is `queued`, `running`,
239
+ `complete`, `partial_failure` or `failed`; `progress` counts `completed` / `failed` /
240
+ `pending` images. `result.creatives[]` carry each creative's `renders[]` (`id`, `status`,
241
+ `ratio`, `output_url`, `age_seconds` since queued, `elapsed_seconds` generating). A creative
242
+ is done when its `pending` is 0, NOT when `current_render_url` is set (during a regenerate it
243
+ still points at the prior image). A render only failed when its `status` is `"failed"`: a slow
244
+ render is healthy, and re-submitting it double-bills. `result.links` holds the app links you end
245
+ the run with: `brand_url` (the brand's page, with all its ads) and `creative_links: [{
246
+ project_id, app_url }]` (each creative's page). `brand_url` is `null` and the list empty only
247
+ if the link lookup failed; the ads are still made. A server older than this skill returns no
248
+ `links` (and no `app_url` / `brand_url` on creative reads): then hand back the images
249
+ only and don't mention links.
250
+ - `ads_creative_read { brand_id }` — the brand's generated creatives, newest first (filter with
251
+ `batch_id`, `tags`, `approved_only`); each row has its `app_url` and the list has the
252
+ `brand_url`. `creative_id` reads one with its `renders`, plus `creative.app_url` and
253
+ `creative.brand_url`.
254
+ - `ads_template_read` — find or inspect a source (see "Picking source ads"). `template_id` reads one.
255
+ - `ads_creative_edit { brand_id, creative_id, action }` — every paid edit of one creative, one
256
+ `action` per call: `regenerate` (`regenerate: { mode: "variation" }` for another take;
257
+ `mode: "edit"` or `"exact"` with `source_render_id` and `prompt`), `precision_edit` (`source_render_id`
258
+ plus a `note` or region `annotations`), `resize` (`source_render_id` plus `platforms` or
259
+ `targets`), `layerize` (`confirmed: true`), `animate` (`source_image_url`; only when
260
+ `account_whoami` shows the Animate Images feature; for the full flow fetch the `animate-image`
261
+ skill). Returns `{ job_id }`: poll `job_get` with `kind: "ads_batch"` (regenerate, resize,
262
+ precision_edit) or `kind: "animate"`; for layerize read
263
+ `ads_creative_read { brand_id, creative_id, include: ["layers"] }`. While the brand's research is
264
+ still running, `regenerate`, `resize` and `precision_edit` refuse with
265
+ `brand_research_in_progress`: tell the user and try again when it finishes.
266
+ - `ads_creative_update { brand_id, creative_id, patch }` — free. `patch.feedback: { render_id, rating:
267
+ "happy" | "neutral" | "sad", comment?, reasons? }` records the user's reaction (it feeds the
268
+ quality loop); `patch.tags` replaces the creative's tags.
269
+ - `ads_template_create { brand_id, source, rights_attested? }` — register the user's own image as a
270
+ private source template (see "Upload" below).
271
+
272
+ ### Campaigns — the only plan-and-approve path
273
+
274
+ `ads_generate` has no plan step: the dry-run quote and the user's yes are the checkpoint, and a
275
+ submit generates at once. Never promise a review step before the images render. Plans exist only
276
+ for a campaign's concepts (planned with `campaign_read`, `campaign_upsert` and
277
+ `add_campaign_concept`; follow the connector guide for those):
278
+
279
+ 1. `request_campaign_generation { campaign_id }` composes the plans for the concepts with no
280
+ creatives yet (`concept_ids` re-runs chosen ones; `count` only for a number the user named). It
281
+ spends nothing and returns `batch_ids` and `credits`. Never say generation has started.
282
+ 2. Tell the user what will be made and the credit total, and wait for their explicit yes in this
283
+ chat. Never send them to a button in the app; a campaign link is only a place to look.
284
+ 3. Read `ads_creative_read { brand_id, view: "approvals", batch_id }` until that batch's plans are
285
+ `awaiting_approval` and none is `composing`. If its credit total differs from what they
286
+ agreed to, state the new total and ask again.
287
+ 4. `ads_approval_decide { brand_id, decision: "approve", batch_id, user_quote: "<their exact words>" }`
288
+ for each batch, then poll the batch ids it returns with `job_get` (`kind: "ads_batch"`) and
289
+ end with each batch's `result.links`, as in step 7 of the workflow below.
290
+
291
+ Before approving, a steer is free: `ads_approval_decide { brand_id, creative_id, decision: "revise",
292
+ revise: { message } }` recomposes that plan (read the approvals view again), and
293
+ `decision: "edit_plan"` patches it directly. Editing the campaign in between discards these plans.
201
294
 
202
295
  ## Keep the brand kit in sync — reconcile, then save or propose
203
296
 
@@ -228,8 +321,9 @@ able to flow back into the kit — with their ok — instead of being lost.
228
321
  ## Save durable brand answers, then verify them
229
322
 
230
323
  Read the selected brand with `brand_read { brand_id, sections: ["summary", "kit", "products", "learnings", "onboarding"] }`
231
- (fallback: `brand_get_context` with the same sections). Keep founder answers, user corrections,
232
- research and your own hypotheses distinct. Reuse matching saved answers; ask only about gaps.
324
+ (older clients: `brand_get_context` with the same sections, only when that tool is advertised).
325
+ Keep founder answers, user corrections, research and your own hypotheses distinct. Reuse
326
+ matching saved answers; ask only about gaps.
233
327
 
234
328
  When the user asks to remember a rule, answers a brand interview, or explicitly corrects a
235
329
  standing fact, save that answer in the same turn. The capture request authorizes those answers;
@@ -283,159 +377,206 @@ routed skill; claims still pass their own safety gate.
283
377
  ## Picking source ads — use approved sources, not the retired catalog
284
378
 
285
379
  When the user wants to make ads but has NOT named a specific template (id/slug/Community
286
- ad/upload), do NOT silently browse the raw catalog and hand-pick for them. Instead run this
287
- short ask flow — it mirrors the web app and keeps the human in the loop:
288
-
289
- 1. **Ask what kind of ads they want** — the angle/offer/theme/season. **The brand context already
290
- gives you the vibe (voice), the audience, and the product catalog — do NOT ask for those.**
291
- Offer the real `products[]` to pick from rather than asking "which product?", and derive the
292
- tone from the brand's voice. This shapes both the source choice and your steering `prompt`.
293
- Keep it to one quick question about campaign intent.
294
- 2. **Ask how to pick a source: their own ads, Community, upload, or "Surprise me".**
295
- - **Their own ads** → use `list_user_ad_templates` to load the active brand's own sources and
296
- let them choose from the results.
297
- - **Community** → `search_ad_templates`, let them choose, then call `remix_community_ad`
298
- before submitting.
299
- - **Upload** → upload through the workspace and call `create_user_ad_template`. If its live
300
- schema requires an ownership or permission answer, only supply it after explicit confirmation.
301
- - **Surprise me** (they want you/the app to pick) → call `surprise_me_templates` for the active
302
- brand and hand the user the returned `create_url`.
303
- It opens /create in **CLI mode** with the picks pre-selected, a preview modal, and the
304
- **copyable remix prompt at the bottom** (in place of the Generate input). They can swap
305
- picks and copy that prompt. If they'd rather you "just make them" without reviewing in the
306
- app, you MAY submit the `surprise_me_templates` picks directly (skip to submit).
307
- - **Browse in the app** → hand the user this URL, with the
308
- active brand's slug filled in:
309
- `https://make.gooseworks.ai/create?brand=<brand-slug>&cli=true`
310
- In CLI mode the app shows the copyable remix prompt at the bottom (dismissable / switchable
311
- back to the UI composer). They browse the available own/Community sources and copy the prompt.
380
+ ad/upload), do NOT silently browse the raw catalog and hand-pick for them. Instead send **one
381
+ proposal** — it mirrors the web app and keeps the human in the loop without an interview:
382
+
383
+ 1. **Propose the direction yourself.** From the brand read and the evidence brief, recommend the
384
+ product, angle/offer and tone, with a one-line reason naming what the Brain showed (a past
385
+ approved angle, a rule it respects). **Do NOT ask what kind of ads they want, which product,
386
+ or the vibe.** Keep any direction the user already gave. This shapes both the source choice
387
+ and your steering `prompt`.
388
+ 2. **Recommend a source in the same message: their own ads, Community, upload, or "Surprise me".**
389
+ Default to their own approved ads when suitable ones exist, otherwise Surprise-me picks for
390
+ the brand; list the other paths as one-line alternatives. You may resolve the picks and run the
391
+ free dry run first so the proposal already carries the credit total. Show a list of sources as
392
+ one table with every row and its image link, and mark your one suggestion.
393
+ - **Their own ads** → `ads_template_read { brand_id, mode: "mine", filters: { relationship: "self" } }`
394
+ and let them choose. `mode: "competitor"` rows are research and inspiration, never proof that
395
+ the user owns the ad.
396
+ - **Community** → `ads_template_read { brand_id, mode: "query", query: "<the angle and look>" }`
397
+ ranks Community ads by meaning; each row's `sourceId` (with `title` and `thumbnailUrl`) goes
398
+ in `source.community_ad_ids[].community_id`. To browse the feed instead, use `mode:
399
+ "community"`: its rows carry `item_type`, and a `template` id goes in `source.template_ids`,
400
+ a `creative` id in `source.community_ad_ids`. The backend snapshots a Community creative
401
+ itself; there is no separate step. Let the user choose.
402
+ - **Upload** → the user's own image becomes a private template: `media_upload` it (`scope:
403
+ "brand"`, `scope_id: <brand_id>`, `kind: "image"`; in a chat app `source.type: "bytes"`), then
404
+ `ads_template_create { brand_id, source: { type: "media", media_id } }` (or `source: { type:
405
+ "url", url }` for a public image). Set `rights_attested: true` only after the user explicitly
406
+ confirms they own it; this is the ownership/rights input. Never claim rights for a competitor
407
+ ad or an image found online.
408
+ - **Surprise me** (they want you/the app to pick) → `ads_template_read { brand_id, mode:
409
+ "surprise", count: 4 }` picks remixable Community ads for the brand, shuffled so picks stay
410
+ fresh. Every pick is a template: show them, and generate
411
+ from the ones the user keeps (or from all of them if they said "just make them").
412
+ - **Browse in the app** → the one link you build yourself: `<app>/create?brand=<brand-slug>&cli=true`,
413
+ with the active brand's slug, where `<app>` is the origin of a `brand_url` a tool returned
414
+ (the part before `/?brand=`: `https://ads-staging.gooseworks.ai/?brand=acme` gives
415
+ `https://ads-staging.gooseworks.ai`), so it opens on the user's own environment. Reuse a
416
+ `brand_url` you already have from this run, or read one cheaply with
417
+ `ads_creative_read { brand_id, limit: 1 }`; if none comes back, use `https://make.gooseworks.ai`.
418
+ In this mode the app shows a copyable remix prompt at the bottom (dismissable / switchable
419
+ back to the UI composer). They browse their own and Community sources and copy the prompt.
312
420
  3. **Close the loop.** When the user **pastes back the copyable remix prompt** from the app
313
421
  (it names the brand + the templates they chose), THAT is your cue to generate: resolve the
314
- named source(s), inspect `submit_remix_batch`, and collect only its unresolved required inputs.
422
+ named source(s) with `ads_template_read`, quote, and collect only the unresolved required inputs.
315
423
 
316
424
  If the user already named an owned source (id/slug), a Community ad, or an upload, skip the source
317
425
  choice. Competitor ads may inform the angle or structure, but describe them as inspiration, never
318
- claim ownership, and never attest rights for the user.
426
+ claim ownership, and never attest rights for the user. Never use the retired curated third-party
427
+ catalog.
319
428
 
320
429
  ## Workflow — make ads from a template
321
430
 
322
- 1. **Resolve the brand.** Use `list_ad_brands` by name/site, then call `get_brand_kit` for the
323
- selected brand. If the
324
- kit's `researchStatus` isn't `complete`, you can still submit (the batch queues and runs when
325
- research finishes) — just tell the user. Use the kit to pick `product_name` (a real entry from
326
- `products[]`, not a guess) and, if the user supplied product photos, `reference_image_urls`.
327
- 2. **Pick the source ad(s) via the ask flow above.** Once you have concrete ids:
328
- call `get_static_ad_template` for each.
329
- For a Community ad, `remix_community_ad` first; for an uploaded image, `create_user_ad_template`
330
- first.
431
+ 1. **Resolve the brand and its evidence.** List brands with `brand_read` (no `brand_id`), then
432
+ read the selected brand's summary, kit, products and
433
+ learnings and search the Brand Brain as above. If research isn't `complete`, you can still
434
+ submit (the batch queues and runs when research finishes) — just tell the user. Use the read to
435
+ pick `product_name` (a real entry from `products.items`, not a guess) and, if the user supplied
436
+ product photos, `reference_image_urls` (public URLs; `media_upload` a local file first).
437
+ 2. **Pick the source ad(s) via the proposal above.** Read each chosen template with
438
+ `ads_template_read { brand_id, template_id }`. Community creatives (a query row's `sourceId`,
439
+ a feed row with `item_type: "creative"`) and the user's own finished ads go straight into
440
+ `source.community_ad_ids` / `source.creative_ids`.
331
441
  3. **(Optional) Craft the steering prompt.** The `prompt` is OPTIONAL — this is where the skill
332
442
  adds value: turn the user's intent (from step 1) into a concise steering note (e.g. tone,
333
443
  season, emphasis). Don't over-specify; the backend pipeline + brand kit handle palette, fonts,
334
444
  product swap.
335
- 4. **Quote the cost.** Inspect and call `estimate_remix_batch`, then tell the user.
336
- 5. **Submit ONE batch.** Inspect the current `submit_remix_batch` schema, fill known required
337
- inputs, ask only for unresolved user decisions, and omit unspecified optional settings. Keep
338
- the returned `batch_id` and `links`.
339
- 6. **Poll until done.** Call `get_remix_batch` for the returned batch (or use
340
- `list_brand_creatives`) every ~20-30s
341
- until every creative's `pending` is 0. Most images finish in a few minutes; text-heavy templates
342
- and `quality: high` take longer. Read each render's `elapsed_seconds` rather than guessing — a
343
- render that's still `running` is healthy; do NOT re-submit thinking it stalled (that double-bills).
344
- 7. **Hand back the links** from the batch's `links` block — `brand_url` (gallery) and each
345
- creative's `app_url` — copied verbatim. Never end on just "done" or a file path.
445
+ 4. **Quote the cost.** Call `ads_generate` with the exact arguments you will submit plus
446
+ `dry_run: true` (template sources), or work out the total as in the credits table. Drop or
447
+ replace anything in `unknown_template_ids`. State the image count and credit total in one line
448
+ and wait for the user's explicit yes.
449
+ 5. **Submit ONE batch** after that yes: the same `ads_generate` call without `dry_run`. Keep the
450
+ returned `job_id`.
451
+ 6. **Poll until done.** `job_get { job_id, kind: "ads_batch" }` every ~20-30s until every creative's
452
+ `pending` is 0. Most images finish in a few minutes; text-heavy templates and `quality: high`
453
+ take longer. Read each render's `elapsed_seconds` rather than guessing; do NOT re-submit
454
+ thinking it stalled (that double-bills). If `ads_generate` refused with
455
+ `brand_research_required`, the brand was never researched: run "Brand research" below, then
456
+ quote and submit again.
457
+ 7. **Hand back the ads with their links.** Show every finished image (`renders[].output_url` of
458
+ completed renders) and say in one line what failed, if anything. Then give the links from the
459
+ last `job_get`'s `result.links`, copied verbatim: the `brand_url` where all the brand's
460
+ ads are, and the `app_url` of each creative with a finished image (match
461
+ `creative_links[].project_id` to `result.creatives[].id`; skip a creative whose renders all
462
+ failed). For a big batch (more than about 8 creatives) give the `brand_url` and offer the
463
+ rest. Skip a missing or `null` link; never build an app URL yourself. Never end on just
464
+ "done" or a file path.
346
465
 
347
466
  ## Workflow — edit an existing ad
348
467
 
349
- User wants to tweak a creative they already made → use `regenerate_creative`. Infer whether they
350
- want another take, a targeted edit, or an exact instructed change from their request. Then inspect
351
- the live schema, ask only for any required source or instruction that is still missing, submit,
352
- poll with `get_remix_batch`, and hand back the links.
468
+ User wants to tweak a creative they already made → `ads_creative_edit`. Read the creative first
469
+ (`ads_creative_read { brand_id, creative_id }`) to get the render they mean. Infer the action
470
+ from their request: another take (`regenerate`, `mode: "variation"`), a targeted change
471
+ (`regenerate` with `mode: "edit"`, or `precision_edit` when they point at a region), an exact
472
+ instructed change (`mode: "exact"`), new placements (`resize`), editable layers (`layerize`) or a
473
+ short video (`animate`). Ask only for a required source or instruction that is still missing,
474
+ state the credit total from the credits table, get the yes, submit, poll as above, and hand back
475
+ the new images with their links: `result.links` from `job_get` for `regenerate`, `resize` and
476
+ `precision_edit`; `creative.app_url` and `creative.brand_url` from `ads_creative_read { brand_id,
477
+ creative_id }` for `animate` and `layerize`.
353
478
 
354
479
  ## Brand research
355
480
 
356
- Prefer the backend's result: call `get_brand_kit` for the selected brand. If `researchStatus` is
357
- `complete`, REUSE it — never re-research.
481
+ Prefer the backend's result. `brand_read { brand_id, sections: ["summary"] }`: if
482
+ `research_status` is `complete`, REUSE it — never re-research. Proof points and the full product
483
+ catalog keep arriving until `enrichment.settled` is true.
358
484
 
359
485
  **The split — backend owns visuals, you own the qualitative depth:**
360
486
 
361
- - **Backend LIGHT pass (automatic).** `create_ad_brand` with a `website_url` kicks off the same
362
- backend research the web app uses, in `mode: "light"`: it resolves the **authoritative logo,
363
- colors, and fonts** (Brandfetch + context.dev) plus a baseline kit, then flips
364
- `research_status` to `complete` — usually under a minute. You can't reproduce those visual
365
- signals locally, so **never re-derive logo/colors/fonts.** (Web onboarding via `/api/ads/onboard`
366
- runs the full thing; nothing to do but read it.)
367
- - **Your DEEP pass (local, agentic).** You add the qualitative depth the light pass leaves thin —
368
- positioning, audience segments, voice, brandType, value props, proof points, products — grounded
369
- on the actual site.
370
-
371
- **CLI brand-research flow:**
372
-
373
- 1. Inspect and call `create_ad_brand` with the known brand identity and website, then keep its id
374
- and slug. The brand comes back with
375
- `research_status: "pending"` (light pass in flight).
376
- 2. **Wait for the backend light pass:** poll `get_brand_kit` for that brand until `researchStatus`
377
- is `complete` (usually <60s). Now the kit has authoritative logo/colors/fonts + a baseline.
378
- At this point generation is already unblocked — but do the deep pass to make it good.
379
- 3. **Deep research locally:** `gooseworks fetch brand-research` and follow its phases. **Ground
380
- every fact on the fetched site** — if the site can't be read, say so and ask the user; never
487
+ - **Backend LIGHT pass (automatic).** A new brand comes from the connector's setup flow
488
+ (`brand_onboarding { action: "status" }`, then its `next_step`). For an additional brand, check
489
+ it is absent (`brand_read` with no `brand_id`), then `brand_create { name, website_url }` (free).
490
+ The website starts the same backend research the web app uses: it resolves the
491
+ **authoritative logo, colors, and fonts** plus a baseline kit and returns `research_job_id`; poll
492
+ `job_get { job_id: research_job_id, kind: "brand_research" }` (or `brand_read`) until
493
+ `research_status` is `complete` — usually under a minute. If it returns `reused_existing: true`,
494
+ tell the user and use that brand. You can't reproduce those visual signals, so **never
495
+ re-derive logo/colors/fonts.**
496
+ - **Your DEEP pass (optional).** You add the qualitative depth the light pass leaves thin —
497
+ positioning, audience, voice, brand type, value props, proof points, products — grounded on
498
+ the actual site.
499
+
500
+ **Deep research flow:**
501
+
502
+ 1. Fetch the `brand-research` skill (`catalog_fetch { type: "skill", slug: "brand-research" }` in a
503
+ chat app; `gooseworks fetch brand-research` in a terminal) and follow its phases. Its data
504
+ calls are paid: state the credit total (credits table) and get the yes first. **Ground every
505
+ fact on the brand's own site** — if the site can't be read, say so and ask the user; never
381
506
  guess a category from the brand name alone.
382
- 4. **Write the pack** with `write_file` under `agent-config/brands/<slug>/`:
383
- - the `brand-research/*.md` docs + `brand-assets/manifest.json` (human-readable pack), AND
384
- - `brand-research/kit-patch.json` — the STRUCTURED fields the web UI renders. Field-for-field
385
- contract; only what you put here reaches the kit. Shape:
386
- `{ positioning?: string, audience?: string, voice?: string, brandType?: string, tagline?: string, valueProps?: string[], proofPoints?: string[], products?: [{ name, description?, link?, pricing?, imageUrls?: string[] }] }`
387
- (`brandType` ∈ product | saas | service | agency | restaurant | fashion | beauty | fitness |
388
- finance | education | health). Only URLs already in our storage for product images.
389
- - **Do NOT set logo / colors / fonts here** — the backend light pass already owns those.
390
- 5. **Persist it:** call `finalize_brand_research` for the brand. It merges `kit-patch.json` into the kit
391
- NON-CLOBBERINGLY (it will NOT overwrite the backend's visuals or any user edit), then re-confirms
392
- `research_status: complete`.
393
- 6. **Verify:** call `get_brand_kit` again and confirm the qualitative fields you wrote are present
394
- before generating.
395
-
396
- **If the brand has NO website**, the backend light pass can't run (nothing to fetch) — do the whole
397
- thing locally (steps 3–6) and finalize; an un-finalized brand has no kit for generation and leaves
398
- no artifact to debug a wrong run (this is how a bad local classification, e.g. mislabelling a SaaS
399
- as a "drink company", used to vanish without a trace).
507
+ 2. **Save what you improved.**
508
+ - **As proposals (the default):** `brand_update { brand_id,
509
+ knowledge_intent: "agent_proposal", rationale, patch: { knowledge: { positioning?, audience?,
510
+ voice?, brandType?, tagline?, valueProps? } } }`. They stay pending until the user accepts
511
+ them in the app.
512
+ - **As the full research pack (only when you wrote all of it; in a chat app, only for a brand
513
+ with no website, see below):** with `file_write`, under
514
+ `agent-config/brands/<slug>/brand-research/`, write all four docs `brand-summary.md`,
515
+ `visual-identity.md`, `audience.md` and `competitors.md` (real content, at least a few
516
+ sentences each) plus `kit-patch.json`: `{ positioning?, audience?, voice?, brandType?,
517
+ tagline?, valueProps?: string[], proofPoints?: [{ text, source_url }], products?: [{ name,
518
+ description?, link?, pricing?, imageUrls?: string[] }] }` with only the fields you improved;
519
+ every proof point copied word for word from the brand's own page at `source_url`; product
520
+ images only from URLs already in GooseWorks storage; **no logo / colors / fonts**. Then
521
+ `brand_update { brand_id, patch: { finalize_research: true } }` merges it NON-CLOBBERINGLY
522
+ (never over the backend's visuals or a user edit). **If any of the four docs is missing or
523
+ nearly empty, finalize fails and marks the brand's research as failed**, so never finalize a
524
+ partial pack.
525
+ 3. **Verify:** `brand_read` again (`summary`, `kit`) and confirm what you saved before generating.
526
+
527
+ **If the brand has NO website**, the backend light pass can't run and generation goes ahead with
528
+ an empty kit, so ads come out off-brand. Do the deep pass from what the user tells you and save the
529
+ full research pack, so the brand has a kit and a record to debug a wrong run (this is how a bad
530
+ classification, e.g. mislabelling a SaaS as a "drink company", used to vanish).
400
531
 
401
532
  ## Analyze / intelligence (fetched recipes — NOT generation)
402
533
 
403
- These are analysis recipes you fetch from goose-skills with `gooseworks fetch <slug>` and
404
- follow; they do NOT touch the generation tools or credits-for-images. Pick the closest match;
405
- if unsure, `gooseworks search "<what the user wants>"` first:
534
+ These are analysis recipes you fetch and follow; they don't use the generation tools, but their
535
+ data calls are paid (credits table: state the total and get the yes before the first one). Fetch with `catalog_fetch { type: "skill", slug: "<slug>" }` in a chat app or
536
+ `gooseworks fetch <slug>` in a terminal. Pick the closest match; if unsure, search first with
537
+ `catalog_search { type: "skill", query: "<what the user wants>" }` (terminal:
538
+ `gooseworks search "<what the user wants>"`):
406
539
  - **Campaign performance diagnosis** ("why is my Meta/Google campaign underperforming",
407
- creative fatigue, learning phase, pacing, auction overlap) → `gooseworks fetch meta-ads-analyzer`
540
+ creative fatigue, learning phase, pacing, auction overlap) → `meta-ads-analyzer`
408
541
  (or `ad-campaign-analyzer` for cross-platform).
409
542
  - **Lead/CAC quality** ("are these ads driving qualified leads", true CAC vs vanity CPA,
410
- Scale/Keep/Investigate/Cut) → `gooseworks fetch ad-lead-quality-analyzer`.
543
+ Scale/Keep/Investigate/Cut) → `ad-lead-quality-analyzer`.
411
544
  - **Competitor ad intelligence** ("what ads are competitors running") →
412
- `gooseworks fetch competitor-ad-intelligence` (Meta Ad Library: `meta-ad-scraper`;
413
- Google: `google-ad-scraper`).
414
- - **Creative ideation** (ad angles, winning hooks) → `gooseworks fetch ad-angle-miner` /
415
- `gooseworks fetch trending-ad-hook-spotter`.
416
- - **Policy / landing-page checks** → `gooseworks fetch meta-ad-policy-checker` /
417
- `gooseworks fetch ad-to-landing-page-auditor`.
545
+ `competitor-ad-intelligence` (Meta Ad Library: `meta-ad-scraper`; Google: `google-ad-scraper`).
546
+ - **Creative ideation** (ad angles, winning hooks) → `ad-angle-miner` / `trending-ad-hook-spotter`.
547
+ - **Policy / landing-page checks** → `meta-ad-policy-checker` / `ad-to-landing-page-auditor`.
418
548
 
419
- Save their scripts to `/tmp/gooseworks-scripts/<slug>/` and follow their instructions. These
420
- run through the `gooseworks` CLI (`gooseworks fetch` / `gooseworks call`), like the GTM skills.
549
+ A recipe's provider calls go through the connector in a chat app (`data_call_provider` for GET,
550
+ `data_post_provider` for POST) and through `gooseworks call` in a terminal; both are billed. Saving and running
551
+ its scripts (under `/tmp/gooseworks-scripts/<slug>/`) is terminal-only: without a terminal, do
552
+ that step's analysis yourself from the data the tools return, and never ask the user to run a
553
+ command.
421
554
 
422
555
  ## Rules
423
556
 
424
- - **MCP required** — if `mcp__gooseworks__*` is unavailable, stop and tell the user to run
425
- `gooseworks install --claude --mcp`.
426
- - **One backend workflow** — generation is `submit_remix_batch` / `regenerate_creative` ONLY.
557
+ - **Connector tools only** — every step uses the tool names above. A missing tool means the
558
+ GooseWorks connection is stale: ask the user to reconnect or refresh GooseWorks. Never send a
559
+ chat-app user to a terminal or a CLI install.
560
+ - **One backend workflow** — generation is `ads_generate` / `ads_creative_edit` ONLY.
427
561
  Do NOT call FAL, the media proxy, `submit_render`, `update_render_status`, or upload render
428
- files yourself; do NOT `gooseworks fetch` a local remix recipe to generate. The backend owns it.
429
- - **Always end a successful run with the links** from the batch's `links` block (`brand_url` +
430
- each creative's `app_url`), copied verbatim. Never end on just "done" or a file path.
431
- - **Quote cost before generating** when it's non-trivial (use `estimate_remix_batch`), and
432
- relay `insufficient_credits` plainly if the submit is rejected — don't retry blindly.
433
- - **Use approved source paths.** If the user didn't name a source, run the ask flow (own ads,
434
- Community, upload, Surprise me, or browse in the app). "Surprise me" goes through
435
- `surprise_me_templates`; browsing uses `/create?brand=<slug>&cli=true`. Never use the retired
436
- curated third-party catalog.
437
- Generate when they paste the app's copyable remix prompt back (or submit the surprise picks
438
- directly if they'd rather not review).
562
+ files yourself; do NOT fetch a local remix recipe to generate. The backend owns it.
563
+ - **State the credit total and get an explicit yes before every paid call** (credits table above).
564
+ Relay `insufficient_credits` plainly if the submit is rejected — don't retry blindly.
565
+ - **No plan step for one-off ads.** Only a campaign's plans wait for approval
566
+ (`request_campaign_generation` → `ads_approval_decide` with the user's words as `user_quote`).
567
+ - **Always end a successful run with the finished images and their links**, copied verbatim:
568
+ each creative's `app_url` and the `brand_url` from `result.links`, or from the creative
569
+ read (`creative.app_url`, `creative.brand_url`) after `animate` or `layerize`. When the
570
+ server returns no links, end with the images only. Never end on just "done" or a file path, and
571
+ never build an app URL yourself (the one exception is the browse link below).
572
+ - **Search the Brain before proposing.** After the brand read and before choosing an angle,
573
+ claim or source — or asking for a brand fact — run the task's `knowledge_search` and carry
574
+ its evidence brief. A failed or empty search is stated as such, never as "no evidence exists".
575
+ - **Use approved source paths.** If the user didn't name a source, recommend one in the single
576
+ proposal (own ads, Community, upload, Surprise me, or browse in the app). Surprise me is
577
+ `ads_template_read` with `mode: "surprise"`; browsing uses `/create?brand=<slug>&cli=true`.
578
+ Never use the retired curated third-party catalog. Generate when they paste the app's copyable
579
+ remix prompt back, or when they accept the surprise picks.
439
580
  - **Treat competitor ads as inspiration** — never attest rights, imply ownership, or promise to
440
581
  copy a competitor's distinctive expression.
441
582
  - **Reconcile brand facts into the kit** — when the user states or changes something brand-level
@@ -443,14 +584,12 @@ run through the `gooseworks` CLI (`gooseworks fetch` / `gooseworks call`), like
443
584
  `brand_update` with correction intent and the user's exact statement, or the user's own
444
585
  images through `media_upload`; read back before saying saved. Proposed improvements stay
445
586
  pending. Ask only when it is unclear whether a one-ad direction should apply to future ads.
446
- - **Record feedback** — when the user reacts to a generated image, inspect and call
447
- `set_creative_feedback` so the quality loop learns.
448
- - **Plan mode is opt-in** — only use the live approval option, then `list_ad_approvals` and
449
- `approve_ad_plan`, when the user wants to review before spending credits; otherwise generate
450
- immediately.
451
- - **Don't busy-loop** — poll `get_remix_batch` on a sensible interval (~20-30s); a `queued`
452
- batch is waiting on research and will start on its own.
453
- - **Report problems so we can fix them** — when a batch fails/is rejected and you can't resolve it,
454
- a required brand input/asset is missing, or a recipe/instruction is ambiguous or contradictory,
455
- call the **`log_cli_event`** MCP tool (`event_type`: `error`/`blocker`/`missing_input`/`confusion`,
456
- with the real error + step in `details`) so the team gets visibility. Still tell the user too.
587
+ - **Record feedback** — when the user reacts to a generated image, call `ads_creative_update`
588
+ with `patch.feedback` so the quality loop learns.
589
+ - **Don't busy-loop** — poll `job_get` on a sensible interval (~20-30s); a `queued` batch is
590
+ waiting on research and will start on its own.
591
+ - **Report problems so we can fix them** — when a batch fails or is rejected and you can't resolve
592
+ it, a required brand input/asset is missing, or an instruction is ambiguous or contradictory:
593
+ in a terminal run `gooseworks log "<what happened>" --event-type <error|blocker|missing_input|confusion> --details '<json with the real error and step>'`,
594
+ or call the `log_cli_event` tool if your connection lists it. A chat app without either skips
595
+ this step. Always tell the user too.