ADR-0016: Node pack dependencies ([node_packs])¶
Status: accepted (2026-08-14; enforcement lands in comfy-env after the existing packs migrate to pinned entries)
Still unenforced, and the gap is wider than it reads
Verified 2026-09-07 against comfy-env 1cd4839: install_node_packs
(packages/node_packs.py) contains no pin check, no host-clean
requirements.txt check, and no registry refusal. An unpinned
owner/repo installs from HEAD, and a registry = "..." entry installs
from api.comfy.org and runs its install.py
(packages/node_packs.py). Every "mandatory" and "mechanically
checked" below describes the decision, not the code. Nothing fails a
build when a pack violates it, and no test asserts any of it, so the
migration this status line waits on has no tripwire to end it.
Amended 2026-08-24 (comfy-env 0.4.27): the section is [node_packs].
It shipped as [node_reqs], which read as "the requirements of my node" --
pip packages -- when every entry is a whole pack. Renamed to match this ADR's
own title and to sit parallel to [cuda_packages]. No compatibility shim: the
root file has a closed schema, so a stale [node_reqs] is rejected by name at
parse time. The [settings] auto_install_node_reqs opt-out below was never
built -- per-pack [settings] was removed in 0.4.25.
Decision¶
A pack may depend on other packs -- automatically installed, but only pinned and only comfy-envved.
[node_packs]stays an install-time mechanism (headless testing needs it); in exchange every entry must name an exact git ref and point at a pack that honors the host-env principle. Anything else is a test-workflow convenience and belongs in the test config, not in runtime dependencies.
[node_packs]lives incomfy-env-root.toml(ADR-0003 root role) and is auto-installed atinstall()time, recursively, with a cycle guard.- Pinning is mandatory. Every entry carries
tag = "..."orcommit = "...". Bareowner/repo(tracking HEAD) is refused: an unpinned dependency makes every downstream install and every CI run nondeterministic. Registry versions are NOT accepted as pins -- the registry is not currently trusted for integrity (mutable, unsigned);registry/versionentries are rejected until that changes. Git refs are the only pin vocabulary for now; revisit when the registry can be verified. - Compliance is mandatory and mechanically checked. At clone time
the dependency must (a) carry a comfy-env config and (b) have a
host-clean
requirements.txt-- comfy-env and nothing else. A dep that fails the check is a named install error, not a warning: one non-compliant dependency pip-installs its requirements into the host env and silently defeats the host-env principle for the whole machine ("violation by proxy"). - Runtime vs test dependencies split. Third-party utility packs that example workflows use (video IO, UI helpers) are not runtime dependencies of the pack -- they are test/demo dependencies, declared in the comfy-test config and installed only into the disposable test ComfyUI, where any pack is acceptable because the whole tree is thrown away.
- Conflicts are errors. The same dependency required at two different pins by two installed packs fails the install naming both requirers -- never first-installed-silently-wins (the current behavior).
- Opt-out setting:
[settings] auto_install_node_packs(defaulttrue) through the existing settings machinery, for users who want to audit before anything is cloned.
Context¶
A census of the author's 53 packs (2026-08) found [node_packs] in 24 of
them, with a real dependency graph: GeometryPack has 11 dependents;
chains run three deep (Cadderizer -> CADabra -> GeometryPack;
WorldStereo -> WorldNav -> MoGe2/PanoPack/Multiband). The declared needs
fall into three kinds: producer packs (the only source of a socket the
depending pack consumes -- e.g. HyMotion's SMPL_PARAMS for
MotionCapture), suite stacks (CAD packs), and third-party workflow
utilities (VideoHelperSuite x4, KJNodes x2, RMBG, cg-use-everywhere).
Every entry today tracks HEAD, unpinned -- while the environment layer below it pins pixi by version and sha256. And the third-party entries auto-install native packs whose requirements pip straight into the host env, violating the host-env principle by proxy.
Two developments reshaped the question. First, ADR-0015 dissolved the type-dependency motivation: consuming another pack's socket type needs nothing installed (type-identity tags; the transport holds unknown values as materialized receipts). What remains is producer nodes and suite composition. Second, comfy-test needs headless, deterministic dependency setup -- install the pack under test, get its producers, run the example workflows -- which ComfyUI-Manager (interactive, workflow-driven, GUI-consent) cannot provide. That testing requirement is why auto-install survives at all; determinism is why it must be pinned.
Rejected alternatives¶
- Delete
[node_packs]; delegate to ComfyUI-Manager. Manager resolves missing nodes from a loaded workflow with user consent -- the right UX for humans, no story for headless CI. Testing decided this. - Advisory-only ("pairs with X -- install via Manager"). Same CI gap; keeps the documentation value but serves no machine.
- Registry-version pinning. The natural long-term answer, rejected for now: the registry is mutable and unsigned, so a "pin" there pins nothing. Explicitly revisit when registry integrity (immutability/signing) exists.
- Unpinned status quo. Nondeterministic installs and CI; a third-party force-push changes what users get. Incompatible with the pinned-everything discipline the env layer already follows.
- Growing a full pack manager (dependency resolution, version ranges, lockfiles). Out of scope: comfy-env's identity is environments and transport. Pins + refuse-on-conflict is the entire resolution algorithm, on purpose.
Consequences¶
- Installing a compliant pack cascades only through compliant packs:
the host env gains
comfy-envand nothing else, no matter how deep the graph. - The 24 existing packs must migrate before enforcement ships: add
tag/commitpins to every entry; move VideoHelperSuite / KJNodes / RMBG / cg-use-everywhere entries into comfy-test config as test dependencies. Until migration, enforcement stays off (shipping the check today would fail every install in the suite). - Suite releases carry pin-bump churn: updating a producer pack means bumping pins in its dependents. Accepted cost of determinism; the registry, once trustworthy, is the designated relief.
- Named plainly, this is the exact-pin diamond: with GeometryPack
at 11 dependents, every GeometryPack release forces a lockstep
pin-bump across the suite, and two packs pinning GeometryPack at
different commits are uninstallable together -- refuse-on-conflict
fires by design. Livable while one author owns all 24 consumers and
releases in barrages (ADR-0017);
the first external pack pinning GeometryPack independently makes
the diamond a stranger's problem. That moment is the same rollout
tripwire as 0017's, and the designated exits are registry-backed
version ranges (above) or hoisting shared producers out of
[node_packs]entirely -- to be chosen then, not now. - comfy-test runs additionally record each cloned dependency's resolved commit SHA in the run report, so even future registry-based installs stay reproducible after the fact.