RB Command
Run ffmpeg and your own scripts from inside a ComfyUI workflow
- input_0
- stdout
- stderr
- exit_code
ComfyUI ends where your terminal begins. Need to hstack two videos, thumbnail a batch, or hand a generated image to a Python script that doesn't have a node? Normally that's "save it, alt-tab, run the command, come back." RB Command (class RB_Command, from the comfyui-rb-command pack) pulls that step back inside the graph: it runs an arbitrary shell command as part of your workflow, lets you wire images, video, audio and text straight into it as inputs, and hands back stdout, stderr and the exit code as wireable outputs.
It's glue, and it's the kind of node that quietly disappears into your more elaborate pipelines - you install it for one annoying thing and end up using it everywhere: ffmpeg filters that don't exist as nodes, your own post-processing scripts, or ComfyUI as the middle of an automation chain.
How it works
Under the hood it's a subprocess that runs your command through /bin/bash (configurable), with three layers of substitution that make graph data usable inside the shell:
{placeholder}syntax in the command text.{input0},{input1}, ... become the file paths of whatever you connected;{seed}becomes your seed value. Paths are auto-quoted withshlex.quote, so filenames with spaces and weird characters are handled for you.- Environment variables -
$INPUT_0,$INPUT_ALL,$SEED, plus counts like$INPUT_IMAGE_COUNT- if you prefer scripting to string replacement. - Type conversion on the way in. An
IMAGEtensor is flushed to a temp PNG, video inputs to a temp MP4, audio to WAV, plain strings/numbers pass through as text. Those temp files are deleted after the run, and the only real dependency cost is numpy/Pillow/scipy - all of which you almost certainly already have. No models to download, no heavy extras.
While the process runs, stdout and stderr stream live to the console and to a small output panel on the node (the pack ships a web extension for that). There's also a one-entry result cache: it hashes the command, seed, working dir, executable, timeout and input files' size/mtime, and skips re-executing if the exact same thing runs again.
The inputs and outputs that matter
command- a multiline string, the whole show. Default is a demoecho. Supports every placeholder above.seed- plain INT with acontrol_after_generatetoggle, so you can randomize it per run. Only matters if your command references{seed}or$SEED.timeout- seconds (1–3600, default 30). The process gets killed if it exceeds this.working_dirandexecutable- cwd for the command and the interpreter (/bin/bashby default).input_0- the first of up to 20 dynamic, any-type input slots. Connecting something spawns the next one automatically.- Outputs:
stdoutandstderr(both STRING) andexit_code(INT). Wire stdout into a text preview/display node to see it, or feedexit_codeinto a conditional to branch on success.
A typical ffmpeg job reads like:
ffmpeg -y -i {input0} -i {input1} -filter_complex "[0:v][1:v]hstack" combined.mp4
Note you do not add your own quotes around {input0} - the substitution is already shell-quoted, and double-quoting it backfires.
Installing
ComfyUI Manager is the easy route - search "comfyui-rb-command" (it displays as "RB Command") and install. Or the old-school way:
cd ComfyUI/custom_nodes/
git clone https://github.com/itribs/comfyui-rb-command.git
pip install -r requirements.txt
Then restart ComfyUI. No checkpoints, no config, no API key.
Where people get burned
- The tools aren't bundled. This node runs commands; it doesn't ship ffmpeg or ImageMagick. If
ffmpegisn't on your PATH, the run fails with a non-zero exit in stderr - the first thing to check when "nothing happens." - Windows +
/bin/bash. The default executable doesn't exist on a vanilla Windows box. Setexecutableto something you actually have (or install Git Bash), or the spawn itself fails. - The 30-second default timeout will bite you on real video encodes. Crank
timeoutup before running something long. working_dirmust exist - it raises aValueErrorotherwise.- Caching can look like a bug. If you re-queue with an unchanged command and identical inputs, you get the cached result rather than a fresh run. That's the feature working as designed; change any input and the fingerprint changes. And because this isn't an output node, ComfyUI's normal graph cache also applies - if nothing it depends on changed, it may not re-execute at all.
- It's arbitrary shell execution. Full stop. A
commandwidget runs whatever's in it with your user's permissions - exactly the no-sandbox situation that's made custom nodes a malware vector in this ecosystem. Only use it in workflows you wrote yourself and trust; never load a shared workflow containing this node without reading its commands.
The pack is new and still early, but the mechanism is simple and the README is honest. If you keep hitting the "I just need to run one command" wall, this is a clean way through it.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| command | STRING | echo input: {input0} seed: {seed} | Placeholders: {input0} {input_count} {input_all} {input_image_count} {input_video_count} {input_audio_count} {seed} Environment variables: $INPUT_0 $INPUT_1 $SEED $INPUT_COUNT $INPUT_ALL $INPUT_IMAGE_COUNT $INPUT_VIDEO_COUNT $INPUT_AUDIO_COUNT |
| working_dir | STRING | /tmp/ComfyUI/custom_nodes | Working directory for command execution |
| executable | STRING | /bin/bash | Shell interpreter to use (e.g. /bin/bash, /bin/sh, python3) |
| timeout | INT | 301–3600 | Timeout in seconds, process will be killed if exceeded |
| seed | INT | 00–18446744073709550000 | Random seed, accessible via {seed} or $SEED |
| input_0opt | * | Dynamic input slot, connect any type (image, audio, video, text, etc.). Connecting triggers more slots up to 20 |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| stdout | STRING | — |
| stderr | STRING | — |
| exit_code | INT | — |