xz-agent-hooks
Product-agnostic lifecycle hook contract, ordered registry, Claude/Codex wire parsing, context buffer, and ExternalHookRunner adapter.
xz-agent/
core/ → xz-agent-core
engine/ → xz-agent-engine
hooks/ → xz-agent-hooks ← this crate
Features
| Capability | API |
|---|---|
| Event kinds + Claude aliases | HookEventKind::parse, HookEvent::{pre_tool,post_tool,permission_request,unit} |
| Outcomes | Continue, AdditionalContext, Deny, MutateArgs, Allow, Ask, ReplaceResult |
| Typed merge | merge_pre_tool / merge_post_tool / merge_permission / merge_inject → MergedEffect |
| PreTool helpers | PreToolEffect::{is_denied, final_args, into_final_args}, apply_pre_tool_args |
| PostTool helpers | PostToolEffect::effective_result (replace > block_feedback > original) |
| Permission helpers | PermissionDecision::{Allow,Deny,Ask,Unspecified} |
| Ordered fire | HookRegistry (Vec order; PreTool deny short-circuit; fail-open errors) |
| Wire protocol | parse_handler_output — exit 0/2/3 + JSON updatedInput / permissionDecision |
| External adapter | ExternalHookHandler + ExternalHookRunner |
| Context buffer | ContextInjectionBuffer |
What this crate is not
- Product tool names (
BashExec, …) .xz-code/.claudepath discovery- Permission UI / TUI
- Session / Message types
Product integration sketch
// 1. Implement ExternalHookRunner (shell/HTTP) in the product.
// 2. Register ExternalHookHandler into HookRegistry.
// 3. Before tool exec:
// let r = registry.fire_pre_tool(&HookEvent::pre_tool(name, args)).await;
// let effect = r.effect.as_pre_tool()...;
// let args = effect.clone().into_final_args(args)?; // Err = deny reason
// 4. After tool exec: fire_post_tool → effective_result
// 5. Drain ContextInjectionBuffer into the next LLM turn / UI
Tests
Coverage targets (unit + tests/end_to_end.rs):
- All merge modes and priority rules
- Wire exit codes 0/1/2/3 + Claude JSON shapes
- Registry ordering, matcher, kind filter, remove/clear, fail-open
- ExternalHookHandler rewrite + I/O fail-open
- Context buffer drain/join
- Outcome/event serde roundtrip