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 fromEngineHook. The base class defines no-op methods for every lifecycle callback, so you only override the ones you need.
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 aHookContext dataclass that carries everything a hook might need:
ToolHookContext, which extends HookContext with tool-specific fields:
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 aLifecycleRecorderHook that logs each callback with a timestamp and step ID:
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.
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 theEngine instance before calling run():
Full Lifecycle Diagram
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.
