Autocomplete++ Wildcard & Dynamic Controller
Pin your prompt randomness to the workflow
- passthrough
- passthrough
Every Autocomplete++ setting is global. They live in your browser's localStorage, so they follow you, not the workflow you're editing. That's fine until you want one workflow that rerolls wildcards on every queue and another that needs the exact same outfit line across a 40-image batch. Global settings can't express that. This node can.
Drop it anywhere on the canvas and it overrides the wildcard and dynamic-prompt engine for that workflow only. No wiring. Someone who opens your PNG gets your settings with it.
How the expansion actually works
This is the part worth understanding, because it explains nearly every confusing thing about the node.
The prompt isn't expanded in Python. The extension hooks api.fetchApi in the browser and rewrites the JSON body of the POST /prompt call right before it leaves your machine. The graph, server-side, never sees {red hair | blue hair} - it sees the resolved line. So expansion happens in the frontend, at queue time, using the settings and the active controller node it finds on the canvas.
Which means: the prompt box keeps showing your template. That's not a bug - to see what was actually sent, read the queued prompt, not the textarea. And if you queue from a script that hits /prompt directly, nothing expands at all. This is a UI feature, full stop.
The three inputs that matter
expansion_engine is the master switch for that workflow - Enabled, Disabled, or Default (From Settings).
wildcard_mode governs __clothing/dresses__ style expansion: Random, Follow Seed, Keep Last Choice, Sequential. Follow Seed derives the pick from the KSampler's seed so the same seed gives the same prompt. Keep Last Choice reuses the previous run's picks as long as the master seed hasn't moved - that's the one you want when you found a good roll and just want to tweak steps or CFG. Sequential walks the file line by line, one per queue.
dynamic_prompt_mode does the same for brace syntax: {red hair | blue hair}, weighted picks like {3::sunny, outdoors | 1::rainy, indoors}, and combinations like {2$$red | blue | green}. Note there's no Sequential here - cycling a {a|b|c} in a fixed order isn't a thing people asked for.
Everything left on Default (From Settings) inherits your global Settings → Autocomplete++ values.
The output is a single passthrough socket of type * - ComfyUI's accept-anything type, so a MODEL, a CLIP or an IMAGE all fit. Whatever you feed in comes straight back out, so while the settings need zero wiring, you can slot the node inline in a chain to keep the graph tidy. The Python side of these nodes is a no-op; the feature is entirely frontend code reading widget values.
Installing
ComfyUI Manager: search Autocomplete++, install the michikora/ComfyUI-Autocomplete-Plus-Plus entry, restart. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/michikora/ComfyUI-Autocomplete-Plus-Plus.git
Then restart ComfyUI and hard-refresh the browser tab so the new JavaScript loads. There is nothing else to install. The pack's pyproject.toml declares dependencies = [] and there's no requirements file - no pip packages, no model downloads. It ships its own tag CSVs (Danbooru, e621, an English dictionary, a small quality-tag file) inside the repo. Wildcard .txt files go in ComfyUI-Autocomplete-Plus-Plus/wildcards/, ComfyUI/wildcards/, or any pack's wildcards/ folder.
When it goes wrong
- The controller is being ignored. It must be present, un-muted (
Ctrl+M) and un-bypassed (Ctrl+B). Muting is deliberately how you toggle between multiple presets in one canvas - a muted controller yields control instead of fighting. - Two controllers, unclear winner. Last-touched wins; with no interaction history, it's the newest node ID. On the Node 2.0 frontend you'll see
Active/Inactivepills telling you exactly which one is driving. On the legacy canvas that badge doesn't render, though the arbitration still works. - Sequential restarts. The per-file index lives in memory, so reloading the page resets it to line one. It's a session counter, not a bookmark.
- Expansion is flattened across passes on purpose. Pass 1, hires fix and your detailer all get the identical sampled text within one run - otherwise an upscale would prompt-drift away from the base image. Handy, but it also means you can't get a different roll per pass from here.
- Choices but no wildcards, or vice versa. Separate modes. Setting one and wondering why the other still rerolls is the classic one.
If you'd rather have wildcard expansion live inside the graph instead of injected at queue time, Impact Pack ships __wildcard__ and {a|b|c} too - that path survives API queueing and headless runs, which this one doesn't.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| expansion_engine | COMBO | Default (From Settings) | 3 options: Default (From Settings), Enabled, Disabled |
| wildcard_mode | COMBO | Default (From Settings) | 5 options: Default (From Settings), Random, Follow Seed, Keep Last Choice, Sequential |
| dynamic_prompt_mode | COMBO | Default (From Settings) | 4 options: Default (From Settings), Random, Follow Seed, Keep Last Choice |
| passthroughopt | * | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| passthrough | * | — |