Skip to content

Architecture decision records

Nygard-style records (Status / Context / Decision / Consequences) for comfy-env. Numbers are chronological-ish by subsystem, not by date; most decisions were made implicitly during development and are recorded here retroactively as of v0.4.12 (August 2026).

Where a status line cites "adversarial review": these are structured LLM review panels (two independently-briefed reviewer personas that investigate the ADRs and code separately, then debate each other's findings), run by the maintainer in August 2026. Their claims were verified against the working tree before being incorporated; treat the citations as "the argument survived cross-examination", not as external human endorsement.

ADR Decision One-liner
0001 Process isolation via persistent subprocess workers Conflicting node deps get their own interpreter; ComfyUI talks to proxies.
0002 pixi as environment manager conda-forge + PyPI in one manifest with a real lockfile; uv speed underneath.
0003 Two config files, two roles comfy-env-root.toml never touches the Python env; comfy-env.toml means full isolation.
0004 Prebuilt CUDA wheel index Kill the ABI x torch x CUDA x OS x arch build matrix for end users.
0005 Tiered tensor serialization Six strategies, best-available-first, zero-copy where the platform allows.
0006 comfy-env is never installed into worker envs The worker script crosses as source text -- materialized as a file, never imported; duplication is deliberate.
0007 Machine-wide workspace, per-env manifests One shared store per machine; one pixi.toml per env; stamps guard staleness.
0008 Graceful degradation everywhere Every failure path ends in "ComfyUI still boots".
0009 Platform strategy Windows/macOS/Linux each get targeted workarounds, not lowest-common-denominator.
0010 Wire protocol and transport Hand-rolled framing stays; the v2 direction versions the wire and unifies the stack.
0011 Isolation before sandboxing v1 ships dependency isolation only; security is deferred with the path mapped, and isolation is never sold as a security boundary.
0012 Unavailable nodes: menu-hidden, never unregistered Workflows must load; menus must not show dead nodes. DEPRECATED separates the two.
0013 Env-file config: honest passthrough Forward everything pixi owns; comfy-env keeps 4 denied keys, 1 rewritten family, 1 merged table. Amends ADR-0003.
0014 Pack-extensible serializer registry Packs register their own wire types; payloads decompose into schema + tensors, never pickle; unknown tags pass through opaque.
0015 Declared wire types One [types] table per pack; serialization.py only for hero types; identity tags make shared types interop; failed serialization errors loudly.
0016 Node pack dependencies [node_packs] auto-install stays for headless testing -- but pinned (git refs only; registry untrusted) and comfy-envved only; test-workflow utilities move to comfy-test config.
0017 Pre-1.0: no backward compatibility, by decision Break freely while all consumers are the author's; the era ends at the slow-rollout tripwire, which starts the compat and security clocks.
0018 Worker call timeout 600 s default becomes per-env call_timeout; expiry keeps kill-the-worker semantics; the mid-call heartbeat is the named successor.
0019 Worker lifecycle Workers are disposable, replacement is invisible; generations, the stale-patcher invariant, consumed-ack, and the idle reaper decided.
0020 Concurrency and env granularity The pack is the unit of concurrency and fate: one worker + one lock per env; disk may dedupe by content, processes never merge.
0021 The three-call contract install/setup_env/register_nodes as one-liners; caller inference via stack frames; the file layout is the configuration.
0022 comfy-env's placement in the host env The one exception to the host-env principle, kept for pre-1.0; the split-and-relocate alternative recorded for the rollout tripwire.
0023 Metadata scan and proxy synthesis The main process interviews packs instead of importing them; scan subprocess + hash-keyed cache + generated V1 proxies.
0024 The upstream interface contract The loan book: every ComfyUI internal we touch, stamped, with the upstream ask that retires it; the posture for the day core ships isolation.
0025 VRAM co-management across processes ComfyUI stays the single VRAM authority; workers hold on lease; WDDM is best-effort by decision; device fields reserved for multi-GPU.
0026 Trust and supply chain What users trust today, enumerated; wheel hashes and farm qualification move to now; bus factor named; pickle flips at the sandbox.
0027 Testing and verification strategy CI proves transport and compilers; the canary IS the GPU test; conformance, benchmark harness, and the HEAD-canary lane get owners.
0028 Workspace disk lifecycle Envs are caches evicted with consent: gc categories, a banner nudge, and the refcount design content-addressing is blocked on.
0029 Parent as switchboard All inter-worker data flows through the parent, which owns what it holds; alternatives rejected at 1-2%; revisit trigger named.
0030 GPU platform floors Pinned-memory D2H is the next GPU investment; pool IPC demoted to experimental pending an ownership contract; floors probed, never assumed.
0031 Frontend JavaScript isolation (deferred) Pack JS shares one browser origin -- backend isolation buys zero here; deferred like 0011, with a comfy-test collision gate as the one build-now item.
0032 Shared-memory lifetime: consumed-ack The reader frees blocks by acking call_id, not by a timer; the TTL is a crash fallback; materialize-on-receipt is the sibling rule.
0033 Local IPC authentication Per-spawn authkey as the worker's first frame + SO_PEERCRED on Linux; addr/key via env not argv; the honest Windows same-user gap and the not-a-sandbox line.
0034 Admission by arithmetic, never mem_get_info mem_get_info is per-process on WDDM (measured: 13 GiB invisible). Mechanism superseded by 0038: the target is upstream's own expression again, and the ledger correction applies only where the reading really is process-local.
0035 The model proxy is a duck-type 18 declared members instead of ~120 inherited; unknown access raises naming the attribute. Deprecation reversed, 2026-09-05: reclaim depends on this object entirely, and the observer meant to replace it was deleted.
0036 Mirroring ComfyUI's memory manager Superseded by 0038. Its Part 1 remains the reference description of upstream's memory manager; the mirroring decision is not what shipped.
0037 No non-isolated paths One execution model: isolated. The off-flags removed (nobody set them; off-states never worked); degradation stays evidence-triggered; value-sensitive tombstones.
0038 The memory floor comfy-env reads, publishes one number, and asks; it does not patch the host. Reclaim of worker VRAM is dropped for idle release. Supersedes the mechanisms of 0034 and 0036. It also deprecated 0035's proxy and dropped reclaim; both were reversed on 2026-09-05 and the proxy is current.
0039 The env directory seam <env-name>_<abi-tag>, underscore seam, version dots kept. One dash used to mean four things and could not be read back. Older spellings are adopted in place, never renamed.