Skip to main content
Hooks are the primary runtime extension point in QitOS. They let you observe and react to every phase transition inside the Engine without modifying the agent itself. This tutorial covers the full hook lifecycle, the context objects hooks receive, and how to write both step-level and tool-level hooks.

Hooks vs. Critics

QitOS has two extension mechanisms that operate at different levels: Use hooks when you want to log, trace, emit metrics, or trigger external notifications. Use critics when you want to constrain or override agent behavior.

Step 1: The EngineHook Base Class

Every hook inherits from EngineHook. The base class defines no-op methods for every lifecycle callback, so you only override the ones you need.
The full callback set, in execution order within a single run: Additional lifecycle callbacks that fire outside the step loop: All no-op methods return None. Override only the callbacks you care about.

Step 2: HookContext and ToolHookContext

Every step-level callback receives a HookContext dataclass that carries everything a hook might need:
Tool-level callbacks receive ToolHookContext, which extends HookContext with tool-specific fields:
The phase field comes from the RuntimePhase enum:

Step 3: Writing a Custom Logging Hook

A common use case is recording every phase transition for later analysis. Here is a LifecycleRecorderHook that logs each callback with a timestamp and step ID:
Because hooks cannot modify the flow, the LifecycleRecorderHook is safe to add to any run without side effects.

Step 4: Tool-Level Hooks

Tool-level hooks fire around individual tool invocations, giving you fine-grained visibility into which tools the agent calls and what they return.
The three tool-level callbacks: Use on_permission_denied to monitor security boundaries without modifying the permission system itself.

Step 5: Registering Hooks with the Engine

Hooks are registered on the Engine instance before calling run():
You can register multiple hooks. They fire in registration order within each callback. Because hooks are observation-only, order does not affect control flow — but it does affect log output ordering, which matters for debugging. To inspect currently registered hooks:
To remove a hook:

Full Lifecycle Diagram

On error recovery, on_recover fires instead of the remaining step callbacks for that step, and the engine may retry or abort depending on configuration.

Related guide: Critics

Learn how critics differ from hooks and how to use them for control flow and decision gating.

Next tutorial: Multi-Agent Systems

Build systems with coordinator and worker agents that dispatch tasks in parallel.