Skip to main content
For the full guide, see Hooks.

Observer hook (background)

A post_tool_execution background hook that logs every tool call to a file. Background hooks run asynchronously and never block the agent loop.
rkat run "Summarize this repo" --hooks-override-json '{
  "entries": [{
    "id": "audit-log",
    "point": "post_tool_execution",
    "mode": "background",
    "command": ["python3", "hooks/log_tool.py"],
    "timeout_ms": 3000
  }]
}'

Guardrail hook (blocking)

A pre_tool_execution blocking hook that must approve each tool call before it runs. If the hook returns deny, the tool call is skipped.
rkat run "Delete old logs" --hooks-override-json '{
  "entries": [{
    "id": "safety-gate",
    "point": "pre_tool_execution",
    "mode": "blocking",
    "command": ["python3", "hooks/approve_tool.py"],
    "timeout_ms": 5000
  }]
}'

In-process hook (Rust only)

Register a Rust closure directly — no subprocess, no serialization overhead. Only available in the Rust SDK.
let engine = DefaultHookEngine::new(hooks_config)
    .with_in_process_handler(
        "pii-scrub",
        Arc::new(|invocation| Box::pin(async move {
            let text = invocation.tool_result.as_ref()
                .map(|r| r.content.as_str()).unwrap_or("");
            let scrubbed = redact_pii(text);
            Ok(RuntimeHookResponse {
                patches: vec![HookPatch::ToolResult {
                    content: scrubbed,
                    is_error: None,
                }],
                ..Default::default()
            })
        })),
    );

HTTP hook

A hook that POSTs the invocation payload to a remote URL. Useful for centralized policy servers.
rkat run "Analyze quarterly data" --hooks-override-json '{
  "entries": [{
    "id": "policy-server",
    "point": "pre_llm_request",
    "mode": "blocking",
    "url": "https://hooks.example.com/policy",
    "timeout_ms": 10000
  }]
}'

All 8 hook points

Hook pointClassificationWhen it fires
run_startedpreStart of Agent::run(), before any LLM call
pre_llm_requestpreBefore each LLM streaming call
pre_tool_executionpreBefore each individual tool call is dispatched
turn_boundarypreBetween turns, after all tool results are collected
post_llm_responsepostAfter the LLM response is received
post_tool_executionpostAfter each tool execution completes
run_completedpostAfter a successful run completes
run_failedpostAfter a run fails with an error
Pre-point hooks in blocking mode halt the agent loop until they return. Pre-point hooks in background mode are limited to observe-only capability.

Disable a hook

Use the disable list to turn off hooks defined in the realm config without removing them.
rkat run "Quick test" --hooks-override-json '{
  "disable": ["safety-gate", "audit-log"]
}'

Hook events

Hooks emit events into the session event stream. Subscribe to these to build dashboards, alerting, or audit trails.
// HookStarted -- emitted when a hook begins execution
{"type": "hook_started", "hook_id": "safety-gate", "point": "pre_tool_execution"}

// HookCompleted -- emitted when a hook finishes successfully
{"type": "hook_completed", "hook_id": "safety-gate", "point": "pre_tool_execution", "duration_ms": 42}

// HookDenied -- emitted when a hook blocks execution
{"type": "hook_denied", "hook_id": "safety-gate", "point": "pre_tool_execution", "reason_code": "policy_violation", "message": "rm -rf not allowed"}

// HookFailed -- emitted when a hook errors or times out
{"type": "hook_failed", "hook_id": "audit-log", "point": "post_tool_execution", "error": "process exited with code 1"}

// HookRewriteApplied -- emitted when a hook applies a patch
{"type": "hook_rewrite_applied", "hook_id": "pii-scrub", "point": "post_tool_execution", "patch": {"ToolResult": {"content": "***", "is_error": null}}}