Skip to content

Pounce config & CLI

Reference for configuring and driving Pounce. For writing your own commands, see Writing pounce commands.

Pounce reads ~/.config/pounce/config.json. Every key is optional; the file is re-read each time the palette opens (no daemon restart needed).

{
"theme": "nebelung", // "nebelung" (default), "mocha", or a themes/ file
"themeLight": "nebelung-latte", // used when macOS is in Light Mode
"themeDark": "nebelung", // used when macOS is in Dark Mode
"windowMode": "default", // "default" (720px) or "compact" (600px, tighter)
"hotkey": {
"enabled": true, // register the global hotkey in-process
"key": "space", // "space", "return", "tab", "escape", "a"–"z", "0"–"9"
"modifiers": ["cmd"] // any of "cmd", "shift", "opt", "ctrl"
},
"clipboard": {
"enabled": true, // watch the pasteboard
"maxEntries": 200, // history size
"blacklistBundleIds": ["com.apple.Passwords"], // never record from these
"autoPaste": false // synthesize ⌘V into the prior app (needs Accessibility)
},
"quickAnswers": {
"currency": true // fetch ECB rates so "100 usd in eur" answers inline
},
"updates": {
"check": true // nudge (never install) when a new release is out
},
"fileSearch": {
"enabled": true, // the Find Files mode
"homeOnly": true, // scope to ~ instead of the whole index
"maxResults": 60 // rows kept per query
},
"apps": {
"demoteBundleIds": [], // sink these apps below everything else
"hideBundleIds": [] // drop these apps from the list entirely
},
"windows": {
"enabled": false, // the MRU window switcher (needs Accessibility)
"key": "tab", // hold the modifiers, tap this to walk windows
"modifiers": ["cmd"]
},
"items": { // per-item enable / alias / hotkey — see below
"cmd:emoji": { "alias": "emo", "hotkey": "opt+space e" }
}
}
KeyValuesDefault
theme"nebelung" | "mocha" | a themes/ file name"nebelung"
themeLightsame values; applies in macOS Light Mode"nebelung-latte"
themeDarksame values; applies in macOS Dark Mode"nebelung"
windowMode"default" | "compact""default"
hotkey.enabledtrue | falsetrue
hotkey.keykey name"space"
hotkey.modifiersarray of cmd/shift/opt/ctrl["cmd"]
clipboard.enabledtrue | falsetrue
clipboard.maxEntriesnumber200
clipboard.blacklistBundleIdsarray of bundle ids["com.apple.Passwords"]
clipboard.autoPastetrue | falsefalse
quickAnswers.currencytrue | falsetrue
updates.checktrue | falsetrue
fileSearch.enabledtrue | falsetrue
fileSearch.homeOnlytrue | falsetrue
fileSearch.maxResultsnumber60
apps.demoteBundleIdsarray of bundle idsa built-in list of background/helper apps
apps.hideBundleIdsarray of bundle ids[]
windows.enabledtrue | falsefalse
windows.keykey name"tab"
windows.modifiersarray of cmd/shift/opt/ctrl["cmd"]
itemsmap of item key → { enabled, alias, hotkey }{}

themeLight / themeDark are resolved per open (like everything else here), so flipping macOS appearance shows on the next summon. Either one falls back to theme, and theme alone pins one palette for both modes.

Setting windows.enabled turns on the MRU window switcher; it needs the Accessibility grant to install its event tap, and without the grant stock ⌘Tab keeps working.

quickAnswers.currency and updates.check are the only two things in Pounce that touch the network. The first fetches the ECB daily reference rates from api.frankfurter.app (at most every 12 hours, cached to ~/.local/share/pounce/currency-rates.json). The second asks GitHub once an hour whether there is a newer release. Set both to false and Pounce makes no network requests at all.

updates.check only ever tells you — it never installs anything. While a release is pending, the Update Pounce row is renamed with the new version and pinned to the palette’s first row, and a notification repeats at most once a day. Press ⌘⏎ on that row to skip the version: the pin and the notification stop until the next release, though searching for the row still shows what’s waiting. The wording follows how you installed Pounce, because not every install can update itself in place:

InstallWhat the nudge says
HomebrewReturn runs brew upgrade pounce and restarts the service
Dragged to /ApplicationsReturn downloads the new release and swaps the app in place
The nebelhaus riceRun haus update — Pounce comes down with the rest of the rice
Your own flakeUpdate your pounce input

The last two update through the Nix store rather than in place, so Pounce deliberately won’t try to overwrite itself there — the next rebuild would revert it anyway.

Setting hotkey.enabled to false frees the hotkey so an external launcher (skhd, AeroSpace) can bind a key to pounce-palette instead.

Any theme value that isn’t a built-in resolves to ~/.config/pounce/themes/<name>.json — a flat catppuccin-style name → "#hex" map (nebelung’s palette/*.hex.json files verbatim), re-read on each open like the config itself. That’s how the rice’s theme.flavor / theme.contrast reach Pounce without a rebuild, and it works the same on a Homebrew install:

Terminal window
mkdir -p ~/.config/pounce/themes
curl -fsSLo ~/.config/pounce/themes/nebelung-latte.json \
https://raw.githubusercontent.com/nebelhaus/nebelung/main/palette/nebelung-latte.hex.json
# config.json: "theme": "nebelung-latte"

An unknown name or malformed file falls back to the built-in nebelung palette.

One map covers what you’d otherwise want three keys for — hide a row, give it a search shorthand, give it a global key. Each entry is keyed by an item key:

Item keyAddresses
cmd:<id>a command script, by filename without .sh
app:/Applications/Foo.appan application, by path
mode:<name>a built-in window — launcher, clipboard, emoji, screenshots, camera, filesearch
{
"items": {
"cmd:emoji": { "alias": "emo", "hotkey": "opt+e" },
"cmd:brew-services": { "enabled": false },
"app:/Applications/Ghostty.app": { "alias": "term", "hotkey": "opt+t" },
"mode:clipboard": { "hotkey": "cmd+shift+v" }
}
}
  • enabled: false drops the row from the launcher. It does not disarm a hotkey you bound to it — keeping an item off the list but on a key is a legitimate setup.
  • alias is a search shorthand, matched at a bonus over the item’s real name so it wins over whatever app fuzzy-matches the same letters.
  • hotkey runs the item directly, skipping the palette. The last segment is the key, the rest modifiers (cmd/shift/opt/ctrl); the {"key": …, "modifiers": …} object form works here too.

Add a space for a two-step key: whitespace separates steps, + separates modifiers, so "opt+space e" is ⌥Space then E — the notation Emacs and VS Code use. Sequences sharing a leader share it (⌥Space registers once and owns a map of next keys), and a sequence can run longer than two: "opt+space g s".

The point on a tiling setup: a leader opens a namespace that can’t collide with the ⌥/⌘ chords AeroSpace already owns, and it needs no Accessibility grant — pressing the leader grabs its next-step keys as ordinary global hotkeys for ~2s and releases them the instant one fires, so there’s no event tap and no TCC prompt. Escape cancels; hesitate ~0.45s and a which-key overlay lists the next keys. pounce doctor reports every binding it actually armed, so a typo or a key some other app holds is visible at startup, not on the day you press it.

If a tool already owns your keystrokes — AeroSpace binding modes, skhd, Shortcuts — let it do the chord and have pounce do the action:

Terminal window
pounce run cmd:emoji
pounce run mode:clipboard

Same target grammar as items, dispatched through the identical path a native binding takes. It exits non-zero with a reason on a malformed target, so a typo fails loudly instead of arming a key that does nothing.

Terminal window
pounce --launcher # apps + commands palette (the default mode)
pounce --max-empty 7 # rows to show before you type
pounce -p "Pick:" # generic picker; reads lines from stdin
pounce -i "sf.symbol.name" # icon for the picker
pounce -p "Search:" --chain # picker whose free-text Enter feeds another pounce step
pounce run cmd:emoji # run one item by its key (for external binders)
# built-in windows — items, not flags (`pounce run <item-key>`)
pounce run mode:clipboard # clipboard history
pounce run mode:emoji # emoji picker
pounce run mode:screenshots # screenshot browser
pounce run mode:camera # live camera preview
pounce run mode:filesearch # file/folder search (Spotlight index)
pounce run cmd:hush # any command, by script name without .sh
pounce run app:/Applications/Ghostty.app
pounce --cheatsheet [path] # cheatsheet overlay
pounce --transform 'tr a-z A-Z' # rewrite the selected text through a shell filter
# housekeeping
pounce doctor # diagnose a dead/slow hotkey (see Troubleshooting)
pounce --help # every flag, from the binary itself
pounce --version
pounce --daemon # run the resident daemon (launchd uses this)
pounce --copy-file <path> # copy a file (contents) to the clipboard
pounce --request-accessibility # prompt for the Accessibility grant
pounce --check-accessibility # exit 0 / prints true when granted
pounce --request-bluetooth # prompt for the Bluetooth grant (v0.4.4+)
pounce --check-bluetooth # exit 0 / prints true when granted
FlagPurpose
-p, --placeholderPrompt text for the search field
-i, --iconSF Symbol icon for the picker
--chainMark a free-text Enter as feeding another pounce step — holds the window with the loading skeleton instead of fading. See two-step commands
run <item-key>Run one item by the key items uses (cmd:emoji, mode:clipboard, app:/…), for binders that own the keystroke
--launcherApps + commands mode
--max-empty NRows shown before any query is typed
--cheatsheet [path]Overlay a cheatsheet (JSON)
--transform <filter>Pipe the current selection through a shell filter and paste the result back (needs Accessibility) — how Capitalize / Lowercase work
run <item-key>Run one item: mode:clipboard | mode:emoji | mode:screenshots | mode:camera | mode:filesearch | mode:launcher, cmd:<id>, app:<path>. The built-in windows had a flag each until 2026-07-30 (--clipboard and friends); they’re items now, so one name works as a palette row, a hotkey target and a CLI argument. Needs the daemon
--versionPrint the version
--request-accessibility / --check-accessibilityManage the Accessibility (TCC) grant
--request-bluetooth / --check-bluetoothManage the Bluetooth (TCC) grant — the bluetooth plugin calls this for you
PathWhat
~/.config/pounce/config.jsonConfiguration
~/.config/pounce/commands/Your commands (highest precedence)
~/.config/pounce/cheatsheet.jsonOptional cheatsheet content
~/.local/share/pounce/frecency.jsonUsage history for ranking
~/.local/share/pounce/pounce.sockDaemon control socket

Set by packagers (the rice), rarely by hand:

VariableMeaning
POUNCE_BUILTIN_DIRDirectory of built-in commands
POUNCE_EXTRA_COMMAND_DIRSColon-separated extra command dirs (Nix layers)
POUNCE_COMMAND_PATHColon-separated ad-hoc command dirs

Installing via brew install pounce puts these on your PATH:

BinaryWhat
pounceThe app / daemon
pounce-paletteThe launcher wrapper (bind a hotkey to this)
pounce-<command>A wrapper per built-in command (e.g. pounce-clipboard)

Inside nebelhaus, set the palette up via nebelhaus.pounce instead — the module handles the daemon, hotkey, and permission survival for you.