Config reference
Every key in ~/.config/pounce/config.json, what it defaults to, the three blocks that need a restart, and where every file lives.
Config file
Pounce reads ~/.config/pounce/config.json, re-read on every open. No restart
is needed, except for the three things the daemon sets up at startup:
windows, autoQuit, and the items hotkeys. Those are captured when armed
and need a restart to change:
launchctl kickstart -k "gui/$(id -u)/com.hausfold.pounce"Inside haus, a rebuild does that bounce for you when one of those keys moves.
pounce config init # writes ~/.config/pounce/config.json
pounce config print # …or just look at it, touching nothinginit writes every setting at its default, one commented-out line each
with a sentence above it. Nothing changes until you uncomment a line, and you
make the file minimal by deleting the lines you never touched. It never
overwrites an existing config (it writes config.json.new beside it instead;
--force replaces).
Inside haus, `config init` refuses
Your config.json is generated from haus.pounce.*, and the next rebuild
would put the generated one straight back. Change it in your host file
instead; see the Launcher room.
Comments and trailing commas are fine (JSON5); unknown keys are ignored, so an older Pounce never chokes on a config written by a newer one.
{
"theme": "nebelung", // "nebelung" (default), "mocha", or a themes/ file
"themeLight": "nebelung-latte", // used in macOS Light Mode
"themeDark": "nebelung", // used in macOS Dark Mode
"windowMode": "default", // "default" (720px) or "compact" (600px, tighter)
"scale": 1.0, // 0.8-2.0: how big the whole UI is drawn
"hotkey": {
"enabled": true,
"key": "space", // "space", "return", "tab", "escape", "a"–"z", "0"–"9"
"modifiers": ["cmd"] // any of "cmd", "shift", "opt", "ctrl"
},
"clipboard": {
"enabled": true,
"maxEntries": 200,
"blacklistBundleIds": ["com.apple.Passwords"],
"autoPaste": false // synthesize ⌘V into the prior app (needs Accessibility)
},
"quickAnswers": { "currency": true }, // ECB rates, so "100 usd in eur" answers inline
"updates": { "check": true }, // nudge (never install) when a release is out
"fileSearch": {
"enabled": true,
"homeOnly": true, // scope to ~ instead of the whole Spotlight index
"maxResults": 60
},
"apps": {
"demoteBundleIds": [], // sink these below everything else; REPLACES a built-in list of Apple utilities (Feedback Assistant, Audio MIDI Setup, …)
"hideBundleIds": [] // drop these from the list entirely
},
"windows": {
"enabled": false, // the MRU window switcher (needs Accessibility)
"key": "tab",
"modifiers": ["cmd"]
},
"autoQuit": {
"enabled": false,
"delay": 2,
"exclude": ["com.apple.finder"] // REPLACES the default, doesn't extend it
},
"items": { // per-item enable / alias / hotkey, see below
"cmd:emoji": { "alias": "emo", "hotkey": "opt+space e" }
}
}quickAnswers.currency and updates.check are the only two settings that
touch the network; set both false for a fully offline Pounce.
autoQuit.enabled and windows.enabled turn on the two opt-in
behaviours; both blocks are startup-only, so
any edit inside them needs the daemon restart above, not just flipping
enabled.
windowMode and scale are independent knobs (proportions vs. size) and
they compose: a compact launcher at 1.4 is still the compact layout, just
bigger. Values outside 0.8–2.0 clamp rather than reject. On haus, scale is
written for you from haus.ui.scale.
Themes
themeLight / themeDark are resolved per open, so flipping macOS appearance
shows on the next summon; either falls back to theme, and theme alone pins
one palette for both modes.
Any theme value that isn't built-in resolves to
~/.config/pounce/themes/<name>.json: a flat catppuccin-style name → "#hex"
map (nebelung's palette/*.hex.json
files verbatim), which is how a desktop's theme.flavor / theme.contrast
reach Pounce without a rebuild:
mkdir -p ~/.config/pounce/themes
curl -fsSLo ~/.config/pounce/themes/nebelung-latte.json \
https://raw.githubusercontent.com/hausfold/nebelung/main/palette/nebelung-latte.hex.json
# config.json: "theme": "nebelung-latte"Per-item settings (items)
One map for what you'd otherwise want three keys: hide a row, give it a search shorthand, give it a global key. Each entry is keyed by an item key:
| Item key | Addresses |
|---|---|
cmd:<id> | a command script, by filename without .sh |
app:/Applications/Foo.app | an 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 without disarming a hotkey bound to it; keeping
an item off the list but on a key is a legitimate setup. alias is a search
shorthand that 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, and the object form {"key": …, "modifiers": …} works too.
The laptop Fn/Globe key is a one-step special case
("mode:emoji": { "hotkey": "fn" }), using a keyboard event tap that needs
Accessibility, firing only on a lone tap so Fn combinations keep working.
"globe" / "function" are accepted aliases; haus binds emoji to it by
default, and haus.pounce.items."mode:emoji".hotkey = null leaves Globe
native.
Leader sequences
Add a space for a two-step key: "opt+space e" is ⌥Space then E, the
Emacs/VS Code notation. Sequences sharing a leader share it (⌥Space registers
once), and can run longer than two steps.
The payoff on a tiling setup: a leader can't collide with the ⌥/⌘ chords a
window manager already owns, and it needs no Accessibility grant: pressing
it grabs the next-step keys as ordinary global hotkeys for ~2s and releases
them the instant one fires. Escape cancels; hesitate ~0.45s and a which-key
overlay lists the next keys. pounce doctor reports every binding it actually
armed.
Driving Pounce from another binder
AeroSpace modes, skhd, Shortcuts:
pounce run cmd:emoji
pounce run mode:clipboardSame target grammar as items, through the same path a native binding takes; a
malformed target exits non-zero with a reason.
File paths
| Path | What |
|---|---|
~/.config/pounce/config.json | Configuration |
~/.config/pounce/commands/ | Your commands (highest precedence) |
~/.config/pounce/themes/ | Extra palettes, by name |
~/.config/pounce/cheatsheet.json | Optional cheatsheet content |
~/.local/share/pounce/frecency.json | Usage history for ranking |
~/.local/share/pounce/pounce.sock | Daemon control socket |
~/.local/state/pounce/drafts/ | Saved drafts, per --draft key |
Environment variables
Set by packagers (haus), rarely by hand: POUNCE_BUILTIN_DIR,
POUNCE_EXTRA_COMMAND_DIRS (colon-separated Nix layers),
POUNCE_COMMAND_PATH (colon-separated ad-hoc dirs).