Skip to main content

Pure Python automation for ComfyUI: convert workflows, submit jobs, fetch images—no GUI required

Project description

                      $$\                                                      $$\       
                      $$ |                                                     $$ |      
 $$$$$$\  $$\   $$\ $$$$$$\    $$$$$$\   $$$$$$\   $$$$$$\  $$$$$$\   $$$$$$\  $$$$$$$\  
 \____$$\ $$ |  $$ |\_$$  _|  $$  __$$\ $$  __$$\ $$  __$$\ \____$$\ $$  __$$\ $$  __$$\ 
 $$$$$$$ |$$ |  $$ |  $$ |    $$ /  $$ |$$ /  $$ |$$ |  \__|$$$$$$$ |$$ /  $$ |$$ |  $$ |
$$  __$$ |$$ |  $$ |  $$ |$$\ $$ |  $$ |$$ |  $$ |$$ |     $$  __$$ |$$ |  $$ |$$ |  $$ |
\$$$$$$$ |\$$$$$$  |  \$$$$  |\$$$$$$  |\$$$$$$$ |$$ |     \$$$$$$$ |$$$$$$$  |$$ |  $$ |
 \_______| \______/    \____/  \______/  \____$$ |\__|      \_______|$$  ____/ \__|  \__|
                                        $$\   $$ |                   $$ |                
                                        \$$$$$$  |                   $$ |                
                                         \______/                    \__|                
ComfyUI                                                                      version: 2.1.0

PyPI version Python License: MIT GitHub stars GitHub issues Downloads

flowchart LR
  workflowJson["workflow.json"] --> autograph["autograph"]
   --> apiFlow[workflow-api.json]

Imagine...

What if you could load, edit, and submit ComfyUI workflows without ever exporting an API workflow from the GUI?

What if you could batch-convert and patch workflows offline No running ComfyUI instance required?

What if you could attach studio metadata to your workflow and have it carry through the entire production lifecycle?

What if you could render comfyui node workflows with all of the above features, without ever launching the comfyui server?

  • Let me introduce comfyui-autograph


autograph

Skip the GUI. autograph handles the backend so you can automate/pipeline your ComfyUI renderables with full control through the entire conversion and submission process. autograph is a small and efficient, pure Python package (stdlib-only +extendable) for ComfyUI automation that gives you access to renderable conversion with or without ComfyUI.

Features

Feature Description
Convert workflow.json workflow.json → renderable API payload, skip the GUI export entirely
Offline / Online Convert without a running ComfyUI server, or fetch live from one
Submit + Images Send to ComfyUI, wait for completion, fetch and save output images
Progress Hook into WebSocket render events for real-time progress control
Edit + Introspect api.KSampler.seed = 42, .find(...), .choices(), .tooltip(). OOP access to every node and widget
Metadata Attach studio metadata to workflows that carries through the entire production lifecycle
Serverless Execute .execute() runs ComfyUI nodes in-process, no HTTP server required
Map Sweep seeds, prompts, paths across nodes for batch pipelines
Save + Load .save() / .load() on Flow, ApiFlow, and NodeInfo for simple serialization of any object
Extract Load workflows directly from ComfyUI PNG outputs (embedded metadata)
Stdlib-only Zero dependencies by default; optional Pillow, ImageMagick, ffmpeg
Subgraphs Flattens nested definitions.subgraphs into a normal API payload

Requirements

  • Python 3.7+ (dict insertion order preserved)
  • ComfyUI server (optional, for API mode)
  • No additional Python packages required

Tested ComfyUI Versions:

  • ComfyUI 0.8.2
  • ComfyUI_frontend v1.35.9

The Two ComfyUI Formats you should know about

ComfyUI uses two JSON formats:

Format File Description
Workspace workflow.json The UI-editable graph with node positions, colors, widgets. What you save from ComfyUI.
API Payload workflow-api.json The renderable blueprint—just nodes + inputs, ready for POST /prompt. This is what ApiFlow represents.

autograph converts Workspace → API Payload (or loads an existing API Payload directly).

flowchart LR
  workspace["workflow.json (workspace)"] --> convert["autograph"]
  convert --> payload["workflow-api.json (API payload / ApiFlow)"]
  payload --> submit["POST /prompt"]
  submit --> comfy["ComfyUI renders"]

Installation

pip install comfyui-autograph

Then use with python -m autograph ... or import autograph from Python.

  • Optional: set AUTOGRAPH_COMFYUI_SERVER_URL once (then server_url / --server-url become optional):
    • Linux/macOS: export AUTOGRAPH_COMFYUI_SERVER_URL="http://localhost:8188"
    • Windows PowerShell: $env:AUTOGRAPH_COMFYUI_SERVER_URL = "http://localhost:8188"
    • Windows CMD: set AUTOGRAPH_COMFYUI_SERVER_URL=http://localhost:8188
    • Python: import os; os.environ["AUTOGRAPH_COMFYUI_SERVER_URL"] = "http://localhost:8188"
  • Optional: set AUTOGRAPH_NODE_INFO_SOURCE=modules|fetch|server|/path/to/node-info.json to auto-resolve node_info.

autograph - Quick Start

Get node-info.json (optional, one-time)

Save node-info.json so you can convert offline. You can also convert against a running ComfyUI instance, but for efficiency we recommend pulling a new node-info.json per instance (reproducible, no server needed).

flowchart LR
  comfy["ComfyUI server"] --> obj["/object_info"]
  obj --> file["node-info.json"]
# api — set AUTOGRAPH_COMFYUI_SERVER_URL first (see Installation above)
from autograph import NodeInfo

node_info = NodeInfo('fetch')
node_info.save('node-info.json')
# cli
python -m autograph --download-node-info-path node-info.json
  • Direct modules (no server): NodeInfo.from_comfyui_modules() builds node_info from local ComfyUI nodes.

  • Env source (optional): set AUTOGRAPH_NODE_INFO_SOURCE=modules|fetch|server|/path/to/node-info.json.

  • More: docs/node-info-and-env.md

Convert live (using running ComfyUI)

Convert workflow.json by fetching /object_info from your running ComfyUI server.

flowchart LR
  env["AUTOGRAPH_COMFYUI_SERVER_URL"] --> wf["Flow(...)"]
  wf --> flow["Flow"]
  comfy["ComfyUI server"] --> obj["/object_info"]
  obj --> wf

If environment variable AUTOGRAPH_COMFYUI_SERVER_URL is set, server_url becomes optional.

If AUTOGRAPH_NODE_INFO_SOURCE is set, Flow(...) / ApiFlow(...) will auto-resolve node_info when none is provided.

# api — use Flow to work with workflow.json natively
from autograph import Flow

flow = Flow("workflow.json")   # uses AUTOGRAPH_COMFYUI_SERVER_URL
flow.save("workflow-out.json") # stays in workspace format

# or convert to API payload
api = flow.convert()
api.save("workflow-api.json")

Note: ApiFlow("workflow.json") also works and always converts to the API format. Flow keeps the workspace format and converts on demand.

# cli
python -m autograph --input-path workflow.json --output-path workflow-api.json

Convert workflow to workflow-api (offline)

Convert using your saved node-info.json (no server needed).

flowchart LR
  workflowJson["workflow.json"] --> wf["Flow(...)"]
  objectInfo["node-info.json"] --> wf
  wf --> flow["Flow"]
  flow --> convert["flow.convert()"]
  convert --> apiFlow["ApiFlow"]
  apiFlow --> saveApi["save(workflow-api.json)"]
# api — Flow-first: load, optionally edit, then convert
from autograph import Flow

flow = Flow("workflow.json", node_info="node-info.json")
flow.save("workflow-out.json")       # save workspace format

api = flow.convert()                  # convert to API payload
api.save("workflow-api.json")         # save API format
# cli
# Offline mode (saved node_info)
python -m autograph --input-path workflow.json --output-path workflow-api.json --node-info-path node-info.json

# Short form (flags)
python -m autograph -i workflow.json -o workflow-api.json -f node-info.json

Build Workflows from Scratch

Create and wire ComfyUI workflows entirely from Python — full tab completion, Pythonic dict-like views, and multiple connection syntaxes.

from autograph import Flow, NodeInfo

flow = Flow(node_info="node-info.json")

# Add nodes
ckpt = flow.add_node("CheckpointLoaderSimple")
pos  = flow.add_node("CLIPTextEncode", text="a beautiful landscape")
neg  = flow.add_node("CLIPTextEncode", text="ugly, blurry")
lat  = flow.add_node("EmptyLatentImage", width=1024, height=1024)
ks   = flow.add_node("KSampler", seed=42, steps=20, cfg=7.0)
vae  = flow.add_node("VAEDecode")
save = flow.add_node("SaveImage", filename_prefix="test")

# Wire connections — all equivalent styles:
ckpt.outputs.MODEL >> ks.inputs.model      # explicit push
ks.inputs.positive << pos                  # pull (auto-resolve output)
ckpt.outputs.CLIP >> [pos.inputs.clip, neg.inputs.clip]  # fan-out
ckpt >> vae.vae                            # shorthand (auto-resolve)

# Inspect connections
ks.inputs               # {'model': 'CheckpointLoaderSimple.MODEL', 'positive': None, ...}
ckpt.outputs             # {'MODEL': 'KSampler.model', 'CLIP': '...', 'VAE': None}
print(ks.inputs.status()) # full ANSI-colored status table

# Disconnect
ks.inputs.model << None                   # operator
ckpt.outputs.CLIP.disconnect(pos.inputs.clip)  # targeted

# Save
flow.auto_layout()
flow.save("my-workflow.json")
  • node.inputs / node.outputs — dict-like views: [], pop(), del, keys/values/items
  • flow.nodes.KSampler returns the same NodeRef as flow.add_node()
  • .status() on any view gives a full ANSI-colored connection table

Load from PNG (extract embedded workflow)

ComfyUI embeds workflow metadata in PNG outputs. Extract it directly—no external dependencies needed.

# api
from autograph import Flow, ApiFlow

# From PNG file
api_flow = ApiFlow.load("ComfyUI_00001_.png")  # extracts API payload
flow = Flow.load("ComfyUI_00001_.png")          # extracts workspace

# From bytes (e.g., HTTP upload, database blob)
with open("output.png", "rb") as f:
    api_flow = ApiFlow.load(f.read())

All .load() methods accept: dict, bytes, str (JSON or path), Path

Submit + images (optional)

Submit your ApiFlow directly to ComfyUI and get images back

flowchart LR
  apiFlow["ApiFlow"] ==> submit["submit(wait=True)"]
  submit ==> comfy["ComfyUI server"]
  comfy --> |job handle|apiFlow
  apiFlow ---> |job handle| images["fetch_images().save(...)"]
# api
from autograph import ApiFlow

api = ApiFlow("workflow.json")
api.saveimage.inputs.filename_prefix='autograph'
res = api.submit(server_url="http://localhost:8188", wait=True)
images = res.fetch_images()
images.save("outputs/frame.###.png")

You can also set an output default with env AUTOGRAPH_OUTPUT_PATH and then just provide a filename= template:

# api
images.save(filename="frame.{src_frame}.png")  # or "frame.###.png" for zero-indexed numbering
# cli
# Prints prompt_id first, then (if saving) the written file paths. Progress logs go to stderr.
python -m autograph --submit --input-path workflow.json --server-url http://localhost:8188 \
  --save-images outputs --filepattern "frame.###.png" --index-offset 1001

Serverless execute (no ComfyUI HTTP server)

If you're running inside a ComfyUI environment (repo + venv), you can run workflows serverlessly:

Optional Functionality

  • Polymorphic loading (dict, bytes, JSON string, file path, PNG):
    • all .load() methods auto-detect input type: docs/load-vs-convert.md
    • extract workflows from ComfyUI PNG outputs (no dependencies)
  • OOP node access:
    • api.KSampler.seed = 42 — attribute-style access by class_type
    • api.find(class_type="KSampler")[0].seed = 42 — search + then edit (returns NodeProxy objects)
    • api.KSampler._meta / .meta — access node metadata
    • api["ksampler/seed"] — path-style access
    • api["18:17:3/seed"] = 42 — edit nodes inside flattened subgraph exports (ComfyUI-style path IDs)
    • flow.nodes.KSampler.type — explicit via .nodes for workspace flows
    • flow.nodes.find(title="NewSubgraphName")[0].path() — find renamed subgraph instances; prints a stable path like 18:17:3
    • flow.extra.ds.scale — drill into nested dicts with DictView
    • node.properties.models.url — single-item list-of-dicts drill via ListView (otherwise index first)
    • Widget-value repr: NodeRef/NodeSet display widget values as dicts — f.nodes.CheckpointLoaderSimple{'nodes.CheckpointLoaderSimple[0]': {'ckpt_name': '...'}}
    • Widget introspection: .choices() returns valid combo options, .tooltip() shows help text, .spec() gives the raw node_info spec
    • Tab completion: curated __dir__ on ApiFlow, NodeSet, FlowTreeNodesView, and WidgetValue — only shows user-facing attrs
    • Indexed nodes: standard Python REPL can't tab-complete api.KSampler[0].<tab> — assign to a variable first: k = api.KSampler[0] then k.<tab>
  • Mapping (seeds/paths/prompts):
  • Filename pattern saving:
  • Service patterns:
  • When things break:

CLI Reference

Argument Short Description
--input-path -i Input workflow JSON file path
--output-path -o Output API format JSON file path
--server-url ComfyUI server URL (or set AUTOGRAPH_COMFYUI_SERVER_URL)
--node-info-path -f Path to saved node_info.json file
--download-node-info-path Download /object_info and save to file
--submit Submit converted API payload to ComfyUI
--no-wait Submit without waiting for completion (prints prompt_id and exits)
--no-progress Disable progress output during --submit when waiting
--save-images Directory to save fetched images (requires waiting)
--filepattern Filename pattern used when saving images (default: frame.###.png)
--index-offset Index offset for # patterns (default: 0)
--save-files Directory to save fetched registered files (requires waiting)
--output-types Comma-separated registered output types when saving files (e.g. images,files)

Note: The CLI supports submission and saving registered outputs via --submit (see docs/submit-and-images.md and docs/progress-events.md).

Contributing

This script is designed to be production-ready and maintainable. Key design principles:

  • Minimal Dependencies: Uses only Python standard library
  • Cross-Platform Compatibility: Works on Linux, Windows, and macOS
  • Robust Error Handling: Graceful degradation and detailed error reporting
  • Exact Replication: Matches ComfyUI's internal conversion exactly

For development setup, running tests, and code style guidelines, see CONTRIBUTING.md.

License

MIT License

Related

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

comfyui_autograph-2.1.0.tar.gz (119.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

comfyui_autograph-2.1.0-py3-none-any.whl (122.2 kB view details)

Uploaded Python 3

File details

Details for the file comfyui_autograph-2.1.0.tar.gz.

File metadata

  • Download URL: comfyui_autograph-2.1.0.tar.gz
  • Upload date:
  • Size: 119.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for comfyui_autograph-2.1.0.tar.gz
Algorithm Hash digest
SHA256 01f74c543cb262c4b04c9e60234a36c57b8ffb2300c615a59e7491ecead710df
MD5 b1ebb89e57220dd33aa7a63f1d3ebbb0
BLAKE2b-256 54603276f3c804f6ff53e2dcc445963a6e9cc2567b00769dab124f54071917ac

See more details on using hashes here.

File details

Details for the file comfyui_autograph-2.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for comfyui_autograph-2.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5bada5c37edb56ebf798df52fe9b64cb69d972b03b569356734d637d16f2e6ba
MD5 4dec95f87317e745316b036fcd684460
BLAKE2b-256 b83c781d86a1f5f68cba9c7f3f4d75598e40860ce9e8558fa9d3cbd2a1287851

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page