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

# Hooks

> Observe every lifecycle event during an agent run

<Info>
  Source: [`04_hooks_logging.py`](https://github.com/opper-ai/opper-sdks/blob/main/python/examples/agents/04_hooks_logging.py), [`05_hooks_timing.py`](https://github.com/opper-ai/opper-sdks/blob/main/python/examples/agents/05_hooks_timing.py) · [`04-hooks-logging.ts`](https://github.com/opper-ai/opper-sdks/blob/main/typescript/examples/agents/04-hooks-logging.ts), [`05-hooks-timing.ts`](https://github.com/opper-ai/opper-sdks/blob/main/typescript/examples/agents/05-hooks-timing.ts)
</Info>

Hooks let you log, time, or measure agent execution without touching the agent logic itself. Pass a `Hooks` object to the agent constructor.

## Lifecycle events

| Hook                                      | Fired when                            |
| ----------------------------------------- | ------------------------------------- |
| `on_agent_start` / `onAgentStart`         | A run begins.                         |
| `on_agent_end` / `onAgentEnd`             | A run completes (or fails).           |
| `on_iteration_start` / `onIterationStart` | A new think→act cycle.                |
| `on_llm_call` / `onLLMCall`               | About to send a request to the model. |
| `on_llm_response` / `onLLMResponse`       | Got a model response.                 |
| `on_tool_start` / `onToolStart`           | About to execute a tool.              |
| `on_tool_end` / `onToolEnd`               | Tool finished (with `duration_ms`).   |

## Example

<CodeGroup>
  ```python Python theme={null}
  from opperai.agent import Agent, Hooks, tool

  hooks = Hooks(
      on_agent_start=lambda ctx: print(f'-> {ctx["agent"]}: {ctx["input"]}'),
      on_tool_start=lambda ctx: print(f'  tool {ctx["name"]}({ctx["input"]})'),
      on_tool_end=lambda ctx: print(f'  -> {ctx["output"]} ({ctx["duration_ms"]:.0f}ms)'),
      on_agent_end=lambda ctx: print(
          f'<- done in {ctx["result"].meta.iterations} iterations'
          if ctx.get("result") else f'<- failed: {ctx.get("error")}'
      ),
  )

  agent = Agent(name="city-expert", instructions="...", tools=[lookup_city], hooks=hooks)
  ```

  ```typescript TypeScript theme={null}
  import { Agent, type Hooks } from "opperai";

  const hooks: Hooks = {
    onAgentStart: ({ agent, input }) => console.log(`-> ${agent}: ${input}`),
    onToolStart: ({ name, input }) => console.log(`  tool ${name}(${JSON.stringify(input)})`),
    onToolEnd: ({ name, output, durationMs }) =>
      console.log(`  -> ${JSON.stringify(output)} (${durationMs}ms)`),
    onAgentEnd: ({ result, error }) =>
      error
        ? console.log(`<- failed: ${error.message}`)
        : console.log(`<- done in ${result!.meta.iterations} iterations`),
  };

  const agent = new Agent({ name: "city-expert", instructions: "...", tools: [lookupCity], hooks });
  ```
</CodeGroup>

## Common uses

* Logging: print events or ship them to your logger.
* Timing: add up `duration_ms` per tool to find bottlenecks (see `05_hooks_timing`).
* Custom metrics: push counters or histograms to your metrics backend.
* Span enrichment: attach extra metadata to the trace span the SDK already creates.

Hooks sit on top of built-in tracing. Every run, LLM call, and tool execution already lands in the [Opper dashboard](https://platform.opper.ai/) without any setup.
