Complete reference for every neru command, flag, and argument.
Neru runs as a background daemon. Most commands are thin clients that send a
request to that daemon over a Unix socket (a named pipe on Windows) and print
the reply. "The daemon" below means the process started by neru launch.
The same content is available as manpages (man neru) after installation.
Related: Configuration Reference · Installation · Troubleshooting
- How to read this reference
- Global flags
- Command index
- Daemon lifecycle —
launch·start·stop·idle·status·doctor - Navigation modes —
hints·grid·recursive_grid·scroll·monitor_select - Actions —
actionand its subcommands - Sequences —
run·macro - Configuration commands —
config - Runtime toggles
- Utilities —
roles·services·docs - Scripting
- IPC protocol
Every command is documented in the same shape: a one-line purpose, a synopsis, a description, a flag table, and examples. The navigation modes share one flag table, the mode flag reference, which is generated from the source that registers those flags.
Synopsis notation
| Notation | Meaning |
|---|---|
<value> |
Required placeholder you replace |
[--flag] |
Optional flag |
a|b |
Choose one |
[<key>...] |
Repeatable argument |
Daemon requirement is stated per command. Commands that do not need the
daemon are launch, doctor, roles, config init, and config validate;
every other command requires a running daemon.
Platform support is listed for every command and flag whose behaviour is not
identical on all three platforms, as a Platforms: line or a Platforms
column. Anything without such a note works the same on macOS, Linux, and
Windows. Commands that are unavailable return ERR_NOT_SUPPORTED.
On Linux, "supported" means an X11 session or a Wayland session on wlroots or KWin. GNOME Wayland is not supported at all — the daemon exits at startup. See CROSS_PLATFORM.md.
-h, --help is accepted by every command and is omitted from the flag tables
below.
Accepted by every command.
| Flag | Shorthand | Type | Default | Description |
|---|---|---|---|---|
--config |
-c |
string | "" |
Path to the config file. Overrides the default search paths. See Config file location. |
--timeout |
int | 10 |
IPC timeout in seconds. |
| Command | Purpose | Needs daemon | Platforms |
|---|---|---|---|
launch |
Start the daemon | No | All |
start |
Resume after stop |
Yes | All |
stop |
Pause without exiting | Yes | All |
idle |
Exit the active mode | Yes | All |
status |
Print daemon state | Yes | All |
doctor |
Run diagnostics | No | All |
hints |
Label and click UI elements | Yes | All ¹ |
grid |
Coordinate grid navigation | Yes | All |
recursive_grid |
Recursive cell navigation | Yes | All |
scroll |
Vim-style scrolling | Yes | All |
monitor_select |
Jump the cursor to a display | Yes | macOS · Linux |
action |
One-shot mouse/scroll/key input | Yes | All ² |
run |
Run several actions in order | Yes | All |
macro |
Run a named sequence from config | Yes | All |
config |
Inspect and change config | Mixed | All |
toggle-scroll-invert |
Invert scroll direction | Yes | All |
toggle-cursor-follow-selection |
Toggle cursor follow | Yes | All |
toggle-screen-share |
Hide overlays while sharing | Yes | macOS |
roles |
List the role vocabulary | No | All |
services |
Manage the system service | No | macOS |
docs |
Open documentation in a browser | No | macOS |
¹ Element discovery quality differs by platform: a full accessibility tree on
macOS, an AT-SPI walk on Linux whose coverage depends on the application, and an
initial shallow UI Automation walk on Windows. The vision strategy is macOS
only. See Accessibility and hints.
² Two action subcommands are limited: hide_cursor and show_cursor are macOS
only, and scroll_left / scroll_right have no effect on Windows. See
Action platform support.
Start the Neru daemon.
neru launch [-c <path>] [--timeout <seconds>]
Runs the background process that owns the event tap, overlays, and IPC server. Does not require a running daemon; this is what starts one. Takes only the global flags.
Resume Neru after neru stop.
neru start
Requires a running daemon. Re-enables mode switching and overlay rendering.
Pause Neru without exiting the daemon.
neru stop
Requires a running daemon. The process keeps running and keeps its socket open,
but mode switching and overlay rendering are disabled. Resume with
neru start.
Exit the active navigation mode.
neru idle
Requires a running daemon. Returns to idle. No-op when no mode is active.
Takes no flags and no arguments — idle leaves a mode rather than entering one, so there is nothing to describe. Anything written after it is refused.
Print the daemon state and current mode.
neru status [--json]
Requires a running daemon.
Flags
| Flag | Type | Default | Description |
|---|---|---|---|
--json |
bool | false |
Print the status as a JSON object, for scripts. |
Output fields
| Field | Values |
|---|---|
Status |
running, disabled |
Mode |
idle, hints, grid, recursive_grid, scroll, monitor_select |
JSON output
--json prints the same state as an object, so a script does not have to parse
the human form. The object goes to stdout on its own; errors go to stderr and
set a non-zero exit status, so a pipeline never has to distinguish them:
$ neru status --json | jq -r .mode
idleThe examples here and in Tips & Tricks use
jq to read the object; any JSON tool does.
| Key | Type | Description |
|---|---|---|
enabled |
bool | false after neru stop, true after neru start. |
mode |
string | The active mode, same values as Mode above. |
config |
string | Path of the configuration file in use. |
hints_enabled, grid_enabled, recursive_grid_enabled |
bool | Whether each mode is enabled in the configuration. |
scroll_inverted |
bool | Set by toggle-scroll-invert. |
hidden_for_screen_share |
bool | Set by toggle-screen-share. true means hidden. |
cursor_follow_selection |
bool or null | Set by toggle-cursor-follow-selection. null when no mode is running. |
saved_cursor_slots |
object | The occupied cursor slots, each {"x": …, "y": …}. Empty object when none are saved. |
capabilities |
object | Per-subsystem support on this platform, as neru doctor reports it. |
profile |
object | The platform backend profile: which adapter serves each subsystem, and whether it needs CGO. |
Everything above except capabilities and profile is the stable part of this
output. Those two follow the platform support matrix and gain entries as
subsystems are added, so read the keys you need rather than assuming the whole
set.
The three toggle-* commands change state that would otherwise be invisible.
Each reports under the key above, so a script can set a state with --state and
confirm it:
neru toggle-scroll-invert --state on
neru status --json | jq -r .scroll_inverted # truecursor_follow_selection is null rather than false when no mode is running,
because the two are different answers: false is a running mode that is not
following the selection, null is that there is nothing to follow it with.
Test for it before treating the value as a boolean:
neru status --json | jq -r 'if .cursor_follow_selection == null then "no mode" else .cursor_follow_selection end'Run system diagnostics.
neru doctor
Does not require a running daemon. Reports config validity, socket health, platform capabilities, and internal component state. Platform capabilities come from the capability matrix described in CROSS_PLATFORM.md.
Modes take over the keyboard until you select a target or exit. All five require a running daemon.
Every flag a mode command accepts, and which modes accept it. The same command
is understood identically wherever it is written — typed after neru, as a
step in a hotkey binding, or sent over the
IPC socket — so a flag listed here works in all three, and a
flag a mode is not listed for is refused rather than ignored.
A flag written more than once replaces its earlier value, unless the value
column says it is repeatable, in which case each occurrence adds to the last.
--action may also be given positionally: hints left_click. neru idle
appears in no row — it leaves a mode rather than entering one, so it accepts
nothing.
| Flag | Shorthand | Value | Modes | Description |
|---|---|---|---|---|
--action |
-a |
value | hints · grid · recursive_grid |
Mouse button action to perform on the selection (left_click, right_click, middle_click, left_mouse_down, left_mouse_up, right_mouse_down, right_mouse_up, middle_mouse_down, middle_mouse_up, left_mouse_toggle, right_mouse_toggle, middle_mouse_toggle). Commas chain multiple actions (e.g. left_click,left_click for double-click). Other actions, such as scroll or move_mouse, are actions in their own right and need no mode |
--modifier |
value | hints · grid · recursive_grid |
Comma-separated modifier keys to hold during action (cmd, super, meta, shift, alt, option, ctrl) (requires --action) | |
--on-exit |
value, repeatable | hints · grid · recursive_grid |
Step to run after the action is fulfilled and the mode exits (same syntax as hotkeys, e.g. 'action left_click' or 'exec notify-send done'). Repeat the flag to run several steps in order. Requires --action; not run on manual escape/idle | |
--repeat |
-r |
none | hints · grid · recursive_grid |
Re-activate mode after performing the action (requires --action) |
--toggle |
-t |
none | hints · grid · recursive_grid · scroll · monitor_select |
Toggle mode on/off (exit to idle if already active) |
--search |
-s |
none | hints |
Show search input when the mode is activated |
--hide-on-empty-search |
none | hints |
Hide all hints when search query is empty (requires --search) | |
--role |
value, repeatable | hints |
Filter by element role (comma-separated: button,link — the hints.clickable_roles vocabulary, see 'neru roles'). Repeat the flag to add more | |
--text |
value, repeatable | hints |
Filter elements by text content (comma-separated, case-insensitive substring match). Repeat the flag to add more | |
--strategy |
value | hints |
Element detection strategy: axtree (macOS AX API) or vision (Vision Framework) | |
--label-direction |
value | hints |
Hint label enumeration: normal (default, prefix-avoidance, prefers shorter labels) or reverse (spreads labels across the alphabet) | |
--split-word |
none | hints |
Split detected text into word-level regions (requires vision strategy) | |
--zoom-to-depth |
value | recursive_grid |
Auto-zoom to the given depth (a non-negative integer) in recursive-grid at the current cursor position | |
--cursor-selection-mode |
value | hints · grid · recursive_grid |
How the real cursor should behave during selection: follow or hold |
Where the values come from
--actiontakes the mouse-button action names. Commas chain several, soleft_click,left_clickis a double-click.--on-exittakes a step in hotkey-binding syntax, and several of them make one action sequence. The steps do not run when the mode is left manually via escape orneru idle.--roletakes the role vocabulary listed byneru roles.--textmatches case-insensitively on a substring, and several values match any of them.--label-directionis explained under Choosing a label direction.--strategy visionand--split-wordare macOS only. See Accessibility and hints.
Where the defaults come from
A flag left out inherits the configuration rather than a zero value:
--strategy from hints.strategy and
--label-direction from hints.label_direction. --cursor-selection-mode
defaults to follow, and a presence-only flag left out asks for nothing.
Label clickable elements and act on the one you type.
neru hints [flags]
Scans the focused window for interactive elements and overlays a short letter label on each. Typing a label selects that element.
Element discovery uses the axtree strategy by default. The vision strategy
is macOS-only and detects on-screen text and rectangles via the Vision
framework. Coverage per platform is documented in
CROSS_PLATFORM.md.
Flags — every flag listed for hints in the
mode flag reference, plus the probe below.
| Flag | Shorthand | Type | Default | Description |
|---|---|---|---|---|
--debug |
-d |
bool | false |
Print the elements that would be hinted, with a count and a sample, without showing the overlay. |
--debug runs a probe rather than activating hints, so it is not a mode flag:
it is absent from the reference above, unknown inside a hotkey binding, and
cannot be combined with a flag that only describes an activation — --action,
--modifier, --on-exit, --repeat, --toggle, --search,
--hide-on-empty-search, --label-direction or --cursor-selection-mode. It
does accept the flags that decide which elements are collected: --role,
--text, --strategy and --split-word. On the wire a probe is its own
command; see IPC protocol.
Examples
neru hints
neru hints --action left_click
neru hints --action left_click --modifier shift
neru hints --action left_click --repeat
neru hints --search
neru hints --role button --text submit
neru hints --strategy vision --split-word
neru hints --debugDivide the screen into a labelled coordinate grid.
neru grid [flags]
Overlays a grid of labelled cells. Typing a cell label moves the cursor there.
Flags — every flag listed for grid in the
mode flag reference.
Grid size, labels, and appearance are configured under
[grid].
Typing a full label opens a 3x3 subgrid inside that cell. To correct an
off-by-one label without retyping it, bind
move_cell — it moves the open subgrid to a
neighbouring cell.
Examples
neru grid
neru grid --action left_click --repeat
neru grid --cursor-selection-mode hold
neru grid --action left_click --on-exit 'exec notify-send clicked'Narrow the screen recursively, one keypress per level.
neru recursive_grid [flags]
Each keypress subdivides the selected cell, so successive presses converge on a
point. Depth limits and per-depth layout are configured under
[recursive_grid].
Backspace backtracks one level. To correct sideways instead of upwards, bind
move_cell — it slides the selection to a
neighbouring cell without leaving the current depth.
Flags — every flag listed for recursive_grid in the
mode flag reference.
--zoom-to-depth drills at the current cursor position as the mode activates.
It stops early if the grid cannot subdivide further, at the minimum cell size
or the maximum depth.
Examples
neru recursive_grid
neru recursive_grid --action middle_click
neru recursive_grid --zoom-to-depth 2
neru recursive_grid --zoom-to-depth 3 --action left_clickScroll at the cursor with vim-style keys.
neru scroll [flags]
Flags — every flag listed for scroll in the
mode flag reference.
Default key bindings
Every binding below is configurable under [scroll.hotkeys].
| Key | Action |
|---|---|
j / k |
Scroll down / up |
h / l |
Scroll left / right |
d / PageDown |
Page down |
u / PageUp |
Page up |
gg |
Jump to top |
Shift+G |
Jump to bottom |
Up / Down / Left / Right |
Move the cursor by 10 px |
Shift+L / Shift+R / Shift+M |
Left / right / middle click |
Shift+I / Shift+U |
Press / release the left button |
Escape |
Exit to idle |
Step sizes come from scroll.scroll_step, scroll_step_half, and
scroll_step_full.
Examples
neru scroll
neru scroll --toggleMove the cursor to another display.
neru monitor_select [flags]
Platforms: macOS · Linux. Not implemented on Windows, where it returns
ERR_NOT_SUPPORTED.
Opens a labelled panel on each display. Typing a label moves the cursor to that display. The current display is excluded.
Flags — every flag listed for monitor_select in the
mode flag reference.
Default key bindings
| Key | Action |
|---|---|
1–9 |
Select the display with that label |
Escape |
Cancel and return to idle |
Labels come from monitor_select.characters (default 123456789).
Examples
neru monitor_select
neru monitor_select --toggleOne-shot input that runs without entering a mode. All action subcommands require a running daemon.
neru action <subcommand> [flags]
Each subcommand accepts only the flags documented in its own section. Passing
any other flag fails with ERR_INVALID_INPUT and a message naming the actions
that do accept it — flags are never accepted and then ignored.
Point-targeted actions resolve their target in this order: the active mode selection when one exists, otherwise the current cursor position.
| Flag | Type | Description |
|---|---|---|
--selection |
bool | Target the active mode selection. |
--bare |
bool | Target the cursor position even when a mode selection exists. |
Every action has a name usable anywhere a name is expected: a mode --action,
a hotkey binding string, or neru action directly.
| Category | Names |
|---|---|
| Click | left_click, right_click, middle_click |
| Press | left_mouse_down, right_mouse_down, middle_mouse_down |
| Release | left_mouse_up, right_mouse_up, middle_mouse_up |
| Toggle | left_mouse_toggle, right_mouse_toggle, middle_mouse_toggle |
| Movement | move_mouse, move_mouse_relative, move_monitor |
| Scroll | scroll, scroll_up, scroll_down, scroll_left, scroll_right, page_up, page_down, go_top, go_bottom |
| Mode | reset, backspace, move_cell, cycle_hint, wait_for_mode_exit |
| Cursor | save_cursor_pos, restore_cursor_pos, hide_cursor, show_cursor |
| Keys | feed |
| Timing | sleep — hotkey bindings only |
Mode --action accepts mouse-button names only — the click, press, release,
and toggle rows above, plus the deprecated mouse_down / mouse_up. Every
other name, including move_mouse, move_mouse_relative, and scroll, is
rejected with ERR_INVALID_INPUT and must be run as neru action <name> or
bound as a hotkey action instead.
Every action not listed here behaves identically on macOS, Linux, and Windows.
| Action | macOS | Linux | Windows | Note |
|---|---|---|---|---|
hide_cursor, show_cursor |
Yes | No | No | Uses a Quartz API with no cross-platform equivalent; a no-op elsewhere. |
scroll_left, scroll_right |
Yes | Yes | No | Windows scroll injection ignores the horizontal delta. |
move_monitor |
Yes | Yes | Yes | Requires more than one display. |
The injection mechanism differs per platform even where behaviour matches:
CGEventPost on macOS, XTest on X11, zwlr_virtual_pointer on wlroots, libei
on KDE, and SendInput on Windows. This affects nothing user-visible except the
scroll limitation above.
Press and release a mouse button, or perform one half of that.
neru action left_click|right_click|middle_click
[--modifier <mods>] [--selection] [--bare] [--state down|up] [--toggle]
| Flag | Type | Description |
|---|---|---|
--modifier |
string | Modifiers held during the click: cmd, shift, alt, ctrl. Comma-separated. |
--state |
string | Perform one half only: down presses and holds, up releases. Without it the button is pressed and released in one action. |
--toggle |
bool | Release the button if held, press and hold it otherwise. |
--selection |
bool | See Targeting. |
--bare |
bool | See Targeting. |
--state and --toggle cannot be combined, and are accepted only by these
three click subcommands. Held buttons are released automatically when Neru
returns to idle.
Flag forms and their action names
--state and --toggle are flags, so they cannot appear inside a comma chain
or a mode --action. Each combination also has an action name, which can:
| Flag form | Action name |
|---|---|
left_click --state down |
left_mouse_down |
left_click --state up |
left_mouse_up |
left_click --toggle |
left_mouse_toggle |
right_click --state down |
right_mouse_down |
right_click --state up |
right_mouse_up |
right_click --toggle |
right_mouse_toggle |
middle_click --state down |
middle_mouse_down |
middle_click --state up |
middle_mouse_up |
middle_click --toggle |
middle_mouse_toggle |
Examples
neru action left_click
neru action left_click --modifier cmd
neru action left_click --modifier cmd,shift
neru action right_click --modifier alt
# Drags: press at the start, release at the destination
neru action left_click --state down
neru action middle_click --state down
neru action middle_click --state up
# One binding for both halves
neru action left_click --toggle
# Comma chains
neru action left_click,left_click # Double-click
neru action left_click,left_click,left_click # Triple-click
neru hints --action left_click,left_click # Same, via a mode
# Action-name equivalents
neru action right_mouse_down
neru hints --action right_mouse_downmouse_down and mouse_up are the original left-button spellings, from before
the right and middle buttons could be pressed and released separately. They
still work everywhere left_mouse_down and left_mouse_up do, including in
existing configs, and the CLI prints a deprecation warning on stderr naming the
replacement.
Use neru action left_click --state down and neru action left_click --state up.
Move the cursor to an absolute position.
neru action move_mouse [--x <px>] [--y <px>] [--center] [--window] [--selection] [--bare]
| Flag | Type | Default | Description |
|---|---|---|---|
--x |
int | 0 |
X coordinate in pixels. With --center or --window, a horizontal offset. |
--y |
int | 0 |
Y coordinate in pixels. With --center or --window, a vertical offset. |
--center |
bool | false |
Target the center of the active screen. |
--window |
bool | false |
Target the center of the focused window. |
--selection |
bool | false |
See Targeting. |
--bare |
bool | false |
See Targeting. |
Examples
neru action move_mouse --x 500 --y 300
neru action move_mouse --center
neru action move_mouse --center --x 50 --y -30
neru action move_mouse --window
neru action move_mouse --window --x -50Move the cursor by a delta.
neru action move_mouse_relative --dx <px> --dy <px>
| Flag | Type | Required | Description |
|---|---|---|---|
--dx |
int | Yes | Horizontal delta. Positive right, negative left. |
--dy |
int | Yes | Vertical delta. Positive down, negative up. |
Examples
neru action move_mouse_relative --dx 10 --dy -5Move the cursor to another display.
neru action move_monitor [--name <name>] [--previous]
Cycles to the next display by default. An active mode overlay follows the cursor to the new display.
| Flag | Type | Default | Description |
|---|---|---|---|
--name |
string | Target a display by name, e.g. "Built-in Retina Display". |
|
--previous |
bool | false |
Cycle to the previous display instead of the next. |
Examples
neru action move_monitor
neru action move_monitor --previous
neru action move_monitor --name "DELL U2720Q"Slide the active mode's selection to a neighbouring cell on the same layer.
neru action move_cell --direction left|right|up|down [--count <n>]
In recursive-grid mode the highlighted region moves at the current depth.
Movement is spatial rather than confined to the region you drilled into: when
the selection reaches the edge of its parent it crosses into the neighbouring
one, and the depth you can backtrack through follows it. Once the grid has
bottomed out (max_depth or min_size_*), the final cell moves instead.
In grid mode an open subgrid moves to the neighbouring cell. Before a subgrid is open no cell is selected, so the action does nothing.
Movement stops at the screen edge rather than wrapping. A --count that runs
past the edge applies as many steps as fit. Modes with no cell selection —
hints, scroll, idle — ignore the action.
| Flag | Type | Default | Description |
|---|---|---|---|
--direction |
string | Required. One of left, right, up, down. |
|
--count |
int | 1 |
Number of cells to move. Must be at least 1. |
This action is held-key repeatable: with
[held_repeat] enabled (it is off by default),
a hotkey bound to it slides continuously while the key is held.
Examples
neru action move_cell --direction right
neru action move_cell --direction up --count 3Bound as hotkeys, using arrow keys because letters are already taken by cell selection:
[recursive_grid.hotkeys]
"Left" = "action move_cell --direction=left"
"Right" = "action move_cell --direction=right"
"Up" = "action move_cell --direction=up"
"Down" = "action move_cell --direction=down"Scroll one step in a direction.
neru action scroll_up|scroll_down|scroll_left|scroll_right [--steps <px>] [--selection] [--bare]
| Flag | Type | Description |
|---|---|---|
--steps |
int | Scroll amount in pixels. Uses scroll.scroll_step when omitted. |
--selection |
bool | See Targeting. |
--bare |
bool | See Targeting. |
Platforms: vertical scrolling works everywhere. Horizontal scrolling
(scroll_left, scroll_right) is not implemented on Windows and has no effect
there.
Examples
neru action scroll_down
neru action scroll_down --steps 200
neru action scroll_left --steps 100Scroll by a page, or to the top or bottom.
neru action page_up|page_down|go_top|go_bottom [--selection] [--bare]
Page actions use scroll.scroll_step_half and scroll.scroll_step_full. These
subcommands take no --steps flag.
Examples
neru action page_up
neru action page_down
neru action go_top
neru action go_bottomSend keystrokes to the focused application or to Neru's mode system.
neru action feed [--mode] <key> [<key>...]
Chords use +, for example ctrl+c or Cmd+Shift+P. Use space for a
literal space key.
| Flag | Type | Default | Description |
|---|---|---|---|
--mode |
bool | false |
Route the keys through Neru's active mode instead of posting them to the OS. |
Arguments
<key> — one or more keys or chords. Accepted names:
| Group | Names |
|---|---|
| Letters | a–z |
| Numbers | 0–9 |
| Symbols | =, -, [, ], and similar |
| Named keys | space, return, escape, tab, delete |
| Navigation | left, right, up, down, pageup, home, end |
| Function | f1–f24 (f21–f24 on Linux and Windows only) |
| Modifiers | cmd, shift, alt, ctrl, LeftCmd, RightShift |
Examples
neru action feed o
neru action feed ctrl+c
neru action feed Cmd+Shift+P
neru action feed h e l l o return
neru action feed --mode o
neru action feed --mode EscapeMove the hint selection without acting on it.
neru action cycle_hint [--backward]
Valid in hints mode only.
| Flag | Type | Default | Description |
|---|---|---|---|
--backward |
bool | false |
Cycle to the previous hint instead of the next. |
Block an action chain until the current mode exits.
neru action wait_for_mode_exit [--bail]
| Flag | Type | Default | Description |
|---|---|---|---|
--bail |
bool | false |
Abort the chain with ERR_CHAIN_BAIL if the mode exits with no selection. |
Mode state control.
neru action reset
neru action backspace
reset clears the current mode's input state. backspace applies
mode-specific backspace behaviour: hints and grid input, grid subgrid, or
recursive-grid backtracking.
Cursor position and visibility.
neru action save_cursor_pos [--slot <name>]
neru action restore_cursor_pos [--slot <name>]
neru action hide_cursor
neru action show_cursor
Platforms: save_cursor_pos and restore_cursor_pos work everywhere.
hide_cursor and show_cursor are macOS only and are no-ops on Linux and
Windows.
save_cursor_pos records the cursor position; restore_cursor_pos returns it
there and consumes the record. hide_cursor and show_cursor control the
visibility of the system cursor.
Flags
| Flag | Type | Default | Description |
|---|---|---|---|
--slot |
string | default |
Named slot to save into or restore from. |
A saved position goes into a named slot. Without --slot that slot is
default, and --slot default means the same thing — the default has no
privileges the others lack.
Slots exist because one shared position is not enough once a sequence can invoke another one. A macro that saves the cursor, called from a sequence that also saved, would overwrite the caller's position; the caller's restore would then move the cursor somewhere it never asked for, with nothing to signal the collision. Give each one its own slot and they cannot interfere:
[macros]
# Safe to call from a sequence that has itself saved the cursor.
peek = [
"action save_cursor_pos --slot peek",
"action move_mouse --x 0 --y 0",
"action left_click",
"action restore_cursor_pos --slot peek",
]Slot names follow the same rule as macro names: start with a letter, then letters, digits, underscores, and dashes.
Restoring consumes the slot. A second restore of the same slot finds nothing, succeeds, and moves nothing — so a sequence that restores twice is not an error a caller has to special-case. Save again to reuse the slot.
The occupied slots are reported by neru status --json:
neru status --json | jq '.saved_cursor_slots'
{
"default": { "x": 640, "y": 400 }
}Pause between steps of a hotkey action array.
"action sleep <duration>"
There is no neru action sleep subcommand. Running it from a shell fails with
ERR_INVALID_INPUT. The name exists only inside a hotkey binding, where the
daemon executes it directly.
Arguments
<duration> — plain numbers are seconds (0.2, 1). Explicit units are ms
and s.
sleep cannot appear in a comma-separated chain; action left_click,sleep is
rejected at config validation. It must be its own entry in an action array.
Examples
[hotkeys]
"Return" = ["action left_click", "action sleep 0.5", "hints"]
"F1" = ["action left_click", "action sleep 500ms", "action right_click"]To pause inside a shell script, use the shell's own sleep.
Run several actions in order, in a single call.
neru run <step> [step...]
Each argument is one step, written exactly as it would be written in a hotkey
binding: an action (action left_click), a mode (hints --action left_click),
a shell command (exec open -a Safari), or a named sequence from the
[macros] table (macro window_click 100 70). The
daemon executes the steps in order.
This is the same executor that runs a multi-action hotkey binding, so a
sequence behaves identically whether it is written in [hotkeys], passed to
--on-exit, or run here. Reach for it from an external driver (skhd,
Hammerspoon, a shell script) that would otherwise spawn one neru process per
step and lose the sequencing rules between them.
Sequencing rules
- Steps run in order; blank steps are rejected.
- A step that asks the sequence to stop ends it. Today that is
action wait_for_mode_exit --bailafter a mode was cancelled — the command then exits withERR_CHAIN_BAIL. - A failing step is reported, and by default the remaining steps still run. The
command exits with
ERR_ACTION_FAILEDnaming the first failure. - To stop at a failure instead, end that step with
--bail-on-error, or pass--stop-on-errorto make every step in the sequence fatal. See Failure policy. - A sequence may start another sequence, up to five levels deep. Deeper nesting is refused rather than recursing.
Flags
| Flag | Type | Default | Description |
|---|---|---|---|
--stop-on-error |
bool | false |
End the sequence at the first failing step, as if every step carried --bail-on-error. |
By default a failing step is reported and the sequence carries on. That is
rarely what a workflow wants: in ["action left_click", "idle"] the mode exits
even when the click failed.
--bail-on-error marks one step as fatal. It is a sequencing directive rather
than a flag of the action, so the daemon consumes it and the step runs without
it. It must be the last thing in the step:
[hints.hotkeys]
# Exit only if the click actually landed.
"Shift+L" = ["action left_click --bail-on-error", "idle"]# Same policy for every step, without repeating the directive.
neru run --stop-on-error "action left_click" "action restore_cursor_pos"It works in any sequence — a hotkey binding, a mode's --on-exit, or neru run.
Text that merely looks like the directive is left alone, so
exec sh -c "echo --bail-on-error" still passes it through to the shell.
The policy applies to the steps of one sequence. A step that runs a nested
sequence — another run, or a macro — keeps its
own policy inside; its overall failure is then reported to the caller as that
one step failing, which an outer --stop-on-error or --bail-on-error acts on.
A stopped sequence reports which step ended it and that the later steps did not run; a tolerated failure says the opposite, so the two are distinguishable by a script.
Timeouts
The sequence runs while the caller waits, so a sequence containing sleeps or
wait_for_mode_exit can outlast the default 10-second IPC timeout. Raise it
with the global --timeout flag; the daemon holds the reply until the sequence
finishes, however long that takes.
A sequence that is not worth waiting on at all — one that ends with an interactive mode, say — is better bound to a hotkey, which is dispatched in the background with no caller attached.
Examples
# Save the cursor, pick a target, click it, then put the cursor back
neru run "action save_cursor_pos" "hints --action left_click" \
"action wait_for_mode_exit" "action restore_cursor_pos"
# Click, wait for the app to settle, then re-scan for hints
neru --timeout 30 run "action left_click" "action sleep 0.8" hints
# Stop early when the user escapes out of hints instead of selecting
neru run "hints --action left_click" "action wait_for_mode_exit --bail" \
"exec notify-send clicked"Run a named sequence from the [macros] table.
neru macro <name> [arg...]
Requires a running daemon. The daemon runs the macro exactly as it would when a
hotkey binding invokes macro <name>, so a sequence written once is available
to bindings and to external drivers alike.
Arguments fill the macro's positional placeholders ($1, $2, …), and the
count must match the highest placeholder the body uses. They are passed through
as given, so an argument containing spaces or quotes needs no quoting beyond
what the shell already does:
neru macro say_it "hello there"This is why the command exists alongside neru run "macro say_it 'hello there'",
which would work for that example but requires quoting the whole call into one
step — something no argument containing both kinds of quote survives.
Exit status
Same as neru run: ERR_INVALID_INPUT for an unknown macro or the
wrong number of arguments, ERR_CHAIN_BAIL when a step cancelled the sequence,
ERR_ACTION_FAILED when a step failed.
Timeouts
A macro containing sleeps or wait_for_mode_exit can outlast the default
10-second IPC timeout, exactly as a run can. Raise it with --timeout.
Examples
neru macro window_click
neru macro zoom_click 3
neru --timeout 30 macro click_and_settleFull option reference: CONFIGURATION.md.
Create a default configuration file.
neru config init [-f] [-c <path>]
Does not require a running daemon.
| Flag | Shorthand | Type | Default | Description |
|---|---|---|---|---|
--force |
-f |
bool | false |
Overwrite an existing file. |
--config |
-c |
string | "" |
Write to a specific path. |
Examples
neru config init
neru config init --force
neru config init -c /path/to/config.tomlCheck a config file for syntax errors and invalid values.
neru config validate [-c <path>]
Does not require a running daemon. Exits successfully when no config file is found, because Neru runs on built-in defaults in that case.
It reads the flags of the mode commands in your bindings, so a mistyped flag is
found here rather than when the key is pressed. A binding that will load and
not do everything it says — grid --search, where grid has no search — is
printed as a warning and still exits successfully:
Configuration is valid, with warnings:
hotkeys.Primary+Shift+G: grid does not accept --search
These parts of the configuration load and will not take effect.
A clickable role that this platform's accessibility vocabulary has no name for — the shape a configuration written on another machine has — is reported the same way; see Clickable roles.
See Global Hotkeys for which mistakes warn and which refuse the file.
Change a configuration value on the running daemon.
neru config set [--no-reload] <key> <value>
Requires a running daemon. Changes take effect immediately and are written to an override file so they survive restarts.
<key> is a dotted TOML path matching the config file, for example
hints.hint_characters or general.passthrough_unbounded_keys. Run
neru config dump to list every key and its current value.
| Flag | Type | Default | Description |
|---|---|---|---|
--no-reload |
bool | false |
Skip hotkey re-registration and mode exit. Use when setting interdependent fields in sequence, then run neru config reload once at the end. |
Value types
| Type | Example |
|---|---|
| string | "asdfghjkl" |
| integer | 14 |
| boolean | true |
| float | 0.5 |
| color | "#FF0000AA" or {"light":"#000","dark":"#FFF"} |
| array | "button,link" or '["button","link"]' |
Override file
The override file name is derived from the config file name: config.toml
becomes config.override.toml, my-neru.toml becomes
my-neru.override.toml.
Examples
neru config set hints.hint_characters "asdfghjkl"
neru config set hints.ui.font_size 14
neru config set general.passthrough_unbounded_keys true
neru config set hints.clickable_roles "button,link"
neru config set scroll.scroll_step 50
# Interdependent fields, applied together
neru config set --no-reload recursive_grid.grid_cols 3
neru config set --no-reload recursive_grid.keys "abcdefghijkl"
neru config reloadRemove a field from the override file.
neru config reset [--no-reload] <key>
Requires a running daemon. The field reverts to the value in the base config file, or the built-in default, on the next reload.
| Flag | Type | Default | Description |
|---|---|---|---|
--no-reload |
bool | false |
Defer reloading. Run neru config reload after the last reset. |
Examples
neru config reset recursive_grid.grid_cols
neru config reset --no-reload recursive_grid.grid_rows
neru config reset --no-reload recursive_grid.keys
neru config reload
# Remove every override at once
rm ~/.config/neru/config.override.toml
neru config reloadPrint the active configuration as JSON.
neru config dump
Requires a running daemon. Reflects the merged result of the base config, overrides, and defaults.
Examples
neru config dump | jq
neru config dump | jq '.hints'Reload the configuration from disk.
neru config reload
Requires a running daemon. Some settings, such as systray.enabled, take
effect only after a full daemon restart.
Each toggle changes daemon state for the current session only; the configured value is restored on restart.
All three toggle-* commands accept --state, which names the state to end up
in instead of flipping whatever is there:
| Value | Effect |
|---|---|
on |
Turn it on, whether or not it already was. |
off |
Turn it off, whether or not it already was. |
toggle (default) |
Flip it. Same as passing no flag. |
Flipping is the right default for a key binding, where you see the result and
press again if it went the wrong way. A script has no such feedback loop: it
cannot tell a state it set from one a stray keypress set, and a binding pressed
twice leaves the daemon somewhere the script does not expect. --state makes
these commands idempotent, and neru status --json reports every state they
change — see Reading the toggles.
--state toggle exists so a value can be passed straight through without the
caller special-casing the flip:
[macros]
scroll_invert = ["toggle-scroll-invert --state $1"]Invert the scroll direction.
neru toggle-scroll-invert [--state on|off|toggle]
Requires a running daemon. Overrides scroll.invert_scroll until restart. Also
available from the systray menu. Reported as scroll_inverted by
neru status --json.
Toggle whether the real cursor follows the selection.
neru toggle-cursor-follow-selection [--state on|off|toggle]
Requires a running daemon. Applies to the active hints, grid, or recursive_grid session.
The preference belongs to that session rather than to the daemon, so unlike the
other two toggles this one fails when no mode is running — including when
--state names the state it wants, since there is nothing yet to hold it.
Reported as cursor_follow_selection by neru status --json, and null while
no mode is running.
Hide or show overlays on shared screens.
neru toggle-screen-share [--state on|off|toggle]
Platforms: macOS only.
Requires a running daemon. Hidden overlays remain visible locally.
--state on hides the overlay and --state off shows it, matching the
hidden_for_screen_share field of neru status --json: the flag names the
state that is reported, not the visibility.
Implemented with the deprecated NSWindow.sharingType API, so effectiveness
depends on the macOS version and the screen-sharing application:
| macOS version | Behaviour |
|---|---|
| 14 and older | Reliable |
| 15.0 – 15.3 | Partially effective |
| 15.4 and newer | Limited to ScreenCaptureKit-based apps |
List the accessibility role vocabulary.
neru roles [--explain] [-c <path>]
Does not require a running daemon. Lists the semantic roles accepted by
hints.clickable_roles and neru hints --role, and shows how each resolves on
the current platform.
A role is written either as a semantic name, such as button or text_field,
which resolves to the native roles of the current platform, or as a native role
carrying a vocabulary prefix:
| Prefix | Platform | Example |
|---|---|---|
ax: |
macOS Accessibility | ax:AXDisclosureTriangle |
atspi: |
Linux AT-SPI | atspi:page tab list |
uia: |
Windows UI Automation | uia:Custom |
Prefixed entries belonging to other platforms are ignored rather than rejected, so one config file can serve several machines.
| Flag | Type | Default | Description |
|---|---|---|---|
--explain |
bool | false |
Resolve the loaded config entry by entry, showing which native roles each contributes and which entries do not apply here. |
Examples
neru roles
neru roles --explainManage Neru as a system service that starts on login.
neru services install|uninstall|start|stop|restart|status
Platforms: macOS only, using launchd. Other platforms return
ERR_NOT_SUPPORTED. When
Neru was installed through Nix, Homebrew, or another package manager, use that
tool's service manager instead.
| Subcommand | Description |
|---|---|
install |
Install and load the launchd service |
uninstall |
Unload and remove the service |
start |
Start the service |
stop |
Stop the service |
restart |
Restart the service |
status |
Report whether the service is loaded and running |
Open documentation in a browser.
neru docs config|cli
Platforms: macOS only; other platforms return ERR_NOT_SUPPORTED.
URLs point at the Git tag matching the installed version. Development builds
fall back to main.
| Subcommand | Opens |
|---|---|
config |
The configuration reference |
cli |
This CLI reference |
Neru commands are ordinary processes with conventional exit statuses, so they compose with shell scripts and external hotkey daemons.
Toggle the daemon
if [ "$(neru status --json | jq -r .enabled)" = "true" ]; then
neru stop
else
neru start
fiCheck whether the daemon is reachable
neru status &>/dev/null && echo "Running" || echo "Not running"Drive Neru from an external hotkey manager
# ~/.config/skhd/skhdrc
ctrl - f : neru hints
ctrl - g : neru grid
ctrl - r : neru hints --action right_click
ctrl - t : neru hints --action left_click --repeat
Run several steps as one unit
Chaining neru invocations with && spawns a process and opens a connection
per step. neru run sends the whole sequence once and the daemon
executes it in order, under the same rules a hotkey binding gets:
neru run "action save_cursor_pos" "hints --action left_click" \
"action wait_for_mode_exit --bail" "action restore_cursor_pos"The CLI and the daemon exchange JSON over a Unix domain socket, or a named pipe on Windows. The daemon queues incoming commands, so concurrent calls from scripts are safe.
Request
{ "action": "hints", "params": {}, "args": [] }action names either a mode command — hints, grid, recursive_grid,
scroll, monitor_select, idle — or one of the standalone commands. args
carries the same flags a user would type.
A mode command's flags are read exactly as the CLI reads them, and answered
with the same message: an unknown flag, a flag the named mode does not accept,
an unusable value, and an unmet dependency such as --on-exit without
--action are all refused with ERR_INVALID_INPUT rather than accepted and
dropped. Repeating the mode's own name as the first entry of args is accepted
and ignored, so anything modelled on the CLI's earlier traffic keeps working.
The CLI no longer sends it: the action already names the mode.
Probing without activating
hints-probe reports what hints mode would target for the focused window and
answers with a count and a sample in message. It draws nothing and enters no
mode, so it takes only the flags that decide which elements are collected:
--role, --text, --strategy, --split-word. Anything else is refused with
ERR_INVALID_INPUT. This is what neru hints --debug sends.
{ "action": "hints-probe", "args": ["--role=button", "--strategy=vision"] }Response
{ "success": true, "message": "OK", "code": "OK" }Response codes
| Code | Meaning |
|---|---|
OK |
Command succeeded |
ERR_UNKNOWN_COMMAND |
No such command |
ERR_INVALID_INPUT |
Malformed arguments or flag values |
ERR_NOT_RUNNING |
Neru is paused via neru stop |
ERR_ALREADY_RUNNING |
Target is already in the requested state |
ERR_MODE_DISABLED |
The requested mode is disabled in the configuration |
ERR_ACTION_FAILED |
The action was dispatched but did not complete |
ERR_CHAIN_BAIL |
An action chain aborted, for example --bail |
ERR_NOT_SUPPORTED |
Not implemented on this platform |
ERR_VERSION_MISMATCH |
Client and daemon builds differ; restart the daemon |
A connection error rather than a response code means no daemon is running.
Log file locations are listed in TROUBLESHOOTING.md.