My agentic slop goes here. Not intended for anyone else!
1(** SDK Control Protocol for Claude.
2
3 This module defines the typed SDK control protocol for bidirectional
4 communication between the SDK and the Claude CLI. It handles:
5
6 - Permission requests (tool usage authorization)
7 - Hook callbacks (intercepting and modifying tool execution)
8 - Dynamic control (changing settings mid-conversation)
9 - Server introspection (querying capabilities)
10
11 {2 Protocol Overview}
12
13 The SDK control protocol is a JSON-based request/response protocol that
14 runs alongside the main message stream. It enables:
15
16 1. {b Callbacks}: Claude asks the SDK for permission or hook execution
17 2. {b Control}: SDK changes Claude's behavior dynamically
18 3. {b Introspection}: SDK queries server metadata
19
20 {2 Request/Response Flow}
21
22 {v
23 SDK Claude CLI
24 | |
25 |-- Initialize (with hooks) --> |
26 |<-- Permission Request --------| (for tool usage)
27 |-- Allow/Deny Response ------> |
28 | |
29 |<-- Hook Callback -------------| (pre/post tool)
30 |-- Hook Result -------------> |
31 | |
32 |-- Set Model ---------------> | (dynamic control)
33 |<-- Success Response ----------|
34 | |
35 |-- Get Server Info ----------> |
36 |<-- Server Info Response ------|
37 v}
38
39 {2 Usage}
40
41 Most users won't interact with this module directly. The {!Client} module
42 handles the protocol automatically. However, this module is exposed for:
43
44 - Understanding the control protocol
45 - Implementing custom control logic
46 - Debugging control message flow
47 - Advanced SDK extensions
48
49 {2 Dynamic Control Examples}
50
51 See {!Client.set_permission_mode}, {!Client.set_model}, and
52 {!Client.get_server_info} for high-level APIs that use this protocol. *)
53
54(** The log source for SDK control operations *)
55val src : Logs.Src.t
56
57(** {1 Control Subtypes}
58
59 These modules define the individual request/response subtypes for
60 the SDK control protocol. Each subtype represents a specific control
61 operation with its own request and response structure. *)
62
63(** {2 MCP Message Routing}
64
65 The [Mcp_message] subtype routes JSONRPC messages to in-process MCP servers.
66 This is used when the SDK manages MCP servers directly (SDK MCP servers).
67
68 External MCP servers (stdio, HTTP, SSE) are handled by the CLI directly
69 and don't use this control message.
70
71 Example:
72 {[
73 let req = Mcp_message.make_request
74 ~server_name:"calculator"
75 ~message:(* JSONRPC tools/list request *)
76
77 (* CLI routes to SDK MCP server and returns response *)
78 let resp = (* receive Mcp_message response *)
79 let jsonrpc_response = resp.mcp_response
80 ]} *)
81module Mcp_message : sig
82 module Unknown : sig
83 type t = Jsont.json
84 val empty : t
85 val is_empty : t -> bool
86 val jsont : t Jsont.t
87 end
88
89 type request = {
90 server_name : string;
91 (** Name of the SDK MCP server to route the message to *)
92
93 message : Jsont.json;
94 (** JSONRPC message to send to the MCP server *)
95
96 unknown : Unknown.t;
97 (** Unknown fields for forward compatibility *)
98 }
99 (** Request to route JSONRPC message to an in-process MCP server. *)
100
101 type response = {
102 mcp_response : Jsont.json;
103 (** JSONRPC response from the MCP server *)
104
105 unknown : Unknown.t;
106 (** Unknown fields for forward compatibility *)
107 }
108 (** Response containing JSONRPC response from MCP server. *)
109
110 val request_jsont : request Jsont.t
111 (** [request_jsont] is the jsont codec for MCP message requests. *)
112
113 val response_jsont : response Jsont.t
114 (** [response_jsont] is the jsont codec for MCP message responses. *)
115
116 val make_request : server_name:string -> message:Jsont.json -> ?unknown:Unknown.t -> unit -> request
117 (** [make_request ~server_name ~message ?unknown ()] creates an MCP message request. *)
118
119 val make_response : mcp_response:Jsont.json -> ?unknown:Unknown.t -> unit -> response
120 (** [make_response ~mcp_response ?unknown ()] creates an MCP message response. *)
121
122 val pp_request : Format.formatter -> request -> unit
123 (** [pp_request fmt req] pretty-prints an MCP message request. *)
124
125 val pp_response : Format.formatter -> response -> unit
126 (** [pp_response fmt resp] pretty-prints an MCP message response. *)
127end
128
129(** {1 Request Types} *)
130
131module Request : sig
132 (** SDK control request types. *)
133
134 type interrupt = {
135 subtype : [`Interrupt];
136 unknown : Unknown.t;
137 }
138 (** Interrupt request to stop execution. *)
139
140 type permission = {
141 subtype : [`Can_use_tool];
142 tool_name : string;
143 input : Jsont.json;
144 permission_suggestions : Permissions.Update.t list option;
145 blocked_path : string option;
146 unknown : Unknown.t;
147 }
148 (** Permission request for tool usage. *)
149
150 type initialize = {
151 subtype : [`Initialize];
152 hooks : (string * Jsont.json) list option; (* Hook event to configuration *)
153 unknown : Unknown.t;
154 }
155 (** Initialize request with optional hook configuration. *)
156
157 type set_permission_mode = {
158 subtype : [`Set_permission_mode];
159 mode : Permissions.Mode.t;
160 unknown : Unknown.t;
161 }
162 (** Request to change permission mode. *)
163
164 type hook_callback = {
165 subtype : [`Hook_callback];
166 callback_id : string;
167 input : Jsont.json;
168 tool_use_id : string option;
169 unknown : Unknown.t;
170 }
171 (** Hook callback request. *)
172
173 type set_model = {
174 subtype : [`Set_model];
175 model : string;
176 unknown : Unknown.t;
177 }
178 (** Request to change the AI model. *)
179
180 type get_server_info = {
181 subtype : [`Get_server_info];
182 unknown : Unknown.t;
183 }
184 (** Request to get server information. *)
185
186 type t =
187 | Interrupt of interrupt
188 | Permission of permission
189 | Initialize of initialize
190 | Set_permission_mode of set_permission_mode
191 | Hook_callback of hook_callback
192 | Mcp_message of Mcp_message.request
193 | Set_model of set_model
194 | Get_server_info of get_server_info
195 (** The type of SDK control requests. *)
196
197 val interrupt : ?unknown:Unknown.t -> unit -> t
198 (** [interrupt ?unknown ()] creates an interrupt request. *)
199
200 val permission :
201 tool_name:string ->
202 input:Jsont.json ->
203 ?permission_suggestions:Permissions.Update.t list ->
204 ?blocked_path:string ->
205 ?unknown:Unknown.t ->
206 unit -> t
207 (** [permission ~tool_name ~input ?permission_suggestions ?blocked_path ?unknown ()]
208 creates a permission request. *)
209
210 val initialize : ?hooks:(string * Jsont.json) list -> ?unknown:Unknown.t -> unit -> t
211 (** [initialize ?hooks ?unknown ()] creates an initialize request. *)
212
213 val set_permission_mode : mode:Permissions.Mode.t -> ?unknown:Unknown.t -> unit -> t
214 (** [set_permission_mode ~mode ?unknown] creates a permission mode change request. *)
215
216 val hook_callback :
217 callback_id:string ->
218 input:Jsont.json ->
219 ?tool_use_id:string ->
220 ?unknown:Unknown.t ->
221 unit -> t
222 (** [hook_callback ~callback_id ~input ?tool_use_id ?unknown ()] creates a hook callback request. *)
223
224 val mcp_message : server_name:string -> message:Jsont.json -> ?unknown:Unknown.t -> unit -> t
225 (** [mcp_message ~server_name ~message ?unknown] creates an MCP message request. *)
226
227 val set_model : model:string -> ?unknown:Unknown.t -> unit -> t
228 (** [set_model ~model ?unknown] creates a model change request. *)
229
230 val get_server_info : ?unknown:Unknown.t -> unit -> t
231 (** [get_server_info ?unknown ()] creates a server info request. *)
232
233 val jsont : t Jsont.t
234 (** [jsont] is the jsont codec for requests. *)
235
236 val pp : Format.formatter -> t -> unit
237 (** [pp fmt t] pretty-prints the request. *)
238end
239
240(** {1 Response Types} *)
241
242module Response : sig
243 (** SDK control response types. *)
244
245 type success = {
246 subtype : [`Success];
247 request_id : string;
248 response : Jsont.json option;
249 unknown : Unknown.t;
250 }
251 (** Successful response. *)
252
253 type error = {
254 subtype : [`Error];
255 request_id : string;
256 error : string;
257 unknown : Unknown.t;
258 }
259 (** Error response. *)
260
261 type t =
262 | Success of success
263 | Error of error
264 (** The type of SDK control responses. *)
265
266 val success : request_id:string -> ?response:Jsont.json -> ?unknown:Unknown.t -> unit -> t
267 (** [success ~request_id ?response ?unknown ()] creates a success response. *)
268
269 val error : request_id:string -> error:string -> ?unknown:Unknown.t -> unit -> t
270 (** [error ~request_id ~error ?unknown] creates an error response. *)
271
272 val jsont : t Jsont.t
273 (** [jsont] is the jsont codec for responses. *)
274
275 val pp : Format.formatter -> t -> unit
276 (** [pp fmt t] pretty-prints the response. *)
277end
278
279(** {1 Control Messages} *)
280
281type control_request = {
282 type_ : [`Control_request];
283 request_id : string;
284 request : Request.t;
285 unknown : Unknown.t;
286}
287(** Control request message. *)
288
289type control_response = {
290 type_ : [`Control_response];
291 response : Response.t;
292 unknown : Unknown.t;
293}
294(** Control response message. *)
295
296val control_response_jsont : control_response Jsont.t
297(** [control_response_jsont] is the jsont codec for control response messages. *)
298
299type t =
300 | Request of control_request
301 | Response of control_response
302(** The type of SDK control messages. *)
303
304val create_request : request_id:string -> request:Request.t -> ?unknown:Unknown.t -> unit -> t
305(** [create_request ~request_id ~request ?unknown ()] creates a control request message. *)
306
307val create_response : response:Response.t -> ?unknown:Unknown.t -> unit -> t
308(** [create_response ~response ?unknown ()] creates a control response message. *)
309
310val jsont : t Jsont.t
311(** [jsont] is the jsont codec for control messages. *)
312
313val pp : Format.formatter -> t -> unit
314(** [pp fmt t] pretty-prints the control message. *)
315
316(** {1 Logging} *)
317
318val log_request : Request.t -> unit
319(** [log_request req] logs an SDK control request. *)
320
321val log_response : Response.t -> unit
322(** [log_response resp] logs an SDK control response. *)
323
324(** {1 Server Information}
325
326 Server information provides metadata about the Claude CLI server,
327 including version, capabilities, available commands, and output styles.
328
329 {2 Use Cases}
330
331 - Feature detection: Check if specific capabilities are available
332 - Version compatibility: Ensure minimum version requirements
333 - Debugging: Log server information for troubleshooting
334 - Dynamic adaptation: Adjust SDK behavior based on capabilities
335
336 {2 Example}
337
338 {[
339 let info = Client.get_server_info client in
340 Printf.printf "Claude CLI version: %s\n"
341 (Server_info.version info);
342
343 if List.mem "structured-output" (Server_info.capabilities info) then
344 Printf.printf "Structured output is supported\n"
345 else
346 Printf.printf "Structured output not available\n";
347 ]} *)
348
349module Server_info : sig
350 (** Server information and capabilities. *)
351
352 type t = {
353 version : string;
354 (** Server version string (e.g., "2.0.0") *)
355
356 capabilities : string list;
357 (** Available server capabilities (e.g., "hooks", "structured-output") *)
358
359 commands : string list;
360 (** Available CLI commands *)
361
362 output_styles : string list;
363 (** Supported output formats (e.g., "json", "stream-json") *)
364
365 unknown : Unknown.t;
366 (** Unknown fields for forward compatibility *)
367 }
368 (** Server metadata and capabilities.
369
370 This information is useful for feature detection and debugging. *)
371
372 val create :
373 version:string ->
374 capabilities:string list ->
375 commands:string list ->
376 output_styles:string list ->
377 ?unknown:Unknown.t ->
378 unit ->
379 t
380 (** [create ~version ~capabilities ~commands ~output_styles ?unknown ()] creates server info. *)
381
382 val version : t -> string
383 (** [version t] returns the server version. *)
384
385 val capabilities : t -> string list
386 (** [capabilities t] returns the server capabilities. *)
387
388 val commands : t -> string list
389 (** [commands t] returns available commands. *)
390
391 val output_styles : t -> string list
392 (** [output_styles t] returns available output styles. *)
393
394 val unknown : t -> Unknown.t
395 (** [unknown t] returns the unknown fields. *)
396
397 val jsont : t Jsont.t
398 (** [jsont] is the jsont codec for server info. *)
399
400 val pp : Format.formatter -> t -> unit
401 (** [pp fmt t] pretty-prints the server info. *)
402end