> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lyzr.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Hooks

> Intercept, block, or modify agent behavior at every stage — via shell scripts or programmatic SDK callbacks.

## Hook Events

| Event               | When                  | Can Block | Can Modify |
| ------------------- | --------------------- | --------- | ---------- |
| `on_session_start`  | Before agent runs     | Yes       | No         |
| `pre_tool_use`      | Before each tool call | Yes       | Yes        |
| `post_tool_failure` | After a tool errors   | No        | No         |
| `pre_query`         | Before LLM call       | Yes       | No         |
| `post_response`     | After LLM responds    | No        | No         |
| `file_changed`      | After file write      | No        | No         |
| `on_error`          | On agent error        | No        | No         |

## hooks.yaml Config

```yaml theme={null}
# hooks/hooks.yaml
hooks:
  on_session_start:
    - script:check-auth.sh
      description: "Verify user authorization"

  pre_tool_use:
    - script:validate-command.sh
      description: "Block dangerous CLI commands"

  post_tool_failure:
    - script:notify-error.sh

  post_response:
    - script:log-response.sh

  pre_query:
    - script:rate-limit.sh

  file_changed:
    - script:track-changes.sh

  on_error:
    - script:incident-report.sh
```

## Hook Script Format

stdin (JSON input):

```json theme={null}
{
  "event": "pre_tool_use",
  "session_id": "uuid",
  "tool": "cli",
  "args": {"command": "rm -rf /"}
}
```

stdout (output options):

```json theme={null}
{"action": "allow"}
{"action": "block", "reason": "Destructive command blocked"}
{"action": "modify", "args": {"command": "echo safe"}}
```

## Programmatic Hooks (SDK)

```typescript theme={null}
// sdk-hooks.ts
for await (const msg of query({
  prompt: "Deploy the service",
  hooks: {
    preToolUse: async (ctx) => {
      if (ctx.toolName === "cli" && ctx.args.command?.includes("rm -rf"))
        return { action: "block", reason: "Destructive command blocked" };
      if (ctx.toolName === "write" && !ctx.args.path.startsWith("/safe/"))
        return { action: "modify", args: { ...ctx.args, path: `/safe/${ctx.args.path}` } };
      return { action: "allow" };
    },
    onError: async (ctx) => {
      console.error(`Agent error: ${ctx.error}`);
    },
  },
})) { /* ... */ }
```

<Note>
  SDK hooks run before script hooks — if an SDK hook blocks, the script hook is never called. Both can run independently when the SDK hook allows.
</Note>

<CardGroup cols={2}>
  <Card title="Tools" icon="wrench" href="/open-source/gitagent/capabilities/tools">
    Built-in and declarative tools the agent uses to act
  </Card>

  <Card title="Skills" icon="sparkles" href="/open-source/gitagent/capabilities/skills">
    Reusable task modules the agent learns and crystallizes over time
  </Card>

  <Card title="Workflows" icon="diagram-project" href="/open-source/gitagent/capabilities/workflows">
    Chain skills into deterministic, repeatable pipelines
  </Card>

  <Card title="SDK Reference" icon="code" href="/open-source/gitagent/sdk/overview">
    Embed GitAgent programmatically, including hook callbacks
  </Card>
</CardGroup>
