ComfyUI sends no cache header for .mjs, and the 2.5.1 no-cache header cannot
reach a copy the browser already stored. Firefox then kept running files from
before the update, even through Ctrl+Shift+R, and the preview bar, cards and
editors failed to load.
The server now adds ?v=<tag> to the relative .mjs imports of the pack's
scripts as it serves them. The tag changes whenever any script changes, so
after an update the browser asks for addresses it has never stored. Files on
disk are unchanged. A test fails if a script names a .mjs in a way the tag
would miss.
Workflows saved by the 1.x releases also end in a panel's empty value: the
preview panel on LaMa Inpaint and Mask Refine (Select Frame from 1.2.0) and
LoRA Loader's rows. The inputs added in 2.0.0 sit in those slots, so preview
opened as "" (the switch showed on, but the prompt ran without a preview)
and on_missing opened as "" (the menu showed Stop on missing LoRA off while
the node still stopped the run). Each now opens on its default, which is
also what an API prompt without the input runs with: the three cards reset
preview through resetUnknown, and LoRA Loader, which has no card, applies a
RESET_UNKNOWN when a workflow opens. On a real 1.x save (pack 1.3.0 saved by
frontend 1.47.12) only those four values change.
The guard's history now reaches back to 1.0.0. Mask Refine's preview was
inserted ahead of an existing socket rather than appended, so the table now
lists each node's last input as of this guard and APPENDED_SINCE declares
everything added since the node first saved an empty value. The fallback
check also reads RESET_UNKNOWN, and tests/test_card_fallbacks.py becomes
tests/test_saved_fallbacks.py, which checks both kinds.
Every card and DOM panel was added with options.serialize = false, which
only keeps a widget out of the queued prompt. The frontend saves each
widget whose own serialize is not false and hands saved values back by
position, so each card and panel saved an empty value of its own after the
node's real values, and an input appended to the node later opened holding
it (Stitch Inpaint's seam, Crop For Inpaint's keep_inside). Every DOM widget
now also sets widget.serialize = false, as the frontend's own previews do,
so new saves carry only real values.
Older saves still end in those empty values, and loading them now skips
the cards and panels. On every node that saves by position they come after
all real values (Save Image's card sits mid-list, but Save Image saves by
name), so nothing moves. On frontend 1.53.6 the examples (the 21 from
before the trim and the 7 now) and 14 older saved workflows queue
byte-identical prompts before and after, keep every value, and save and
reopen cleanly.
An input appended later still needs a fallback for those older saves.
tests/saved_widget_values.test.mjs checks that every DOM widget sets the
flag, that the examples keep their values with the panels skipped, and that
each input appended to a node whose older saves end in an empty value is
declared and, as a widget input, has a card resetUnknown fallback that
fires. tests/test_card_fallbacks.py (ComfyUI's Python) checks each fallback
is the input's own default. AGENTS.md states the rule.
A file name in Load Image, Load Image + Pad, Load Video or Image Crop +
Rotate + Pad is one the stranger doesn't have. ComfyUI flags the node red
when the workflow loads, with a toast and a Setup required entry, until
they pick a picture. Saving the loaders blank loads clean.
Adds the rule to the example workflow section, and says "model loader" in
the bullet about official file names so the two don't overlap. The
existing examples are not changed here.
- Qwen Image 2.1 Edit + Realign: type a short edit and Qwen3-VL 8B, the
text encoder the edit already loads, writes the full instruction. The
consistency LoRA sits in a LoRA Loader row, switched off.
- LTX 2.3 Video Outpaint: the distilled LoRA and the outpaint IC-LoRA load
in one LoRA Loader instead of two core loaders. The workflow checks now
refuse core LoRA loaders in examples.
- Realign to Source: description, tooltips and help page rewritten in
plain words, with the technical detail at the end of the help page.
- Settings menus: in a short window the rows no longer squeeze together
and overlap; the menu scrolls instead.
- AGENTS.md: text people read starts with the plainest version.
Every fix PR and model release now ships a failing-then-passing test,
before/after evidence, and a dev server with ready-to-run PROOF workflows,
so the owner can see a change work before merging or publishing.
Save Image joins the shared input_preview panel with the PREVIEW switch,
backed by a new optional preview input (display only: the file is saved
and listed in the queue either way). The embed row reads
Embed workflow: no | yes.
Video Crop + Rotate + Pad -> Frame had gained its four resize inputs as
required, so an API prompt saved before them stopped validating. They
are optional now; the widget order is unchanged.
tests/test_node_api.py loads the pack the way ComfyUI does and holds every
node to tests/fixtures/node_api.json: inputs and outputs may only be
appended, never renamed, reordered, removed or newly required. Its rule
tests need only the standard library and run in CI.
AGENTS.md: the lab sync is the maintainer's step, the no-network rule and
the link helper are written down, the node template it pointed to never
existed, validation lists all four checks, publishing follows version
changes only, and the dated registry status becomes durable history. A
new section sets the bar for example workflows. docs/adding_a_node.md
adds the PUBLIC_NODE_IDS step and the documentation a node needs, and
the brand skill matches Save Image's pill and the shared helpers.
shields.io's dynamic TOML badge reads the version straight out of
pyproject.toml on main at view time, so the badge cannot go stale by
construction - no third version string to bump. Preflight check 3 flips
from comparing a hardcoded number to guarding the mechanism: the dynamic
badge must be present and a hardcoded release-X.Y.Z badge fails the
check. AGENTS.md's release step 1 goes back to two version strings.
The README badge advertised 1.0.0 through two releases, and the registry
side had two silent failure modes nobody was watching:
- release_preflight.py check 3: the README release badge must name the
pyproject version, so the three places a version lives (pyproject,
AUSBOSS_JS_VERSION, badge) can never disagree again. Badge bumped to
1.2.0; README also names the real ComfyUI-floor key (requires-comfyui).
- AGENTS.md release step 4: the push-triggered publish run has failed
before (1.2.0's run died; the version only shipped via a manual
dispatch) - a red run is an unpublished release until re-run.
- AGENTS.md release step 5: verify the version AND its status on the
registry. Every version this pack has published sits in
NodeVersionStatusFlagged - the automated scan holding it for human
review - and flagged versions are invisible in Manager's Select
Version picker and set no last-update, which is exactly the empty
picker on the live install. Ask the Comfy team for review; do not
re-publish.
makeScrubInput in js/shared/scrub_input.mjs is the LoRA strength box's
interaction made reusable: drag the value to scrub (dead zone keeps
clicks clicks), click to type an exact value, chevron arrows step,
ArrowUp/Down step from the keyboard, Shift always means the fine step.
Values are quantized through one choke point, and edit mode re-asserts
itself a frame after the click because the graph canvas can steal focus
mid-sequence.
The gesture math is pure and tested (tests/scrub_input.test.mjs).
AGENTS.md and the brand skill record the convention - numeric fields in
pack panels use this control, never a bare input[type=number] - and
AGENTS.md also picks up the lab shared-code vendoring pull step.
Landing a pyproject.toml change on main now publishes to the Comfy
Registry automatically, so the working rules must say so: a Releasing
section covers the version + AUSBOSS_JS_VERSION pairing (preflight
enforced), the changelog retitle, and keeping the registry description
naming the actual nodes since Manager search matches against it. The
hard rule against casual version bumps points at the consequence, and
the brand skill reminds that a new public node gets named in the
description at the next release.
- New nodes: Image Resize plus the Utility group (Text, Integer, Float,
Show Text, Math Expression, Select Every Nth, Split Batch, Merge
Batches, Free Memory) - the dependency-free gaps that let shared
workflows drop heavy packs.
- Replace with AusBoss nodes (prototype): preview-then-confirm graph
rewrite swapping known third-party nodes for pack equivalents, with a
tested translation map, per-node opt-out, and refuse-with-reason for
nodes the pack cannot stand in for.
- Load Video: single-frame FRAME picker, an honest "what will load"
label from the probed source rate, drop-a-video-to-restore. Save
Video: format-aware widgets and a file_path output. Stitch Inpaint
gained a blend_mask output, Select Frame negative from-the-end
indexing, Image Size a batch count - all appended, saved workflows
load unchanged.
- LoRA Loader: drag-to-reorder rows, hover thumbnails on rows, file
size and date in the info card.
- Appearance: flagship scheme deepened to slate-teal; the retired
bright-teal pair upgrades automatically via LEGACY_SCHEME_PAIRS.
Optional queue-completion chime, off by default.
- Image Resize invariant: pixels are only invented on an explicit
width+height pad request - scale-derived modes resolve divisible_by
snaps with a sub-half-step resize, never bars.
- Docs refreshed for six stale pages, stale text and metadata fixed
across the pack, the panel-height rule codified in AGENTS.md and the
brand skill, and ausboss_node_tour.json added - a model-free example
exercising 17 node types in one graph.
Validated: scripts/validate_nodes.py (24 files), 300 JS tests, all
Python suites under the ComfyUI embedded interpreter.
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.
Every display name swaps ' (AusBoss)' for ' 🆎' - menus, docs, tooltips,
the README, and the example workflow's notes. Mapping keys never change,
so saved workflows keep loading; 'ausboss' keeps finding everything via
the category, the AUSBOSS_NODES_ prefix, and SEARCH_ALIASES. Python error
messages drop the suffix entirely so exception text stays ASCII for
cp1252 consoles.
The LM Studio endpoint toolbar declared no getMinHeight, so the frontend
gave its wrapper a 12px sliver and the buttons clipped; it now declares
32px through every sizing path, and the buttons breathe at 22px.
Four holes. Two empty literals agree with each other, so a module that
registers nothing passed every rule. A del could retire a node the
scanner goes on advertising - the mirror image of the update() case
already covered. An alias made the mutation invisible: _registry =
NODE_CLASS_MAPPINGS then _registry.update(...) never says the mapping
name at all. And the permanent-id check grepped the whole file for
AUSBOSS_NODES_*, so a key renamed in the literal kept passing as long as
the old id survived in a docstring or a search alias.
The contract is now that a mapping is assigned once to a non-empty dict
literal and its name is never used again. That is what makes the rest
enforceable: the alias is refused where it is made, the last point
anything static can still see it, rather than chased through code no
checker can follow. Permanent ids are measured against the keys parsed
out of the literal.
bad_empty, bad_delete and bad_alias join the fixtures; each one was
dropped into nodes/ and confirmed to exit 1 on its own line.
Both nodes now live under the "AB-button AusBoss" category in the node
search, matching how established packs brand their category trees. The
emoji travels to the frontend as JSON and is never printed to the console,
so the ASCII import-output rule is unaffected. Also aligns the stale
Phase 2 naming note in AGENTS.md with the AUSBOSS_NODES_<Purpose> keys.
AGENTS.md is the tool-neutral convention; CLAUDE.md now just imports it
via @AGENTS.md so nothing is duplicated. Adds a no-agent-attribution rule
and the ASCII-console constraint to the rules while moving them.