---
title: "Hooks Overview"
description: "Run custom logic when specific events occur during a session"
icon: "webhook"
hidden: true
---

<Warning>
**Coming Soon** — Hooks are not yet available in Devin for Terminal. This documentation describes planned functionality.
</Warning>

Hooks let you run custom logic in response to events in the agent's lifecycle. You can use hooks to enforce policies, add context, log actions, modify permissions, or integrate with external systems.

---

## What Can Hooks Do?

<CardGroup cols={2}>
  <Card title="Enforce policies" icon="shield">
    Block dangerous commands, require confirmation for specific actions, or restrict file access.
  </Card>
  <Card title="Add context" icon="message">
    Inject additional instructions or information when specific tools are called.
  </Card>
  <Card title="Run side effects" icon="bolt">
    Execute scripts, send notifications, or log events when things happen.
  </Card>
  <Card title="Modify permissions" icon="lock">
    Dynamically grant or restrict permissions based on the situation.
  </Card>
</CardGroup>

---

## Quick Example

Create `.devin/hooks.yaml` in your project:

```yaml
hooks:
  - name: no-force-push
    on:
      - type: pre_tool
        tool_name: exec
        tool_args.command:
          glob: "*git push --force*"
    then:
      decision: block
      add_context: "Force pushing is not allowed. Use --force-with-lease instead."
```

This hook blocks any attempt to run `git push --force` and tells the agent to use the safer alternative.

---

## Hook Events

Hooks can respond to these lifecycle events:

| Event | When it fires |
|-------|--------------|
| `pre_tool` | Before a tool executes |
| `post_tool` | After a tool finishes |
| `permission_request` | When a permission decision is needed |
| `user_prompt` | When the user submits a message |
| `stop` | When the agent wants to stop |
| `session_start` | When a session begins |
| `session_end` | When a session ends |

---

## Hook Effects

When a hook matches, it can produce these effects:

| Effect | Description |
|--------|-------------|
| `decision` | `approve`, `block`, `ask`, or `interrupt` the action |
| `add_context` | Inject a message into the conversation |
| `command` | Run a shell command |
| `prompt` | Evaluate an LLM prompt |
| `cogs` | Apply middleware (permissions, tools) |

---

## Where Hooks Live

| Location | Scope | Shared? |
|----------|-------|---------|
| `.devin/hooks.yaml` | Project | Yes (committed to repo) |
| `.devin/hooks.local.yaml` | Project | No (gitignored) |
| `.devin/config.json` `"hooks"` key | Project | Yes (committed to repo) |
| `.devin/config.local.json` `"hooks"` key | Project | No (gitignored) |
| `.claude/settings.json` `"hooks"` key | Project | Yes (Claude Code format) |
| `.claude/settings.local.json` `"hooks"` key | Project | No (Claude Code format) |
| `~/.config/devin/config.json` `"hooks"` key | Global | No |
| `~/.claude/settings.json` `"hooks"` key | Global | No (Claude Code format) |
| `~/.claude/settings.local.json` `"hooks"` key | Global | No (Claude Code format) |
| `~/.claude.json` `"hooks"` key | Global | No (Claude Code format) |

<Note>
If both `hooks.local.yaml` and `hooks.yaml` exist, only the local file is used (it fully overrides, not merges).
</Note>

<Note>
Hooks from `.claude/` paths use Claude Code's hook format and are loaded when `read_config_from.claude` is enabled (the default). You can disable this in your user config if needed.
</Note>

---

## Next Steps

<CardGroup cols={2}>
  <Card title="Lifecycle Hooks" icon="rotate" href="/extensibility/hooks/lifecycle-hooks">
    Deep dive into each event type and what data is available
  </Card>
  <Card title="Custom Hooks" icon="code" href="/extensibility/hooks/custom-hooks">
    Full YAML reference with matchers, filters, and effects
  </Card>
</CardGroup>
