Skip to main content

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

Project description

                      $$\                                                      $$\       
                      $$ |                                                     $$ |      
 $$$$$$\  $$\   $$\ $$$$$$\    $$$$$$\   $$$$$$\   $$$$$$\  $$$$$$\   $$$$$$\  $$$$$$$\  
 \____$$\ $$ |  $$ |\_$$  _|  $$  __$$\ $$  __$$\ $$  __$$\ \____$$\ $$  __$$\ $$  __$$\ 
 $$$$$$$ |$$ |  $$ |  $$ |    $$ /  $$ |$$ /  $$ |$$ |  \__|$$$$$$$ |$$ /  $$ |$$ |  $$ |
$$  __$$ |$$ |  $$ |  $$ |$$\ $$ |  $$ |$$ |  $$ |$$ |     $$  __$$ |$$ |  $$ |$$ |  $$ |
\$$$$$$$ |\$$$$$$  |  \$$$$  |\$$$$$$  |\$$$$$$$ |$$ |     \$$$$$$$ |$$$$$$$  |$$ |  $$ |
 \_______| \______/    \____/  \______/  \____$$ |\__|      \_______|$$  ____/ \__|  \__|
                                        $$\   $$ |                   $$ |                
                                        \$$$$$$  |                   $$ |                
                                         \______/                    \__|                
ComfyUI                                                                      version: 2.0.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.0.0.tar.gz (114.6 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.0.0-py3-none-any.whl (117.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: comfyui_autograph-2.0.0.tar.gz
  • Upload date:
  • Size: 114.6 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.0.0.tar.gz
Algorithm Hash digest
SHA256 1d2af468956fd8b94642637a5685f8c178cc86167544f779efa8fa1620239edc
MD5 3ecd2d75e4979cedced1825fe0936448
BLAKE2b-256 242b0c5773085328292357ce686b13ebab0de73c5bbc5cb9c344a074ecd55aa1

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for comfyui_autograph-2.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 bcb903b41396fd7317e99c4d5d5c308bfe1b2c20aef26cd4ad2777090ea45f73
MD5 c678df064c169739062c1e89cca31cc6
BLAKE2b-256 a39ce9e5993aed7c2170cb9d6b422c5d44699f84a9428751ae1af95956a66421

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