Hooks.
A hook is your own command that runs automatically at a fixed moment: before Nilux runs a tool, after it edits a file, when it finishes a task. Use hooks for things that must happen every time, without relying on the model to remember. For example:
- run the code formatter after every edit;
- refuse
git pushin a project where you push by hand; - send a message to your chat when a long task is done.
Where hooks live
Hooks are written in a JSON file:
~/.nilux/hooks.json: your hooks, for every project;.nilux/hooks.jsonin a project: hooks for that project only.
Nilux notices changes to these files by itself; there is no need to restart.
A first hook
This hook stops Nilux from running git push, and tells it why:
json{"hooks": {"PreToolUse": [{"matcher": "Bash","hooks": [{"type": "command","if": "Bash(git push:*)","command": "echo 'In this project we push by hand.' >&2; exit 2"}]}]}}
PreToolUseis the moment: just before a tool runs.matcherpicks the tool: hereBash, the tool that runs commands. UseEdit|Writefor several tools, or leave it empty for all.ifnarrows it down further, here to commands that start withgit push.- The command prints a reason and ends with exit code
2, which means block. Nilux does not run the command, and the model sees your reason.
Moments you can hook into
PreToolUse: before a tool runs. It can block the call, change its arguments, or make Nilux ask you first.PostToolUseandPostToolUseFailure: after a tool has worked or failed.PermissionRequest: when Nilux is about to ask you to approve something.UserPromptSubmit: when you send a message. It can block the message or add information to it.StopandStopFailure: when Nilux finishes its turn, or the turn ends with an error.Notification: when Nilux needs your attention.SubagentStartandSubagentStop: when a helper agent starts or finishes.PreCompactandPostCompact: around shortening a conversation.SessionStartandSessionEnd: when a session begins or closes.PreModelSwitchandPostModelSwitch: around a change of model.
How a hook talks back
The hook receives the details of the moment as JSON on its standard input, for example the tool's name and arguments. A script reads it like piped text, for example with jq. The hook answers with its exit code:
0: all fine; Nilux continues.2: block. What the hook printed to standard error (>&2in a shell script) is shown as the reason.- any other code: the hook failed. You see an error, and Nilux goes on.
A hook that guards a tool call (PreToolUse, PermissionRequest) is careful by design: if it fails, times out or answers something unreadable, the call is blocked rather than let through.
For finer control, the hook can print JSON instead, for example to allow or deny with a reason, change the tool's arguments, or add a note for the model.
Three kinds of hooks
command: runs a command in your shell (on Windows, in Git Bash). The project folder is available asNILUX_PROJECT_DIR.http: sends the same JSON to a web address. If you list addresses inallowedHttpHookUrlsin your hooks file, hooks can send only to those.mcp_tool: calls a tool of one of your MCP servers.
Safety
- A hook can approve ordinary actions, but never a dangerous command or a file deletion. If one hook allows a call and another asks, you are asked.
- Hooks that come with a project do not run until you have seen them. Nilux shows you every command and web address they would use, and asks. If the file changes later, it asks again.
Check your hooks
/hooks shows both files, which hooks are loaded, and why any of them is not running. If something is wrong with a hook, the status line says so.