tiny.acp
Overview · API · Code relationships · Verification · Audit
Overview
A coding agent often runs as a separate program: the caller starts it, sends it a prompt, and reads back its progress and its reply. The package is a client for such agents: it runs the agent as a child process and exchanges messages with it over the child's standard input and output, one JSON message per line. A caller starts the agent, opens a session, sends prompts, and gets back the reply text and the reason the agent stopped. The line reader the client uses is also exported on its own, for any program that reads newline-separated messages from a pipe within a fixed memory budget.
The agent's process, and every process it starts, has to stop when the caller says so. Every message the agent sends has to be recorded exactly and in order before anything acts on it. Each request the agent makes to run a tool has to be answered by the caller's rules. Memory has to stay bounded whatever the agent sends.
The agent is another program: it can write a line of any length, send any number of progress messages, and stream a reply of any size. The agent starts programs of its own to run tools, and stopping the agent alone would leave those programs running. While a prompt is in flight, the agent's final response arrives after a stream of progress messages and requests of its own, and each one has to be handled in order before the response can be read. A record written after the client acts can fall behind what the agent saw: a permission answer sent first has already reached the agent when the recording of it fails.
The Agent Client Protocol (https://agentclientprotocol.com/) defines the messages. The client sends initialize, session/new, session/prompt and session/cancel, and it handles the agent's session/update notifications and session/request_permission requests. JSON-RPC 2.0 (https://www.jsonrpc.org/specification) supplies the message format: every message carries "jsonrpc":"2.0", each request carries a numeric id that its response repeats, and the client answers a request it does not handle with error code -32601, "method not found". The client speaks version 1 of the protocol, and its tests replay one message of each of the eleven kinds of session update that version defines.
The client owns the agent's process: it starts the agent in a process group of its own with standard error discarded. To cancel or tear down, the client signals the whole group to terminate and then to die, so the tools the agent started stop with it, and teardown also waits for the agent to exit.
The client runs one request at a time: each call writes its request and then handles the agent's messages until the matching response arrives.
Input is bounded by one buffer sized from the caller's line limit (ReaderLimits) and allocated before the agent starts. A line longer than that limit stops reading for good, before any JSON is parsed. The line limit bounds the reader's buffer alone: the JSON the client parses, the updates it builds and the reply it collects come from the caller's allocator. Traffic is bounded by caller limits (TransferLimits) on each outgoing message, each incoming update, the number of updates, and the size and chunk count of one prompt's reply, and a zero limit is refused. At a reply limit the client keeps what fit, records which update it left out, asks the agent to stop with one session/cancel, and still returns the agent's final response.
The client hands every message it acts on to a set of callbacks the caller supplies (an observer, Observer) and waits for each call to return before it goes on, so the caller records each message first. Each update the client passes on carries a nonzero number the caller picks for this client (a transport epoch), and the caller records each change of that number before it starts a client. The client also numbers the updates from 1 in arrival order (an update sequence) for its whole life, and passes on the exact line the agent sent with each one. A client with no observer fails with error.MissingDurableObserver at the first update or permission request. The observer may answer each permission request, and every decision reaches the observer before the answer reaches the agent. When the callbacks give no answer, the client checks two caller lists (a permission policy, PermissionPolicy), tool kinds and tool-title prefixes, and it rejects every request that neither list allows. The client tells the agent it offers no client capabilities, and it answers any other request from the agent with "method not found".
Definitions
Types and contracts
Public types and contracts.
Initialize: A caller uses this structure to learn which protocol version the agent speaks, which kinds of prompt block it accepts, and how it authenticates.Update: Onesession/updatenotification from the agent, with the two numbers the client gave it, the exact line, and fields read from it, received by the observer so the caller records and inspects the agent's progress.Modes: A caller uses this structure to learn which mode the session starts in, such asplanoract, and how many modes the agent offers.ClientInfo: A caller names the calling program to the agent, which reads these strings in the first message of the conversation.EnvVariable: A caller gives an MCP server its own environment, one variable at a time.McpServer: A caller gives the agent extra tools for the session, which the agent gets by starting the listed tool servers.Observer: The caller keeps the lasting record of the conversation and may answer permission requests itself, so the client calls out to it before it acts on each message.Options: A caller states in one value passed toClient.initwhich program to start and how, and what limits, numbering and callbacks the conversation runs under.Overflow: Records what a reply kept when one more chunk would have passed a limit, and which update the client left out, so the caller tells a cut reply from a whole one and sees where the reply stopped.OverflowKind: The reply limit a prompt reached.PermissionPolicy: A caller that trusts some tools lists them here, so the client grants those requests without asking the observer.PermissionReply: An observer that decides a permission request itself returns this value, so the client sends that decision to the agent.PromptBlobResource: A caller uses this structure to put a resource's content in the prompt as a blob string.PromptContent: A prompt is a list of these blocks, so a caller can mix text with files, links and media in one prompt.PromptMedia: A caller uses this structure to put an image or an audio clip in a prompt.PromptResourceLink: A caller uses this structure to point the agent at a resource by URI without putting its content in the prompt.PromptResult: The caller gets the reply with the reason the agent stopped and whether the reply was cut short becauseClient.promptDetailedandClient.promptDetailedContentreturn one of these results.PromptTextResource: A caller uses this structure to put a file's text in the prompt, such as source code the agent should read.TransferLimits: A caller caps what the client writes to the agent and what it keeps from the agent, because the agent is another program and can send without end.UpdateKind: The kind of one progress report (session update), read from the report'ssessionUpdatename, so the caller switches on the kind of each progress report the agent sends.ReaderCapacity: A caller learns the buffer size before any buffer exists, for example to set aside the reader's share of one larger region of memory.ReaderExhaustion: A caller uses this error to tell an overlong line apart from other failures.ReaderLimits: A caller chooses the longest line the reader must accept, so the reader's buffer size follows.ReaderPoll: A caller's read loop switches on this result to handle a line, read more input, or stop.ReaderStatus: A caller uses this snapshot to report how the reader is doing, or to explain why it stopped.ReaderStorage: A caller uses this type to read lines from a pipe or a file within a memory budget fixed in advance, as the client does with the agent's output.PermissionRequest: Onesession/request_permissionrequest from the agent: the tool call it names, the decision, and the exact line.Client: A caller owns a client for the life of one agent program, to send it prompts and get replies back.
Namespaces
Public namespaces.
protocol: Zig shapes for the Agent Client Protocol messages the client reads and writes: the agent's answer toinitialize, the session's modes, the blocks a prompt carries, the progress reports the agent sends, its permission requests, and the result of a prompt.reader: A reader splits a stream of bytes into lines at each newline, inside one buffer whose size the caller fixes in advance.client: The client side of one conversation with a coding agent: the options that start the agent, the callbacks and lists that let the caller watch and steer it, and the calls that run the conversation.
Values and defaults
Public values and defaults.
default_reader_limits: A line limit of 2 MiB (2 1024 1024 bytes) for callers with no size of their own.
Code relationships
Direct static dependencies extracted from parsed source by semantic graph analysis.
Uses: tiny.pluck, tiny.smg, tiny.sys
Used by: None
Verification
No verification records are cataloged for this module in this build.
Audit
| Evidence | Value |
|---|---|
| Source | lib/acp/src/root.zig |
| Definitions | 32 of 32 documented |
| Members | 0 of 0 documented |
| Public names | 32 API, 127 indexed |
| Version | 26.7.0 |
| Revision | daab053ee433 |