Custom-node dependencies
A published workflow should declare which Comfy custom-node packs it needs. Comfy Workflows resolves those declarations against the Comfy Registry. cwf setup prepares a local Comfy installation after you approve the exact plan.
pnpm add @alice/some-workflow
cwf inspect @alice/some-workflow --url http://127.0.0.1:8188
cwf setup @alice/some-workflow --comfy C:\ComfyUI
# restart Comfy if setup says so
cwf inspect @alice/some-workflow --url http://127.0.0.1:8188
cwf run @alice/some-workflow --url http://127.0.0.1:8188You should not have to hunt GitHub for missing custom nodes.
Package format is host-agnostic. The same inspect / resolve-nodes / setup path works whether the tarball came from npm, GitHub Packages, a GitHub Release, or a local file. Distribution.
A project-local @stepupgaming:registry=https://npm.pkg.github.com mapping is valid for authenticated installs because core and first-party workflows are all on GitHub Packages. It remaps the entire scope — keep it out of ~/.npmrc unless you want that on every project. Anonymous installs use the GitHub Release .tgz. Distribution.
Security contract
Custom nodes are executable Python.
cwf runnever installs them. Missing classes fail at compile/validate time.cwf inspectnever installs them. It only reports.cwf initnever installs them. With--urlit may discover verified registry metadata.- Installation happens only through
cwf setup. - Default confirmation is No.
--yesmeans “approve this verified plan”, not “allow arbitrary untrusted sources”. - Registered Comfy Registry packs are eligible for setup after version-level verification. Arbitrary Git URLs and pip specs are not auto-installed.
- Workflow-package JavaScript is never executed to inspect dependency metadata.
- Manifests are declarative: no
install,script,command,shell,pip, orgitfields. - Registry names, descriptions, and repository prose never become shell commands or argv.
This SDK consumes /object_info. It does not author Python node implementations. Consume vs author.
nodeClasses vs nodePacks
requires.nodeClasses— the non-negotiable set of Comfyclass_typenames the graph uses.cwf packrequires this to match the IR.requires.nodePacks— installable packs that provide those classes. Identity is the Comfy Registry package id (for examplecomfyui-videohelpersuite).
Manifest spec versions
| specVersion | nodePacks wire format |
|---|---|
| 1 | string[] of registry ids (legacy) |
| 2 | NodePackRequirement[] objects |
Existing published v1 packages remain valid. Rich dependency metadata is specVersion 2. The parser never silently writes objects under specVersion 1.
Source defaults:
| Wire form | Normalized source |
|---|---|
| v1 bare string id | manual |
v2 object with source omitted | registry (a claim, not install proof) |
v2 source: "manual" | explicit manual |
v2 source: "registry" | explicit registry claim |
Automatic installation still requires positive per-version Registry verification. An omitted v2 source is not a skip-install signal.
A v2 pack entry:
{
"id": "comfyui-videohelpersuite",
"name": "ComfyUI-VideoHelperSuite",
"version": "^1.7.9",
"repository": "https://github.com/Kosinkadink/ComfyUI-VideoHelperSuite",
"provides": ["VHS_LoadVideo", "VHS_VideoCombine"],
"source": "registry"
}repository is informational. It is never an instruction to clone a URL.
How resolution works
cwf resolve-nodes . --url http://127.0.0.1:8188
cwf resolve-nodes . --url http://127.0.0.1:8188 --writeWithout --write, nothing is mutated. With --write, verified packs are merged into comfy.workflow.json as specVersion 2.
GET https://api.comfy.org/nodes/search?comfy_node_search={className} is the candidate universe (paginated). GET /comfy-nodes/{className}/node is an additional ranked hint only, never the complete set. Official Comfy source treats the ranked endpoint as a preempted “best” pack. It can attribute a core class to a third-party pack, hide other claimants, or 404 for a real custom class.
Verification pipeline:
- Required class
- Live
/object_info(availability — a present class needs no install) - Known-core evidence (bundled defs snapshot plus known newer stock classes such as
CLIPLoader/UNETLoader) - Author-declared
provides(explicit mapping — a claim, not proof) - Registry search candidates (all pages) plus ranked hint
- Exact pack version (
GET /nodes/{id}/versions, then/install?version=) - Pack-version definitions (
GET /nodes/{id}/versions/{version}/comfy-nodes, paginated) - Verified provider set
A publisher source: "registry" declaration is a claim. Only provided === true for the selected version authorizes automatic installation. provided === false or provided === undefined is UNKNOWN / unverifiable and never reaches the installer.
Outcomes per class:
| Outcome | Meaning |
|---|---|
CORE | Known stock class. Never installed as a custom pack. |
RESOLVED_CUSTOM | Exactly one verified pack/version supplies the class. |
AMBIGUOUS | More than one verified pack supplies the class. Author must pick. E_NODE_PACK_AMBIGUOUS. |
UNKNOWN | No verified provider. Not “definitely core” and not “definitely custom”. E_NODE_PACK_UNKNOWN. |
A ranked hint that does not list the class in that version’s definitions is dropped. --write never records an unverified guess.
Manual authoring when the registry cannot help:
cwf node-pack add comfyui-videohelpersuite --provides VHS_LoadVideo,VHS_VideoCombine
cwf node-pack map SomeInternalNode my-internal-packManual entries still pass manifest validation. They are source: "manual" and are not auto-installed by cwf setup. Mapping is author intent, not a shell escape.
cwf pack warns (W_PACK_UNRESOLVED_NODE_PACK) when a class has no owning pack. That stays a warning: absence from the bundled core snapshot is not proof the class is custom. cwf pack --publish still fails contradictory/invalid pack metadata.
Exact versions
A manifest version of ^1.7.9 does not mean “install latest”. Setup resolves the range against published Registry versions and records:
requestedVersion:^1.7.9resolvedVersion: an exact published version that satisfies the range
The installer is then invoked with the exact resolved version. If no published version satisfies the range: E_NODE_PACK_VERSION_UNSATISFIED. No silent latest.
How cwf setup works
cwf setup @alice/cool-video-workflow --comfy C:\ComfyUI- Load the manifest + IR as data (no package JS).
- Diff required classes against live
/object_infowhen--urlis given, and against the localcustom_nodestree. - Verify missing classes; resolve exact compatible pack versions.
- Build an install plan (library API:
buildDependencyReport/createSetupPlan/applySetupPlan). - Print exactly which registered packs and versions will be installed.
- Ask
Continue? [y/N](default No).--yesskips the prompt;--dry-runprints the plan and exits. - Delegate to ComfyUI-Manager
cm-cli.py install <registry-id>@<exact-version>with an argument array (no shell concatenation).COMFYUI_PATHis set to the target root. The subprocess uses the target Python (python_embeded\python.exeon portable Windows, otherwise the target venv). If Python cannot be established:E_COMFY_PYTHON_UNKNOWN— nothing is installed. - Report that Comfy must be restarted. Setup never kills a running Comfy process.
Agent / CI shape:
cwf setup workflow --comfy C:\ComfyUI --dry-run --json
cwf setup workflow --comfy C:\ComfyUI --yes --json--yes still refuses unresolved, ambiguous, unregistered, and version-unsatisfied packs.
JSON distinguishes alreadyInstalled, toInstall, unresolved, ambiguous, failed, restartRequired, ready, availabilityKnown.
ready: true means every required node class is known available on the target Comfy instance (/object_info). Installing a pack is not readiness: after a successful install the plan is installed / restartRequired: true / ready: false until availability is re-verified. Manual-source skipped dependencies never make ready true while their classes are still missing.
Inspect JSON classifies required classes as coreNodeClasses, resolvedCustomNodeClasses, unknownNodeClasses, and ambiguousNodeClasses. UNKNOWN is not CUSTOM.
Local vs remote Comfy
cwf inspect workflow --url https://remote-comfy is fine: /object_info is readable.
cwf setup --url remote without --comfy produces a plan and states that local filesystem access is required to apply it. There is no remote shell, no invented Manager HTTP install against a stranger's server.
--comfy always wins over detection. Supported layouts: a git checkout (main.py + comfy/ + venv), a portable Windows tree (python_embeded / inner ComfyUI/), and COMFYUI_PATH. Personal machine paths are never hard-coded. If more than one install could match, pass --comfy. Paths containing spaces are supported. Windows.
Models
requires.models is reported. There is no model downloader. cwf setup does not install checkpoints. Models.
JSON / agent mode
cwf inspect, cwf resolve-nodes, and cwf setup all accept --json.
Library entry: @stepupgaming/comfy-workflows/deps — resolveNodeClasses, createSetupPlan, applySetupPlan, buildDependencyReport.
Typed node codegen is how you author against custom nodes. This page is how you declare and install them.