neru-setup-config
Sets up keyboard shortcuts and behavior for the Neru app launcher so it works the way you want.
Installation
Paste this into Claude Code, Cursor, or any agent that can run commands.
SKILL.mdShow the author's original SKILL.md
---
name: neru-setup-config
description: "Set up or change a user's Neru config.toml: find or create the file, bind or disable hotkeys, tune hints, grids, or scroll, add per-app overrides, macros, or declared modes, set up the login service, then validate and apply it the way the running daemon needs. Use when a Neru user asks to configure Neru, bind a key, change hint or grid behaviour, make one app work, or fix a config that does not take effect."
---
# Setting up a Neru config
Neru reads one TOML file, and every key in it has a documented default and a
platform column saying where it does anything. The work is choosing what to
change, then applying it correctly. Most keys reload on demand, a few need a
daemon restart, and a one-value change is faster through `neru config set`
than through the file. The reference is `docs/reference/configuration.md` in the repo,
`man neru-config` on any install, and `neru docs config` in a browser.
## Where the reference lives
The user rarely has a checkout. Every install method ships the binary and man
pages only. Resolve the docs in this order:
1. A checkout in the working directory: `docs/reference/configuration.md` exists.
2. Man pages on macOS and Linux: `man neru-config-init`,
`man neru-config-set`, `man neru-config-validate`, `man neru-services`,
and `man neru-hints` or another mode page for the flags a hotkey may pass.
On Windows, `neru <command> --help` carries the same text.
3. The doc at the installed version, fetched from GitHub:
```bash
tag=$(neru --version | sed -n '1s/^Neru version //p' | cut -d- -f1)
case $tag in v*.*.*) ;; *) tag=main ;; esac
base="https://raw.githubusercontent.com/y3owk1n/neru/$tag/docs"
curl -fsSL "$base/reference/configuration.md" || curl -fsSL "$base/CONFIGURATION.md"
```
A release build prints its tag. A dev build prints `v1.2.3-14-gabcdef`,
which the `cut` maps to the release it was built from. Releases before
the docs moved name the file `docs/CONFIGURATION.md`, so the second
fetch covers them.
On Windows, where `man`, `sed`, and `cut` are usually absent, the same
fetch in PowerShell:
```powershell
$tag = (((neru --version)[0] -replace '^Neru version ', '') -split '-')[0]
if ($tag -notmatch '^v\d+\.\d+\.\d+$') { $tag = 'main' }
$base = "https://raw.githubusercontent.com/y3owk1n/neru/$tag/docs"
try { Invoke-RestMethod "$base/reference/configuration.md" } catch { Invoke-RestMethod "$base/CONFIGURATION.md" }
```
`neru docs config` opens the same page in a browser on every platform,
which is enough when the user rather than the agent will read it.
The file `neru config init` writes is fully commented and names every key,
so after step 2 below, the user's own file is the quickest reference.
`docs/guide/recipes.md` (`docs/TIPS_TRICKS.md` before the move) at the same URL has recipes to copy for the common
asks: Vimium-style click on select, auto-exit after click, restoring the
cursor after a mode, drag with any button, one key that cycles modes, and
handing all hotkeys to skhd or another daemon.
## Steps
1. **Check the install.** `neru doctor` runs without the daemon and reports
config validity, socket health, permissions, and what this platform
supports. `neru status` says whether the daemon runs. On macOS, hints
and actions need Accessibility, and the `vision`, `contour` and `segment`
strategies need Screen Recording, both under System Settings, Privacy & Security.
On Linux the user needs the `input` group and a `/dev/uinput` udev rule,
covered in `docs/guide/linux.md`. Windows needs nothing beyond the install.
2. **Find or create the file.** The first existing path wins:
`--config`, `$XDG_CONFIG_HOME/neru/config.toml`,
`%APPDATA%\neru\config.toml` on Windows, `~/.config/neru/config.toml`,
`~/.neru.toml`, then `neru.toml` or `config.toml` in the working
directory. When none exists, run `neru config init`. It refuses to
overwrite without `--force`, so never pass `--force` over a file the user
did not ask to replace.
Look for `config.override.toml` beside it. `neru config set` writes
there, and it wins over the base file on every start, so an edit to the
base file that "does nothing" is often shadowed by an override.
`neru config reset <key>` removes one, or delete the file and reload.
3. **Ask what they want, then edit only those sections.** Leave everything
else at defaults. Read the platform column before writing a key on Linux
or Windows, and say so when a request needs a key the platform ignores.
- **A global key.** `[hotkeys]`, with a mode command and its flags as the
value: `"Primary+Shift+Space" = "hints --action left_click"`. The
table merges over the defaults. `"<key>" = "__disabled__"` drops one
default, an empty `[hotkeys]` section drops them all, and `--toggle`
on any mode makes the key open and close it. Overrides for one app go
under a top-level `[[app_configs]]` entry with a `bundle_id`.
- **A key inside a mode.** `[hints.hotkeys]`, `[grid.hotkeys]`, and the
rest hold the keys that work while the mode is open, such as Shift+L
for a click or Tab to cycle. Same merging rules.
- **Hints that miss elements.** Run `sleep 3; neru query hints` and
switch to the app first. A role missing from the list goes into
`hints.clickable_roles`, checked against `neru roles --explain`. An
app whose tree is empty gets `strategy = "vision"`, `"contour"` or `"segment"`,
globally or under `[[hints.app_configs]]` with its `bundle_id`. The
per-app table also takes `additional_clickable_roles`,
`ignore_clickable_check`, and `label_direction`, and it is the
supported way to make one app behave, not a request for a code change.
- **Sequences and custom modes.** `[macros]` names a list of commands to
run with `neru macro <name>` or from a hotkey. `[modes]` declares a
mode with its own hotkey table and indicator. A built-in mode's name
and the word `mode` are refused as names.
- **Look and feel.** `[hints.ui]`, `[grid.ui]`, `[theme]`,
`[mode_indicator]`, `[smooth_cursor]`, `[held_repeat]`, and
`[sticky_modifiers]`. Colours take `#AARRGGBB` or `#RRGGBB`.
For a single value, prefer `neru config set <key> <value>` over editing.
It applies immediately, persists to the override file, and needs the
daemon. Chain interdependent keys with `--no-reload`, then
`neru config reload` once. `neru config dump` lists every dotted key.
The per-app tables cannot be set this way, so those go in the file.
4. **Validate.** `neru config validate` must pass before anything else. It
runs without the daemon and parses the mode commands inside hotkeys, so a
mistyped flag is caught here. Read its warnings, because a flag the mode does not
accept, a role the platform cannot name, or a key inert on this platform
all load and then do nothing, which is the failure the user will report
later.
5. **Apply it.** With the daemon running, `neru config reload` re-reads the
file. Nearly everything reloads, including hotkeys, modes, macros, and
theme. `[systray]` needs a full restart: `neru services restart` for the
installed service, or quit and `neru launch` otherwise. Then
`neru config dump | jq '.hints'` or the section in question shows what the
daemon holds, which confirms the key took effect.
6. **Prove it.** Press the hotkey and watch the mode open. Run the macro.
Open the app and check the hints appear. Do not declare done on a green
validate alone.
## What the reference does not make obvious
- **Colours are alpha first.** `#AARRGGBB` or `#RRGGBB`, never `#RRGGBBAA`.
- **Hotkey mistakes split into warn and refuse.** A bad flag, an orphaned
flag such as `--repeat` without `--action`, or an inert key warns and
loads. An unknown mode name, a reserved mode name under `[modes]`, or a
non-ASCII hint character refuses the whole file.
- **A bad config is rejected whole on reload.** The previous config stays in
place and the failure is logged. Validate before reloading so the user
never runs on a stale config without knowing.
- **There is no log file by default.** `logging.disable_file_logging` is
`true`. To read why a reload failed or a hotkey did nothing, set it to
`false`, restart, and read `~/Library/Logs/neru/app.log` on macOS,
`~/.local/state/neru/log/app.log` on Linux, or
`%LOCALAPPDATA%\neru\log\app.log` on Windows. `log_level = "debug"` shows
per-keypress detail.
- **Linux has no default global hotkeys.** A fresh Linux config binds
nothing on purpose, to avoid colliding with the compositor. Either write
`[hotkeys]` or bind `neru hints` and friends in the compositor's keymap.
- **`bundle_id` works on every platform.** Per-app tables match a bundle
identifier on macOS, a window class on Linux, and the full executable
path on Windows, under the same key. The reference names how to find each.
- **Runtime toggles are not config.** `neru toggle-scroll-invert` and its
siblings last until restart. The lasting version is the matching key.
- **A stale Accessibility grant looks like a broken hotkey.** After an
update on macOS, remove Neru from the Accessibility list and add it back
before touching the config.
## Installing the service
When the user wants Neru at login, `neru services install` writes a launchd
agent on macOS, a systemd user unit on Linux, or a Task Scheduler task on
Windows, and starts it. `neru services status` confirms. It refuses when
nix-darwin or home-manager already manages Neru, and those users configure
the service in their Nix module instead.
Ships with 1 supporting file:
- agents/openai.yaml
Mirrored from the author's public source. Install counts from the open skills registry.