$npx -y skills add gooseworks-ai/goose-skills --skill create-image-gpt-image-falGenerate a single photoreal or designed image with OpenAI gpt-image via fal.ai. Supports gpt-image-1 (default, fixed sizes — the FAL fallback for Higgsfield's gpt_image_2) and gpt-image-2 (openai/gpt-image-2, custom output sizes up to 3840px). Routes to text-to-image or the e
| 1 | # create-image-gpt-image-fal |
| 2 | |
| 3 | ## Purpose |
| 4 | |
| 5 | Generate one image via fal.ai's OpenAI gpt-image endpoints. Two model families are supported through a single `--model` flag: |
| 6 | |
| 7 | - **`gpt-image-1`** (default) — `fal-ai/gpt-image-1`. The FAL fallback for Higgsfield's `gpt_image_2`. Fixed output sizes only. Used by: |
| 8 | - `video-orchestrator/lock-character` Phase 0 (anchor portrait) and Phase 1 (angle keyframes via `/edit`) |
| 9 | - `video-orchestrator/create-clips` Phase 1 for photoreal scenes |
| 10 | - the orchestrator's `generate_with_fallback.py` router on Higgsfield failure |
| 11 | - **`gpt-image-2`** — `openai/gpt-image-2`. The newer model; accepts **custom output sizes** (any multiple of 16, up to 3840px) and renders dense text/layouts well. Used for designed sheets such as ad storyboards (`create-storyboard-sheets-fal`). |
| 12 | |
| 13 | The default stays `gpt-image-1` so existing callers and the lock-character anchor-parity contract are unaffected. Opt into the newer model with `--model gpt-image-2`. |
| 14 | |
| 15 | ## Pricing (approximate, as of 2026-05) |
| 16 | |
| 17 | - **gpt-image-1** — $0.04 (low), $0.08 (medium), $0.20 (high) per image. Source: [fal.ai/models/fal-ai/gpt-image-1](https://fal.ai/models/fal-ai/gpt-image-1). |
| 18 | - **gpt-image-2** — token-priced; rough per-image estimate $0.02 (low), $0.07 (medium), $0.19 (high). Source: [fal.ai/models/openai/gpt-image-2](https://fal.ai/models/openai/gpt-image-2). |
| 19 | |
| 20 | The script defaults to `medium`; pass `--quality high` for finals. |
| 21 | |
| 22 | ## Inputs |
| 23 | |
| 24 | Required: |
| 25 | - `--prompt` — text prompt. A verbatim character descriptor block goes here for character work. |
| 26 | - `--output` — local PNG destination. |
| 27 | |
| 28 | Optional: |
| 29 | - `--model` — `gpt-image-1` (default) or `gpt-image-2`. |
| 30 | - `--aspect-ratio` — `9:16` (default), `16:9`, `1:1`, `2:3`, `3:2`. gpt-image-2 also accepts `3:4`, `4:3`, `4:5`. Used when `--image-size` is not given. |
| 31 | - `--image-size` — explicit `WIDTHxHEIGHT` (e.g. `1728x2304`). **gpt-image-2 only** — values are rounded to multiples of 16 and capped at 3840px. On `gpt-image-1` a custom size is ignored with a warning and the aspect-ratio mapping is used instead. |
| 32 | - `--quality` — `low | medium | high` (default `medium`). |
| 33 | - `--ref-image` / `--ref-url` — a **PUBLIC image URL** for the `/edit` variant. **Repeatable** — pass it twice to send multiple refs (e.g. identity + style). The proxy does **not** upload local files, so a **local path is rejected** — host the image first (MCP `get_upload_url` → `get_download_url`, or any public URL) and pass that URL. When present, routes to the model's `/edit` variant so the model can match the references. Order matters: pass identity (character) first, then style refs. |
| 34 | - `--with-logs` — stream fal queue logs. |
| 35 | |
| 36 | Credentials (proxy-routed — NOT a raw FAL key): |
| 37 | - The bundled `scripts/media_proxy.py` routes every call through the GooseWorks **fal-proxy**, which **bills the Ads agent**. It reads `~/.gooseworks/credentials.json` (`api_base`, `api_key`, `agent_id`) — written by `gooseworks login`. Do **not** set `FAL_API_KEY`: an agent (`cal_`) token is not a FAL key and 401s against fal directly. |
| 38 | - Set `GW_PROJECT_ID=<ad project id>` in the env so the generation's spend attributes to that ad project (per-project cost shows in the app). |
| 39 | |
| 40 | ## Preflight |
| 41 | |
| 42 | ```bash |
| 43 | test -f ~/.gooseworks/credentials.json || { echo "Missing credentials — run: gooseworks login"; exit 1; } |
| 44 | python3 -c "import requests" || pip3 install requests |
| 45 | ``` |
| 46 | |
| 47 | ## Workflow |
| 48 | |
| 49 | ```bash |
| 50 | # Text-to-image, default model (gpt-image-1) |
| 51 | python3 skills/ads/capabilities/create-image-gpt-image-fal/scripts/generate.py \ |
| 52 | --prompt "..." \ |
| 53 | --output /path/to/anchor.png \ |
| 54 | --aspect-ratio 9:16 \ |
| 55 | --quality medium |
| 56 | |
| 57 | # Edit-from-reference (anchor -> angle). --ref-image must be a PUBLIC URL, |
| 58 | # NOT a local path (the proxy does not upload local files): |
| 59 | python3 .../generate.py \ |
| 60 | --prompt "..." \ |
| 61 | --output /path/to/angle-3q-left.png \ |
| 62 | --ref-image "https://.../anchor.png" \ |
| 63 | --aspect-ratio 9:16 |
| 64 | |
| 65 | # gpt-image-2 with a custom output size (e.g. a designed storyboard sheet) |
| 66 | python3 .../generate.py \ |
| 67 | --prompt "..." \ |
| 68 | --output /path/to/storyboard.png \ |
| 69 | --model gpt-image-2 \ |
| 70 | --image-size 1728x2304 \ |
| 71 | --quality high |
| 72 | ``` |
| 73 | |
| 74 | The script: |
| 75 | 1. Loads the agent credentials from `~/.gooseworks/credentials.json` via the bundled `media_proxy.py` (proxy-routed; bills the Ads agent). |
| 76 | 2. Resolves the model family (`--model`) and output size (`--image-size` if given and supported, else the aspect-ratio mapping). |
| 77 | 3. If one or more `--ref-image` / `--ref-url` flags are |