Multi-step pipelines.
ComfyUI-compatible JSON.

Workflows let you chain generation steps — prompt conditioning, image generation, video synthesis, remixing — into a single replayable pipeline defined in a JSON file that follows the ComfyUI node-graph schema. Run them from the GUI toolbar or headlessly from the terminal with tt-ctl workflow run.

Write a workflow → See the 1964 example ↓

What is a workflow?

A workflow is a directed acyclic graph of nodes. Each node does one thing — load a model, generate an image, polish a prompt, convert a file — and passes its output to the next node as an input. The graph is stored as JSON and is replayable, shareable, and version-controllable.

ComfyUI compatibility. Workflow JSON follows the same node-graph schema used by ComfyUI — a widely-adopted open standard for diffusion pipelines. Nodes declare their class_type, a dictionary of inputs (literal values or references to other nodes' outputs), and an optional _meta block for display labels. The app reads ComfyUI-format workflow JSON natively and maps class_type values to registered node handlers.

Workflow vs plugin

A plugin is a single generator — it takes parameters and produces one artifact. A workflow is a multi-node pipeline that may invoke several plugins in sequence, carry intermediate results between steps, branch on conditions, and produce multiple output artifacts. Plugins are the atomic units; workflows are the compositions.

Supported class_types

class_typeWhat it doesHardware
TTLGTextToImage Text-to-image via FLUX.1-schnell (~3s) or SDXL/cpp_server (~2s) QB2 (P300X2)
TTLGImageToVideo Image-to-video via SkyReels V2 I2V (~90s) or Wan2.2 T2V QB2 (P300X2)
TTLGGenerateText LLM text generation — Llama-3.3-70B, Qwen3-32B, Qwen3-8B, etc. QB2 artgen server
TTLGCaptionImage Image captioning via BLIP — returns a natural-language description CPU (tenstorrent venv)
TTLGRemoveBackground Background removal via RMBG-1.4 — returns a transparent PNG CPU (tenstorrent venv)
TTLGEstimateDepth Depth map via GLPN-KITTI — returns a grayscale depth PNG (brighter = closer) CPU (tenstorrent venv)
TTLGPromptCompose String template — combines outputs from prior nodes into a new prompt string None (string operation)
TTLGAddToPlaylist Imports all output artifacts into the app and creates a named playlist for TT-TV None (app store write)

The ⚙ Workflow toolbar button

Click the ⚙ Workflow button in the main toolbar to open the workflow panel. The panel is divided into three zones that cover the full lifecycle: selecting a spec, supplying parameters, and reviewing what ran.

Zone 1 — Spec picker
Choose a workflow

A dropdown listing all workflow JSON files found in ~/.config/tt-local-gen/workflows/ and the built-in workflows/ directory at the repo root. Selecting a spec loads its parameter declarations into zone 2. A folder icon beside the picker opens the workflow directory in the file manager.

Zone 2 — Parameters
Supply inputs

Each workflow declares its user-facing parameters in the top-level "x-ttlg-params" block. Zone 2 renders these as form fields — text inputs, dropdowns, sliders, file pickers — based on the declared type. Default values are pre-filled. Click Run to launch the workflow with the current values, or Dry run to validate the graph without executing any nodes.

Zone 3 — Run history
Review past runs

Every workflow execution is recorded with a timestamp, the resolved parameter values, execution time per node, and the paths of any artifacts produced. Click any run to expand its node execution log. Failed nodes are highlighted with the error message inline. Artifacts from successful runs appear in the main gallery automatically.

Dry run. The Dry run button validates the workflow graph without calling any model or server. It resolves all node references, checks that required inputs are connected, reports the execution order, and identifies which nodes would need the inference server to be running. Use it to verify a new workflow JSON before committing to a long generation run.

The 1964 World's Fair workflow

The worlds_fair_1964.json workflow ships as a built-in example. It demonstrates a complete multi-step pipeline: algorithmic prompt generation, LLM conditioning, image synthesis, and video generation — all chained together with intermediate artifact handoff.

What it produces

A short video — 5 seconds at 24 fps — depicting a stylised scene from the 1964 New York World's Fair. The pipeline generates a landscape SVG as visual reference, conditions a video prompt from it, and submits the prompt to Wan2.2. The entire run takes approximately 12 minutes on a QB2 (P300x2) system.

Node graph — six nodes, left to right

Node colors: teal = input · gold = processing · green = model inference · pink = output/save

Node 1 · input SeedPhrase
Literal text: "1964 New York World's Fair, Unisphere, monorail, optimistic futurity, late afternoon sun"
Generated seed image — World's Fair scene
→ step1-seed.jpg · TTLGTextToImage · ~3s
text → nodes 2 and 3
Node 2 · ArtGenNode landscape plugin
plugin_name: "landscape" · palette: "golden" · style: "retro-futurist"
theme input wired from node 1's text output
"a large crowd of people walking around a large sphere"
→ TTLGCaptionImage output · BLIP-2 · ~1.2s
SVG file → node 4 as visual reference
Node 3 · PromptConditioner LLM polish
model: "qwen3-0.6b" · style_hint: "cinematic, warm-toned, wide angle"
Expands the seed phrase into a full video generation prompt
Background-removed foreground subject — transparent PNG
→ step3-foreground.png · TTLGRemoveBackground · transparent PNG · ~4s
polished text → node 5
Node 4 · FFmpegExtractFrame SVG rasteriser
Converts the landscape SVG to a 960x540 PNG via rsvg-convert and ffmpeg.
Produces an optional seed image for image-to-video. Skipped if T2V is selected.
Grayscale depth map — brighter = closer to camera
→ step4-depth.png · TTLGEstimateDepth · grayscale depth map · ~2s
PNG path → node 5 seed_image input
Node 5 · VideoGenNode Wan2.2-T2V-A14B
model_name: "wan2.2" · num_frames: 121 · server_url: "http://localhost:8000"
Receives polished prompt from node 3. Seed image from node 4 is optional.
"a large crowd of people walking around a large sphere — 1964 World Fair, retro-futuristic, Kodachrome, cinematic, warm-toned, wide angle, late afternoon sun"
→ TTLGPromptCompose · composed video prompt · ~0.1s
video file → node 6
Node 6 · SaveImage Write to history
filename_prefix: "worlds_fair_1964"
Writes to the history store with full node-graph provenance as metadata
Sample frame from the generated SkyReels video
→ step6-video-frame.jpg · TTLGImageToVideo · MP4, 121 frames · ~90s

User-facing parameters

The workflow exposes three parameters in zone 2 of the toolbar panel:

ParameterTypeDefaultEffect
style_hint string "cinematic, warm-toned" Injected into the PromptConditioner's style guidance at node 3
palette enum golden Controls the landscape SVG color palette at node 2. Options: golden, arctic, volcanic, midnight, toxic, neon
num_frames integer (9–241, step 4) 121 Number of video frames passed to VideoGenNode. 121 frames is approximately 5 seconds at 24 fps.

Running it from the terminal

# Run with default parameters
tt-ctl workflow run worlds_fair_1964

# Override palette and style hint
tt-ctl workflow run worlds_fair_1964 \
  --param palette=volcanic \
  --param style_hint="moody, low-contrast, fog"

# Validate the graph without running anything
tt-ctl workflow run worlds_fair_1964 --dry-run

Five world's fairs — one pipeline

The same workflow JSON ran on five different prompts: 1964 New York, 1939 New York, 1893 Chicago, 1970 Osaka, and 1967 Montreal. Each produced a seed image, a video, and a poem image. Here's what came out.

Node 1 TTLGTextToImage — FLUX.1-schnell · ~3s each · QB2 (P300X2)
1964 New York
1964 NY World's Fair seed image
seed image · 230KB
1939 New York
1939 NY World's Fair seed image
seed image · 129KB
1893 Chicago
1893 Chicago World's Fair seed image
seed image · 253KB
1970 Osaka
1970 Osaka World Expo seed image
seed image · 200KB
1967 Montreal
1967 Montreal Expo seed image
seed image · 138KB
Why CPU for the forge steps (caption, background removal, depth)? The RMBG, BLIP, and GLPN models run on CPU via the tenstorrent Python venv — not on TT hardware. These models are small enough (100MB–2GB) that CPU inference takes 3–30s, making the overhead of TTNN compilation and device dispatch unnecessary for single-image transforms. The TT hardware stays free for the heavy lifting: FLUX image generation (~3s) and SkyReels video generation (~90s).
Node 6 TTLGImageToVideo — SkyReels V2 I2V · 97 frames · ~90s each · QB2 (P300X2)
1964 New York
1964 NY video frame
video frame · 1.4MB mp4
1939 New York
1939 NY video frame
video frame · 880KB mp4
1893 Chicago
1893 Chicago video frame
video frame · 1.3MB mp4
1970 Osaka
1970 Osaka video frame
video frame · 1.1MB mp4
1967 Montreal
1967 Montreal video frame
video frame · 808KB mp4
Node 8 TTLGTextToImage — FLUX.1-schnell · poem as prompt · ~3s each · QB2 (P300X2)
1964 New York
1964 NY poem image
poem image · 188KB
1939 New York
1939 NY poem image
poem image · 88KB
1893 Chicago
1893 Chicago poem image
poem image · 168KB
1970 Osaka
1970 Osaka poem image
poem image · 228KB
1967 Montreal
1967 Montreal poem image
poem image · 96KB

Total pipeline time: ~45 min wall time · ~3 min pure inference · 30 artifacts · 1 playlist

Write your own workflow JSON

A workflow is a single JSON file. Drop it in ~/.config/tt-local-gen/workflows/ and it appears in the spec picker immediately — no restart required.

Minimal 2-node example

This workflow takes a theme string, runs the verse art generator plugin, and saves the result to the history store. Two nodes, one connection.

{
  "x-ttlg-params": {
    "theme": {
      "type": "string",
      "label": "Theme",
      "default": "the last train",
      "description": "What the verse is about"
    }
  },

  "nodes": {

    "1": {
      "class_type": "ArtGenNode",
      "_meta": { "title": "Generate verse" },
      "inputs": {
        "plugin_name": "verse",
        "args": {
          "form":  "haiku",
          "theme": ["x-ttlg-param", "theme"]
        }
      }
    },

    "2": {
      "class_type": "SaveImage",
      "_meta": { "title": "Save to history" },
      "inputs": {
        "images":          ["1", 0],
        "filename_prefix": "my-verse"
      }
    }

  }
}

How to build one — step by step

  1. 1

    Declare user parameters in x-ttlg-params

    Each key becomes a form field in zone 2 of the toolbar panel. Supported types: string, integer, number, boolean, enum (renders as a dropdown), and file (renders as a file picker). Set a default to pre-fill the form. Set "required": true to block the Run button until the field is filled in.

  2. 2

    Reference a parameter inside a node

    Use the two-element array ["x-ttlg-param", "param_name"] wherever you want the runtime to substitute the user-supplied value. This is analogous to how ComfyUI uses [node_id, slot] tuples for node-to-node connections — the same syntax, a different first element.

  3. 3

    Wire node outputs to downstream inputs

    Connect one node's output to another's input with a ["node_id", output_slot] tuple — the standard ComfyUI convention. ["1", 0] means "the first output of node 1". The runtime resolves these references at execution time, respecting topological order.

  4. 4

    Add a _meta.title to every node

    Titles appear in the zone-3 run history log and in dry-run output. Without them, nodes are identified only by their numeric key, which makes debugging failure reports substantially harder. One line per node; always worth it.

  5. 5

    Validate with --dry-run before the real run

    tt-ctl workflow run my-workflow --dry-run validates the graph structure, checks all node references resolve, prints the resolved execution order, and flags which nodes require an active inference server. No models are called. Costs nothing to run repeatedly.

Parameter references vs node connections. ["x-ttlg-param", "name"] injects a user-supplied value at runtime. ["node_id", slot] injects the output of another node at execution time. Both use the same two-element tuple syntax and compose consistently. Plain literal values — strings, numbers, booleans — are just JSON; no tuple needed.

tt-ctl workflow commands

All workflow operations are available headlessly via tt-ctl. The CLI and GUI share the same workflow engine — running a workflow from the terminal produces the same artifacts as clicking Run in the toolbar.

CommandWhat it does
tt-ctl workflow list List all available workflow specs — built-in and user-installed — with their parameter summaries
tt-ctl workflow run <name> Execute a workflow by name using all default parameter values
tt-ctl workflow run <name> --param key=value Override one or more parameters. Repeat --param for multiple overrides.
tt-ctl workflow run <name> --dry-run Validate the graph and print the resolved execution plan without running any nodes
tt-ctl workflow show <name> Print the full workflow JSON with parameter documentation
tt-ctl workflow history Show recent workflow runs with status and output artifact paths
tt-ctl workflow history <run-id> Show the per-node execution log for a specific run, including timings and any errors

Usage examples

# See all available workflows
tt-ctl workflow list

# Run the built-in 1964 World's Fair example with defaults
tt-ctl workflow run worlds_fair_1964

# Override palette and request fewer frames (faster run)
tt-ctl workflow run worlds_fair_1964 \
  --param palette=arctic \
  --param num_frames=33

# Validate a new workflow without running it
tt-ctl workflow run my_workflow --dry-run

# Show the JSON for a built-in workflow
tt-ctl workflow show worlds_fair_1964

# See the last 10 runs across all workflows
tt-ctl workflow history

# Inspect per-node timings for a specific run
tt-ctl workflow history run-2026-05-29-143201
Headless generation. tt-ctl workflow run uses the same engine as the GUI, so you can schedule runs with cron, trigger them from scripts, or chain them in shell pipelines. Artifacts written by SaveImage nodes appear in the GUI gallery the next time the app opens — the history store is shared between CLI and GUI.

Where to put workflow files

Both locations are scanned at startup. A user-installed workflow overrides a built-in with the same filename stem.

LocationPurpose
~/.config/tt-local-gen/workflows/ User-installed workflows. Persists across app updates.
workflows/ (repo root) Built-in example workflows shipped with the app.