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.
Converted and distributed by TomeVault — claim your Tome and manage your conversions.