My agentic slop goes here. Not intended for anyone else!
at jsont 7.1 kB view raw
1(** Claude Code Hooks System 2 3 Hooks allow you to intercept and control events in Claude Code sessions, 4 such as tool usage, prompt submission, and session stops. 5 6 {1 Overview} 7 8 Hooks are organized by event type, with each event having: 9 - A typed input structure (accessible via submodules) 10 - A typed output structure for responses 11 - Helper functions for common responses 12 13 {1 Example Usage} 14 15 {[ 16 open Eio.Std 17 18 (* Block dangerous bash commands *) 19 let block_rm_rf ~input ~tool_use_id:_ ~context:_ = 20 let hook = Hooks.PreToolUse.of_json input in 21 if Hooks.PreToolUse.tool_name hook = "Bash" then 22 let tool_input = Hooks.PreToolUse.tool_input hook in 23 match Ezjsonm.find tool_input ["command"] with 24 | `String cmd when String.contains cmd "rm -rf" -> 25 let output = Hooks.PreToolUse.deny ~reason:"Dangerous command" () in 26 Hooks.continue 27 ~hook_specific_output:(Hooks.PreToolUse.output_to_json output) 28 () 29 | _ -> Hooks.continue () 30 else Hooks.continue () 31 32 let hooks = 33 Hooks.empty 34 |> Hooks.add Hooks.Pre_tool_use [ 35 Hooks.matcher ~pattern:"Bash" [block_rm_rf] 36 ] 37 38 let options = Claude.Options.create ~hooks:(Some hooks) () in 39 let client = Claude.Client.create ~options ~sw ~process_mgr () in 40 ]} 41*) 42 43(** The log source for hooks *) 44val src : Logs.Src.t 45 46(** {1 Hook Events} *) 47 48(** Hook event types *) 49type event = 50 | Pre_tool_use (** Fires before a tool is executed *) 51 | Post_tool_use (** Fires after a tool completes *) 52 | User_prompt_submit (** Fires when user submits a prompt *) 53 | Stop (** Fires when conversation stops *) 54 | Subagent_stop (** Fires when a subagent stops *) 55 | Pre_compact (** Fires before message compaction *) 56 57val event_to_string : event -> string 58val event_of_string : string -> event 59 60(** {1 Context} *) 61 62module Context : sig 63 type t 64 val create : ?signal:unit option -> unit -> t 65end 66 67(** {1 Decisions} *) 68 69type decision = 70 | Continue (** Allow the action to proceed *) 71 | Block (** Block the action *) 72 73(** {1 Generic Hook Result} *) 74 75(** Generic result structure for hooks *) 76type result = { 77 decision: decision option; 78 system_message: string option; 79 hook_specific_output: Ezjsonm.value option; 80} 81 82(** {1 Typed Hook Modules} *) 83 84(** PreToolUse hook - fires before tool execution *) 85module PreToolUse : sig 86 (** Typed input for PreToolUse hooks *) 87 type t 88 89 (** Permission decision for tool usage *) 90 type permission_decision = Allow | Deny | Ask 91 92 (** Typed output for PreToolUse hooks *) 93 type output = { 94 permission_decision: permission_decision option; 95 permission_decision_reason: string option; 96 } 97 98 (** Parse hook input from JSON *) 99 val of_json : Ezjsonm.value -> t 100 101 (** {2 Accessors} *) 102 val session_id : t -> string 103 val transcript_path : t -> string 104 val tool_name : t -> string 105 val tool_input : t -> Ezjsonm.value 106 val raw_json : t -> Ezjsonm.value 107 108 (** {2 Response Builders} *) 109 val allow : ?reason:string -> unit -> output 110 val deny : ?reason:string -> unit -> output 111 val ask : ?reason:string -> unit -> output 112 val continue : unit -> output 113 114 (** Convert output to JSON for hook_specific_output *) 115 val output_to_json : output -> Ezjsonm.value 116end 117 118(** PostToolUse hook - fires after tool execution *) 119module PostToolUse : sig 120 type t 121 122 type output = { 123 decision: decision option; 124 reason: string option; 125 additional_context: string option; 126 } 127 128 val of_json : Ezjsonm.value -> t 129 130 val session_id : t -> string 131 val transcript_path : t -> string 132 val tool_name : t -> string 133 val tool_input : t -> Ezjsonm.value 134 val tool_response : t -> Ezjsonm.value 135 val raw_json : t -> Ezjsonm.value 136 137 val continue : ?additional_context:string -> unit -> output 138 val block : ?reason:string -> ?additional_context:string -> unit -> output 139 val output_to_json : output -> Ezjsonm.value 140end 141 142(** UserPromptSubmit hook - fires when user submits a prompt *) 143module UserPromptSubmit : sig 144 type t 145 146 type output = { 147 decision: decision option; 148 reason: string option; 149 additional_context: string option; 150 } 151 152 val of_json : Ezjsonm.value -> t 153 154 val session_id : t -> string 155 val transcript_path : t -> string 156 val prompt : t -> string 157 val raw_json : t -> Ezjsonm.value 158 159 val continue : ?additional_context:string -> unit -> output 160 val block : ?reason:string -> unit -> output 161 val output_to_json : output -> Ezjsonm.value 162end 163 164(** Stop hook - fires when conversation stops *) 165module Stop : sig 166 type t 167 168 type output = { 169 decision: decision option; 170 reason: string option; 171 } 172 173 val of_json : Ezjsonm.value -> t 174 175 val session_id : t -> string 176 val transcript_path : t -> string 177 val stop_hook_active : t -> bool 178 val raw_json : t -> Ezjsonm.value 179 180 val continue : unit -> output 181 val block : ?reason:string -> unit -> output 182 val output_to_json : output -> Ezjsonm.value 183end 184 185(** SubagentStop hook - fires when a subagent stops *) 186module SubagentStop : sig 187 include module type of Stop 188 val of_json : Ezjsonm.value -> t 189 val raw_json : t -> Ezjsonm.value 190end 191 192(** PreCompact hook - fires before message compaction *) 193module PreCompact : sig 194 type t 195 type output = unit 196 197 val of_json : Ezjsonm.value -> t 198 199 val session_id : t -> string 200 val transcript_path : t -> string 201 val raw_json : t -> Ezjsonm.value 202 203 val continue : unit -> output 204 val output_to_json : output -> Ezjsonm.value 205end 206 207(** {1 Callbacks} *) 208 209(** Generic callback function type. 210 211 Callbacks receive: 212 - [input]: Raw JSON input (parse with [PreToolUse.of_json], etc.) 213 - [tool_use_id]: Optional tool use ID 214 - [context]: Hook context 215 216 And return a generic [result] with optional hook-specific output. 217*) 218type callback = 219 input:Ezjsonm.value -> 220 tool_use_id:string option -> 221 context:Context.t -> 222 result 223 224(** {1 Matchers} *) 225 226(** A matcher configuration *) 227type matcher = { 228 matcher: string option; (** Pattern to match (e.g., "Bash" or "Write|Edit") *) 229 callbacks: callback list; (** Callbacks to invoke on match *) 230} 231 232(** Hook configuration: map from events to matchers *) 233type config = (event * matcher list) list 234 235(** {1 Generic Result Builders} *) 236 237(** [continue ?system_message ?hook_specific_output ()] creates a continue result *) 238val continue : ?system_message:string -> ?hook_specific_output:Ezjsonm.value -> unit -> result 239 240(** [block ?system_message ?hook_specific_output ()] creates a block result *) 241val block : ?system_message:string -> ?hook_specific_output:Ezjsonm.value -> unit -> result 242 243(** {1 Configuration Builders} *) 244 245(** [matcher ?pattern callbacks] creates a matcher *) 246val matcher : ?pattern:string -> callback list -> matcher 247 248(** Empty hooks configuration *) 249val empty : config 250 251(** [add event matchers config] adds matchers for an event *) 252val add : event -> matcher list -> config -> config 253 254(** {1 JSON Serialization} *) 255 256val result_to_json : result -> Ezjsonm.value 257val config_to_protocol_format : config -> Ezjsonm.value