# How to Configure DeepSeek Reasonix Hooks: PreToolUse, PostToolUse, PermissionRequest, and Stop

> Learn how to configure DeepSeek Reasonix hooks like PreToolUse, PostToolUse, PermissionRequest, and Stop within your settings.json file for advanced control. Optimize your workflow now.

- Repository: [YHH/DeepSeek-Reasonix](https://github.com/esengine/DeepSeek-Reasonix)
- Tags: how-to-guide
- Published: 2026-08-06

---

**DeepSeek Reasonix provides 14 static hook events—including PreToolUse, PostToolUse, PermissionRequest, and Stop—that you configure exclusively in [`settings.json`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/settings.json) files at either the project level ([`.reasonix/settings.json`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/.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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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/internal/config/paths.go)](https://github.com/esengine/DeepSeek-Reasonix/blob/main-v2/internal/config/paths.go):

1. **Project-level**: `<workspace>/.reasonix/settings.json` (loaded only when the workspace is trusted)
2. **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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/settings.json) follows this structure:

```json
{
  "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 execute
- **`if`**: 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:

```json
{
  "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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/.reasonix/settings.json) in your project root or the global settings location.

### Logging Tool Usage with PostToolUse

Capture completion events for audit trails:

```json
{
  "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:

```json
{
  "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:

```json
{
  "hooks": {
    "Stop": [
      {
        "command": "rm -rf /tmp/reasonix-session-*"
      }
    ]
  }
}

```

### Claude-Compatible Payload Format

For integrations requiring structured output, specify `payloadFormat` and return JSON:

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "match": "bash",
        "command": "/usr/local/bin/guard-script.sh",
        "payloadFormat": "claude"
      }
    ]
  }
}

```

The script [`/usr/local/bin/guard-script.sh`](https://github.com/esengine/DeepSeek-Reasonix/blob/main//usr/local/bin/guard-script.sh) should output:

```json
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "unsafe operation detected"
  }
}

```

See [[`internal/hook/hook_test.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/hook/hook.go)**: Defines the 14 static hook events and the blocking logic that interprets exit code `2`
- **[`internal/hook/hook_test.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/hook/hook_test.go)**: Comprehensive test suite demonstrating JSON schema validation, tool matching, and Claude payload format handling
- **[`internal/config/paths.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/config/paths.go)**: Calculates `GlobalSettingsPath` and `ProjectSettingsPath` for the settings loader
- **[`docs/DESKTOP_HOOKS.md`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/docs/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.go`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/hook/hook.go) including `PreToolUse`, `PostToolUse`, `PermissionRequest`, and `Stop` that cannot be modified at runtime
- **JSON-only configuration**: Hooks are configured exclusively in [`settings.json`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/settings.json) files located at either `<workspace>/.reasonix/settings.json` (project) or `<reasonix-home>/settings.json` (global)
- **Blocking capability**: Only `PreToolUse`, `PermissionRequest`, and `UserPromptSubmit` support blocking via exit code `2` to cancel operations
- **Conditional matching**: Use the `match` field to filter by tool name and the `if` field for conditional expression filtering
- **Structured output**: Set `payloadFormat` to `"claude"` and output `hookSpecificOutput` JSON 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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/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`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/internal/config/paths.go). You can verify the exact location by checking the `GlobalSettingsPath` variable or consulting the [`reasonix.example.toml`](https://github.com/esengine/DeepSeek-Reasonix/blob/main/reasonix.example.toml) file in the repository root for configuration examples.