Skip to main content

日本語 | 中文 | Español | Français | हिन्दी | Italiano | Português (BR)

comfy-preflight

CI PyPI npm MIT License Landing page

A gate that runs on a ComfyUI workflow graph in the seconds before it is submitted,
and halts a submission that would spend credits producing a known-wrong result.
It does not submit. It does not fix your graph.


The gap it lives in

A Comfy Cloud dry_run PASS does not prove link sanity. A hand-retyped payload with a self-referencing node link — VAEDecode.samples = ["14", 0], the node pointing at itself — returned status: validated.

The provider's validator answers is this graph well-formed enough to run. It does not answer is this the graph you meant. Every check here lives in that gap, and each one was paid for by a run that got past dry_run.

Submission is the irreversible act with no real undo, and a preflight is a compensator you run BEFORE instead of after. A completed cloud job is billed; the only compensator afterwards is cancel it if it is still queued, otherwise none. That is the whole argument for this package.

Install

npx @mcptoolshop/comfy-preflight check graph.json   # no Python needed
pip install comfy-preflight                          # for the in-process gate
pip install "comfy-preflight[mcp]"                   # + the MCP stdio server

The npx launcher downloads a binary from this repo's GitHub Release and verifies its SHA256 against the checksums in that same release before running it. Python ≥ 3.11; binaries for linux-x64 and win-x64 (macOS installs via pip).

Use it

The production gate — in-process, on the submit path:

from comfy_preflight import preflight

# Inside the function that submits. Not in a shell step before it.
preflight(graph, register, input_dims=(width, height))   # raises PreflightHalt
submit(graph)                                            # only reached if nothing raised

The development door:

comfy-preflight check graph.json \
  --input-dims 1072x1024 --register subject.json --saved sidecar.json --json
exit meaning
0 nothing halted — PASS, ADVISORY or NOT_APPLICABLE, each named in the output
1 HALT
2 nothing was examined — bad arguments, unreadable file, or an internal error

ADVISORY exits 0 on purpose: a nonzero status stops a && chain, which would turn an advisory into a halt in every shell that runs one.

What it checks

# check halts on
1 Link topology a node input reading its own node; a link to a node id not in the graph
2 The inverted register scan a declared register that does not match the graph's construction — in both directions
4 Saved-is-submitted the saved sidecar and the submitted payload differing as parsed graphs
5 Generator-legal frame a dimension the effective frame's VAE cannot decode at
8 Declared envelope nothing — it never halts. Out-of-band is an ADVISORY

Three checks from the original design are not built, and are named rather than quietly missing: recipe-vs-profile agreement (no subject-profile fixture exists), estimate-before-submit (transport-side — no graph-structural operand), and anchor reproduction (needs the graph builder; the corpus holds outputs, not the scripts that made them).

Check 2 — the one that names the method

When a subject's register declares no style adapter, the claim being asserted is not "the weight is 0.0". It is that no loader node and no adapter card reference exist anywhere in the graph.

A weight of 0.0 is not a weight of zero on a loaded card; it is no card.

And it asserts the mirror image. A decided positive weight with no loader node is silently inert: the run completes, costs money, and produces base-model output while every log line says the adapter was requested. That direction produces no signal a human could notice — which is exactly where a gate earns its place over a person looking.

Check 5 — the effective frame, not the declared one

1066 / 8 = 133.25 encodes to 133 latent columns and decodes to 1064, putting every output 2 px off its control image and breaking every downstream pairing.

The defect happened upstream of the graph. The 1066 was derived correctly from a mesh, the image was rendered at that width and uploaded, and the graph never declared it — so a check reading graph literals could not have caught the incident that motivates it. The operand is the frame the run will actually produce, which on an img2img graph is the input image's dimensions.

÷8 halts. ÷16 advises. A floor and a preference, not two floors.

Check 8 — advisory, and honest about what it cannot say

For each checkpoint the graph loads, parameters are compared against a cited envelope table. Every entry carries its band, source URL, retrieval date and a quote of the card's own words — and the constructor refuses to build an entry that does not.

The day-one entry is Qwen-Image-InstantX-ControlNet-Union. It carries the controlnet_conditioning_scale band its card documents, and a declared absence for denoise, because that card publishes no denoise range at all — verified against the live card rather than recalled. So a run on a graph at denoise=0.92 reports the 0.92, names the parameter, and says plainly that it cannot judge it and why.

Reporting the value it cannot judge is the honest half of the finding. Inventing a band to judge it against would be the dishonest half.

The adoption contract

Call it in-process on the submit path. There is no skip flag.

The check lives inside the tool that performs the irreversible step. A preflight in a shell chain before a submit is a transport, not a guard — in the incident that produced this rule, 47,020 texels were committed after a gate had already fired, because a PowerShell chain walked past a failing exit code. Nobody decided to proceed; the construction was incapable of stopping.

The CLI and the MCP server are both transports, not gates. Reading a HALT from either and then submitting from somewhere else is that same chain with a nicer interface.

No function here takes a skip, force, warn_only or enabled parameter, and tests read each signature rather than trusting the docs. Every gate raises; none is a bare assert — python -O deletes assert silently, and CI runs the whole suite under -O and PYTHONOPTIMIZE=1 to prove the gates survive it.

Over MCP

python -m comfy_preflight.mcp_server     # stdio
npx @mcptoolshop/comfy-preflight mcp     # same server, no Python required

One tool, preflight, returning the same structured result the library returns — a test asserts byte-identity. A HALT is a successful call returning {"verdict": "halt", ...}, because reporting it as a protocol error would throw away the structure the caller needs.

Security

No network calls, no credentials, no telemetry, and it writes nothing anywhere. It reads a graph and a profile, and returns a verdict. Full threat model — data touched, data not touched, and the permissions required — in SECURITY.md.

Documentation

📖 The handbook — getting started, every check in detail, the adoption contract, and the envelope table.

License

MIT — see LICENSE.

Built by MCP Tool Shop

Metadata

Release files for comfy-preflight 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for comfy-preflight 1.0.0
File Size Uploaded
comfy_preflight-1.0.0.tar.gz 93.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for comfy-preflight 1.0.0
File Interpreter ABI Platform
comfy_preflight-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 152.7 kB

Release files / comfy_preflight-1.0.0.tar.gz

Download URL comfy_preflight-1.0.0.tar.gz
Size 93.2 kB
Tags Source
SHA-256 checksum
How to use checksums
a5ebdf399dcba09e246404e517381007d4560988556e8552da7e5e60924dd1f3
BLAKE2b-256 checksum
How to use checksums
a6601694aab9860ea57886e6a777c356826c74f83af8ac9a8e90d8761f73a47c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.

Transparency log

Release files / comfy_preflight-1.0.0-py3-none-any.whl

Download URL comfy_preflight-1.0.0-py3-none-any.whl
Size 59.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b93a58261fbb05989e2e5dc12c34c65ce9375a914769f11a20795c08f4156b54
BLAKE2b-256 checksum
How to use checksums
a33e50e4593c1acc0b26233eeb79d25d55dcd371fe8e0c3053e7d8ff0fecde45
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page