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

# Invocation hooks

> Observe or transform agent, model, and tool execution in a portable way.

Portable hooks apply the same policy around Harnest-owned ADK and LangGraph boundaries.

From the agent root, create an observational agent hook starter:

```bash theme={null}
harnest add lifecycle audit
```

Use `--project <agent-root>` when running the command from elsewhere, then choose the boundary and phase that owns the policy.

| Boundary | Decorators                              | Typical use                      |
| -------- | --------------------------------------- | -------------------------------- |
| Agent    | `lifecycle.agent.before/after/on_error` | Request policy and accounting    |
| Model    | `lifecycle.model.before/after/on_error` | Input and output policy          |
| Tool     | `lifecycle.tool.before/after/on_error`  | Tool guardrails and results      |
| MCP      | `lifecycle.mcp.before/after/on_error`   | Governed remote-tool policy      |
| HTTP     | `lifecycle.http.before/after/on_error`  | Routing and response-head policy |

```python theme={null}
from harnest import lifecycle


@lifecycle.tool.before(order=-100)
async def check_tool(context, request):
    if context.tool_name == "delete_account":
        return context.finish({"error": "tool_disabled"})
    return context.next()
```

## Control flow

| Return                      | Effect                               |
| --------------------------- | ------------------------------------ |
| `context.next()`            | Continue unchanged                   |
| `context.next(replacement)` | Pass a replacement to the next stage |
| `context.finish(result)`    | Stop the chain with a final result   |

Tool, MCP, and HTTP `before` and `after` interceptors require explicit control flow. Agent and model hooks accept legacy return values, but explicit transitions keep policy readable and portable.

Error hooks normally return `context.next()`. An MCP error hook can use `finish(...)` only for a recoverable provider failure; it cannot bypass approval or cancellation.

## Ordering

| Property       | Behavior                                                                     |
| -------------- | ---------------------------------------------------------------------------- |
| Primary order  | Lower integer `order` values run first                                       |
| Tie-break      | Plugin dependency/source order, then source location                         |
| Transformer    | Can replace the current value                                                |
| Observer       | Reads an event without replacing it                                          |
| Rejection      | Stops work before the protected phase                                        |
| Error observer | Cannot hide the original failure                                             |
| Agent identity | Model hooks receive the managed agent or SubAgent performing that model call |

The `agent_name` on a model lifecycle context is call-specific. When a managed
SubAgent calls a model, it contains that SubAgent's name rather than the root
agent's name. The authenticated user, session, and invocation IDs remain those
of the root request, including when sibling SubAgents run concurrently.

Keep business operations in Agent Tools. Hooks should apply policy, observation, or transformation around those operations.

## Portable or native?

| Requirement                           | Choose                       |
| ------------------------------------- | ---------------------------- |
| Same policy on ADK and LangGraph      | Portable hook                |
| ADK runner or plugin API              | ADK native integration       |
| LangGraph middleware or graph runtime | LangGraph native integration |

<Card title="Native integrations" icon="code" href="/docs/harnest/runtime/lifecycle/native-integrations">
  Isolate behavior that must use the selected framework directly.
</Card>
