TheFluxTrain

CLI

Install the TheFluxTrain CLI, sign in from your terminal, and run API commands.

The TheFluxTrain CLI (tft) lets you call TheFluxTrain APIs from your terminal. Sign in once with a device code, then run generation and other commands without hand-writing HTTP requests.

Install

pip install thefluxtrain-cli

Or with uv:

uv tool install thefluxtrain-cli

Confirm the install:

tft --help

Quick start

tft login
tft commands
tft whoami
  1. tft login — starts device-code sign-in (see below).
  2. tft commands — lists available API command groups.
  3. tft whoami — shows the signed-in account and API key id.

After login, run any command listed by tft commands. For example:

tft image-generate generate --prompt "a cat in a spacesuit" --model flux-2-pro

Use tft <group> <command> --help for flags and examples for that endpoint.

Sign in (device code)

You do not paste an API key manually. The CLI creates one for you after you approve it in the browser.

  1. Run tft login in your terminal. You will see a short code and a link.
  2. Open https://thefluxtrain.com/cli/authorize (the CLI may open it for you).
  3. Sign in to TheFluxTrain if you are not already.
  4. Enter the code from your terminal and click Authorize CLI.
  5. Return to the terminal — the CLI stores credentials and refreshes its command list.

Credentials are saved to ~/.config/thefluxtrain/credentials.json. To sign out and clear local data:

tft logout

You can also create and manage API keys manually on API keys. Keys created in the browser work for REST calls; the CLI uses its own key after tft login.

Command List

The CLI keeps its available commands, flags, and help text up to date for you.

  • Synced automatically after login.
  • Refreshed when missing or older than 7 days.
  • Run tft sync to refresh the command list at any time.

If the command list is unavailable, run tft login or tft sync after signing in.

Configuration

Optional environment variables:

VariableDefault
THEFLUXTRAIN_API_URLhttps://api.thefluxtrain.com/api/v1
THEFLUXTRAIN_CONFIG_DIR~/.config/thefluxtrain
THEFLUXTRAIN_CACHE_DIR~/.cache/thefluxtrain
THEFLUXTRAIN_RENDER_APIhttps://render.thefluxtrain.com

Point THEFLUXTRAIN_API_URL at a local or staging API when developing against your own backend. Point THEFLUXTRAIN_RENDER_API at a local render service when developing media info or cloud render (same as frontend VITE_RENDER_API).

Core commands

CommandDescription
tft loginDevice-code sign-in via thefluxtrain.com
tft logoutClear local credentials and local CLI data
tft syncRefresh the CLI command list
tft whoamiShow logged-in user and API key id
tft commandsList all available API command groups
tft media infoGet video, audio, or image metadata via the render service API

Commands for image generation, Flow Studio, video, jobs, and more appear after the command list is refreshed. Run tft commands to see the current list.

Media metadata

Probe video, audio, or image files through the render service API:

tft media info --file ./clip.mp4
tft media info --url UPLOAD_URL --output json

Set THEFLUXTRAIN_RENDER_API for local render service development (default: https://render.thefluxtrain.com, same as frontend VITE_RENDER_API).

Use the returned data.duration for audio clips; use data.width, data.height, and data.duration for video/image createAsset apply actions.

Flow Studio

Use the CLI to list, create, read, and edit Flow Studio graphs programmatically. Changes are saved to your account—the same flows you open in the browser at Flow Studio.

Authentication is the same as other CLI commands: run tft login once. You do not need a separate API key for Flow Studio.

If flow-studio commands are missing, run tft sync to refresh the command list after a backend update.

Commands

CommandDescription
tft flow-studio listList your saved flows (id, name, timestamps)
tft flow-studio createCreate a blank flow or duplicate an existing one
tft flow-studio getFetch one flow's metadata and full graph state
tft flow-studio applyApply ordered graph mutations (create/update/delete/connect)
tft flow-studio nodesList available node types, ports, and usage hints
tft flow-studio collectionsList collections for wiring input-collection nodes

Run tft flow-studio <command> --help for flags and copy-pastable examples.

Typical workflow

  1. List or create — find an existing flow or start a new one:
tft flow-studio list
tft flow-studio create --name "Product ad pipeline"
  1. Inspect the catalog — before adding nodes, look up definitionId values and port ids:
tft flow-studio nodes
  1. Load the graph (optional) — see current nodes and connections:
tft flow-studio get --flow-id YOUR_FLOW_ID
  1. Patch the graph — send one or more actions in order:
tft flow-studio apply --flow-id YOUR_FLOW_ID --actions '[
  {"op":"create","definitionId":"utils-prompt-template","position":{"x":100,"y":100}},
  {"op":"create","definitionId":"flux-2-pro","position":{"x":400,"y":100}}
]'
  1. Wire collections (when using input-collection nodes) — list collections first, then pass the returned id (not the display name) in an update action:
tft flow-studio collections

Duplicate an existing flow instead of building from scratch:

tft flow-studio create --name "Copy of demo" --source-flow-id YOUR_FLOW_ID

Apply actions

Pass --actions as a JSON array. Each element is one mutation applied in sequence. Property names inside actions use camelCase (matching the graph JSON in the browser).

create

Add a node to the canvas.

{
  "op": "create",
  "definitionId": "utils-prompt-template",
  "position": { "x": 100, "y": 100 },
  "id": "optional-custom-node-id",
  "label": "Optional label"
}

update

Patch fields on an existing node (position, label, size, inputs, internalState, dynamicInputs, dynamicOutputs).

{
  "op": "update",
  "nodeId": "node-uuid",
  "patch": {
    "inputs": { "prompt": "A cat in a spacesuit" }
  }
}

For input-collection nodes, set inputs.folder_id to a collection id from tft flow-studio collections.

delete

Remove a node (its connections are removed too).

{ "op": "delete", "nodeId": "node-uuid" }

connect

Wire an output port to an input port. nodeId must equal targetNodeId.

{
  "op": "connect",
  "nodeId": "target-node-id",
  "sourceNodeId": "source-node-id",
  "sourceOutputId": "output-port-id",
  "targetNodeId": "target-node-id",
  "targetInputId": "input-port-id"
}

Prefer small batches of actions; if apply fails, read the error message and fix the batch before retrying.

Response format

Flow Studio commands return the standard API envelope (data / error). Useful fields:

CommandKey data fields
listflows[] with id, name, created_at, updated_at
createflow_id, name, flow (graph state)
getflow_id, name, flow (nodes, connections, viewport, videoTaskList)
applyflow_id, flow (updated graph state)
nodesnodes[] with id, inputs/outputs, use_when, avoid_when
collectionscollections[] with id, name, description, source

Use --output yaml on any command for YAML instead of JSON. Default output is compact single-line JSON; use --output pretty for indented JSON. Use --fields data.url to print a single value without parsing JSON.

Shell tips for --actions

  • Wrap the JSON in single quotes so the shell does not expand $ or backticks.
  • For long action lists, store JSON in a file and pass with @:
tft flow-studio apply --flow-id YOUR_FLOW_ID --actions @actions.json

Or read from stdin: --actions -

Browser live sync

While you edit a flow from the CLI or REST API, open it in Flow Studio and turn on Live sync in the toolbar. The canvas reloads from your saved graph every few seconds in read-only mode so you can watch changes without conflicting edits. Turn live sync off to edit manually in the browser.

REST API equivalent

The CLI calls the same endpoints as the REST API (see Authentication):

MethodPath
GET/flow-studio/flows
POST/flow-studio/flows
GET/flow-studio/flows/{flow_id}
POST/flow-studio/flows/{flow_id}/apply
GET/flow-studio/nodes
GET/flow-studio/collections

Flow Studio commands edit graph structure only—they do not run generation jobs. To execute nodes, use the browser or call image, video, and other generation endpoints directly.

Video Editor

The video-editor command group edits timeline projects stored in your account. Projects sync with the browser video editor at /video-editor.

Typical workflow

  1. Probe local media (for width, height, duration):
tft media info --file ./clip.mp4
  1. Upload media (for video/image/audio clips):
tft files upload --file ./clip.mp4
  1. Create a project:
tft video-editor create --name "My edit"
  1. Add assets via apply-asset (creates mediaLibrary entry + timeline clip with sourceAssetId):
tft video-editor apply-asset --project-id YOUR_PROJECT_ID --actions '[
  {"op":"createAsset","type":"video","trackId":"track-1","cloudUrl":"UPLOAD_URL",
   "name":"clip.mp4","width":1920,"height":1080,"duration":10.5}
]'

Add an audio clip (duration only — no width/height):

tft video-editor apply-asset --project-id YOUR_PROJECT_ID --actions '[
  {"op":"createAsset","type":"audio","trackId":"track-2","cloudUrl":"UPLOAD_URL",
   "name":"voice.mp3","duration":6.0}
]'

Re-use the same upload on another track or time with sourceAssetId from the prior response:

tft video-editor apply-asset --project-id YOUR_PROJECT_ID --actions '[
  {"op":"createAsset","type":"video","trackId":"track-2","sourceAssetId":"media-abc123"}
]'
  1. Inspect the timeline:
tft video-editor get --project-id YOUR_PROJECT_ID

Apply actions

The CLI provides four apply commands that call the same REST endpoint:

  • tft video-editor apply-asset — asset ops (clips + media)
  • tft video-editor apply-subtitle — subtitle ops (enable/disable, per-word edits)
  • tft video-editor apply-timeline — timeline ops (tracks + settings)
  • tft video-editor apply-story — project story text (--text)

Pass --actions as a JSON array with camelCase fields.

apply-asset operations

opPurpose
createAssetAdd clip on timeline. Video/image: new upload needs cloudUrl, width, height, duration. Audio: new upload needs cloudUrl, duration. Re-use any media type with sourceAssetId only.
updateAssetPatch asset fields (assetId, patch)
deleteAssetRemove asset (assetId)
splitAssetSplit video at asset-relative times (assetId, splitTimes[] — seconds from clip start, not global timeline)

apply-subtitle operations

opPurpose
updateAssetToggle subtitles or set/replace full subtitle track (patch.subtitlesEnabled, patch.subtitles)
updateSubtitleWordPatch one word by index (assetId, wordIndex, wordPatch)

apply-timeline operations

opPurpose
createTrackAdd a track (name, optional id)
deleteTrackRemove track and its assets (trackId)
updateSettingsPatch composition settings (patch: width, height, fps, backgroundColor)

apply-story

Set the project narrative stored in the Story tab:

tft video-editor apply-story --project-id YOUR_PROJECT_ID --text "Scene 1: Opening shot..."
tft video-editor apply-story --project-id YOUR_PROJECT_ID --text ""

The get response includes project.story. You can also pass [{"op":"updateStory","text":"..."}] via --actions on the apply endpoint.

Get width, height, and duration with tft media info --file ./clip.mp4 or --url UPLOAD_URL.

Browser live sync

Open the project in the video editor and turn on Live sync in the toolbar. The timeline reloads from Supabase every few seconds in read-only mode while CLI or REST edits are applied. Turn live sync off to edit manually.

REST API equivalent

MethodPath
GET/video-editor/projects
POST/video-editor/projects
GET/video-editor/projects/{project_id}
POST/video-editor/projects/{project_id}/apply
POST/video-render/media/info
DELETE/video-editor/projects/{project_id}

Troubleshooting

What you seeWhat to try
Login timed outRun tft login again and complete authorization in the browser before the code expires.
Command list unavailableRun tft login or tft sync.
403 UnauthorisedRun tft logout, then tft login again. Or revoke the old key on API keys and sign in fresh.
Command not foundRun tft sync to refresh the command list — new API endpoints are added server-side.
flow-studio group missingRun tft sync after upgrading the backend; confirm with tft commands.
Apply returns 422Check action JSON: valid op, camelCase fields, and port ids from tft flow-studio nodes.
Apply returns 404Confirm --flow-id exists (tft flow-studio list) and belongs to your account.
video-editor group missingRun tft sync after upgrading the backend; confirm with tft commands.
Video apply returns 422Check action JSON; video/image need cloudUrl + dimensions from tft media info; audio needs cloudUrl + duration. (Tip: use apply-asset for clip/media ops.)

Next steps

  • API keys — create keys for REST integrations outside the CLI.
  • Authentication — how API keys are sent on HTTP requests.
  • Introduction — REST API overview and endpoint reference.