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. Pre-points block loop progression in foreground mode; post-points publish results asynchronously in background mode.
Capabilities
| HookCapability | Purpose | Default failure policy |
|---|---|---|
Observe | Read-only logging and metrics | FailOpen |
Guardrail | Can issue Deny decisions to block execution | FailClosed |
Rewrite | Can return HookPatch values to mutate data | FailClosed |
failure_policy field.
Execution modes
| HookExecutionMode | Behavior |
|---|---|
Foreground | Blocks loop progression. Decision and patches are applied synchronously. |
Background | Runs asynchronously. Patches are published via HookPatchEnvelope. |
HookPatchEnvelope (containing revision, hook_id, point, patch, published_at). These envelopes are drained and included in the HookExecutionReport on subsequent execute() calls.
How to add a hook
Choose hook point and capability
Decide which
HookPoint to fire at (e.g., PreToolExecution for tool guardrails) and which HookCapability you need (Observe, Guardrail, or Rewrite).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 .rkat/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 and patches.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 | On timeout | On runtime error |
|---|---|---|
FailOpen | Logged as error, execution continues | Logged as error, execution continues |
FailClosed | Emits Deny with HookReasonCode::Timeout | Emits Deny with HookReasonCode::RuntimeError |
HookEntryConfig::effective_failure_policy():
- If
failure_policyis explicitly set on the entry, that value is used. - Otherwise,
default_failure_policy(capability)is applied.
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) |
HookPatch variants
HookPatch variants
Each variant is valid only at certain hook points:
| HookPatch variant | Fields | Valid at |
|---|---|---|
LlmRequest | max_tokens: Option<u32>, temperature: Option<f32>, provider_params: Option<Value> | PreLlmRequest |
AssistantText | text: String | PostLlmResponse |
ToolArgs | args: Value | PreToolExecution |
ToolResult | content: String, is_error: Option<bool> | PostToolExecution |
RunResult | text: String | RunCompleted |
Runtime hook response
All three runtimes return the sameRuntimeHookResponse structure:
decision and patches are optional. An empty response {} is equivalent to “no opinion”.
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,is_error
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 (.rkat/config.toml)
Config file example (.rkat/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 | Override default failure policy |
timeout_ms | Option<u64> | None | Override default timeout |
runtime | HookRuntimeConfig | in_process/noop | Runtime configuration |
Layered config loading
Layered config loading
Hook entries from global config (
~/.rkat/config.toml) and project config (.rkat/config.toml) are combined additively via HooksConfig::append_entries_from(). Global entries load first, then project entries are appended after them.Per-run overrides
TheHookRunOverrides struct allows per-request hook customization:
- CLI
- RPC / REST / MCP
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 |
HookPatchPublished | A background hook publishes a patch envelope |
SDK usage
Registering an in-process hook
Registering an in-process hook
Using hook overrides in AgentBuildConfig
Using hook overrides in AgentBuildConfig
