gooseworks 0.3.8 → 0.3.10

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.
@@ -0,0 +1,292 @@
1
+ ---
2
+ name: goose-video
3
+ slug: goose-video
4
+ description: >
5
+ GooseWorks video ads — remix a video ad template (iMessage chat-reveal, more coming) into a
6
+ branded video ad for the user's product. Renders LOCALLY on the user's machine (Playwright +
7
+ ffmpeg + GooseWorks media proxies) and saves the finished MP4 back to the project over MCP.
8
+ Use when the user says "make the video for project <id>", references a video ad project or
9
+ template, or asks to remix a video ad. Unlike goose-ads (static images, generated server-side),
10
+ video renders locally and reports progress + the result back through the gooseworks MCP tools.
11
+ category: ads
12
+ version: 0.2.0
13
+ author: GooseWorks
14
+ tags: [gooseworks, ads, video, remix, imessage, local-render, byoa]
15
+ ---
16
+
17
+ # GooseWorks Video Ads — local remix runtime
18
+
19
+ You produce **video** ad creative on the user's OWN machine and sync the result back to the
20
+ GooseWorks app over MCP. This document is the **runtime contract** (auth, credits, the media
21
+ proxies, data I/O, the review gate). A separate **recipe skill** — fetched per format — tells
22
+ you *what to make*; read both, and this doc wins on any conflict about the environment.
23
+
24
+ You run inside the user's own Claude Code session (they pasted an instruction with a project
25
+ id). The app NEVER runs you — it is the viewer + review surface; you are the renderer.
26
+
27
+ ## CLI-free environments (cowork / headless)
28
+
29
+ You may be running WITHOUT the `gooseworks` CLI binary (e.g. Anthropic cowork). The
30
+ `mcp__gooseworks__*` tools work over the MCP connection regardless, so wherever this skill
31
+ says to shell out, use the MCP equivalent:
32
+
33
+ - `gooseworks fetch <slug>` → the **`fetch_skill`** MCP tool (returns the same content/scripts/
34
+ files/dependencySkills). `gooseworks search <q>` → **`search_skills`**.
35
+ - `gooseworks credits` → the **`get_ad_credits`** MCP tool.
36
+ - `gooseworks doctor` → do the manual toolchain check in the preflight below.
37
+
38
+ ## Prerequisite — MCP + a render toolchain (Phase 0 preflight)
39
+
40
+ - The `mcp__gooseworks__*` tools are REQUIRED. If they're unavailable, stop and tell the user
41
+ to connect the GooseWorks MCP server (or run `gooseworks install --claude --mcp` on the CLI)
42
+ and restart. There is no REST fallback.
43
+ - **The render runs wherever THIS agent runs, and it needs a real toolchain: `ffmpeg` +
44
+ `ffprobe` + a Playwright **Chromium**.** Establish it in this priority order, and do NOT start
45
+ rendering until one is confirmed:
46
+ 1. **CLI present →** run `gooseworks doctor` (checks login, MCP, ffmpeg/ffprobe, Playwright
47
+ Chromium in one shot). Fix any ✗ with the command it prints, then continue.
48
+ 2. **No CLI →** check the toolchain yourself: `ffmpeg -version`, `ffprobe -version`, and a
49
+ Playwright Chromium probe (`npx playwright --version` and, if needed, `npx playwright install
50
+ chromium`). If all resolve, continue.
51
+ 3. **Docker available →** this is the most reliable way to get the toolchain in a sandbox that
52
+ lacks it: run the render steps inside the prebuilt image
53
+ **`ghcr.io/gooseworks-ai/goose-video-render`** (ffmpeg + ffprobe + Playwright Chromium baked
54
+ in), mounting the project working directory. Use Docker whenever the host is missing ffmpeg or
55
+ Chromium and `docker` is on PATH. (Note: nested Docker is usually disabled inside managed
56
+ sandboxes like cowork — treat this as an option, not a guarantee.)
57
+ 4. **None of the above works →** STOP and tell the user plainly, e.g.: *"Video rendering needs
58
+ ffmpeg + a Playwright Chromium (or Docker) on the machine running this agent. This environment
59
+ doesn't have them and I can't install them here. Options: (a) enable/allow Docker so I can use
60
+ the goose-video-render image, (b) install ffmpeg + `npx playwright install chromium`, or
61
+ (c) run this skill locally in your own Claude Code where the toolchain is available."* Do not
62
+ half-render or fake a result. Static image ads (the `goose-ads` skill) do NOT need any of this
63
+ and work anywhere — offer that as the fallback if they just want an ad now.
64
+
65
+ ## Identity, token, credits
66
+
67
+ - Read `~/.gooseworks/credentials.json` → `api_key` (your agent token), `api_base`, `agent_id`.
68
+ Never print the token.
69
+ - **CRITICAL — target the org-default Ads agent on EVERY file op.** The app serves project files
70
+ (the render-file route) from the org's DEFAULT agent, but MCP file writes default to your
71
+ token's pinned agent — which can be a DIFFERENT agent, so a render written with the default
72
+ scope is **invisible in the app**. First resolve the Ads agent: `list_accessible_scopes` → the
73
+ scope with `is_org_default: true` (the ORG default — NOT the `is_default` / `default_agent_id`
74
+ fields, which are the *user's* default agent and are often a DIFFERENT agent). Its `agent_id` is
75
+ `ADS_AGENT` (name "Ads agent", slug `org-default`; usually also the `agent_id` in
76
+ credentials.json). Then pass `target: { type: "agent", agent_id: ADS_AGENT }` on EVERY
77
+ `get_upload_url` / `get_download_url` / `write_file` / `list_directory` / `read_file` — NEVER
78
+ omit `target`.
79
+ - **CRITICAL — publish under the PROJECT FOLDER, not the workspace root (the #1 "video renders but
80
+ is invisible" bug).** `get_upload_url` stores at `<ADS_AGENT>/files/<path>` verbatim, but the
81
+ render-file route reads from
82
+ `<ADS_AGENT>/files/agent-config/brands/<brand_slug>/projects/<project_id>/<path>`
83
+ (see backend `resolveProjectFileKey`). So EVERY publish/preview `path` MUST be prefixed with
84
+ `agent-config/brands/<brand_slug>/projects/<project_id>/` — e.g. upload to
85
+ `agent-config/brands/<brand_slug>/projects/<project_id>/working/final.mp4`, NEVER bare
86
+ `working/final.mp4`. A bare path 404s in the app even though the render row AND a bare-path
87
+ `get_download_url` both "succeed" (they resolve the wrong key). The render `output_url` still
88
+ stays the project-relative `...render-file?path=working/final.mp4` — the route re-prepends the
89
+ prefix itself. Always verify with `get_download_url` on the FULL `agent-config/...` path (must
90
+ be non-empty; curl it for HTTP 200) BEFORE marking the render complete.
91
+ - Media generation (FAL / ElevenLabs) is billed to the agent through the GooseWorks proxies.
92
+ `submit_render { kind: "full" }` debits **1 ad credit at row creation** — so sequence it LAST
93
+ (render + verify a good MP4 first), and never re-submit on a guess (that double-bills). Call
94
+ `get_ad_credits` first; the user can check `gooseworks credits`.
95
+
96
+ ## Step 1 — resolve the project, source, brand
97
+
98
+ 1. `get_ad_project { project_id }` → keep `brand_id`, `source_sample_id`, `name`, `status`.
99
+ 2. `get_ad_template { template_id: source_sample_id }` → the source video: `media_url`,
100
+ `recipe`, `format` (e.g. "imessage"), `extracted_script`, `how_to`, `remix_spec`.
101
+ 3. Brand gate: `get_brand_kit { brand_id }`. If `researchStatus` is `complete`, REUSE it —
102
+ never re-research. If not, run brand research first (`gooseworks fetch brand-research`,
103
+ follow it, then `finalize_brand_research { brand_id }`) before continuing.
104
+
105
+ ## Step 2 — read the template's recipe (it carries everything; NO hardcoded format map)
106
+
107
+ The ad format is a **template (data) in the ad_sample DB**, not a per-format skill.
108
+ `get_ad_template(source_sample_id)` returns the template's `recipe` — a self-contained brief you
109
+ read and execute. **Do NOT map `format` to a hardcoded recipe slug** (there is no such table):
110
+
111
+ - `recipe.format` — the format label (e.g. `vignette`), for display only.
112
+ - `recipe.atoms` — the **capabilities** this template composes (e.g. `create-video-seedance-2-fal`,
113
+ `create-image-gpt-image-fal`, `review-ugc-render`, `watch`). `gooseworks fetch <name>` each — they
114
+ live in `skills/ads/capabilities/` and are reused across templates (so they cache).
115
+ - `recipe.instructions` — the **playbook** to follow: `instructions.inline` prose, or
116
+ `instructions.doc_url` (an S3 markdown doc — fetch it).
117
+ - `recipe.config` — every param (prompts, layout, timings, palette, model choices).
118
+ - `recipe.inputs` — the brand-asset contract (which product / logo / offer this template needs).
119
+ - `recipe.assets` — reference material as S3 links (reference render, style guide, example frames) —
120
+ fetch as needed.
121
+
122
+ Runtime: **read the recipe → `gooseworks fetch` each capability in `recipe.atoms` → follow
123
+ `recipe.instructions` with `recipe.config` + the brand's bound `inputs`.** The template IS the recipe;
124
+ there is no `format → recipe-slug` table and no per-format skill to fetch.
125
+
126
+ Save each fetched capability's scripts + files under `/tmp/gooseworks-scripts/<name>/`. If a capability
127
+ is a Node package (a phone-mockup renderer), `npm install` in its folder so its `generate.js` +
128
+ Playwright resolve, and point the recorder's `NODE_PATH` at it.
129
+
130
+ > **Migration note:** older phone-mockup formats (`imessage` / `chatgpt` / `apple-notes`) whose DB
131
+ > recipe does not yet carry `atoms` / `instructions` still hold the legacy `recipe.thread` payload;
132
+ > migrate them to this shape (capabilities + instructions in the DB) — do not reintroduce a CLI map.
133
+
134
+ ## Step 3 — prepare ALL the ingredients, then review ONCE (always, before any paid render)
135
+
136
+ This is a **review-once** flow: prepare every ingredient the video needs, show the whole set to
137
+ the user in the app, get ONE approval, then render. Never render before approval, and don't drip
138
+ ingredients out one at a time.
139
+
140
+ 1. **Generate every ingredient the format needs — not just the script.** For an iMessage video
141
+ that's typically: the **script** (the bubble thread), the **image(s)** shown in the conversation
142
+ (one or more), and the **end card**. Richer templates add more (hook frame, background, product
143
+ shots, music bed…). Read the recipe for the exact ingredient list. Generate the visuals NOW
144
+ (media proxies / recipe), and `get_upload_url` each preview asset to the project folder
145
+ `agent-config/brands/<brand_slug>/projects/<project_id>/working/review/<name>` (the same
146
+ path-prefix rule as final publish — a bare `working/review/<name>` won't render in the panel).
147
+ In `script_drafts`, set each ingredient's `path` to the project-relative `working/review/<name>`.
148
+ You may ask the user a couple of clarifying questions about the generation first if the recipe
149
+ calls for it (angle, which product, offer/code) — batch them, then prepare everything.
150
+ 2. **Mirror the whole ingredient set for review** — `update_ad_project_script { project_id,
151
+ script_drafts, script }`. `script_drafts` is a structured payload of **container-tagged
152
+ ingredients** so the app renders each piece the right way:
153
+ `{ format, scenes?, ingredients: [{ container, label, subtitle?, path?, text? }] }`. Each
154
+ ingredient's `container` tells the app HOW to show it:
155
+ - `image` (a frame shown in the video), `endcard` (the end card), `avatar` (a character
156
+ headshot), `background` → rendered as an image tile.
157
+ - `voice` (a voiceover clip — put the voice NAME in `subtitle`), `music` (the bed),
158
+ `audio` → rendered as an audio player.
159
+ - `video` (a clip) → a video player. `text` (a copy line like the CTA) → a text tile.
160
+ - `script` / `thread` / `note` / `conversation` → the written script (or set `scenes[]`
161
+ for the podcast shape, or pass the readable `script` string).
162
+ `path` = `working/review/<name>` (upload the preview asset first via `get_upload_url`); `url`
163
+ works too. **Label every ingredient** ("Hook image", "End card", "Voiceover", "Background
164
+ music", "HER"). This writes NO render and costs NO credits — it populates the review panel.
165
+ 3. **STOP and ask the user to approve the ingredients in THIS Claude Code session.** Do not render
166
+ until they say go. If they want changes, regenerate the affected ingredient, call
167
+ `update_ad_project_script` again, and re-ask. Only AFTER approval do Step 4.
168
+
169
+ ## Step 4 — render locally, report stages, publish
170
+
171
+ 1. Render per the recipe (Playwright record → ffmpeg stitch → `mix-master` audio). Generate any
172
+ hook / background / end-card assets through the media proxies (below).
173
+ 2. Open the row LAST: `submit_render { project_id, kind: "full" }` → keep `render_id`, then
174
+ `update_render_status { render_id, status: "running" }`. The render row tracks status only
175
+ (queued / running / complete / failed) — narrate fine-grained progress with
176
+ `append_project_message` instead.
177
+ 3. **MANDATORY final-video review gate — review EVERY finished master before `set_final_render`,
178
+ whatever the format (UGC or not).** The render credit is already spent (`submit_render` in 4.2);
179
+ this gate stands between a rendered master and PINNING/publishing it, so a bad render never gets
180
+ set as final. A master that looks fine on a still can still have a mis-voiced word, a caption
181
+ drifting off its line, a beat out of order, or a deformation — review the actual VIDEO, not
182
+ stills. Run the passes that APPLY to this format:
183
+ - **Audio ↔ script** — any master with SPEECH (VO or native/Seedance voice); **skip for
184
+ music-only / no-speech formats.** `review-ugc-render` is format-agnostic despite the name —
185
+ a deterministic Whisper transcript-vs-script diff, not UGC-specific: persist the approved
186
+ spoken lines to `working/approved-script.txt`, then `gooseworks fetch review-ugc-render` and
187
+ run `review_render.py --video <master>.mp4 --script-file working/approved-script.txt --json
188
+ working/review-verdict.json` (exit 0 PASS / 2 FAIL / 3 ERROR). It blocks a mis-voiced word
189
+ (approved "human-vetted" → "human witted"), a dropped phrase, or silence. It routes Whisper
190
+ through the gooseworks proxy when `OPENAI_BASE_URL` is set; with no backend at all, run
191
+ `fal-ai/whisper` via `fal-proxy` (upload the audio, pass its `get_download_url` as `audio_url`)
192
+ and diff the transcript yourself.
193
+ - **Captions / subtitles** — ANY captioned format (the most common non-UGC defect); **skip for
194
+ UGC/Seedance masters, which carry no subtitle track.** Concrete check: diff the caption file
195
+ you burned (SRT/ASS) against the SAME Whisper transcript + word timings from the audio pass —
196
+ every caption line must match the heard/scripted words and sit within ~0.3s of when they're
197
+ spoken; then in the visual pass below, OCR-read the burned caption off 4–5 sampled frames to
198
+ confirm it's actually on screen at that time and not colliding with a hyperframe or the end
199
+ card. Mismatched text or >0.3s drift fails the gate.
200
+ - **Visual + structure** — always: run the `watch` skill on the master — beat/scene order + SFX,
201
+ the brand's product (not the source's) is shown, the end card has the real wordmark + code, no
202
+ deformation/artifact, duration within ~20% of the source.
203
+ If ANY applicable pass fails, FIX it (regenerate/stitch the offending window, rebuild captions)
204
+ and re-review — only a clean pass proceeds to `set_final_render`. **This gate is universal: it
205
+ runs from the master skill for every format, so a recipe never has to opt in.**
206
+ 4. Publish: `get_upload_url { target: { type: "agent", agent_id: ADS_AGENT } }` → PUT the master
207
+ and poster **under the project folder** (see Identity's path-prefix rule) — to
208
+ `agent-config/brands/<brand_slug>/projects/<project_id>/working/final.mp4` and
209
+ `.../working/final-thumb.jpg`. **Always target ADS_AGENT AND use the full project-folder path**
210
+ — a bare `working/final.mp4`, even on the right agent, 404s in the app. Verify servable:
211
+ `get_download_url { target: ADS_AGENT, path: "agent-config/brands/<brand_slug>/projects/<project_id>/working/final.mp4" }`
212
+ must return a non-empty URL (curl it for HTTP 200).
213
+ Then `update_render_status { render_id, status: "complete", output_url, thumbnail_url }` where
214
+ **output_url MUST be the durable render-file URL**
215
+ `/api/ads/projects/<project_id>/render-file?path=working/final.mp4` (the app re-presigns it on
216
+ every view) — NEVER a raw proxy/CDN URL (those expire). Same for `thumbnail_url`.
217
+ 5. `set_final_render { project_id, render_id }` to pin it, then return the `app_url` +
218
+ `brand_url` (from the project/links) verbatim. Never end on just "done" or a file path.
219
+
220
+ Narrate each long step in one line via `append_project_message { project_id, role: "agent",
221
+ content }` — never sit silent on a queue > 90s.
222
+
223
+ ## Media generation — the GooseWorks proxies (queue loop)
224
+
225
+ Media APIs go through GooseWorks proxies with your agent token; do NOT use an SDK's default host
226
+ (your token isn't a FAL/ElevenLabs token → 401). Base = `<api_base>/api/internal/<proxy>`; pass
227
+ `?token=<api_key>&agent_id=<agent_id>&project_id=<project_id>` (agent_id bills the Ads agent;
228
+ `project_id` = the id of the project you're rendering — it attributes this generation's credits to
229
+ that ad project so the user sees per-project spend in the app. ALWAYS pass it). FAL = `fal-proxy`
230
+ (+ `fal-storage-proxy` to host a local image and get a CDN URL); ElevenLabs = `elevenlabs-proxy`
231
+ (VO / music bed).
232
+
233
+ **FAL queue gotcha** (#1 waste of generations): submit returns `status_url`/`response_url` on
234
+ `queue.fal.run` (the real host, not the proxy). Polling those 401s forever — rewrite their host
235
+ to the proxy base (keep the path), re-add `?token=&agent_id=`. Only the final `*.fal.media`
236
+ image is a real public URL. Helper:
237
+
238
+ ```python
239
+ import json, os, pathlib, time, requests
240
+ from urllib.parse import urlparse
241
+
242
+ def _cfg():
243
+ c = json.loads(pathlib.Path(os.path.expanduser("~/.gooseworks/credentials.json")).read_text())
244
+ return c["api_base"].rstrip("/"), c["api_key"], c.get("agent_id")
245
+
246
+ def _params(tok, agent, project_id=None):
247
+ p = {"token": tok}
248
+ if agent: p["agent_id"] = agent
249
+ if project_id: p["project_id"] = project_id # attributes the spend to this ad project
250
+ return p
251
+
252
+ def fal_generate(model_path, payload, project_id=None, timeout_s=180, poll_s=3):
253
+ """model_path e.g. 'fal-ai/nano-banana-2/edit' (the recipe names the model).
254
+ Pass project_id = the ad project you're rendering so credits attribute to it.
255
+ Returns the result image URL (a public *.fal.media CDN URL)."""
256
+ api_base, tok, agent = _cfg()
257
+ base = api_base + "/api/internal/fal-proxy"
258
+ sub = requests.post(f"{base}/{model_path}", params=_params(tok, agent, project_id), json=payload).json()
259
+ to_proxy = lambda u: base + urlparse(u).path
260
+ status_url, response_url = to_proxy(sub["status_url"]), to_proxy(sub["response_url"])
261
+ deadline = time.time() + timeout_s
262
+ while time.time() < deadline:
263
+ st = requests.get(status_url, params=_params(tok, agent, project_id)).json()
264
+ if st.get("status") == "COMPLETED":
265
+ return requests.get(response_url, params=_params(tok, agent, project_id)).json()["images"][0]["url"]
266
+ if st.get("status") in ("FAILED", "ERROR"):
267
+ raise RuntimeError(f"FAL failed: {st}")
268
+ time.sleep(poll_s)
269
+ raise TimeoutError("FAL polling exceeded timeout")
270
+ ```
271
+
272
+ ElevenLabs (VO / music) is the same shape against `<api_base>/api/internal/elevenlabs-proxy`
273
+ with `?token=&agent_id=&project_id=`. Feed FAL a local image by storing it (`get_upload_url`) and passing its
274
+ `get_download_url` presigned URL as an `image_urls` / `audio_url` entry — this is the reliable
275
+ path. (`fal-storage-proxy` may 404 depending on the install; don't block on it — prefer the
276
+ `get_download_url` presigned URL.)
277
+
278
+ ## Rules
279
+
280
+ - **MCP + ffmpeg + Playwright required** — run `gooseworks doctor` in Phase 0; stop with the
281
+ exact fix it prints if anything is ✗.
282
+ - **Prepare ALL ingredients first** (script + every visual: image(s) + end card + whatever else
283
+ the template needs), mirror the whole set with `update_ad_project_script`, and get the user's
284
+ approval in-session BEFORE rendering — always (review-once).
285
+ - **submit_render LAST**; `output_url` = the durable render-file URL, never a CDN URL.
286
+ - **Always pass `project_id` on media-proxy calls** (fal / ElevenLabs) so the credits attribute
287
+ to this ad project — that's what lets the user see per-project spend in the app.
288
+ - **Verify a real, non-empty MP4** (watch it) before marking the render complete.
289
+ - **Reuse the brand** when its research is complete; never re-research.
290
+ - On a hard error (auth/quota/model/timeout) set the render `failed` with a short
291
+ `error_message` and stop — don't ship the source unchanged.
292
+ - Always end a successful run with `app_url` + `brand_url`, verbatim.
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: gooseworks
3
+ slug: gooseworks
3
4
  description: >
4
5
  GooseWorks data toolkit. Search and scrape Twitter/X, Reddit, LinkedIn, websites, and the web.
5
6
  Find people, emails, and company info. Enrich contacts and companies.
@@ -7,16 +8,10 @@ description: >
7
8
  LinkedIn scraping: extract post engagers, commenters, profile data, and job postings.
8
9
  Reach for it when you need data at scale, sources behind auth, or a specific provider — not as
9
10
  a replacement for your built-in web search/fetch on quick, one-off lookups.
11
+ category: general
10
12
  version: 1.0.0
11
13
  author: GooseWorks
12
14
  tags: [gooseworks, data, scraping, search, reddit, twitter, linkedin, email, people, research, gtm, leads, prospecting]
13
- homepage: https://github.com/gooseworks-ai/gooseworks
14
- metadata:
15
- clawdbot:
16
- emoji: "\U0001F9AE"
17
- primaryEnv: GOOSEWORKS_API_KEY
18
- requires:
19
- env: [GOOSEWORKS_API_KEY]
20
15
  ---
21
16
 
22
17
  # GooseWorks
@@ -33,7 +28,7 @@ Before anything else, check whether the request belongs to a specialized domain.
33
28
  | --- | --- | --- |
34
29
  | Remix/make an ad, research a brand for ads, OR analyze ad performance — Meta/Google ad campaigns, creative fatigue, CAC/lead quality, competitor ad intel, ad angles & hooks | **`goose-ads`** | Installed locally as an entry skill. Just use it. If unavailable, run `gooseworks install --claude`. |
35
30
  | Charts, infographics, slides, social graphics, branded visual designs from a style/format | **`goose-graphics`** | If installed locally, use it. Otherwise `gooseworks fetch goose-graphics` (or `gooseworks install --claude --with goose-graphics`). |
36
- | Ad/UGC/talking-head **video** | **`goose-video`** | Coming soon. Until it ships, search the catalog (`gooseworks search "ugc video"`) and `gooseworks fetch` the matching recipe. |
31
+ | Make a **video** ad — remix a video ad template (e.g. iMessage chat-reveal), or "make the video for project <id>" | **`goose-video`** | Installed locally as an entry skill. Just use it. If unavailable, run `gooseworks install --claude`. |
37
32
  | Anything else — scraping, research, lead gen, enrichment, any data lookup | (stay here) | Follow "How to Use" below. |
38
33
 
39
34
  Examples — all of these route to `goose-ads`, not the data flow: "remix this ad with project id 123", "make an ad for my product", "research my brand", "why is my Meta campaign underperforming", "which creatives should I cut".
@@ -42,6 +37,18 @@ Examples — all of these route to `goose-ads`, not the data flow: "remix this a
42
37
 
43
38
  All commands below auto-load credentials from `~/.gooseworks/credentials.json`. If a command exits with "Not logged in", tell the user to run: `npx gooseworks login`. To log out: `npx gooseworks logout`.
44
39
 
40
+ ### CLI-free environments (cowork / headless)
41
+
42
+ If the `gooseworks` CLI binary isn't available (e.g. Anthropic cowork) but the
43
+ `mcp__gooseworks__*` tools are connected, use the MCP equivalents instead of shelling out:
44
+ - `gooseworks search <q>` → the **`search_skills`** MCP tool.
45
+ - `gooseworks fetch <slug>` → the **`fetch_skill`** MCP tool (same content/scripts/files/deps).
46
+ - `gooseworks credits` → the **`get_ad_credits`** MCP tool.
47
+
48
+ Discovery and fetching a skill's instructions work fully CLI-free this way. Note: the paid data
49
+ proxy (`gooseworks call <provider> <path>`) still requires the CLI for now — if a task needs it
50
+ and no CLI is present, tell the user that step must run where the `gooseworks` CLI is installed.
51
+
45
52
  To check credit balance:
46
53
  ```bash
47
54
  gooseworks credits
@@ -81,11 +88,11 @@ If the response includes `dependencySkills` (non-empty array), set up each depen
81
88
  ### Step 4: Set up and run the skill
82
89
  Follow the instructions in the skill's `content` field. **Save ALL files from both `scripts` AND `files` before running anything:**
83
90
 
84
- > **Credential translation rule:** Individual skill instructions may show legacy `export GOOSEWORKS_API_KEY=$(python3 ...)` setup steps and raw `curl` commands. **Ignore those — do not run them.** Instead:
85
- > - Skip any `## Setup` block that exports `GOOSEWORKS_API_KEY` or `GOOSEWORKS_API_BASE` — credentials are already loaded by the `gooseworks` CLI.
86
- > - Replace `curl ... $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/run ... -d '{"api":"X","path":"/Y","body":{...}}'` with `gooseworks call X /Y --body='{...}'`
87
- > - Replace `curl ... $GOOSEWORKS_API_BASE/v1/proxy/<provider>/<path> ... -d '{...}'` with `gooseworks call <provider> <path> --body='{...}'`
88
- > - Replace `curl ... $GOOSEWORKS_API_BASE/v1/proxy/orthogonal/search ... -d '{"prompt":"..."}'` with `gooseworks orthogonal find "..."`
91
+ > **Credential translation rule:** Individual skill instructions may contain a legacy `## Setup` block with `export GOOSEWORKS_API_KEY=$(python3 ...)` and raw `curl` commands. **Replace those with the clean equivalents below.**
92
+ > - **Credentials (only needed before running Python scripts, NOT before gooseworks commands):** replace the python one-liner exports with `eval $(gooseworks env)`. Skip entirely if you are only using `gooseworks call` — it loads credentials automatically.
93
+ > - **Orthogonal run:** replace `curl ... /v1/proxy/orthogonal/run ... -d '{"api":"X","path":"/Y","body":{...}}'` with `gooseworks call X /Y --body='{...}'`
94
+ > - **Direct proxy:** replace `curl ... /v1/proxy/<provider>/<path> ... -d '{...}'` with `gooseworks call <provider> <path> --body='{...}'`
95
+ > - **Orthogonal search:** replace `curl ... /v1/proxy/orthogonal/search ... -d '{"prompt":"..."}'` with `gooseworks orthogonal find "..."`
89
96
 
90
97
  1. Save each script from `scripts` to `/tmp/gooseworks-scripts/<slug>/scripts/` — **NEVER save scripts into the user's project directory**
91
98
  2. **IMPORTANT: Also save everything from `files`** — these contain required modules (like `tools/apify_guard.py`) that scripts import at runtime:
@@ -174,3 +181,4 @@ The `gooseworks` CLI sends authenticated requests (Bearer `GOOSEWORKS_API_KEY`)
174
181
  4. **Parse JSON responses** and present data in a readable format to the user
175
182
  5. **When running scripts**: save to `/tmp/gooseworks-scripts/`, install pip deps, then execute. NEVER pollute the user's project directory
176
183
  6. **Output files default to `~/Gooseworks/`** — always confirm with the user before saving
184
+ 7. **Prefer `gooseworks call` over raw curl** — if it returns an error, first fix the parameters (check types, required fields, format) and retry. Only fall back to raw curl if you have strong reason to believe it is a CLI bug, not a parameter issue.