331 lines
8.0 KiB
Markdown
331 lines
8.0 KiB
Markdown
---
|
|
name: fal-workflow
|
|
description: Generate production-ready fal.ai workflow JSON files. Use when user requests "create workflow", "chain models", "multi-step generation", "image to video pipeline", or complex AI generation pipelines.
|
|
metadata:
|
|
author: fal-ai
|
|
version: "3.0.0"
|
|
---
|
|
|
|
# fal.ai Workflow Generator
|
|
|
|
Generate **100% working, production-ready fal.ai workflow JSON files**. Workflows chain multiple AI models together for complex generation pipelines.
|
|
|
|
**References:**
|
|
- [Model Reference](references/MODELS.md) - Detailed model configurations
|
|
- [Common Patterns](references/PATTERNS.md) - Reusable workflow patterns
|
|
- [Code Examples](references/EXAMPLES.md) - Code snippets and partial examples
|
|
|
|
**Troubleshooting Reference:**
|
|
- [Complete Workflows](references/WORKFLOWS.md) - Working JSON examples for debugging (use ONLY when user reports errors)
|
|
|
|
---
|
|
|
|
## Core Architecture
|
|
|
|
### Valid Node Types
|
|
|
|
⚠️ **ONLY TWO VALID NODE TYPES EXIST:**
|
|
|
|
| Type | Purpose |
|
|
|------|---------|
|
|
| `"run"` | Execute a model/app |
|
|
| `"display"` | Output results to user |
|
|
|
|
**❌ INVALID:** `type: "input"` - This does NOT exist! Input is defined ONLY in `schema.input`.
|
|
|
|
### Minimal Working Example
|
|
|
|
```json
|
|
{
|
|
"name": "my-workflow",
|
|
"title": "My Workflow",
|
|
"contents": {
|
|
"name": "workflow",
|
|
"nodes": {
|
|
"output": {
|
|
"type": "display",
|
|
"id": "output",
|
|
"depends": ["node-image"],
|
|
"input": {},
|
|
"fields": { "image": "$node-image.images.0.url" }
|
|
},
|
|
"node-image": {
|
|
"type": "run",
|
|
"id": "node-image",
|
|
"depends": ["input"],
|
|
"app": "fal-ai/flux/dev",
|
|
"input": { "prompt": "$input.prompt" }
|
|
}
|
|
},
|
|
"output": { "image": "$node-image.images.0.url" },
|
|
"schema": {
|
|
"input": {
|
|
"prompt": {
|
|
"name": "prompt",
|
|
"label": "Prompt",
|
|
"type": "string",
|
|
"required": true,
|
|
"modelId": "node-image"
|
|
}
|
|
},
|
|
"output": {
|
|
"image": { "name": "image", "label": "Generated Image", "type": "string" }
|
|
}
|
|
},
|
|
"version": "1",
|
|
"metadata": {
|
|
"input": { "position": { "x": 0, "y": 0 } },
|
|
"description": "Simple text to image workflow"
|
|
}
|
|
},
|
|
"is_public": true,
|
|
"user_id": "",
|
|
"user_nickname": "",
|
|
"created_at": ""
|
|
}
|
|
```
|
|
|
|
### Reference Syntax
|
|
|
|
| Reference | Use Case | Example |
|
|
|-----------|----------|---------|
|
|
| `$input.field` | Input value | `$input.prompt` |
|
|
| `$node.output` | LLM text output | `$node-llm.output` |
|
|
| `$node.images.0.url` | First image URL | `$node-img.images.0.url` |
|
|
| `$node.image.url` | Single image URL | `$node-upscale.image.url` |
|
|
| `$node.video.url` | Video URL | `$node-vid.video.url` |
|
|
| `$node.audio_file.url` | Audio URL | `$node-music.audio_file.url` |
|
|
| `$node.frame.url` | Extracted frame | `$node-extract.frame.url` |
|
|
|
|
### CRITICAL: No String Interpolation
|
|
|
|
**⚠️ NEVER mix text with variables! Variable MUST be the ENTIRE value.**
|
|
|
|
```json
|
|
// ❌ WRONG - WILL BREAK
|
|
"prompt": "Create image of $input.subject in $input.style"
|
|
|
|
// ✅ CORRECT - Variable is the ENTIRE value
|
|
"prompt": "$input.prompt"
|
|
"prompt": "$node-llm.output"
|
|
```
|
|
|
|
**To combine values:** Use `fal-ai/text-concat` or `fal-ai/workflow-utilities/merge-text`. See [Model Reference](references/MODELS.md#text-utilities-critical-for-combining-values).
|
|
|
|
---
|
|
|
|
## Critical Rules
|
|
|
|
### C1: Dependencies Must Match References
|
|
|
|
```json
|
|
// ❌ WRONG
|
|
"node-b": {
|
|
"depends": [],
|
|
"input": { "data": "$node-a.output" }
|
|
}
|
|
|
|
// ✅ CORRECT
|
|
"node-b": {
|
|
"depends": ["node-a"],
|
|
"input": { "data": "$node-a.output" }
|
|
}
|
|
```
|
|
|
|
### C2: ID Must Match Object Key
|
|
|
|
```json
|
|
// ❌ WRONG
|
|
"my-node": { "id": "different-id" }
|
|
|
|
// ✅ CORRECT
|
|
"my-node": { "id": "my-node" }
|
|
```
|
|
|
|
### C3: Use Correct LLM Type
|
|
|
|
- `openrouter/router` → Text only, no image_urls
|
|
- `openrouter/router/vision` → ONLY when analyzing images
|
|
|
|
### C4: Schema modelId Required
|
|
|
|
```json
|
|
"schema": {
|
|
"input": {
|
|
"field": { "modelId": "first-consuming-node" }
|
|
}
|
|
}
|
|
```
|
|
|
|
### C5: Output Depends on All Referenced Nodes
|
|
|
|
```json
|
|
"output": {
|
|
"depends": ["node-a", "node-b", "node-c"],
|
|
"fields": {
|
|
"a": "$node-a.video",
|
|
"b": "$node-b.images.0.url"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Default Models
|
|
|
|
| Task | Default Model |
|
|
|------|---------------|
|
|
| Image generation | `fal-ai/nano-banana-pro` |
|
|
| Image editing | `fal-ai/nano-banana-pro/edit` |
|
|
| Video (I2V) | `fal-ai/bytedance/seedance/v1.5/pro/image-to-video` |
|
|
| Text LLM | `openrouter/router` with `google/gemini-2.5-flash` |
|
|
| Vision LLM | `openrouter/router/vision` with `google/gemini-3-pro-preview` |
|
|
| Music | `fal-ai/elevenlabs/music` |
|
|
| Upscale | `fal-ai/seedvr/upscale/image` |
|
|
| Text concat (2 texts) | `fal-ai/text-concat` |
|
|
| Text merge (array) | `fal-ai/workflow-utilities/merge-text` |
|
|
| Video merge | `fal-ai/ffmpeg-api/merge-videos` |
|
|
| Audio+Video merge | `fal-ai/ffmpeg-api/merge-audio-video` |
|
|
| Frame extract | `fal-ai/ffmpeg-api/extract-frame` |
|
|
|
|
---
|
|
|
|
## Quick Reference Card
|
|
|
|
### Output References
|
|
|
|
| Model Type | Output Reference |
|
|
|------------|------------------|
|
|
| LLM | `$node.output` |
|
|
| Text Concat | `$node.results` |
|
|
| Merge Text | `$node.text` |
|
|
| Image Gen (array) | `$node.images.0.url` |
|
|
| Image Process (single) | `$node.image.url` |
|
|
| Video | `$node.video.url` |
|
|
| Music | `$node.audio_file.url` |
|
|
| Frame Extract | `$node.frame.url` |
|
|
|
|
### Common App IDs
|
|
|
|
```
|
|
fal-ai/nano-banana-pro
|
|
fal-ai/nano-banana-pro/edit
|
|
fal-ai/text-concat
|
|
fal-ai/workflow-utilities/merge-text
|
|
fal-ai/bytedance/seedance/v1.5/pro/image-to-video
|
|
fal-ai/kling-video/o1/image-to-video
|
|
fal-ai/kling-video/v2.6/pro/image-to-video
|
|
fal-ai/elevenlabs/music
|
|
fal-ai/ffmpeg-api/merge-videos
|
|
fal-ai/ffmpeg-api/merge-audio-video
|
|
fal-ai/ffmpeg-api/extract-frame
|
|
fal-ai/seedvr/upscale/image
|
|
openrouter/router
|
|
openrouter/router/vision
|
|
```
|
|
|
|
---
|
|
|
|
## Input Schema
|
|
|
|
```json
|
|
"schema": {
|
|
"input": {
|
|
"text_field": {
|
|
"name": "text_field",
|
|
"label": "Display Label",
|
|
"type": "string",
|
|
"description": "Help text",
|
|
"required": true,
|
|
"modelId": "consuming-node"
|
|
},
|
|
"image_urls": {
|
|
"name": "image_urls",
|
|
"type": { "kind": "list", "elementType": "string" },
|
|
"required": true,
|
|
"modelId": "node-id"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Pre-Output Checklist
|
|
|
|
Before outputting any workflow, verify:
|
|
|
|
- [ ] **⚠️ All nodes have `type: "run"` or `type: "display"` ONLY (NO `type: "input"`!)**
|
|
- [ ] **⚠️ No string interpolation - variable MUST be ENTIRE value**
|
|
- [ ] Every `$node.xxx` has matching `depends` entry
|
|
- [ ] Every node `id` matches object key
|
|
- [ ] Input schema has `modelId` for each field
|
|
- [ ] Output depends on ALL referenced nodes
|
|
- [ ] Correct LLM type (router vs router/vision)
|
|
|
|
---
|
|
|
|
## Usage
|
|
|
|
### Using Script
|
|
|
|
```bash
|
|
bash /mnt/skills/user/fal-workflow/scripts/create-workflow.sh \
|
|
--name "my-workflow" \
|
|
--title "My Workflow Title" \
|
|
--nodes '[...]' \
|
|
--outputs '{...}'
|
|
```
|
|
|
|
### Using MCP Tool
|
|
|
|
```javascript
|
|
mcp__fal-ai__create-workflow({
|
|
smartMode: true,
|
|
intent: "Generate a story with LLM, create an illustration, then animate it"
|
|
})
|
|
```
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### Invalid Node Type Error (MOST COMMON)
|
|
```
|
|
Error: unexpected value; permitted: 'run', 'display', field required
|
|
```
|
|
**Cause:** You created a node with `type: "input"` which does NOT exist.
|
|
**Solution:** Remove ANY node with `type: "input"`. Define input fields ONLY in `schema.input`.
|
|
|
|
### Dependency Error
|
|
```
|
|
Error: Node references $node-x but doesn't depend on it
|
|
```
|
|
**Solution:** Add the referenced node to the `depends` array.
|
|
|
|
### ID Mismatch Error
|
|
```
|
|
Error: Node key "my-node" doesn't match id "different-id"
|
|
```
|
|
**Solution:** Ensure the object key matches the `id` field exactly.
|
|
|
|
### LLM Vision Error
|
|
```
|
|
Error: image_urls provided but using text-only router
|
|
```
|
|
**Solution:** Switch to `openrouter/router/vision` when analyzing images.
|
|
|
|
---
|
|
|
|
## Finding Model Schemas
|
|
|
|
Every model's input/output schema:
|
|
```
|
|
https://fal.ai/api/openapi/queue/openapi.json?endpoint_id=[endpoint_id]
|
|
```
|
|
|
|
Example:
|
|
```
|
|
https://fal.ai/api/openapi/queue/openapi.json?endpoint_id=fal-ai/nano-banana-pro
|
|
```
|