AGENTS.md and the brand skill both read as if this repo were the only place a node can live, so an agent adding one had no reason not to add it here. Both now name ComfyUI-AusBoss-Lab as the default destination, list what disqualifies a node from the public pack, and carry the namespace table. The brand skill also gets an explicit note not to spend the polish budget on a lab node: example workflows, thumbnails and frontend work are release-gate items, and lab nodes stay outside js/appearance/ by prefix on purpose.
6.6 KiB
ComfyUI-AusBoss — Agent Working Rules
Instructions for any coding agent working in this repo. CLAUDE.md imports
this file, so keep everything here and leave that one as a pointer.
A suite of polished ComfyUI custom nodes by ausboss. Public nodes must solve a repeated workflow need, keep a compact graph footprint, and pass backend plus browser acceptance before release.
This repo is the showroom, not the workshop
Experiments live in the private ComfyUI-AusBoss-Lab repo, not here. Default a new node to the lab and promote it later; adding it here is the deliberate act of publishing it, and after a release its mapping key can never change.
A node belongs in the lab, not this repo, when any of these is true:
- it depends on a third-party pack or model most people will not have
- it encodes constants owned by someone else — a model card, an upstream default — that go stale when they change them, leaving this pack shipping wrong advice under ausboss's name
- it solved a need once rather than a repeated workflow need
- its inputs are still moving
The lab mirrors this repo's layout, so a promotion is a port, not a rewrite.
Its namespaces are held apart (AUSBOSS_LAB_ ids, 🧪 AusBoss Lab/
categories, 🧪 display suffix) so both packs install at once. The port steps
and the release gate are in the lab's docs/promoting.md.
scripts/validate_nodes.py enforces the boundary from this side: a mapping key
that is registered but absent from PUBLIC_NODE_IDS fails the build, so an
experiment cannot ride along into a release unnoticed.
Hard rules
- Never modify
LICENSE. - Never bump
versioninpyproject.tomlunless explicitly asked. - Never add agent attribution to commits or PRs — no
Co-Authored-Bytrailers, no "generated with" footers. Commits are authored by ausboss alone. - Do not read or analyze
__pycache__,.git, or editor config directories. - Ask before whole-repo sweeps or large refactors; propose a short plan first.
- Keep diffs minimal: touch only the lines the task needs.
- Be concise; skip pleasantries.
Third-party independence
- Never copy third-party code, assets, fonts, icons, CSS, or documentation.
- Review ecosystem overlap before accepting a public node. Generic overlap is fine, but implementation, naming, interaction design, and documentation must be this repository's own work.
Architecture
__init__.py # NODE_MODULES list → importlib merge of all mappings.
# Fail-soft: a broken module logs and is skipped, the rest load.
nodes/
node_<name>.py # exactly one node (or one tight family) per file;
# exports NODE_CLASS_MAPPINGS + NODE_DISPLAY_NAME_MAPPINGS
_<topic>_helpers.py # shared backend logic, underscore prefix = not a node
js/
<name>/index.js # frontend entry per node or pack-wide feature, e.g.
# appearance/ (.js files auto-load)
shared/*.mjs # import-only shared modules (.mjs files do NOT auto-load)
docs/ # developer docs
scripts/ # offline checks, stdlib only. validate_nodes.py is the
# entry point; registry_contract.py holds the rules that
# keep nodes visible to registry scanners.
example_workflows/ # example workflows (regular workflow JSON, not API JSON)
Conventions
- Public mapping keys use
AUSBOSS_NODES_<Purpose>. The mapping key is the workflow-compatibility contract and must never be renamed after release. - Write those keys as string literals inside
NODE_CLASS_MAPPINGSandNODE_DISPLAY_NAME_MAPPINGS— never aNODE_IDvariable. Registry scanners (ComfyUI-Manager) AST-parse the source without importing it, so a variable key makes every node invisible and "install missing custom nodes" stops offering the pack.scripts/validate_nodes.pyenforces this. - Assign each mapping once, at module level, to a non-empty dict literal,
and never mention the name again — no
update(), nodel, noalias = NODE_CLASS_MAPPINGS. A scanner reads that one literal and stops, so anything done to the mapping afterwards is invisible to it. Both mappings must carry exactly the same keys. - Display name:
<Name> 🆎— the emoji is the pack signature. Typing "ausboss" still surfaces every node through the🆎 AusBoss/<Group>category, theAUSBOSS_NODES_id prefix, and the "ausboss" entry every node keeps inSEARCH_ALIASES. - Category:
🆎 AusBoss/<Group>. The emoji is safe here — categories reach the frontend as JSON and are never printed to the console at import time. - Every node gets
DESCRIPTION, inputtooltips, andOUTPUT_TOOLTIPS. - IMAGE tensors are BHWC float batches; MASK is BHW. Return tuples always,
even for one output:
(value,). - Console output at import time must stay ASCII — ComfyUI on Windows often runs a cp1252 console, and a UnicodeEncodeError there kills the whole pack.
- No new pip dependencies without an explicit decision; if truly optional,
use
[project.optional-dependencies]and fail soft at runtime. - Frontend JS never assigns prototype callbacks directly — use
chainCallbackfromjs/shared/index.mjs. - Frontend settings use
AusBoss.<Area>.<Name>ids withcategory: ["🆎 AusBoss", "<Area>", "<Leaf>"]and a distinct leaf per setting. Node color schemes live injs/shared/appearance.mjs.
Adding a node
Follow docs/adding_a_node.md. Short version: create nodes/node_<name>.py
from the template, add "node_<name>" to NODE_MODULES in __init__.py,
optionally add js/<name>/index.js, then validate. Brand and design-language
guidance (visual grammar, settings conventions, interaction etiquette) lives
in .claude/skills/ausboss-node-brand/SKILL.md.
Validation
python scripts/validate_nodes.py
Then restart ComfyUI fully, watch the AusBoss banner for failed modules,
confirm the node appears in GET http://127.0.0.1:8188/object_info, queue a
tiny API graph, and load its example workflow. After JS changes, hard-refresh
the browser tab (Ctrl+Shift+R).
Phase 2: porting an existing node
- Drop the old file in
_scratch/(gitignored) and read it fully first. - Rebuild the core compute in a clean
nodes/node_<name>.pyfrom the template — port logic deliberately, don't paste wholesale. - Shared logic goes to
nodes/_<topic>_helpers.py, not duplicated. - Frontend goes to
js/<name>/index.js; reusable bits tojs/shared/. - Keep the old class-name string as the mapping key only if existing saved
workflows must keep loading; otherwise use the
AUSBOSS_NODES_<Purpose>convention. - Run the validation steps above before calling it done.