How to Configure DeepSeek Reasonix Hooks: PreToolUse, PostToolUse, PermissionRequest, and Stop
DeepSeek Reasonix provides 14 static hook events—including PreToolUse, PostToolUse, PermissionRequest, and Stop—that you configure exclusively in settings.json files at either the project level (.reasonix/settings.json) or global level (~/.reasonix/settings.json).
The esengine/DeepSeek-Reasonix repository implements a deterministic hook system that allows you to execute shell commands at strategic points during agent execution. These hooks are defined as string constants in internal/hook/hook.go and provide granular control over tool invocation, session lifecycle, and permission management through JSON-based configuration.
Available Hook Events in DeepSeek Reasonix
According to the source code in [internal/hook/hook.go](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/hook/hook.go) (lines 43-65), Reasonix exposes exactly 14 static hook events that cannot be extended at runtime:
| Hook Event | Description | Blocking |
|---|---|---|
| PreToolUse | Executes before a tool (e.g., bash, read_file) is invoked. |
Yes |
| PostToolUse | Executes after a tool completes successfully. | No |
| PostToolUseFailure | Executes after a tool exits with a non-zero status. | No |
| PermissionRequest | Used by the built-in permission system; behaves like PreToolUse. |
Yes |
| UserPromptSubmit | Fires when the user submits a prompt; can block with exit code 2. |
Yes |
| Stop | Invoked when a session is stopped (e.g., user abort). | No |
| StopFailure | Fires if a stop operation fails. | No |
| PostLLMCall | Executes after the LLM returns a response. | No |
| SessionStart | At the very beginning of a new session. | No |
| SessionEnd | When a session ends normally. | No |
| SubagentStop | When a sub-agent is terminated. | No |
| Notification | Generic notification hook for external events. | No |
| PreCompact | Before the conversation is compacted (e.g., for token-saving). | No |
Blocking hooks (PreToolUse, PermissionRequest, UserPromptSubmit) can cancel the associated operation by returning exit code 2, while non-blocking hooks execute asynchronously without interrupting the workflow.
Configuring Hooks in settings.json
Reasonix reads hook definitions exclusively from JSON files named settings.json. The loader consults two locations in order of precedence, as implemented in [internal/config/paths.go](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/config/paths.go):
- Project-level:
<workspace>/.reasonix/settings.json(loaded only when the workspace is trusted) - Global-level:
<reasonix-home>/settings.json(always loaded)
The default Reasonix home directory is ~/.reasonix/ on Linux/macOS and %APPDATA%\reasonix\ on Windows. Project settings override global settings for the same event.
Configuration Schema
Each settings.json follows this structure:
{
"hooks": {
"<EventName>": [
{
"match": "<ToolMatcher>",
"command": "<ShellCommand>",
"if": "<ConditionalExpr>",
"payloadFormat": "claude"
}
]
}
}
match: Optional tool name filter (e.g.,"bash","write_file", or"*"for all tools)command: Required shell command to executeif: Optional boolean expression for conditional execution (e.g.,Bash(rm *))payloadFormat: Optional; set to"claude"for Claude-compatible plugin output
Hook Exit Codes and Behavior
When a hook executes, Reasonix interprets the exit code to determine flow control, as defined in the hook execution logic:
| Exit Code | Effect |
|---|---|
0 |
Success - processing continues normally |
1 |
Non-blocking warning - emits a message but continues |
2 |
Block - cancels the tool call (blocking events only) |
| Other | Treated as warning (unless the hook is a failure hook) |
For blocking events, exit code 2 immediately cancels the operation. Additionally, if a hook outputs JSON containing a hookSpecificOutput object on stdout, Reasonix can consume structured data such as permissionDecision to surface detailed blocking reasons to the user.
Practical Configuration Examples
Blocking Dangerous Commands with PreToolUse
This example prevents any bash tool invocation that attempts to delete files:
{
"hooks": {
"PreToolUse": [
{
"match": "bash",
"command": "if [[ $REASONIX_TOOL_ARGS == rm* ]]; then echo 'Deletion blocked'; exit 2; fi",
"if": "Bash(rm *)"
}
]
}
}
Save this to .reasonix/settings.json in your project root or the global settings location.
Logging Tool Usage with PostToolUse
Capture completion events for audit trails:
{
"hooks": {
"PostToolUse": [
{
"command": "echo \"[$(date)] Tool $REASONIX_TOOL_NAME completed\" >> $HOME/reasonix-audit.log"
}
]
}
}
Implementing PermissionRequest Guards
Require interactive confirmation before allowing write_file operations:
{
"hooks": {
"PermissionRequest": [
{
"match": "write_file",
"command": "read -p 'Allow write_file? (y/N) ' ans; [[ $ans == [Yy]* ]] && exit 0 || exit 2"
}
]
}
}
Cleaning Up with Stop Hooks
Automatically remove temporary files when a session ends:
{
"hooks": {
"Stop": [
{
"command": "rm -rf /tmp/reasonix-session-*"
}
]
}
}
Claude-Compatible Payload Format
For integrations requiring structured output, specify payloadFormat and return JSON:
{
"hooks": {
"PreToolUse": [
{
"match": "bash",
"command": "/usr/local/bin/guard-script.sh",
"payloadFormat": "claude"
}
]
}
}
The script /usr/local/bin/guard-script.sh should output:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "unsafe operation detected"
}
}
See [internal/hook/hook_test.go](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/hook/hook_test.go) for additional examples of JSON schema validation and payload handling.
Key Source Files
Understanding these hooks requires familiarity with the following implementation files:
internal/hook/hook.go: Defines the 14 static hook events and the blocking logic that interprets exit code2internal/hook/hook_test.go: Comprehensive test suite demonstrating JSON schema validation, tool matching, and Claude payload format handlinginternal/config/paths.go: CalculatesGlobalSettingsPathandProjectSettingsPathfor the settings loaderdocs/DESKTOP_HOOKS.md: User-facing documentation explaining the desktop UI configuration interface and the relationship between global and project settings
Summary
- 14 static hooks: Reasonix defines a fixed set of hook events in
internal/hook/hook.goincludingPreToolUse,PostToolUse,PermissionRequest, andStopthat cannot be modified at runtime - JSON-only configuration: Hooks are configured exclusively in
settings.jsonfiles located at either<workspace>/.reasonix/settings.json(project) or<reasonix-home>/settings.json(global) - Blocking capability: Only
PreToolUse,PermissionRequest, andUserPromptSubmitsupport blocking via exit code2to cancel operations - Conditional matching: Use the
matchfield to filter by tool name and theiffield for conditional expression filtering - Structured output: Set
payloadFormatto"claude"and outputhookSpecificOutputJSON for advanced permission decisions and plugin integrations
Frequently Asked Questions
What is the difference between PreToolUse and PermissionRequest?
PreToolUse is a general-purpose hook that fires before any tool invocation and can be used for logging, validation, or blocking. PermissionRequest is specifically designed for the built-in permission system and behaves identically to PreToolUse in terms of blocking capabilities (exit code 2 cancels the operation), but is semantically reserved for user-consent workflows. According to the source code in internal/hook/hook.go, both are blocking events, but PermissionRequest is typically used in conjunction with the desktop UI's permission settings.
Can I create custom hook events in Reasonix?
No. The hook system in esengine/DeepSeek-Reasonix uses a static enumeration defined in internal/hook/hook.go (lines 43-65). You cannot define custom hook events at runtime or through configuration. You must use one of the 14 predefined events: PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, UserPromptSubmit, Stop, StopFailure, PostLLMCall, SessionStart, SessionEnd, SubagentStop, Notification, or PreCompact.
How do I block a tool call based on user input?
Configure a PreToolUse hook in settings.json that exits with code 2 when your condition is met. For example, create a script that checks $REASONIX_TOOL_ARGS for dangerous patterns and returns exit 2 to block execution. For interactive confirmation, use a PermissionRequest hook with a shell command that prompts the user and returns exit 2 if they decline. The blocking logic is handled in the hook executor defined in the internal hook package.
Where does Reasonix store the global settings.json file?
The global settings.json is stored in the Reasonix home directory, which defaults to ~/.reasonix/settings.json on Linux and macOS, and %APPDATA%\reasonix\settings.json on Windows. This path is calculated by the configuration loader in internal/config/paths.go. You can verify the exact location by checking the GlobalSettingsPath variable or consulting the reasonix.example.toml file in the repository root for configuration examples.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →