Hooks let you run custom logic at defined points in the agent lifecycle — before/after tool execution, LLM calls, or at turn boundaries. Use them for approval workflows, audit logging, content filtering, or typed denials.Documentation Index
Fetch the complete documentation index at: https://docs.rkat.ai/llms.txt
Use this file to discover all available pages before exploring further.
This page is the task-first guide. For the low-level type and payload inventory, see Hooks reference.
What this guide is for
Use this guide when you want to:- add approval gates
- log or audit agent behavior
- block unsafe tool inputs or outputs
- choose between in-process, command, and HTTP hook runtimes
Hook points
Eight extension points are available:| HookPoint | Classification | When it fires |
|---|---|---|
RunStarted | pre | Start of Agent::run(), before any LLM call |
PreLlmRequest | pre | Before each LLM streaming call |
PreToolExecution | pre | Before each individual tool call is dispatched |
TurnBoundary | pre | Between turns, after all tool results are collected |
PostLlmResponse | post | After the LLM response is received |
PostToolExecution | post | After each tool execution completes |
RunCompleted | post | After a successful run completes |
RunFailed | post | After a run fails with an error |
is_pre() and is_post() methods on HookPoint. Foreground hooks block loop progression; background hooks run asynchronously for observation.
Capabilities
| HookCapability | Purpose |
|---|---|
Observe | Read-only logging and metrics |
Guardrail | Can issue Deny decisions to block execution |
Rewrite | Retired compatibility label; semantic patch authority is removed |
Execution modes
| HookExecutionMode | Behavior |
|---|---|
Foreground | Blocks loop progression. Allow / Deny decisions are handled synchronously. |
Background | Runs asynchronously for observation. |
How to add a hook
Choose hook point and capability
Decide which
HookPoint to fire at (e.g., PreToolExecution for tool guardrails) and whether the hook needs Observe or Guardrail.Choose a runtime
Pick one of the three runtimes: in-process (Rust closure), command (subprocess), or HTTP (remote endpoint).
Add configuration
Add a
[[hooks.entries]] block to the active realm config.toml (or register programmatically via HooksConfig).Implement the handler
Write the handler that receives a
HookInvocation and returns a RuntimeHookResponse with an optional decision.The docs below show run-scoped hook overrides conceptually, but the current CLI does not expose run-scoped hook override flags in normal builds. For now, use RPC, REST, MCP, or the SDK/embedded surfaces when you want per-run hook overrides.
Runtimes
- In-process
- Command (subprocess)
- HTTP
Calls a registered Rust closure. Config:The handler is registered at engine construction time via
DefaultHookEngine::with_in_process_handler() or register_in_process_handler(). The handler type is:Failure policies
HookFailurePolicy is retained as a compatibility field on hook configuration. Current hook runtime failures fail closed through typed HookEngineError values; they are not converted into warning-only success or hook-local Deny decisions by FailOpen / FailClosed.
Background hook failure policy is inert compatibility configuration. Pre-point background hooks are still required to be Observe, because they cannot safely block a pre-execution boundary after the loop has moved on.
Decisions and patches
HookDecision
HookDecision
| HookReasonCode | Meaning |
|---|---|
PolicyViolation | Business rule or policy constraint |
SafetyViolation | Content safety check |
SchemaViolation | Schema or format validation failure |
Timeout | Hook timed out (system-generated) |
RuntimeError | Hook execution failed (system-generated) |
Retired patch payloads
Retired patch payloads
HookPatch no longer has valid variants. Older payloads such as llm_request, assistant_text, tool_args, tool_result, and run_result fail closed during deserialization instead of being ignored or applied.Hooks can observe typed projections and return Allow or Deny. Canonical provider parameters, assistant text, tool arguments, tool results, and final run text are owned by the runtime and tool execution path.Runtime hook response
All three runtimes return the sameRuntimeHookResponse structure:
decision is optional. The compatibility patches field may be empty, but non-empty legacy semantic patch payloads are rejected.
Invocation payload
Hooks receive aHookInvocation struct containing contextual data. Fields are populated based on the hook point:
| Field | Type | Populated at |
|---|---|---|
point | HookPoint | Always |
session_id | SessionId | Always |
turn_number | Option<u32> | Most points |
prompt | Option<String> | RunStarted |
error | Option<String> | RunFailed |
llm_request | Option<HookLlmRequest> | PreLlmRequest |
llm_response | Option<HookLlmResponse> | PostLlmResponse |
tool_call | Option<HookToolCall> | PreToolExecution |
tool_result | Option<HookToolResult> | PostToolExecution |
Supporting types
Supporting types
HookLlmRequest:max_tokens,temperature,provider_params,message_countHookLlmResponse:assistant_text,tool_call_names,stop_reason,usageHookToolCall:tool_use_id,name,argsHookToolResult:tool_use_id,name,content,content_blocks,is_error
HookToolResult.content_blocks carries the typed tool-result blocks, including image blocks, in original order. HookToolResult.content remains as a legacy text projection for existing hooks. Both fields are observational projections and cannot be returned as a rewrite.
Priority ordering and deny short-circuiting
Foreground hooks are sorted bypriority (ascending), then by registration_index (ascending, for determinism when priorities are equal). Lower numeric priority values run first.
When a foreground hook returns Deny:
A priority-1 guardrail that denies will prevent a priority-100 observer from running.
Configuration
Config file example (realm config.toml)
Config file example (realm config.toml)
Hook configuration lives under the
[hooks] table:HookEntryConfig fields
HookEntryConfig fields
| Field | Type | Default | Description |
|---|---|---|---|
id | HookId | "hook" | Unique identifier for the hook |
enabled | bool | true | Whether the hook is active |
point | HookPoint | TurnBoundary | Which hook point to fire at |
mode | HookExecutionMode | Foreground | Foreground or background |
capability | HookCapability | Observe | What the hook can do |
priority | i32 | 100 | Execution order (lower runs first) |
failure_policy | Option<HookFailurePolicy> | None | Compatibility field; runtime failures remain typed engine errors |
timeout_ms | Option<u64> | None | Override default timeout |
runtime | HookRuntimeConfig | in_process/noop | Runtime configuration |
Layered config loading
Layered config loading
Hook loading is runtime-root aware. In workspace-derived realms, global and project hook entries are layered (
~/.rkat/config.toml then .rkat/config.toml) and merged with active realm config hooks. In non-workspace realms, realm config is primary and no project config may be discovered.Per-run overrides
TheHookRunOverrides struct allows per-request hook customization:
- CLI
- RPC / REST / MCP
Run-scoped hook override flags are not currently exposed on the normal
rkat run surface. Use JSON-RPC, REST, MCP, or SDK/embedded surfaces for per-run hook override testing.Agent events
The hook engine emitsAgentEvent variants during execution:
| Event | When |
|---|---|
HookStarted | A hook begins execution |
HookCompleted | A hook finishes successfully |
HookFailed | A hook encounters an error |
HookDenied | A hook returns a Deny decision |
SDK usage
Registering an in-process hook
Registering an in-process hook
Using hook overrides in AgentBuildConfig
Using hook overrides in AgentBuildConfig
