A3S CodeExamples
Hooks
Lifecycle event interception — PreToolUse, PostToolUse, PrePrompt, PostResponse, OnError
Hooks
Hooks let you intercept agent lifecycle events to audit, modify, or block operations. Register a Hook + HookHandler pair on a session.
Hook Event Types
Prop
Type
Audit Hook (Log All Tool Calls)
use a3s_code_core::hooks::{Hook, HookEvent, HookEventType, HookHandler, HookResponse};
use std::sync::{Arc, Mutex};
struct AuditHandler {
log: Arc<Mutex<Vec<String>>>,
}
impl HookHandler for AuditHandler {
fn handle(&self, event: &HookEvent) -> HookResponse {
if let HookEvent::PreToolUse(e) = event {
println!("→ tool: {}", e.tool);
self.log.lock().unwrap().push(e.tool.clone());
}
HookResponse::continue_()
}
}
// Register
let log = Arc::new(Mutex::new(Vec::new()));
let hook = Hook::new("audit", HookEventType::PreToolUse);
session.register_hook(hook);
session.register_hook_handler("audit", Arc::new(AuditHandler { log: Arc::clone(&log) }));
println!("Hooks: {}", session.hook_count());
// Run agent
let result = session.send("List files in the workspace", None).await?;
// Inspect log
println!("Tools called: {:?}", log.lock().unwrap());
// Cleanup
session.unregister_hook("audit");Run: cargo run --example 08_hooks
Source: core/examples/08_hooks.rs
tool_log = []
def on_pre_tool_use(event):
tool = event.get("tool", "unknown")
print(f"→ tool: {tool}")
tool_log.append(tool)
return None # allow execution
session.register_hook("audit", "pre_tool_use", on_pre_tool_use)
print(f"Hooks: {session.hook_count()}")
result = await session.send("List files in the workspace")
print(f"Tools called: {tool_log}")
session.unregister_hook("audit")Run: python examples/test_advanced_features.py
Source: sdk/python/examples/test_advanced_features.py
const toolLog = [];
session.registerHook('audit', 'pre_tool_use', (event) => {
const tool = event.tool || 'unknown';
console.log(`→ tool: ${tool}`);
toolLog.push(tool);
return null; // allow execution
});
console.log(`Hooks: ${session.hookCount()}`);
const result = await session.send('List files in the workspace');
console.log('Tools called:', toolLog);
session.unregisterHook('audit');Run: node examples/test_advanced_features.js
Source: sdk/node/examples/test_advanced_features.js
Block Hook (Deny Specific Tools)
struct DenyBashHandler;
impl HookHandler for DenyBashHandler {
fn handle(&self, event: &HookEvent) -> HookResponse {
if let HookEvent::PreToolUse(e) = event {
if e.tool == "bash" {
return HookResponse::block("bash is not allowed in this session");
}
}
HookResponse::continue_()
}
}
let hook = Hook::new("no-bash", HookEventType::PreToolUse);
session.register_hook(hook);
session.register_hook_handler("no-bash", Arc::new(DenyBashHandler));def deny_bash(event):
if event.get("tool") == "bash":
return {"action": "block", "reason": "bash is not allowed"}
return None
session.register_hook("no-bash", "pre_tool_use", deny_bash)session.registerHook('no-bash', 'pre_tool_use', (event) => {
if (event.tool === 'bash') {
return { action: 'block', reason: 'bash is not allowed' };
}
return null;
});For persistent hook configuration across sessions, see Hooks.
API Reference
Hook Registration
Prop
Type
HookResponse (Rust)
Prop
Type
Hook Event Fields
Prop
Type