fal.ai Skill Creator
Generate reusable Claude Code Skills from fal.ai model IDs using the Platform API.
Authentication
All fal.ai operations require the FAL_KEY environment variable:
export FAL_KEY="your-fal-api-key"
File Upload (for image/audio/video inputs)
Many models require URL inputs for media files. Use fal_client to upload local files:
# Upload file and get URL
python -c "import fal_client; url=fal_client.upload_file(r'/path/to/file.png'); print(f'URL: {url}')"
# Linux/Mac
python -c "import fal_client; url=fal_client.upload_file('/home/user/image.png'); print(f'URL: {url}')"
# Android (Termux)
python -c "import fal_client; url=fal_client.upload_file('/storage/emulated/0/Download/image.png'); print(f'URL: {url}')"
Supported formats: png, jpg, gif, webp, mp3, wav, mp4, webm, etc.
Quick Start
Generate Skill from Model ID
# Generate skill for a model python .claude/skills/fal-skill-creator/scripts/generate_fal_skill.py \ --model-id fal-ai/flux/dev # Lazy mode (minimal SKILL.md, details in YAML) python .claude/skills/fal-skill-creator/scripts/generate_fal_skill.py \ --model-id fal-ai/flux/dev --lazy # Standalone mode (copy shared scripts instead of symlinks) python .claude/skills/fal-skill-creator/scripts/generate_fal_skill.py \ --model-id fal-ai/flux/dev --standalone # Public mode (implies --standalone and validates skill tree has no symlinks) python .claude/skills/fal-skill-creator/scripts/generate_fal_skill.py \ --model-id fal-ai/flux/dev --public # Multiple models python .claude/skills/fal-skill-creator/scripts/generate_fal_skill.py \ --model-id fal-ai/flux/dev \ --model-id fal-ai/flux/schnell
Output: .claude/skills/<model-name>/
Search for Models
python .claude/skills/fal-skill-creator/scripts/generate_fal_skill.py \ --search "flux" --category "text-to-image"
Direct API Call
python .claude/skills/fal-skill-creator/scripts/fal_api_call.py \
--model-id fal-ai/flux/schnell \
--args '{"prompt": "a cat in a garden"}' \
--output ./output
Using Generated Skills
After generation, use the wrapper script:
python .claude/skills/fal-ai-flux-dev/scripts/fal_ai_flux_dev.py \
--args '{"prompt": "sunset over mountains"}' \
--output ./output
CLI Reference
generate_fal_skill.py
| Option | Short | Description |
|---|---|---|
--model-id | -m | fal.ai model ID (can specify multiple) |
--search | -s | Search for models by query |
--category | -c | Filter search by category |
--output | -o | Output directory (default: .claude/skills) |
--name | -n | Custom skill name (single model only) |
--lazy | -l | Minimal SKILL.md (details in YAML) |
--standalone | Copy shared scripts into generated skill (no symlink) | |
--public | Public-ready mode (--standalone + full skill-tree symlink checks) | |
--api-key | -k | DEPRECATED; disabled by default (set FAL_ALLOW_API_KEY_ARG=1 for temporary compatibility) |
fal_api_call.py
| Option | Short | Description | Default |
|---|---|---|---|
--model-id | -m | fal.ai model ID (required) | - |
--args | -a | Submit arguments (JSON) | - |
--args-file | Load args from JSON file | - | |
--api-key | -k | DEPRECATED; disabled by default (set FAL_ALLOW_API_KEY_ARG=1 for temporary compatibility) | FAL_KEY env |
--output | -o | Output directory | ./output |
--output-file | -O | Output file path (--output配下のみ) | auto |
--auto-filename | {request_id}_{timestamp}.{ext} | off | |
--poll-interval | Status poll interval (seconds) | from config | |
--max-polls | Max poll attempts | computed | |
--save-logs | Save logs to {output}/logs/ | off | |
--save-logs-inline | Save logs alongside output | off | |
--no-queue | Skip queue daemon only (direct queue submit/status/result flow) | off | |
--sync-only | Use fal.run sync API directly (skip queue submit/poll) | off |
Download size limit: 100MB per file.
Queue Management
# Start daemon python .claude/skills/fal-skill-creator/scripts/queue_daemon.py --background # Check status python .claude/skills/fal-skill-creator/scripts/queue_client.py --status # Shutdown python .claude/skills/fal-skill-creator/scripts/queue_client.py --shutdown
Generated Skill Structure
.claude/skills/<model-name>/
├── SKILL.md
├── queue_config.yaml
├── agents/
│ └── openai.yaml # UI metadata (display_name / prompt)
├── scripts/
│ ├── fal_api_call.py # default: symlink / --standalone: copy
│ ├── queue_client.py # default: symlink / --standalone: copy
│ ├── queue_protocol.py # default: symlink / --standalone: copy
│ ├── queue_daemon.py # default: symlink / --standalone: copy
│ └── <model_name>.py # Wrapper with MODEL_ID preset
└── references/
├── model_config.json # {model_id, name, category, description}
└── tools/ # lazy mode only
└── <model-name>.yaml # Input/output schema + usage examples
fal.ai Queue API Flow
1. SUBMIT → POST queue.fal.run/{model_id} → Get request_id
2. STATUS → GET .../requests/{id}/status → Wait for COMPLETED
3. RESULT → GET .../requests/{id} → Get output URLs
4. DOWNLOAD → Save files locally
Status values: IN_QUEUE, IN_PROGRESS, COMPLETED, FAILED
Recovery behavior:
- •If submit returns timeout/network error or HTTP 405, attempt request recovery via Platform API (
/v1/models/requests/by-endpoint) and continue with recoveredrequest_id. - •If queue result endpoints return 405 after submit, do not auto-fallback to sync (duplicate billing risk). Return metadata-only result with
status=RESULT_ENDPOINT_ONLYandplatform_requestwhen possible.
Queue Daemon Configuration (queue_config.yaml)
| Setting | Default | Description |
|---|---|---|
max_concurrent | 2 | Max simultaneous jobs |
start_interval | 1.0 | Seconds between job starts |
poll_interval | 5.0 | Seconds between status polls |
job_timeout | 600 | Job timeout (10 min) |
global_rate_per_min | 10 | Global rate limit |
global_burst | 5 | Burst allowance |
model_rates | {} | Per-model rate overrides |
client_idle_timeout | 0 | Client idle timeout in seconds (0 = disabled) |
sync_only | true | Keep queue manager enabled but execute each queued job via fal.run sync API (set false to use queue submit/status/result in worker) |
Environment variable overrides: FAL_QUEUE_MAX_CONCURRENT, FAL_QUEUE_RATE_PER_MIN, FAL_QUEUE_CLIENT_IDLE_TIMEOUT, etc.
Security: queue daemon enforces runtime dir ownership/permissions (0700) and only removes stale socket paths when the existing path is a socket/symlink.
Runtime scope:
- •Generated wrappers isolate runtime dirs per skill/model (
~/.cache/fal-queue/<skill>__<model>__v2), so concurrency/rate limits apply per skill-model daemon. - •Queue client restarts stale daemons when local scripts/config are newer than the daemon start marker (PID file mtime), reducing mixed old/new behavior risks.
Programmatic Usage
import sys, os
sys.path.insert(0, os.path.join(".claude", "skills", "fal-skill-creator", "scripts"))
from fal_api_call import run_fal_api_job
result = run_fal_api_job(
model_id="fal-ai/flux/schnell",
submit_args={"prompt": "a cat in a garden"},
output_dir="./output",
)
print(result.get("saved_path") or result)
Error Handling
- •API errors (4xx/5xx) with automatic retry on transient errors (429, 5xx)
- •Job failures (
FAILEDstatus) with descriptive messages - •Timeout after max polls
- •Download failures
- •Queue daemon connection failures with fallback to direct API
- •On submit timeout/network/405, recover
request_idfrom Platform API before deciding fallback - •If queue submit succeeds but queue endpoints return 405, sync fallback is blocked to prevent duplicate execution/billing
- •If queue result endpoints remain unavailable, return
RESULT_ENDPOINT_ONLYwithplatform_requestmetadata (no automatic retry)
All errors raise exceptions with descriptive messages.