github y3owk1n/neru v1.58.0

4 hours ago

1.58.0 (2026-10-12)

This release opens Neru up to other tools. A config can now react to what Neru does through [hooks], and a status bar or script can follow it with neru watch, ask it what it sees with neru query, and talk to it over a versioned IPC protocol or the new Go client. Config files get an editor schema and warnings for unknown keys. On macOS, a leak that grew memory by about 4 GB a day is fixed, and Mission Control and Stage Manager get hints again.

Migration Guide

Warning

Every valid config still loads, but eight behaviours change.

A disabled mode now fails instead of reporting success.
With [grid] enabled = false, neru grid used to exit 0 and do nothing. It now exits 1 with ERR_MODE_DISABLED. A neru run step or hotkey array that names a disabled mode is reported as a failed step. This covers hints, grid, recursive_grid, bisect and monitor_select.

neru services stop keeps the service stopped, across logins, until neru services start.
On macOS, launchd used to restart Neru seconds after a stop. restart on a stopped service now exits non-zero and asks you to run start. On Linux and Windows, start, stop and restart refuse a unit or task that Neru did not write, such as one from nix or home-manager.

neru hints --debug is removed.
Use neru query hints, which lists every element instead of a sample of ten. The hints-probe IPC action is replaced by query-hints.

--on-exit with --repeat is refused.
The steps never ran, since a repeating mode only closes on cancel. A binding that writes both now enters no mode, and neru config validate warns about it. Drop --on-exit from the binding.

neru config dump uses the key names from config.toml.
recursiveGrid is now recursive_grid, hotkeys.bindings is now a flat hotkeys table, and so on. The same applies to the IPC config reply.

exec cmd & no longer blocks the sequence.
A step ends when the shell exits, even if it left a process running. To wait for a command, run it without &.

neru config set no longer splits a list of steps at commas.
Pass a TOML array instead, such as '["exec echo a,b", "idle"]'.

toggle-screen-share fails with ERR_NOT_SUPPORTED on Linux and Windows.
It used to report the overlay as hidden while nothing hid it. Nothing changes on macOS.

Note

hints.on_mission_control_activated and hints.on_mission_control_deactivated are deprecated and removed in v2. Move each value to the same key under [hooks].


Hooks

  • [hooks] runs steps when something happens in Neru. Each key takes a step or an array of steps, like a binding. Hooks run apart from key handling, so a slow hook never delays a mode, and a hook never retriggers itself from its own steps
Key Runs when exec steps also see
on_mode_enter, on_mode_exit A mode opens or closes NERU_MODE, and on exit NERU_REASON and NERU_ACTION
on_select A step sets the target, such as a hint label, a grid cell or a recursive grid level NERU_MODE, NERU_X, NERU_Y, NERU_ACTION
on_app_focus Another app comes to the front NERU_BUNDLE_ID
on_enable, on_disable Neru resumes or pauses
on_config_reload A reload finishes NERU_OK
on_ready, on_quit The daemon starts or shuts down. on_quit runs exec steps only
on_scroll_invert, on_screen_share_hide The toggle switches. Screen share is macOS only NERU_ON
on_cursor_save, on_cursor_restore A cursor slot is saved or restored NERU_SLOT, and on save NERU_X, NERU_Y
on_sticky_modifiers A sticky modifier is armed or released NERU_MODIFIERS
on_monitor_move, on_screen_change Neru moves to another display, or the displays change NERU_MONITOR on move
on_mission_control_activated, on_mission_control_deactivated Mission Control opens or closes (macOS)

Every exec step also sees NERU_EVENT.

[hooks]
on_mode_enter = "exec sketchybar --trigger neru_mode MODE=\"$NERU_MODE\""
on_mode_exit  = "exec sketchybar --trigger neru_mode MODE=idle"

neru watch

  • neru watch streams Neru's status and events as JSON lines. The first line is a snapshot of neru status --json, and each event after it carries the same names and values hooks see. A slow reader is told how many events it missed, and the daemon never waits on it
  • --event streams only the events you name, such as neru watch --event mode_enter,mode_exit
  • neru status --json gains sticky_modifiers
{"seq":0,"event":"snapshot","status":{"enabled":true,"mode":"idle"}}
{"seq":1,"event":"mode_enter","mode":"hints"}
{"seq":2,"event":"select","mode":"hints","action":"left_click","x":1721,"y":439}

neru query

  • neru query reports what the daemon sees right now. displays, cursor, window, app and hints, each with --json. Positions use the coordinates neru action move_mouse takes, and query app prints the exact bundle_id per-app config matches
  • query hints reports each element's hint label, the one neru hints with the same flags would draw
  • neru hints --targets labels targets another tool supplies, for canvas apps, games or remote desktops that accessibility and vision miss. It takes the JSON query hints --json prints, or - for stdin
neru query hints --json | jq '.hints |= map(select(.width > 20))' \
  | neru hints --targets - --action left_click

Modes

  • move_mouse works as a mode --action. It leaves the cursor on the selection and presses nothing, so hints --action move_mouse --on-exit scroll picks a hint and opens scroll mode there
  • --on-exit steps see the selection. exec steps get NERU_X, NERU_Y, NERU_MODE and NERU_ACTION

Config

  • A JSON Schema for config.toml gives editors completion and error checking. New configs from neru config init start with a #:schema line. To use it in an existing config, add the line from the configuration reference at the top
  • neru config validate warns about keys Neru does not read, such as a misspelled hints.enabeld. The file still loads

IPC and integrations

  • The IPC protocol is versioned. Every reply carries "protocol": 1, and the number rises only on a breaking change at a major release. The IPC reference now lists every command
  • A JSON Schema covers IPC replies and watch lines, so a client can generate its types
  • github.com/y3owk1n/neru/client is an importable Go client with typed replies for status, the queries and watch
  • --json on neru doctor, neru roles and neru services status

Fixes

  • exec steps no longer hold a background command's output in memory. A long-running exec cmd & used to grow the daemon without limit, and a hook stuck on one never fired again
  • config set, config reset and config dump honour --timeout
  • Man pages show the installed version instead of Neru dev

macOS

  • Memory no longer grows while Neru runs. Drawing and capture calls leaked on every use, worst while the cursor was hidden, at about 50 KB a second
  • Mission Control is detected again. Its hooks run, and with include_dock_hints on, hints cover the current desktop's windows, the Dock and the expanded Spaces bar
  • The Stage Manager strip gets hints again with include_stage_manager_hints on
  • Quitting with monitor_select open no longer crashes the daemon

Linux

Note

Linux implementations are mainly contributor driven, feel free to help improving it!

  • The X11 overlay no longer piles up unread redraw events on every hint, grid or indicator show
  • Fixed leaks after a Wayland reconnect, monitor unplug or failed buffer allocation, finished processes left behind by the tray, and keys seen twice after a keyboard replug when the overlay is the input path

Features

  • add [hooks] for mode, focus, pause and reload events (#1746) (c8d576e)
  • add hooks and watch events for toggles, cursor slots, displays and lifecycle (#1753) (1f449f6)
  • cli: add --json to doctor, roles and services status (#1767) (27d4811)
  • cli: add neru watch to stream status and events (#1750) (3f3a6f5)
  • cli: add neru query for displays, cursor, window, app and hints (#1759) (de39c65)
  • config: implement json schema for toml config (#1763) (b02041b)
  • config: print config dump under the key names config.toml uses (#1766) (26010dd)
  • config: warn about keys that neru doesnt know (#1764) (923c4ed)
  • hints: allow external tools supply the targets hints mode labels (#1770) (8514f5c)
  • hints: report each element's hint label in query hints (#1769) (e59dee4)
  • hooks: add the select event and on_select hook (#1760) (5f52713)
  • ipc: add an importable go client package (#1768) (97a79a7)
  • ipc: add protocol version on ipc (#1761) (5a9468d)
  • ipc: allow filtered watch stream (#1771) (ff4e848)
  • ipc: publish a json schema for ipc replies and watch lines (#1765) (76526d9)
  • modes: accept move_mouse as mode --action (#1748) (e2d67d9)
  • modes: pass the selection to --on-exit steps via vars (#1762) (521355a)

Bug Fixes

  • build: stamp the man pages with the release version (#1757) (94ffda3)
  • cli: make neru services stop keep the service stopped (#1755) (592240e)
  • darwin: detect mission control and it's hints properly (#1745) (6adbb9d)
  • darwin: hint Stage Manager's strip (#1747) (b93858d)
  • darwin: more autoreleasepool that are missing (#1776) (35d94ad)
  • darwin: stop the daemon crashing on quit with monitor_select open (#1754) (baa0ab8)
  • ensure config set, health, toggle-screen-share and the config timeouts behave consistently (#1773) (b793e7a)
  • ipc: refuse a disabled mode (#1737) (8db242b)
  • linux: stop native leaks in the overlay, keymap and accessibility paths (#1778) (fca5ec1)
  • modes: refuse --on-exit with --repeat (#1758) (53d7f68)
  • modes: report a mode switch that fails to open as a canceled exit (#1780) (7652a39)
  • stop exec steps from waiting on and holding output of background commands (#1777) (74c7458)

Don't miss a new neru release

NewReleases is sending notifications on new releases.