---
title: "Hooks Reference"
source: https://docs.autohand.ai/working-with-autohand-code/hooks
---

# Hooks Reference

Hooks let you run custom scripts in response to agent events. Use them to enforce coding standards, run tests automatically, notify your team, or integrate with external tools.

## Overview

Hooks are shell commands that execute at specific points during agent operation. They enable automation without modifying agent behavior directly.

Common use cases:

-   Run linters after file changes
-   Execute tests after code modifications
-   Send notifications on task completion
-   Validate changes against team policies
-   Log agent actions for audit trails
-   Integrate with CI/CD pipelines

**View hooks:** Use `/hooks` during a session to see currently configured hooks.

## Configuration

Hooks are configured in your `~/.autohand/config.json` or project-level `.autohand/config.json`.

### Basic structure

``` json
{
  "hooks": {
    "on_file_change": [
      "npm run lint --fix {{file}}"
    ],
    "after_tool_call": [
      "echo 'Tool {{tool}} completed'"
    ],
    "on_session_end": [
      "./scripts/notify-slack.sh"
    ]
  }
}
```

### Hook format

Each hook is an array of shell commands. Commands run in order, and execution stops if any command fails (non-zero exit code).

``` json
{
  "hooks": {
    "event_name": [
      "command1",
      "command2",
      "command3"
    ]
  }
}
```

## Hook events

Autohand supports hooks for these lifecycle events:

### Session events

| Event | Trigger | Variables |
|---|---|---|
| on_session_start | Session begins | {{session_id}}, {{project}} |
| on_session_end | Session ends | {{session_id}}, {{duration}} |
| on_session_resume | Session resumed | {{session_id}} |

### Tool events

| Event | Trigger | Variables |
|---|---|---|
| before_tool_call | Before any tool executes | {{tool}}, {{args}} |
| after_tool_call | After any tool completes | {{tool}}, {{result}}, {{duration}} |
| on_tool_error | Tool execution fails | {{tool}}, {{error}} |

### File events

| Event | Trigger | Variables |
|---|---|---|
| on_file_change | File is modified | {{file}}, {{action}} |
| on_file_create | New file created | {{file}} |
| on_file_delete | File deleted | {{file}} |
| on_file_read | File is read | {{file}} |

### Command events

| Event | Trigger | Variables |
|---|---|---|
| before_command | Before shell command runs | {{command}}, {{cwd}} |
| after_command | After shell command completes | {{command}}, {{exit_code}}, {{output}} |

### Message events

| Event | Trigger | Variables |
|---|---|---|
| on_user_message | User sends a message | {{message}} |
| on_agent_response | Agent responds | {{response}}, {{tokens}} |

### Error events

| Event | Trigger | Variables |
|---|---|---|
| on_error | Any error occurs | {{error}}, {{context}} |
| on_permission_denied | Action blocked by permissions | {{action}}, {{resource}} |

### Auto-mode events

| Event | Trigger | Variables |
|---|---|---|
| on_automode_start | Auto-mode loop begins | {{task}}, {{max_iterations}} |
| on_automode_stop | Auto-mode loop ends | {{task}}, {{iterations}}, {{reason}} |
| on_automode_iteration | Each loop iteration completes | {{iteration}}, {{total}} |

### Sub-agent events

| Event | Trigger | Variables |
|---|---|---|
| on_subagent_start | Sub-agent task begins | {{agent}}, {{task}} |
| on_subagent_stop | Sub-agent task completes | {{agent}}, {{task}}, {{duration}} |

### Notification events

| Event | Trigger | Variables |
|---|---|---|
| on_permission_request | Agent requests permission for an action | {{tool}}, {{action}} |
| on_notification | System notification is generated | {{message}}, {{level}} |

## Template variables

Use double curly braces to include event data in your commands:

``` json
{
  "hooks": {
    "on_file_change": [
      "eslint {{file}} --fix",
      "prettier --write {{file}}"
    ]
  }
}
```

### Available variables

| Variable | Description | Example |
|---|---|---|
| {{file}} | File path | src/utils/auth.ts |
| {{tool}} | Tool name | write_file |
| {{command}} | Shell command | npm test |
| {{session_id}} | Current session ID | abc123 |
| {{project}} | Project directory | /home/user/myapp |
| {{timestamp}} | ISO timestamp | 2026-01-16T10:30:00Z |
| {{duration}} | Execution time (ms) | 1234 |
| {{exit_code}} | Command exit code | 0 |
| {{error}} | Error message | File not found |

### Environment variables

Standard environment variables are available in hook commands:

``` json
{
  "hooks": {
    "on_session_end": [
      "curl -X POST $SLACK_WEBHOOK -d '{\"text\": \"Session complete\"}'"
    ]
  }
}
```

## Examples

### Auto-lint on file changes

Run ESLint and Prettier whenever the agent modifies a file:

``` json
{
  "hooks": {
    "on_file_change": [
      "if [[ {{file}} == *.ts || {{file}} == *.tsx ]]; then eslint {{file}} --fix; fi",
      "prettier --write {{file}}"
    ]
  }
}
```

### Run tests after changes

Execute related tests when files change:

``` json
{
  "hooks": {
    "on_file_change": [
      "npm test -- --findRelatedTests {{file}}"
    ]
  }
}
```

### Slack notifications

Send a message when a session ends:

``` json
{
  "hooks": {
    "on_session_end": [
      "curl -X POST $SLACK_WEBHOOK -H 'Content-type: application/json' -d '{\"text\": \"Autohand session completed in {{duration}}ms\"}'"
    ]
  }
}
```

### Audit logging

Log all tool calls for compliance:

``` json
{
  "hooks": {
    "after_tool_call": [
      "echo '{{timestamp}} | {{tool}} | {{duration}}ms' >> ~/.autohand/audit.log"
    ]
  }
}
```

### Block dangerous commands

Prevent certain commands from executing:

``` json
{
  "hooks": {
    "before_command": [
      "if [[ '{{command}}' == *'rm -rf'* ]]; then echo 'Blocked dangerous command' && exit 1; fi"
    ]
  }
}
```

### Type checking on TypeScript files

Run type checker when TypeScript files change:

``` json
{
  "hooks": {
    "on_file_change": [
      "if [[ {{file}} == *.ts || {{file}} == *.tsx ]]; then npx tsc --noEmit; fi"
    ]
  }
}
```

### Git pre-commit style check

Validate code style before committing:

``` json
{
  "hooks": {
    "before_command": [
      "if [[ '{{command}}' == 'git commit'* ]]; then npm run lint && npm run typecheck; fi"
    ]
  }
}
```

## Advanced configuration

### Conditional hooks

Use shell conditionals to run hooks selectively:

``` json
{
  "hooks": {
    "on_file_change": [
      "case {{file}} in *.test.ts) npm test {{file}};; *.ts) eslint {{file}};; esac"
    ]
  }
}
```

### External scripts

For complex logic, use external scripts:

``` json
{
  "hooks": {
    "on_file_change": [
      "./scripts/on-change.sh {{file}}"
    ],
    "on_session_end": [
      "./scripts/session-complete.sh {{session_id}} {{duration}}"
    ]
  }
}
```

### Timeout configuration

Set timeouts for long-running hooks:

``` json
{
  "hooks": {
    "on_file_change": [
      {
        "command": "npm test -- --findRelatedTests {{file}}",
        "timeout": 30000
      }
    ]
  }
}
```

### Async hooks

Run hooks in the background without blocking:

``` json
{
  "hooks": {
    "on_file_change": [
      {
        "command": "npm run build",
        "async": true
      }
    ]
  }
}
```

## Debugging hooks

### View configured hooks

Use the `/hooks` command to see all configured hooks:

``` bash
/hooks

# Output:
# on_file_change:
#   - eslint {{file}} --fix
#   - prettier --write {{file}}
# on_session_end:
#   - ./scripts/notify.sh
```

### Enable debug logging

Set `AUTOHAND_DEBUG=true` to see hook execution details:

``` bash
AUTOHAND_DEBUG=true autohand

# Shows:
# [hook] on_file_change triggered for src/auth.ts
# [hook] Running: eslint src/auth.ts --fix
# [hook] Completed in 234ms (exit code: 0)
```

### Test hooks manually

Test your hook commands outside of Autohand first:

``` bash
# Replace variables manually to test
eslint src/auth.ts --fix
prettier --write src/auth.ts
```

### Common issues

| Issue | Solution |
|---|---|
| Hook not running | Check event name spelling and JSON syntax |
| Command not found | Use full paths or ensure command is in PATH |
| Variables not expanding | Use {{variable}} not $variable |
| Hook blocking agent | Use async: true for slow commands |
| Permission denied | Make scripts executable with chmod +x |

## Best practices

### Keep hooks fast

Hooks run synchronously by default. Slow hooks create a poor user experience. For long-running tasks, use `async: true`.

### Handle failures gracefully

If a hook fails, subsequent hooks won't run. Design hooks to be resilient:

``` json
{
  "hooks": {
    "on_file_change": [
      "eslint {{file}} --fix || true"
    ]
  }
}
```

### Use project-level config

Put team hooks in `.autohand/config.json` and commit to version control so everyone gets the same behavior.

### Document your hooks

Add comments in your AGENTS.md explaining what hooks do and why:

``` markdown
# AGENTS.md

## Hooks
The following hooks are configured:
- **on_file_change**: Auto-formats code with Prettier and ESLint
- **on_session_end**: Posts summary to #dev-updates Slack channel
```

## Frequently asked questions

### What are hooks in Autohand CLI?

Hooks are shell scripts that run automatically in response to specific agent events. They let you automate workflows like running linters after file changes, sending Slack notifications on commits, or blocking dangerous commands. Hooks are configured in ~/.autohand/config.json or .autohand/config.json at the project level.

### What events can trigger hooks in Autohand?

Autohand supports over 20 hook events grouped into categories: session events (session-start, session-end), tool events (pre-tool, post-tool), file events (file-modified), command events (pre-clear, pre-prompt), auto-mode events (automode:start, automode:checkpoint, automode:complete), and team events (teammate-spawned, task-completed).

### How do I create a hook in Autohand?

Add a hook entry to the hooks object in your config.json file. Each hook has an event name and a command to run. Template variables like {{file}}, {{tool}}, and {{session\_id}} inject context into your command. Example: { "hooks": { "file-modified": "eslint --fix {{file}}" } } runs ESLint every time the agent modifies a file.