Wildcards, but they can filter.
You know how a SwarmUI wildcard works: you make a text file, put one option per line, and <wildcard:name> grabs a random line. Simple and great. Quarry takes that idea and gives it a brain.
Instead of plain text files, Quarry reads data files: CSV, TSV, JSON, JSONL, Parquet, or LanceDB. The difference is that every entry can carry extra info in columns, the prompt itself, tags, a source, a rating, whatever the file happens to have. Because those columns are there, you can filter right inside your prompt and pull exactly the entries you want. "Only punk." "Anything but nsfw." "Girls from this one source." One big dataset quietly does the job of a hundred little .txt files.
Here is the whole idea in two tags:
<q:characters> a random entry from your "characters" dataset
<q:characters[tags=goth]> a random entry that happens to be tagged goth
Neat, right? Let's take the tour.
Everything happens in the Quarry tab down in SwarmUI's bottom bar, right next to Wildcards. Open it and you get a table of every dataset Quarry found, each with its prompt column, its tag columns, a row count, and a Preview button (more on all of those below).
The very first time you open the tab, Quarry will offer a one-time helper download (the DuckDB "lance" reader it uses to open datasets, around 235 MB). Click the button, give it a minute, and you are set. You only ever do this once.
- Open the Quarry tab.
- Quarry already made you a datasets folder, sitting right next to your Wildcards folder. Want it somewhere else? Type a new path in the Datasets folder box and click Save Settings.
- Drop some data files into that folder (or grab ready-made ones with the Download button described below), then click Refresh.
- Use them in any prompt:
<q:characters[tags=goth]>.
That is genuinely it. There is no "enable" switch to hunt for; set a folder, or just keep the default, and Quarry is on.
No data of your own yet? No problem. There is a whole collection of prompt datasets, already converted and ready to drop straight in:
Dozens of sets covering Stable Diffusion, Midjourney, Flux, Danbooru tags, photography, and more.
The easy way: in the Quarry tab, click Download Datasets. A window lists every dataset in the collection with its size. Click Download next to any one and it streams straight into your datasets folder with a live progress bar. Ones you already have are highlighted with a green check and get a Redownload button instead (handy when a set has been updated). One download runs at a time, and you can cancel partway through.
It will use your Hugging Face token if you have set one (under the User tab), but this collection is public, so it works perfectly well without one.
Prefer the command line? Install the Hugging Face tool and pull the whole collection into your datasets folder in one go:
pip install -U huggingface_hub
hf download jtreminio/prompt-dataset --repo-type dataset \
--local-dir /path/to/your/quarry-datasetsOnly want a few? Add an --include "<name>.lance/*" line per dataset (the names are listed on the dataset page):
hf download jtreminio/prompt-dataset --repo-type dataset \
--include "Gustavosta.Stable-Diffusion-Prompts.lance/*" \
--include "succinctly.midjourney-prompts.lance/*" \
--local-dir /path/to/your/quarry-datasetsThis is the fun part. A Quarry tag always begins with <q: followed by the name of a dataset, and it grows from there as you need it:
<q:characters> one random entry from "characters"
<q:characters,creatures> one random entry from either set
<q:*> one random entry from your top-level datasets
<q:**> like <q:*>, but reaches into subfolders too
<q:portraits-*> one random entry from any "portraits-..." set
<q:characters[tags=girl]> a random entry tagged "girl"
<q:characters,creatures[tags=girl]> the same filter, across both sets
<q:*[tags=girl]> the same filter, across your top-level sets
<q:characters:caption> read the prompt from the "caption" column
Let's unpack that line by line.
The basics. <q:characters> rolls the dice and drops one random entry from the characters dataset into your prompt. Same spirit as a plain wildcard, just reading from a richer file.
List more than one name, separated by commas, and Quarry treats them as a single combined pool, then picks one random entry from the whole thing. <q:characters,creatures> might hand you a character or a creature. (The bigger a dataset, the more of that pool it makes up, so it gets picked proportionally more often.)
The * is a wildcard for your wildcards. On its own, <q:*> stands for all your top-level datasets at once and picks a random entry from them.
If you keep some datasets in subfolders, a single * stays at one level: <q:*> covers the datasets sitting loose in your datasets folder, and <q:anime/*> covers the ones directly inside anime. Use a double star to recurse — <q:**> reaches every dataset no matter how deeply nested, and <q:anime/**> reaches everything under anime. (No subfolders? Then * and ** mean the same thing: everything.)
It also matches partial names, which is perfect when you keep a family of related sets. Say you have portraits-photo, portraits-anime, and portraits-vintage: then <q:portraits-*> pulls from all three at once. The * can stand in for as much of the name as you like, so even <q:por*> would catch the lot. And partial names take filters just like everything else, so <q:portraits-*[tags=girl]> grabs a "girl" entry from every one of your portrait sets.
Every dataset in the Quarry tab has a little on/off switch next to it. Flip it off and that dataset is skipped whenever a wildcard would otherwise sweep it in — <q:*>, <q:**>, <q:anime/**>, <q:por*>, and so on all pretend it isn't there. Handy for a set you keep around but don't want mixed into "everything" rolls.
The switch only affects wildcard matches. Name the dataset directly and it still works, even while switched off: <q:portraits-vintage[tags=girl]> reads portraits-vintage no matter what its toggle says. So "off" means "don't pull me in automatically," not "disabled." The switch saves the moment you click it — no need to press Save Settings.
Add [ ... ] after the name to filter. <q:characters[tags=girl]> keeps only the entries tagged "girl," then picks one of those at random. A filter reads as column operator value: which column to look in, how to match, and what to match.
A filter applies to every dataset in the tag. <q:characters,creatures[tags=girl]> keeps the "girl"-tagged entries from both sets, combines them, and picks one. And <q:*[tags=girl]> does the same thing across your top-level datasets — each one, filtered, pooled together, one pick — while <q:**[tags=girl]> widens that to every dataset in every subfolder.
Heads up on
<q:*[ ... ]>: the very first time you use a particular filter across all datasets, Quarry has to look through each one to see what matches, so it can take a moment to warm up. It remembers the answer for each dataset, though, so the next time you use that same filter it is quick. (And if some datasets do not have the column you asked for, Quarry simply skips those and uses the ones that do, so a wildcard query never breaks.)
When you list several values, the operator decides how they have to match:
| Operator | Meaning | Example |
|---|---|---|
= |
match any of them | tags=punk,goth keeps punk or goth |
== |
match all of them | tags==punk,goth keeps punk and goth |
!= |
match none of them | tags!=nsfw drops anything nsfw |
+= |
number is at least | score+=0.8 keeps entries scoring 0.8 or higher |
-= |
number is at most | width-=768 keeps entries up to 768 wide |
Easy way to remember: = one, == all, != none, and for numbers += up, -= down.
The last two, += (at least) and -= (at most), are for number columns (a rating, a width, a year). They use +/- rather than the usual >=/<= because SwarmUI reads a > as the end of the tag, so >= would cut the tag short. If you point +=/-= at a column that does not hold numbers, Quarry quietly skips that dataset rather than guessing — so across a wildcard like <q:*[score+=0.8]> only the datasets with a numeric score take part.
Want more than one condition? Stack filters with a semicolon and Quarry requires all of them at once:
<q:characters[tags=punk,goth ; source=civitai]>
That reads as "(punk or goth) and from civitai."
Every dataset has a prompt column — the column whose text actually lands in your prompt (Quarry guesses a sensible default, see The prompt column below). Add :column to the end of a tag to read from a different column just for that tag:
<q:characters:caption> read each entry's "caption" column instead of the default
<q:characters[tags=girl]:caption> same, but only "girl"-tagged entries — the column goes after the filter
<q:characters,creatures:caption> read the "caption" column across both sets
The column always comes last, after the name list and after any [ ... ] filter.
If a dataset does not have the column you asked for, Quarry quietly falls back to that dataset's own default prompt column — and it decides per dataset. So with <q:FOO,BAZ:caption>, if FOO has a caption column but BAZ does not, Quarry reads FOO's caption and BAZ's default. A column override never breaks a multi-dataset tag.
Need more than one column from the same row? Separate column names with commas after the : — Quarry pulls all of them from the same randomly picked row and joins them with a comma:
<q:danbooru:full,copyright> the "full" and "copyright" columns from the same row
<q:danbooru[tags=1girl]:full,copyright> same, but only 1girl-tagged rows
<q:danbooru:prompt,style,source> three columns from the same row
This is handy when you want to combine metadata with the prompt — say, the caption plus the artist credit, or a description plus a source URL — without spinning up two separate <q:*> tags (which would each roll their own random row). The filter still applies to both columns, so you always get a coherent pair.
Want several picks, each with multiple columns? The count syntax works too: <q[3]:danbooru:full,copyright> gives you three different rows, each contributing its full and copyright values.
By default, multi-column output is joined with , (comma + space). If you prefer something else — |, \n, nothing at all — set columnSeparator in your Quarry.json settings file (located next to your wildcards folder):
{
"datasetsFolder": "...",
"columnSeparator": " | ",
...
}This affects every multi-column tag in your prompts. The default is ", ".
| Tag | What you get |
|---|---|
<q:prompts> |
any random prompt |
<q:prompts[tags=brunette,punk]> |
tagged brunette or punk |
<q:prompts[tags==brunette,punk]> |
tagged brunette and punk |
<q:prompts[tags!=nsfw]> |
not tagged nsfw |
<q:prompts[score+=0.8]> |
a number column at least 0.8 |
<q:prompts[width-=768]> |
a number column up to 768 |
<q:midjourney[prompt=girl]> |
prompts containing "girl" |
<q:*[tags=cyberpunk]> |
a cyberpunk entry from any top-level set |
<q:**[tags=cyberpunk]> |
…the same, reaching into subfolders too |
<q:portraits-*[tags=girl]> |
a "girl" from any of your portraits-* sets |
<q:midjourney:caption> |
any prompt, read from the caption column |
<q:midjourney[tags=girl]:caption> |
a "girl" entry, read from the caption column |
<q:danbooru:full,copyright> |
the full and copyright columns from the same row |
<q:danbooru[tags=1girl]:full,copyright> |
same, filtered to 1girl |
<q[3]:danbooru:full,copyright> |
3 different rows, each with full and copyright |
<q[3]:prompts[tags=punk]> |
3 different punk prompts |
You do not have to remember your dataset names. Start typing a Quarry tag in any prompt box and SwarmUI's suggestion popup helps you fill it in, exactly the way it does for <wildcard: and the other built-in tags:
- Type
<qand Quarry shows up in the list of tags. - After
<q:you get a list of every dataset. Keep typing to narrow it. - Type a comma and it suggests the next dataset for a combined pull (the ones you have already added drop out of the list).
- With a single dataset, type
[and it lists that dataset's columns to filter on, with its tag columns first — so<q:characters[immediately offerstags. Once you have picked a column it offers the operators (=any,==all,!=none, plus+=and-=when the column holds numbers); after a;it starts over for your next condition. - Type
:(after the name and any[filter]) and it lists the columns you can use as the prompt — the default prompt column first — for the:columnoverride. You can chain multiple columns with commas:<q:danbooru:full,then pickcopyrightto get<q:danbooru:full,copyright>. Type>to finish.
Picking a suggestion leaves the tag open so you can keep going — add another comma, open a [ filter, or just type > to finish.
You never have to type any of this by hand if you would rather not. In the Quarry tab, click a dataset's name and Quarry drops a <q:NAME> reference straight into your prompt at the cursor. Click that same name again and it pops back out. Datasets your current prompt is using get highlighted in the table, so you can always see what is in play.
There is a small checkbox in the tab: Add to existing <q:> tag, and it is on by default. While it is on, clicking a dataset name adds it to the first <q:...> tag you already have, so clicking "creatures" while <q:characters> is sitting in your prompt turns it into <q:characters,creatures>. It is the quickest way to build up a combined pull without wrangling brackets yourself. Prefer a separate tag every time? Switch it off, and each click inserts its own.
Each dataset row in the tab has two column settings, and Quarry fills both in with sensible guesses, so most of the time you can leave them alone.
This is the column whose text actually lands in your prompt. Quarry guesses it by looking for an obvious name like prompt, text, caption, description, or value, and if none of those exist it just uses the first column in the file. Guessed wrong? Pick the right one from the dropdown and click Save Settings.
This setting is the default for every tag. Want a different column for one tag only? Append :column to the tag itself — see Picking the prompt column above.
These are the columns the tags= keyword searches. Tick whichever columns hold tags (a dataset can have several, and Quarry searches every one you tick). Here is the friendly part: if you do not set any tag columns at all, tags= just searches the prompt column instead. So <q:something[tags=girl]> still does something useful on every dataset, even a bare one that has nothing but a prompt.
Not sure what is in a dataset, or which column is which? Hit Preview on its row. A pop-up shows the first rows of the dataset in a plain table with every column on display, so you can eyeball the real data, spot which column holds the prompt, and see what your tag columns actually look like. Need more? Load 500 more pulls the next chunk. There is also a Clear cache button for when you have changed a file and want a fresh look.
- Matching is "contains," not exact.
prompt=girlfinds every entry whose prompt contains "girl" (exact matching would rather defeat the point of a wildcard). Capitalization does not matter. - Tag columns are matched tag by tag, but each tag is still "contains," so
tags=girlalso matchesgirlsandyoung girl(and yes,tags=punkwill matchcyberpunktoo). - Values can include spaces (
long hair), but these characters are reserved and cannot appear inside a value:; , = ! [ ] < > - Need several picks from a single tag? SwarmUI's built-in count works:
<q[3]:characters>gives you 3 different entries.
Quarry reads your data with DuckDB and its LanceDB reader. Building from source:
npm install
npm run build # build the UI
./run-tests # run the test suite