Lightweight, headless runner for submitting ComfyUI workflows via API.
Features:
- Zero external dependencies (stdlib only)
- Clean workflow submission with fluent API
- Multi-GPU round-robin distribution
- Simple result handling
# Clone the repo
git clone https://github.com/SagiPolaczek/comfy-api-runner.git
cd comfy-api-runner
# Or install in development mode
pip install -e .from comfy_runner import ComfyClient, Workflow
# Load and modify workflow
wf = Workflow.load("my_workflow.json")
wf.set_node("32", "image", "/path/to/image.png")
wf.set_node("28", "text", "my prompt")
wf.set_node("29", "filename_prefix", "outputs/run_001")
# Submit
client = ComfyClient(port=5892)
result = client.queue(wf)
print(f"Queued: {result['prompt_id']}")from comfy_runner import Workflow, BatchRunner
# Define node mappings once
NODES = {
"input_image": "32",
"prompt": "28",
"output": "29",
}
# Setup
runner = BatchRunner(ports=[5892, 5893, 5894, 5895])
workflow = Workflow.load("my_workflow.json")
# Generate and queue jobs
for params in my_params:
job = (workflow.copy()
.set_node(NODES["input_image"], "image", params.image)
.set_node(NODES["prompt"], "text", params.prompt)
.set_node(NODES["output"], "filename_prefix", f"out/{params.name}"))
runner.queue(job)
print(runner.summary())client = ComfyClient(host="127.0.0.1", port=8188)
client.queue(workflow) # Submit workflow, returns {"prompt_id": ...}
client.get_queue() # Get queue status
client.get_history(id) # Get execution historywf = Workflow.load("path/to/workflow.json")
wf.set_node("32", "image", value) # Set node input (fluent, returns self)
wf.get_node("32") # Get entire node dict
wf.get_node("32", "image") # Get specific input value
wf.has_node("32") # Check if node exists
wf.copy() # Deep copy for batch jobs
wf.validate() # Returns list of warnings
wf.to_dict() # Export as dict
wf.save("output.json") # Save to filerunner = BatchRunner(ports=[5892, 5893], host="127.0.0.1")
runner.queue(workflow) # Queue to next server (round-robin)
runner.queue_all(workflows) # Queue multiple with progress
runner.summary() # Get job distribution summary
runner.reset() # Reset countersOpen your workflow JSON and look for the node you want to modify:
{
"32": {
"class_type": "LoadImage",
"inputs": {
"image": "example.png"
}
}
}The key ("32") is the node ID. Use it with set_node():
wf.set_node("32", "image", "/path/to/my/image.png")See the examples/ directory:
simple_submit.py- Single workflow submissionbatch_submit.py- Batch submission across multiple GPUs
Before (repeated boilerplate):
def load_workflow(path): ... # 15 lines
def queue_prompt(wf, port): ... # 20 lines
def modify_workflow(wf, ...): ... # 50+ linesAfter:
from comfy_runner import Workflow, BatchRunner
runner = BatchRunner(ports=[5892, 5893])
wf = Workflow.load("workflow.json")
wf.set_node("32", "image", path).set_node("28", "text", prompt)
runner.queue(wf)