comfy-node

v2026.09.24

Orchestrate a ComfyUI node pack from idea to registry: scaffold, create + seed the repo, open the gitops adoption PR. Use when releasing or spinning up a new comfyui node pack.

GitHub
Install command
npx skhub add laurigates/comfy-node
Markdown
SKILL.md

comfy-node

Take a ComfyUI custom-node idea and drive it through every step from empty to publish-ready, collapsing the manual repo-creation + gitops wiring into one orchestrated pass with a single human approval gate.

This is the orchestrator around the comfyui-node-scaffold skill (which only generates the local repo). Use comfyui-node-scaffold alone if you just want the files; use this when you want the GitHub repo created, pushed, and adopted into gitops too.

Canonical owner of the gitops repo-adoption procedure. Phases 3–5 below (seed main → open the gitops PR → human gate → remove the import block), the branch-protection hook note, and the generic failure-mode rows are the single source of truth for every laurigates repo class, not just ComfyUI packs. foundryvtt-plugin:foundryvtt-module carries only its own deltas and defers here. If you arrived from another skill, read Adapting Phases 3–5 to another repo class first — it names every value you substitute.

When to Use This Skill

Use this skill when...Use the alternative when...
The user gives an idea and wants the whole pipeline stood up — repo created, seeded, and gitops-adoptedYou only want the local files → comfyui-node-scaffold
Spinning up a project:comfyui-nodes taskwarrior backlog idea end to endAdding a node to an existing pack → edit that repo directly

Do not use it to add a node to an existing pack, or to publish a release (release-please + publish.yml already automate that once the repo exists).

The shape it automates

flowchart LR
  idea["idea"] --> sc["scaffold.py"] --> gh["gh repo create<br/>+ seed main"] --> gop["gitops PR<br/>(entry + import block)"]
  gop --> gate["👤 merge gitops PR"] --> apply["tofu-apply on release:<br/>adopt + secrets + protection"] --> rm["remove import block"] --> impl["implement + release"]
  classDef g fill:#1b4332,stroke:#2d6a4f,color:#fff
  classDef m fill:#6a040f,stroke:#9d0208,color:#fff
  class sc,gh,gop,apply,rm g
  class gate,impl m

Everything left of the gate is one orchestrated pass. There is no scaffold PR — the seed goes straight to main (see Phase 3 for why). The single gate (merging the gitops PR) is intentionally human — it feeds the apply pipeline on shared infra state (release-please cuts a gitops release, whose publication triggers the tofu-apply.yml GitHub Actions workflow). Never merge it on the user's behalf.

Preconditions

  • Run from the workspace root repos/laurigates/ (new repo lands as a sibling of the reference packs; modal-variant primitive copy resolves there).
  • gh auth status is a personal account that can create repos. The gitops GitHub App cannot create repos on user accounts — that is exactly why the repo is created out-of-band here and then imported into Terraform state.
  • The gitops repo is clean (no uncommitted repositories.tf / main.tf changes) so the orchestrator's gitops PR is isolated.

Phase 0 — Derive and confirm the spec

From the idea, derive and show the user before creating anything external:

FieldHow to deriveExample
--namecomfyui-<kebab>; reuse the family prefix (touch-… for touch UX).comfyui-touch-resize
--displayTitle-case.Touch Resize
--descOne line, registry-facing.Selection-gated pinch-to-resize for ComfyUI nodes and groups on touch devices.
--variantgesture for canvas interactions (resize/move/region); frontend for a per-widget modal; backend only if it reads disk / serves data.gesture
--widgetsCSV of target widget names (modal variants only; omit for gesture).—
topics["comfyui","comfyui-nodes",…] + facet tags.…,"mobile","touch","resize"

Confirm the name and variant with the user — these are hard to change after the repo exists. If the idea matches a project:comfyui-nodes task, mark it in_progress:

task project:comfyui-nodes export | jq -r '.[] | select(.description | test("resize"; "i")) | .uuid'

Phase 1 — Preflight (fail fast if the name is taken)

test ! -e comfyui-touch-resize && echo "local: free" || echo "local: EXISTS"
grep -q '"comfyui-touch-resize"' gitops/repositories.tf && echo "gitops: EXISTS" || echo "gitops: free"
gh repo view laurigates/comfyui-touch-resize >/dev/null 2>&1 && echo "github: EXISTS" || echo "github: free"

All three must report free. Stop and surface any collision.

Phase 2 — Scaffold + local green check

python3 ${CLAUDE_SKILL_DIR}/../comfyui-node-scaffold/scaffold.py --name comfyui-touch-resize --display "Touch Resize" --desc "Selection-gated pinch-to-resize for ComfyUI nodes and groups on touch devices." --variant gesture

Then bring the pack to green locally (the scaffold prints these too):

cd comfyui-touch-resize
uv sync --group dev
npm install --no-audit --no-fund
just check

just check must pass before anything is pushed. If it fails, fix locally and re-run — do not create the remote repo on a red pack.

The scaffold prints a finishing-pass audit (issue #1877): it emits the registry icon/banner SVGs + Icon/Banner wiring and the renovate / registry-health / clear-autorelease workflows, and grades the follow-ups it can't do itself. Before the first release, run just assets (rasterizes icon.svg / banner.svg → the PNGs the registry serves; needs rsvg-convert) and commit the PNGs. The screenshot pipeline stays deferred to the comfyui-screenshot-pipeline skill (just screenshots) — surface it as a Phase 6 follow-up.

Treat the audit's ERROR rows as blocking, not as notes: Icon/Banner already point at PNG URLs, so a pack that skips just assets publishes a 404 icon. The pack's own tests/test_publish_hygiene.py fails CI on exactly that, and Phase 6 re-checks it before hand-back.

Phase 3 — Create the GitHub repo and seed main

Seed main directly as the first commit — no scaffold branch, no PR. The repo has no branch protection yet (gitops adds it on adoption in Phase 5), so this is allowed, and it avoids the branch juggling you'd otherwise hit: if the first push were a feature branch, main would be missing on origin, forcing a later rename + default-branch change + base-branch fixups. Pushing main first sidesteps all of it. Implementation work afterward goes through feature-branch PRs as normal (protection is live by then).

git init -b main
git add -A
git commit -m "feat: scaffold comfyui-touch-resize (gesture pack)"
gh repo create laurigates/comfyui-touch-resize --public --source . --remote origin --push

Branch-protection hook note (expect this): in a Claude Code session the branch-protection hook will block the agent from git add/commit on main (confirmed on the first real run). For a brand-new, not-yet-protected repo this is a false positive. Hand the whole seed to the user as one paste-safe line to run with the ! prefix, e.g.:

cd <repo> && git add -A && git commit -m "feat: scaffold <name> (gesture pack)" && gh repo create laurigates/<name> --public --source . --remote origin --push

(git add -A and &&-chaining are fine in the user's shell — those hooks are agent-side.) Do not work around it by seeding a feature branch — that reintroduces the missing-main/rename juggling this phase exists to avoid. Don't fight the hook with quoting tricks either.

The --push makes the seeded main the default branch.

Phase 4 — Open the gitops PR (entry + transient import block)

Two edits in the gitops/ repo, on a dedicated branch.

gitops/repositories.tf — add to the active repositories locals block, next to the other comfyui-* entries (mirror comfyui-touch-connect):

    "comfyui-touch-resize" = {
      description    = "Selection-gated pinch-to-resize for ComfyUI nodes and groups on touch devices"
      visibility     = "public"
      release_please = true
      comfy_registry = true
      topics         = ["comfyui", "comfyui-nodes", "mobile", "touch", "resize"]
    }

gitops/main.tf — add a transient import block alongside the existing ones at the top of the file:

import {
  to = github_repository.this["comfyui-touch-resize"]
  id = "comfyui-touch-resize"
}

Validate, branch, commit, push, open the PR (run inside gitops/):

just check
git -C gitops switch -c feat/adopt-comfyui-touch-resize
git -C gitops add repositories.tf main.tf
git -C gitops commit -m "feat: adopt comfyui-touch-resize (comfy_registry)"
git -C gitops push -u origin feat/adopt-comfyui-touch-resize
gh pr create -R laurigates/gitops -a laurigates -l chore -l opentofu --title "feat: adopt comfyui-touch-resize (comfy_registry)" --body-file /tmp/gitops-pr-body.md

Write a short body (to /tmp/gitops-pr-body.md) rather than --fill — it's an infra PR that triggers an apply, so spell out what merge does: imports the repo, pushes REGISTRY_ACCESS_TOKEN + release-please credentials, applies the branch-protection ruleset, and that a follow-up PR removes the import block. Use labels chore + opentofu (both exist in the gitops repo; check gh label list -R laurigates/gitops if unsure).

Set metadata per github-metadata-hygiene (assignee laurigates; skip self-reviewer — the author is the running user). The tofu-plan.yml workflow posts the plan as a comment on the PR; the expected plan imports the repo and creates the REGISTRY_ACCESS_TOKEN secret + release-please var/secret + branch-protection ruleset.

Phase 5 — Human gate, then finish

Hand the user the new repo URL and the gitops PR URL. The user merges the gitops PR — that starts the apply chain on shared infra state (release-please cuts a gitops release PR; merging that publishes a release, which triggers tofu-apply.yml). Do not merge it for them.

After the user confirms the tofu apply landed, verify the wiring and remove the now-dead import block:

gh secret list -R laurigates/comfyui-touch-resize
gh api repos/laurigates/comfyui-touch-resize/actions/variables/RELEASE_PLEASE_APP_ID --jq .name

REGISTRY_ACCESS_TOKEN should be listed; the variable lookup should return its name. Then open the import-block-removal follow-up PR (it is a one-time adoption artifact — leaving it is harmless but untidy):

git -C gitops switch -c chore/remove-comfyui-touch-resize-import

Remove the import { … "comfyui-touch-resize" … } block from main.tf, then:

git -C gitops commit -am "chore: remove one-time import block for comfyui-touch-resize"
git -C gitops push -u origin chore/remove-comfyui-touch-resize-import
gh pr create -R laurigates/gitops -a laurigates -l chore --fill --title "chore: remove comfyui-touch-resize import block"

Adapting Phases 3–5 to another repo class

Phases 3–5 are repo-class-agnostic: the seed-main-first rationale, the branch-protection hook workaround, the import-block mechanics, the human gate, and the import-block-removal follow-up are identical for a ComfyUI pack, a FoundryVTT module, or anything else gitops adopts. Only these values change — substitute them and the phases read verbatim:

SubstituteComfyUI pack (the examples above)How to find yours
Repo namecomfyui-touch-resizeThe caller skill's Phase 0 spec
Workspace → gitops pathgitops/ (run from repos/laurigates/)gitops/ if the clone is a sibling; ../gitops/ from a nested workspace
repositories.tf adoption flagsrelease_please = true + comfy_registry = truerelease_please = true is universal; extra flags are per-repo-class
Seed commit subjectfeat: scaffold <name> (gesture pack)feat: scaffold <name> (<variant> <noun>)
Phase 5 verificationgh secret list (REGISTRY_ACCESS_TOKEN) and the RELEASE_PLEASE_APP_ID variable lookupCheck one probe per flag you set; release_please always means the RELEASE_PLEASE_APP_ID variable

Everything else — the commands, the PR-body guidance, the labels, the metadata hygiene, the failure-mode rows below — applies unchanged.

Phase 6 — Verify the finishing pass, then hand back

Run the gate before declaring done — do not close on a self-authored summary:

python3 ${CLAUDE_SKILL_DIR}/../comfyui-node-scaffold/scaffold.py --verify comfyui-touch-resize

Read STATUS=; the exit code is 1 on ERROR.

STATUS=Action
ERRORNot done. Finish it now — the ERROR rows are publish-blocking (missing icon.png/banner.png, or surviving PLACEHOLDER-GLYPH). just assets, commit the PNGs, re-run.
WARNDeferrable. Log each WARN to project:comfyui-nodes in taskwarrior (the queue that outlives this session) and say so in the hand-back.
OKHand back.

An ERROR is never a follow-up item. It shipped that way three times — comfyui-touch-manager (Icon = "", weeks), comfyui-output-swap (31 hours), comfyui-touch-shim — each recorded in the closing report as "tracked, not blocking" and each caught only when the user noticed.

The pipeline is now live: conventional-commit feature PRs → merge → release-please PR → merge → tag → publish.yml publishes to registry.comfy.org. Tell the user what's left:

  • Implement the pack logic (for gesture: tune web/js/<short>.js — groups support, affordance hint, the anisotropic-scale TODO).
  • First merged feat:/fix: commits drive the first release-please PR.

Log durable follow-ups (groups support, browser smoke matrix, the jsdom modal DOM test gap) to project:comfyui-nodes per taskwarrior-cross-session.

Failure modes & guards

SymptomCauseFix
publish.yml fails Option '--token' requires an argumentcomfy_registry flag not yet appliedConfirm the tofu apply landed; gh secret list shows REGISTRY_ACCESS_TOKEN; re-run gh workflow run publish.yml -R laurigates/<name>
release-please job fails on empty app-idrelease_please credentials not applied, or repo on the legacy PAT workflowThe scaffold ships the App-token release-please.yml; confirm the apply landed (gh api repos/laurigates/<name>/actions/variables/RELEASE_PLEASE_APP_ID --jq .name returns a name), re-run via workflow_dispatch
403 Resource not accessible by integration on repo createTried to create via the gitops App, not a personal tokenCreate with personal gh auth; the App only adopts via import
The tofu plan shows a create (not import) for the repoImport block missing or id wrongThe id is the bare repo name, not owner/name; add/fix the import block
just check red in gitopstofu fmt/validate failurejust format then re-check before pushing

Notes

  • The orchestrator never runs tofu apply — all applies go through the gitops repo's tofu-apply.yml GitHub Actions workflow, triggered by publishing the release-please release (see gitops/CLAUDE.md). Local gitops work is plan/validate only.
  • The scaffold now emits the registry finishing-pass pieces (icon/banner SVGs + wiring, renovate + registry-health + clear-autorelease workflows) and audits for the rest; just assets (rsvg-convert) produces the served PNGs. See the finishing-pass note in Phase 2 (issue #1877).
  • Screenshots pipeline + docs/blueprint/ PRD/ADR set are not scaffolded; add them later from a reference pack (the comfyui-screenshot-pipeline skill) if the pack warrants them.
Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

MIT

Source path

comfyui-plugin/skills/comfy-node

Default branch

main

Latest commit

1668324

Tree SHA

b2d4cc3