Donut Text · Recursive Wildcards
Wildcards That Reference Other Wildcards — Recursive Prompt Expansion Without the Blowup
- text
By the time you've used wildcards for a week you've hit the wall they all share: __pose__ files that themselves contain __pose__ tokens, or a "random prompt generator" that's really several wildcard files mashed together until they blow the stack. Donut Text is a text-expansion node that treats nesting as a feature. It resolves wildcards, then resolves whatever those resolved, and keeps going until the text is stable or it hits a safety limit - hence "recursive wildcards". Same seed, same files, same output, every time.
Drop it into the positive prompt position of any workflow and wire its STRING output into your CLIP encoder. The syntax is the familiar wildcard dialect, plus a few toys: __filename__ pulls a random line from filename.txt in your wildcards folder, {a|b|c} is an inline choice, <random:0.5:1.2> rolls a number in a range, and %macro% is a macro. Because a wildcard file can itself contain any of these tokens, max_depth (default 128) bounds how deep the recursion digs before it gives up, and the node refuses to loop forever with a clear "cyclic expansion" error instead of freezing.
The tokens worth knowing
__name__- pick a random line fromComfyUI/wildcards/name.txt(or wherever you've pointed the wildcards folders).3$$__name__picks three lines;__name|word1|word2__filters to lines containing a whole-word match.- Repeated tokens get special modifiers:
__!name__forces the same pick as the first time,__+name__/__-name__step one line forward/back. That's the author's deliberate choice to keep "Mikey-style" selection semantics so existing wildcard collections behave like you expect. {option A|option B}inline random choice;<random:0.5:1.2>random float to four decimals.%date:yyyyMMdd%formats today's date (codes for year, month, day, hour, minute, second), and%node.widget%reads another node's widget value live -%12.positive%grabs whatever node 12 currently has in its prompt box, which is a surprisingly handy trick for reusing one prompt in several places without duplicate typing.
Everything is seeded from the seed input, so a run is deterministic: roll a seed, find a composition you love, and the exact text that produced it is reproducible. The missing dropdown decides what happens when you reference a file that doesn't exist: error (loud, default - you'll see exactly which name failed and where it looked), keep (leave the __token__ in the text, useful for optional groups), or empty (silently drop it). For a beginner, keep is the friendly middle ground while you build your library; error is the one to switch to when things mysteriously stop changing.
Wiring and caveats
prefix and suffix are wire-in inputs, and separator joins them to the main text - handy for stamping the same style tag onto every prompt without editing each one. The node re-evaluates cheaply on changes (it fingerprints your wildcards folder), so editing a .txt file invalidates the cached result without re-encoding your CLIP text.
The one honest gotcha: with dynamicPrompts explicitly disabled, this node does not queue multiple generations for {a|b} choices - one seed, one expansion. If you want a batch of variations, randomize the seed (or drive it from a Donut Seed Plan text seed) rather than expecting multi-run behavior. It ships in ComfyUI-DonutNodes; install the pack via ComfyUI Manager ("DonutNodes") or git clone into ComfyUI/custom_nodes + pip install -r requirements.txt with ComfyUI's Python. Nothing to download - it reads plain .txt files from your wildcards folder, and it'll happily work with wildcard sets you already have.
Inputs (7)
| Name | Type | Default | Description |
|---|---|---|---|
| text | STRING | — | |
| seed | INT | 00–9007199254740991 | — |
| max_depth | INT | 1281–1024 | — |
| missing | COMBO | 3 options: error, keep, empty | |
| prefixopt | STRING | — | |
| suffixopt | STRING | — | |
| separatoropt | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| text | STRING | — |