> For the complete documentation index, see [llms.txt](https://orbitron.gitbook.io/orbitron-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://orbitron.gitbook.io/orbitron-docs/user-guide/hooks-guide.md).

# Shell Hooks Guide

> Shell Hooks is a powerful automation system that allows you to automatically execute custom commands before and after AI tool execution. This enables various workflows such as automated testing, security validation, logging, and backups.

***

## 🎯 What are Shell Hooks?

Shell hooks are custom shell commands that automatically execute when specific events occur. In Orbitron, you can execute hooks at two different timings:

* **preToolUse**: Immediately before the AI executes a tool
* **postMessageUse**: Immediately after the AI completes a response with tool execution results

By leveraging these hooks, you can add automated validation, logging, notifications, and more to the AI's workflow.

***

## ⚡ Key Features

### 🔧 1. Two Hook Events

#### preToolUse (Before Tool Execution)

* Executes **immediately before** the AI runs a tool
* **Can block execution**: Can prevent tool execution by returning a non-zero exit code
* Useful for validation, backups, and precondition checks

Example use cases:

* Check Git commit status before code changes
* Automatic backup before file modifications
* Validate that specific conditions are met

#### postMessageUse (After Response Completion)

* Executes **after the AI completes** the full response with tool results
* Useful for post-processing, notifications, and logging

Example use cases:

* Automatically run tests after code changes
* Send work completion notifications
* Record change history logs

***

### 🎯 2. Flexible Tool Targeting

When configuring hooks, you can choose which tools they apply to:

* **Specific tools**: Apply only to specific tools like `bash`, `edit`, `read`, `write`, etc.
* **All tools**: Use `*` to apply to all tools

***

### 📊 3. Context via Environment Variables

Hook commands receive execution context information through the following environment variables.

#### Environment Variable Reference

| Variable Name          | Description                             | Available Events           | Example Value                  |
| ---------------------- | --------------------------------------- | -------------------------- | ------------------------------ |
| `ORBITRON_TOOL_NAME`   | Name of the tool being executed         | preToolUse, postMessageUse | `bash`, `edit`, `read`         |
| `ORBITRON_TOOL_INPUT`  | JSON-formatted input passed to the tool | preToolUse, postMessageUse | `{"file_path": "src/main.go"}` |
| `ORBITRON_SESSION_ID`  | Current session ID                      | preToolUse, postMessageUse | `sess_abc123`                  |
| `ORBITRON_MESSAGE_ID`  | Current message ID                      | preToolUse, postMessageUse | `msg_xyz789`                   |
| `ORBITRON_TOOL_RESULT` | Tool execution result (JSON)            | **postMessageUse only**    | `{"success": true}`            |

#### Environment Variable Usage Examples

**1. Branching by tool name:**

```bash
#!/bin/bash

case "$ORBITRON_TOOL_NAME" in
  bash)
    echo "Validating before bash command execution..."
    ;;
  edit)
    echo "Backing up before file edit..."
    ;;
  *)
    echo "Other tool: $ORBITRON_TOOL_NAME"
    ;;
esac
```

**2. Parsing JSON input:**

```bash
#!/bin/bash
# Using jq to parse JSON

FILE_PATH=$(echo "$ORBITRON_TOOL_INPUT" | jq -r '.file_path')
COMMAND=$(echo "$ORBITRON_TOOL_INPUT" | jq -r '.command')

echo "Processing file: $FILE_PATH"
echo "Executing command: $COMMAND"
```

**3. Analyzing tool results (postMessageUse):**

```bash
#!/bin/bash
# Only available in postMessageUse hooks

if [ -n "$ORBITRON_TOOL_RESULT" ]; then
  SUCCESS=$(echo "$ORBITRON_TOOL_RESULT" | jq -r '.success')

  if [ "$SUCCESS" = "true" ]; then
    echo "✅ Tool execution successful!"
  else
    echo "❌ Tool execution failed"
  fi
fi
```

**4. Using session/message IDs:**

```bash
#!/bin/bash
# Log with session information

LOG_FILE=".orbitron-audit.log"
TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')

echo "[$TIMESTAMP] Session: $ORBITRON_SESSION_ID" >> "$LOG_FILE"
echo "  Tool: $ORBITRON_TOOL_NAME" >> "$LOG_FILE"
```

***

## 🛠️ Managing Hooks

### `/hooks` Command

Enter `/hooks` in the terminal to open the hook management interface.

```
/hooks
```

### Viewing Hook List

The hook list screen displays all currently configured hooks:

* **Name**: Hook name
* **Event**: `preToolUse` or `postMessageUse`
* **Tool**: Tool(s) the hook applies to (`*` means all tools)
* **Status**: Enabled/disabled state

#### Hook List Shortcuts:

* `a`: Add new hook
* `e`: Edit selected hook
* `Enter`: Test selected hook
* `Space`: Toggle selected hook enabled/disabled
* `d`: Delete selected hook
* `ESC`: Close hook management window

***

### Adding/Editing Hooks

When adding or editing a hook, enter the following information:

1. **Name**: Name to identify the hook
2. **Event**: `preToolUse` or `postMessageUse`
3. **Tool**: Specific tool name or `*` (all tools)
4. **Command**: Shell command to execute
5. **Option Settings**:
   * **Enabled**: Whether hook is active
   * **Blocking**: Block tool execution on non-zero exit code (preToolUse only)
   * **InterpretOutput**: AI interprets output and provides summary to user
   * **UseShell**: Execute through shell (enables pipes, redirection)
   * **Args**: Arguments to pass to command (space-separated)

#### Add/Edit Hook Shortcuts:

* `↑/↓`: Navigate between fields
* `Ctrl + T`: Test hook with current settings
* `Ctrl + S`: Save hook
* `ESC`: Cancel

***

### Testing Hooks

You can test hooks before saving them:

1. Press `Ctrl + T` in the add/edit screen, or
2. Select a hook in the list and press `Enter`

During testing, sample context data is provided as environment variables, and the command's output and exit code are displayed.

***

## ⚙️ Hook Options Detailed Guide

### Blocking

Setting `Blocking=true` blocks tool execution when the Hook script exits with a non-zero exit code. **Only meaningful for preToolUse events.**

#### Blocking Behavior

When a Hook blocks tool execution:

1. **Tool execution stopped**: The tool and all subsequent tools are not executed
2. **Error message displayed**: User sees blocking message
3. **Conversation terminated**: AI doesn't receive tool results, so response is interrupted

**Message displayed to user:**

```
❌ PreToolUse hook blocked execution: {hook output content}
```

Since messages output by `echo` in the Hook script are passed directly to the user, **clearly explain why it was blocked and how to resolve it**!

#### Using with InterpretOutput

Using `Blocking=true` with `InterpretOutput=true` allows the AI to interpret Hook output and convert it to a more natural and friendly message.

**Example (without InterpretOutput):**

```
❌ PreToolUse hook blocked execution: ❌ Uncommitted changes exist!

Changed files:
 M internal/config/config.go
 M internal/llm/agent/agent.go

💡 Commit your changes and try again.
```

**Example (with InterpretOutput):**

```
You need to handle uncommitted changes before modifying code.

Currently changed files:
- internal/config/config.go
- internal/llm/agent/agent.go

Please commit your changes with git add and git commit, then try again.
```

***

### InterpretOutput

Setting `InterpretOutput=true` allows the AI to read and interpret Hook output and provide a summarized version to the user. Useful for analyzing complex logs or test results.

#### Optimization Tips

* Output in **JSON format** for more accurate AI parsing
* Structure important information with keys like `"status"`, `"summary"`, `"errors"`
* For long output, show summary section first, details later
* Write error messages in clear, actionable format

**Example:**

```bash
# Output JSON from Hook script
echo '{
  "status": "failed",
  "summary": "3 tests failed",
  "errors": ["test_login", "test_auth", "test_permissions"],
  "recommendation": "Check authentication service logs"
}'
```

***

### Args (Arguments)

Enter space-separated arguments in the `Args` field to access them as `$1`, `$2`, etc. in the script.

**Example:**

```bash
# Hook configuration
Command: ./check-env.sh
Args: API_KEY required

# check-env.sh script
ENV_NAME=$1      # "API_KEY"
REQUIREMENT=$2   # "required"

if [ -z "${!ENV_NAME}" ]; then
  echo "❌ $ENV_NAME is $REQUIREMENT but not set"
  exit 1
fi
```

#### Using Args

* Write reusable generic scripts for multiple situations
* Pass different parameters per environment (dev, staging, prod)
* Pass option flags (`--verbose`, `--strict`)
* Perform various validations with the same script

***

### UseShell

Setting `UseShell=true` executes as `sh -c "command args..."`, enabling shell features (pipes, redirection, etc.).

**UseShell=false (default):**

```bash
# Direct execution: ./script.sh arg1 arg2
Command: ./script.sh
Args: arg1 arg2
```

**UseShell=true:**

```bash
# Executable through shell
Command: echo $ORBITRON_TOOL_NAME | tee -a log.txt
```

#### When to Use UseShell?

**UseShell=true needed for:**

* Using pipes (`|`)
* Redirection (`>`, `>>`, `<`)
* Shell variable substitution (`$VAR`, `$(command)`)
* Chaining multiple commands (`&&`, `||`, `;`)

**UseShell=false sufficient for:**

* Single script execution
* Executable invocation
* Only environment variables needed (ORBITRON\_\* variables provided automatically)

***

## 💡 Usage Examples

### Example 1: Check Git Status Before Code Changes

Check if the Git working directory is clean before modifying files, and block if there are changes.

**TUI Configuration:**

* Event: `preToolUse`
* Matcher: `edit`
* Command: `git diff --quiet || (echo 'Warning: Uncommitted changes exist' && exit 1)`
* Blocking: ✅ (enabled)

**Effect**: Prevents AI from modifying files when uncommitted changes exist

***

### Example 2: Automatically Run Tests After Code Changes

Automatically run tests after AI modifies code.

**TUI Configuration:**

* Event: `postMessageUse`
* Matcher: `edit`
* Command: `npm test`
* InterpretOutput: ✅ (enabled)

**Effect**: Immediately verify changes pass tests, AI interprets and summarizes results

***

### Example 3: Log File Changes

Record all tool executions to a log file.

**TUI Configuration:**

* Event: `postMessageUse`
* Matcher: `*` (all tools)
* Command: `echo "[$(date)] Tool: $ORBITRON_TOOL_NAME" >> .orbitron-changes.log`
* UseShell: ✅ (enabled)

**Effect**: Track all AI work history

***

### Example 4: Validate Before Bash Command Execution

Proactively block dangerous Bash commands.

**TUI Configuration:**

* Event: `preToolUse`
* Matcher: `bash`
* Command: `echo $ORBITRON_TOOL_INPUT | grep -q 'rm -rf' && (echo 'Dangerous command blocked' && exit 1) || exit 0`
* Blocking: ✅ (enabled)
* UseShell: ✅ (enabled)

**Effect**: Protect system from dangerous commands

***

### Example 5: Automatic Backup Before File Modification

Automatically create backup files before modification.

**TUI Configuration:**

* Event: `preToolUse`
* Matcher: `edit`
* Command: `echo $ORBITRON_TOOL_INPUT | jq -r '.file_path' | xargs -I {} cp {} {}.backup`
* UseShell: ✅ (enabled)

**Effect**: Always preserve state before changes

***

## ⚙️ Configuration File

Hook settings are stored in different files depending on **where Orbitron is executed**:

* **Executed from home directory**: `~/.orbitron/hooks.json`
* **Executed from project directory**: `<project>/.orbitron/hooks.json`

### Storage Format

```json
{
  "preToolUse": [
    {
      "matcher": "bash",
      "hooks": [
        {
          "command": "echo 'Running pre-tool hook'",
          "blocking": true,
          "enabled": true,
          "interpretOutput": false,
          "useShell": true,
          "args": ""
        }
      ]
    }
  ],
  "postMessageUse": [
    {
      "matcher": "*",
      "hooks": [
        {
          "command": "echo 'Post message hook'",
          "blocking": false,
          "enabled": true,
          "interpretOutput": true
        }
      ]
    }
  ]
}
```

**Structure Explanation:**

* Top-level keys: `preToolUse`, `postMessageUse` (separated by event type)
* `matcher`: Tool name to apply to (e.g., `bash`, `edit`, `*`)
* `hooks`: Array of hooks applied to that tool and event

{% hint style="warning" %}
**Security Note**: When Orbitron is executed from a project directory, settings are stored in that project's `.orbitron/hooks.json`. When executed from home directory, settings are stored in `~/.orbitron/hooks.json`. Check execution location to prevent unintended command execution.
{% endhint %}

***

## 🔒 Security Considerations

1. **Review hook commands**: Hooks execute directly on your system, so only use trusted commands
2. **Check execution location**: Different hooks apply per project, so verify Orbitron execution location and the corresponding `.orbitron/hooks.json` file
3. **Use blocking feature**: Use `preToolUse` hooks to proactively block dangerous operations
4. **Test first**: Always use the test feature when adding new hooks to verify they work as expected

***

## 🔄 Real-World Workflows

### Fully Automated CI/CD Workflow

Configure an automated workflow from code changes through testing, building, and deployment.

```json
{
  "preToolUse": [
    {
      "matcher": "edit",
      "hooks": [
        {
          "command": "git diff --quiet || exit 1",
          "blocking": true,
          "enabled": true
        }
      ]
    }
  ],
  "postMessageUse": [
    {
      "matcher": "edit",
      "hooks": [
        {
          "command": "npm test",
          "blocking": false,
          "enabled": true,
          "interpretOutput": true
        },
        {
          "command": "npm run build",
          "blocking": false,
          "enabled": true,
          "interpretOutput": true
        }
      ]
    }
  ]
}
```

**Effects:**

1. Check for uncommitted changes before file modification
2. Automatically run tests after file modification
3. Automatically run build if tests pass
4. AI interprets test/build results and provides summary to user

***

### Security-Focused Workflow

Security-focused workflow that proactively blocks dangerous operations:

```json
{
  "preToolUse": [
    {
      "matcher": "bash",
      "hooks": [
        {
          "command": "echo $ORBITRON_TOOL_INPUT | jq -r '.command' | grep -qE 'rm -rf|dd if=|mkfs' && echo '⚠️ Dangerous command detected!' && exit 1 || exit 0",
          "blocking": true,
          "enabled": true,
          "useShell": true
        }
      ]
    },
    {
      "matcher": "edit",
      "hooks": [
        {
          "command": "echo $ORBITRON_TOOL_INPUT | jq -r '.file_path' | grep -qE '\\.env$|credentials' && echo '❌ Cannot directly modify environment configuration files!' && exit 1 || exit 0",
          "blocking": true,
          "enabled": true,
          "useShell": true
        }
      ]
    }
  ]
}
```

***

### Quality Assurance Workflow

Workflow that automatically validates code quality:

```json
{
  "postMessageUse": [
    {
      "matcher": "edit",
      "hooks": [
        {
          "command": "eslint $(echo $ORBITRON_TOOL_INPUT | jq -r '.file_path')",
          "blocking": false,
          "enabled": true,
          "interpretOutput": true,
          "useShell": true
        },
        {
          "command": "prettier --check $(echo $ORBITRON_TOOL_INPUT | jq -r '.file_path')",
          "blocking": false,
          "enabled": true,
          "interpretOutput": true,
          "useShell": true
        }
      ]
    }
  ]
}
```

***

## 🐛 Troubleshooting

### Hook Not Executing

**Check:**

* ✅ Hook is **Enabled** (toggle with `Space` in hook list)
* ✅ Tool name (Matcher) is correct
  * Case-sensitive: `bash` (correct) vs `Bash` (incorrect)
  * Tool list: `bash`, `edit`, `read`, `write`, `grep`, `glob`, etc.
* ✅ Event type is correct (`preToolUse` vs `postMessageUse`)

**Test method:**

```bash
# 1. Select hook in hook list and press 'Enter' key
# 2. Check exit code and output in test results
# 3. Try running script directly in terminal
./your-hook-script.sh
echo $?  # Check exit code (0 means success)
```

***

### Hook Not Blocking Tool Execution

**Check:**

* ✅ `Blocking=true` is set
* ✅ It's a `preToolUse` event (blocking not available in postMessageUse)
* ✅ Script returns non-zero exit code

**Example (correct blocking script):**

```bash
#!/bin/bash
# check-git.sh

if ! git diff --quiet; then
  echo "❌ Uncommitted changes exist!"
  exit 1  # Must exit with non-zero value to block
fi

exit 0  # Normal exit
```

**Test:**

```bash
./check-git.sh
echo $?  # Should output 1 to block (0 won't block)
```

***

### Environment Variables Empty

**Check:**

* ✅ Environment variable name is correct (`ORBITRON_` prefix required)
* ✅ Shell syntax is correct
  * Correct: `$ORBITRON_TOOL_NAME`
  * Incorrect: `$TOOL_NAME`, `${TOOL_NAME}`
* ✅ Using `ORBITRON_TOOL_RESULT` in `postMessageUse`

**Environment variable test script:**

```bash
#!/bin/bash
# test-env.sh

echo "=== Orbitron Environment Variable Test ==="
echo "Tool Name: $ORBITRON_TOOL_NAME"
echo "Tool Input: $ORBITRON_TOOL_INPUT"
echo "Session ID: $ORBITRON_SESSION_ID"
echo "Message ID: $ORBITRON_MESSAGE_ID"

# Only available in postMessageUse
if [ -n "$ORBITRON_TOOL_RESULT" ]; then
  echo "Tool Result: $ORBITRON_TOOL_RESULT"
fi
```

***

### UseShell Enabled But Pipes Not Working

**Check:**

* ✅ `UseShell=true` is set
* ✅ Pipe syntax is correct
* ✅ Intermediate commands work properly

**Debugging method:**

```bash
# 1. Test each step individually
echo $ORBITRON_TOOL_INPUT  # Check input
echo $ORBITRON_TOOL_INPUT | jq .  # Check JSON parsing
echo $ORBITRON_TOOL_INPUT | jq -r '.file_path'  # Check final result

# 2. Run full command directly in terminal
ORBITRON_TOOL_INPUT='{"file_path": "test.js"}' bash -c 'echo $ORBITRON_TOOL_INPUT | jq -r ".file_path"'
```

***

### Hook Testing Method

You can safely test Hooks in Orbitron TUI:

1. Enter Hooks management screen with `/hooks` command
2. Select Hook to test with arrow keys
3. Press `Enter` key (Test)
4. Check output, exit code, and execution time in test results screen

**Test mode features:**

* Executes Hook with sample data (actual tool not executed)
* Environment variables automatically set with sample values
* Safely verify script behavior

***

### Hooks Not Applying to MCP Tools

**Current limitation:**

* Hooks only apply to Orbitron's built-in tools
* MCP (Model Context Protocol) tools currently not supported
* Built-in tools: `bash`, `edit`, `read`, `write`, `grep`, `glob`, etc.

**Alternatives:**

* Post-process with `postMessageUse` + `*` Hook after MCP tool execution
* Indirectly execute MCP functionality through Bash tool

***

## 📚 Related Documentation

* [Command & Shortcut Guide](/orbitron-docs/user-guide/slash-commands-shortcut.md)
* [Bash Mode Guide](/orbitron-docs/user-guide/bash-mode-guide.md)
* [MCP Integration](/orbitron-docs/user-guide/mcp-integration.md)
