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.
- package/dist/agents/claude.d.ts.map +1 -1
- package/dist/agents/claude.js +4 -58
- package/dist/agents/claude.js.map +1 -1
- package/dist/agents/codex.d.ts.map +1 -1
- package/dist/agents/codex.js +4 -58
- package/dist/agents/codex.js.map +1 -1
- package/dist/agents/skill-links.d.ts +18 -0
- package/dist/agents/skill-links.d.ts.map +1 -0
- package/dist/agents/skill-links.js +192 -0
- package/dist/agents/skill-links.js.map +1 -0
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +16 -2
- package/dist/commands/install.js.map +1 -1
- package/dist/skills/master-skill.d.ts.map +1 -1
- package/dist/skills/master-skill.js +151 -23
- package/dist/skills/master-skill.js.map +1 -1
- package/package.json +3 -2
- package/skills/goose-ads/SKILL.md +324 -0
- package/skills/goose-video/SKILL.md +292 -0
- package/skills/gooseworks/SKILL.md +21 -13
|
@@ -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
|
-
|
|
|
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
|
|
85
|
-
> -
|
|
86
|
-
> -
|
|
87
|
-
> -
|
|
88
|
-
> -
|
|
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.
|