Modules
Elixir/OTP implementation of ACP (Agent Client Protocol) — the JSON-RPC 2.0 protocol spoken between code editors ("clients") and AI coding agents ("agents"). See https://agentclientprotocol.com.
use Raxol.AgentClientProtocol.Agent to implement the agent side of
ACP: the process that answers initialize, creates/loads sessions, and
serves session/prompt turns.
The negotiated-capability PREDICATE: given a Connection's snapshotted
capability tree, decide whether a wire method is negotiated and therefore
permitted.
use Raxol.AgentClientProtocol.Client to implement the client side of
ACP: the editor/host process that answers permission asks, filesystem, and
terminal requests, and receives session/update streaming notifications.
Confines fs/read_text_file / fs/write_text_file handling to a sandbox
directory -- backs use Raxol.AgentClientProtocol.Client, fs_sandbox: path (see that module's moduledoc for the option). Not a general-purpose
path library: it exists solely to give a minimal client a working
filesystem story out of the box.
ONE GenServer per peer link, either role — the correlation + dispatch brain of ACP.
Per-dispatch handler context.
Per-session open-turn state, populated only on a client-role Connection.
Ergonomic DX layer for agent handler code running inside session/prompt
turn tasks (the functions a turn_runner closure or one of its subagent
tasks actually calls). This module introduces no new runtime semantics:
every function here is a thin, documented wrapper over
Raxol.AgentClientProtocol.Connection.request/4 (the agent->client
filesystem/terminal/permission requests) or
Raxol.AgentClientProtocol.Session.post_update/2 /
Session.request_permission/2 (the Session-owned turn primitives).
Delivery vocabulary shared by Connection (stamping + direct turn
delivery) and Client (turn consumption).
JSON-RPC 2.0 error object, plus the ACP-specific vendor error codes.
Fail-closed attach admission behaviour.
The BEAM-local :authorize bridge — make an in-process attach seam defer
to the SAME fail-closed admission funnel (Ext.AttachPolicy.Runner) the
untrusted ACP boundary uses.
A successful attach grant.
The DEFAULT deny-by-default attach policy.
THE single fail-closed admission funnel. There is exactly ONE funnel:
authorize/2. No second try/catch wrapper exists anywhere — a second funnel
with weaker timeout/crash semantics would be a dual-ownership hole.
The capability-token attach policy.
The signing side. Mints RXC1 tokens.
Verifier-side keyring load + validation.
The RXC1 capability token — offline-verifiable detached Ed25519 signature.
The durable session journal — behaviour + live-bus registration facade.
ETS-backed in-memory journal — an implementation of
Raxol.AgentClientProtocol.Ext.Journal bound by its OFFSET LAW.
One grow-only journal record.
ONE GenServer per session_id — the SINGLE PUBLISHER of a session's live
tail.
The register-before-h attach seam — the correctness core of the reattach
extension.
Wire schema structs for the reattach extension's _raxol/* notification
vocabulary.
_raxol/session.caught_up: the history→live boundary UX signal (offset = h+1). OPTIONAL, non-load-bearing.
_raxol/session.closed: terminate an ALREADY-REGISTERED subscriber mid-stream. reason is a grow-only string set.
_raxol/session.detach: client→agent voluntary unsubscribe. Idempotent.
_raxol/session.lagged: terminal drop-on-lag. lastOffset is the subscriber's own last forwarded offset; heal by reattaching from lastOffset + 1.
_raxol/session.record: the generic, self-describing delivery frame
for every record kind OTHER than session_update (turn_started,
turn_completed, session_created, and any kind added later). New record
kinds require NO new method rows — readers skip-unknown-kind as a fold.
_raxol/session.steer request: redirect a running turn with
new user input WITHOUT killing it, addressed by sessionId. A steer is the
sibling of interrupt (kill-now); it injects at the next turn boundary.
_raxol/session.steer response: the synchronous, honest CAS
outcome — the full vocabulary a Surface banner renders.
Single source of truth for the ACP method vocabulary: every wire method
string, its direction, its JSON-RPC kind, the callback atom used for both
the behaviour @callback and the Router dispatch clause, its
param/result schema modules, its capability gate, and its layer.
Table-driven JSON-RPC method routing for ACP: decode/4 classifies and
type-decodes an inbound wire method + params into a tagged tuple,
dispatch/4 calls the matching handler callback, and result_marker/1
tells the sending side how to decode a pending outbound request's
response.
JSON-RPC 2.0 primitives for the Agent Client Protocol.
Wraps a Request, Notification, or Response with the required
"jsonrpc": "2.0" field, and decodes a raw wire frame into whichever of
the three it turns out to be.
JSON-RPC 2.0 Notification object: method + optional params, no id,
no response expected.
JSON-RPC 2.0 Request object (id + method + optional params).
JSON-RPC request id: null | integer | string. Wire type is preserved
exactly (no coercion between string and integer ids).
JSON-RPC 2.0 Response object: either a result or an error, represented as
a tagged tuple {:result, id, result} | {:error, id, error} rather than
a struct (a Response is a discriminated union at the wire level, and the
two shapes are mutually exclusive per spec).
Agent-side types for the Agent Client Protocol: the initialize/
authenticate handshake, session lifecycle (session/new, session/load,
session/set_mode, session/prompt, session/cancel), capability
negotiation, and MCP server descriptors.
Authentication-related capabilities supported by the agent: currently
just the optional logout leaf. Not in f1729; ported from the pinned
oracle schema $defs/AgentAuthCapabilities.
Capabilities declared by the agent in the initialize response.
Tagged union of every response the agent may send back to the client.
A method by which a client may authenticate with an agent.
The authenticate request, sent by the client with the chosen auth method id.
The (empty, besides _meta) response to authenticate.
The session/cancel notification.
Tagged union of every notification the client may send to the agent, used for JSON-RPC method-name routing.
Tagged union of every request the client may send to the agent, used for JSON-RPC method-name routing.
A single name=value environment variable for a stdio-launched MCP server.
A single HTTP header for an HTTP/SSE MCP server.
Identifies an agent or client implementation (name, version, optional title).
The initialize request, sent by the client to negotiate protocol version
and capabilities.
The initialize response, sent by the agent with its capabilities and
supported authentication methods.
The session/load request: replays an existing session's history.
The session/load response: optional mode/model/config-option state.
Capability flag for logout: agent supports the logout method. Not in
f1729; ported from the pinned oracle schema $defs/LogoutCapabilities.
MCP transports the agent supports for client-provided MCP servers.
A client-provided MCP server descriptor: tagged union of http, sse
(both discriminated by a "type" wire field), and the untagged stdio
fallback.
A streamable-HTTP MCP server descriptor.
An SSE MCP server descriptor.
A stdio-launched MCP server descriptor (the untagged wire variant: no
"type" field).
The session/new request: creates a new session rooted at cwd, optionally
wiring up MCP servers.
The session/new response: the new session id plus optional mode/model/
config-option state (the latter two are unstable extensions).
Content-block kinds the agent accepts in a session/prompt.
The session/prompt request: a turn's content blocks sent to the agent.
The session/prompt response: why the turn ended.
Session-lifecycle capabilities the agent supports, including the unstable
list/fork/resume extensions.
Capability flag for session/close: agent supports closing sessions.
Not in f1729; ported from the pinned oracle schema
$defs/SessionCloseCapabilities.
Capability flag for session/delete: agent supports deleting sessions
from session/list. Not in f1729; ported from the pinned oracle schema
$defs/SessionDeleteCapabilities.
A single selectable session mode (e.g. "code", "ask").
The set of available session modes and the one currently active.
The session/set_mode request.
The (empty, besides _meta) response to session/set_mode.
Why a session/prompt turn ended.
Optional annotations for the client (audience, priority, last-modified).
Every field is optional and decode-lenient: a malformed value defaults to
absent rather than failing the whole Annotations.
Audio provided to or from an LLM.
A single command the agent can execute, as advertised via
AvailableCommandsUpdate.
Input specification for an AvailableCommand: an untagged union with a
single documented variant, unstructured (free text typed after the
command name). Per package convention, tagged-tuple unions don't get a
Jason.Encoder impl of their own.
Payload for the SessionUpdate available_commands_update variant: the
set of commands the agent can execute has changed. available_commands
is decode-lenient, matching the oracle schema's
x-deserialize-default-on-error + x-deserialize-skip-invalid-items: a
missing/wrong-typed list defaults to [], and items that individually
fail to decode are skipped rather than aborting the whole update.
Binary resource contents.
Enum of all possible agent->client requests, with their wire method names.
Capabilities declared by the client at initialize.
Request to create a new terminal and execute a command (terminal/create).
Response containing the ID of the newly created terminal.
File-system capabilities supported by the client.
Request to kill a terminal command without releasing the terminal
(terminal/kill).
Response to terminal/kill. Carries no data of its own.
An option presented to the user when the agent requests permission for a tool call.
Hint about the nature of a PermissionOption, so clients can choose
appropriate icons/UI treatment.
Request to read content from a text file (fs/read_text_file). Only sent
if the client declared the fs.readTextFile capability.
Response containing the contents of a text file.
Request to release a terminal and free its resources (terminal/release).
Response to terminal/release. Carries no data of its own.
The outcome of a permission request: either the prompt turn was cancelled
before the user responded, or the user selected one of the offered
options. Tagged by the outcome discriminator field on the wire (not a
struct in its own right -- see SelectedPermissionOutcome for the
_meta-carrying payload of the :selected variant).
Request from the agent asking the client for permission to perform a tool call, sent before a sensitive operation.
Response to a session/request_permission request, carrying the user's
decision.
A RequestPermissionOutcome variant: the user selected one of the
offered options.
Exit status of a terminal command: an exit code (normal exit) and/or a signal name (killed by signal), independently nullable per the schema-oracle.
Request to get the current output and status of a terminal
(terminal/output).
Response containing the terminal output captured so far, and its exit status if the command has completed.
Request to wait for a terminal command to exit (terminal/wait_for_exit).
Response containing the exit status of a terminal command.
Request to write content to a text file (fs/write_text_file). Only sent
if the client declared the fs.writeTextFile capability.
Response to fs/write_text_file. Carries no data of its own.
Content blocks represent displayable information in ACP: a tagged union
discriminated by a "type" wire key (text | image | audio |
resource_link | resource). Named ContentBlock both upstream and
here (all other structs ported from content.ex -- Role, Annotations,
TextContent, ImageContent, AudioContent, TextResourceContents,
BlobResourceContents, EmbeddedResourceResource, EmbeddedResource,
ResourceLink -- are separate, bare Schema.* modules, not nested under
this one).
A single streamed content block, used as the payload for the
SessionUpdate user_message_chunk/agent_message_chunk/
agent_thought_chunk variants.
Cumulative session cost information -- the optional cost field of
UsageUpdate.
Payload for the SessionUpdate current_mode_update variant: the
session's active mode has changed.
A diff representing file modifications.
The contents of a resource, embedded into a prompt or tool call result.
Resource content that can be embedded in a message (untagged union,
discriminated by the presence of a "text" or "blob" wire key).
Extension types for ACP protocol extensibility.
An arbitrary _-prefixed extension notification, not part of the core
ACP spec. No reply is expected.
An arbitrary _-prefixed extension request, not part of the core ACP
spec. Carries the raw JSON-RPC method name and already-decoded params.
The reply to an ExtRequest.
An image provided to or from an LLM.
Minimal, oracle-derived param/result structs for v1.19.0 ACP methods that
had no home in the ported f1729 Schema.* layer: session/close,
session/delete, logout, session/update (the notification envelope),
and the protocol-level $/cancel_request.
The protocol-level $/cancel_request notification: {requestId, _meta},
where requestId is a JSON-RPC request id (null | integer | string,
see Raxol.AgentClientProtocol.Rpc.RequestId). Oracle-derived
(schema.json CancelRequestNotification); not a port of any upstream
f1729 module (f1729 has no $/cancel_request support).
Request parameters for session/close: closes an active session, best-
effort cancelling any in-flight work first. Oracle-derived (schema.json
CloseSessionRequest); not a port of any upstream f1729 module.
The (empty, besides _meta) response to session/close. Oracle-derived
(schema.json CloseSessionResponse).
Request parameters for session/delete: deletes an existing session from
session/list. Oracle-derived (schema.json DeleteSessionRequest); not a
port of any upstream f1729 module.
The (empty, besides _meta) response to session/delete. Oracle-derived
(schema.json DeleteSessionResponse).
The (empty, besides _meta) response to logout. Oracle-derived
(schema.json LogoutResponse). See the module doc above for why there is
no sibling LogoutRequest in this file.
The session/update notification envelope: {sessionId, update, _meta},
where update is the Raxol.AgentClientProtocol.Schema.SessionUpdate
discriminated union (ported separately, session_update.ex).
Oracle-derived (schema.json SessionNotification); not a port of any
upstream f1729 module — upstream's ACP.SessionNotification envelope was
explicitly left unported by agent_types.ex's and session_update.ex's
own moduledocs pending whoever wired the routing union it belongs to.
A three-state value type: :undefined, nil (null), or {:value, term}.
An execution plan for accomplishing complex tasks: an ordered list of
PlanEntry structs. Per the ACP schema, entries is decode-lenient
at both levels: a missing/wrong-typed entries field defaults to []
(never fails the whole plan), and entries that individually fail to
decode are skipped rather than aborting the list
(x-deserialize-skip-invalid-items).
A single entry in the execution plan. content, priority, and status
are all required per the ACP schema (no x-deserialize-default-on-error
leniency for this struct's own fields) -- a malformed value for any of
them fails the whole entry's decode; the caller (Plan.from_json/1) skips
entries that fail to decode rather than failing the whole plan.
A resource that the server is capable of reading.
The sender or recipient of messages and data in a conversation.
The session/update notification's sessionUpdate-discriminated union:
real-time feedback the agent streams back to the client during a prompt
turn (message/thought chunks, tool call lifecycle, the execution plan,
available-command changes, mode changes, and the unstable config-option/
session-info updates).
Text provided to or from an LLM.
Text-based resource contents.
Represents a tool call that the language model has requested. Every other
type ported from tool_call.ex (ToolKind, ToolCallStatus,
ToolCallLocation, Diff, ToolCallTerminal, ToolCallContentWrapper,
ToolCallContent, ToolCallUpdateFields, ToolCallUpdate) is a separate,
bare Schema.* module, not nested under this one.
Content produced by a tool call: a tagged union discriminated by a
"type" wire key (content | diff | terminal).
Standard content block wrapper for tool call content (the "content"
variant of ToolCallContent; named Content in the official schema, but
kept as ToolCallContentWrapper here to avoid colliding with
Schema.ContentBlock, the tagged-union content block type).
A file location being accessed or modified by a tool.
Execution status of a tool call. Every place this enum is used in the ACP
schema (ToolCall.status, ToolCallUpdateFields.status) carries
x-deserialize-default-on-error: true, so -- like ToolKind -- decode is
total and infallible: an unrecognized wire value falls back to the
documented default, :pending, rather than failing the enclosing object.
Embeds a terminal created with terminal/create, by its id.
An update to an existing tool call. ToolCallUpdateFields is flattened
into the same wire object as toolCallId and _meta (a "serde flatten"),
not nested under its own key.
Optional fields that can be updated in a tool call. Every field is
optional and decode-lenient per the ACP schema
(x-deserialize-default-on-error, plus x-deserialize-skip-invalid-items
on the two list fields) -- decode of this struct never fails for a map
input. Flattened directly into ToolCallUpdate's wire object (no nested
"_meta" of its own; unrecognized fields fold into the parent's _meta).
Categories of tools that can be invoked. An open enum: the ACP schema
documents "other" as its explicit default, so an unrecognized wire
value decodes to :other rather than failing (no String.to_atom/1 is
ever used -- every value is an explicit, whitelisted clause).
Unstable ACP types that are not yet part of the stable protocol surface —
the Elixir counterpart of the Rust reference implementation's
#[cfg(feature = "unstable_*")]-gated types: session model selection
(session/set_model), generic session config options
(session/set_config_option), session fork/resume/list
(session/fork, session/resume, session/list), and their capability
flags. These may be removed or changed at any point; callers should gate
their use on the corresponding Raxol.AgentClientProtocol.Schema.AgentTypes. SessionCapabilities fields (:list, :fork, :resume) rather than
assuming availability.
Payload for the session/update notification's config_option_update
variant: session configuration options have been updated. The variant
wiring itself lives in SessionUpdate (ported from client_types.ex, not
this file). (Unstable)
Request to fork an existing session (session/fork). (Unstable)
Response from forking a session: the new session id plus optional mode/model/config-option state. (Unstable)
Request to list existing sessions (session/list). (Unstable)
Response from listing sessions. (Unstable)
Information about a selectable model. (Unstable)
Request to resume an existing session without replaying its history
(session/resume). (Unstable)
Response from resuming a session: optional mode/model/config-option state. (Unstable)
Type-specific session configuration option payload: a tagged union by the
wire "type" field. Currently only :select is defined by the spec.
(Unstable)
A session configuration option selector and its current state. The
kind-specific payload (currently only select) is flattened directly
into this struct's top-level wire object alongside id/name/etc.
(Unstable)
Semantic category for a session configuration option. (Unstable)
A single-value selector (dropdown) session configuration option payload. (Unstable)
A named group of SessionConfigSelectOptions. (Unstable)
A possible value for a select-kind session configuration option.
(Unstable)
Possible values for a select-kind session configuration option: an
untagged union of either a flat list of options ({:ungrouped, [...]}) or
a list of groups ({:grouped, [...]}), distinguished on decode by whether
the first list element has a "group" key. (Unstable)
Capability flag for session/fork. (Unstable)
Information about a session returned by session/list. (Unstable)
Payload for the session/update notification's session_info_update
variant: a partial update to session metadata. The variant wiring itself
lives in SessionUpdate (ported from client_types.ex, not this file).
Capability flag for session/list. (Unstable)
The set of selectable models and the one currently active. (Unstable)
Capability flag for session/resume. (Unstable)
Request to set a session configuration option value
(session/set_config_option). (Unstable)
Response to session/set_config_option: the full, refreshed set of config
options. (Unstable)
Request to set the active model for a session (session/set_model).
(Unstable)
The (empty, besides _meta) response to session/set_model. (Unstable)
Unstructured command input: raw free text typed after the command name,
as a hint for what's expected.
Payload for the SessionUpdate usage_update variant: a context-window
and cost update for a session -- tokens currently in context (used),
the total context window size (size), and an optional cumulative
session cost.
Protocol version identifier for ACP (protocolVersion on the wire).
One GenServer per session_id: the ACP turn state machine.
The Session emit seam — one injection point through which every
session/update and every turn boundary flows.
The DEFAULT emitter. emit/2 forwards a session/update to
Connection.notify on the same FIFO lane as the eventual prompt reply; the
turn-boundary hooks are no-ops (it keeps no durable journal). Selecting this
emitter (or omitting :emitter) means the reattach extension is OFF.
The durable emitter — reroutes updates and turn boundaries through the
single-publisher Writer (Ext.Journal.Writer) so the session's durable,
offset-addressed journal is FILLED by live turns, and every attached
reattacher replays it.
The Session's steer seam — the one injection point through which a live turn's compare-and-swap steer decision is driven.
The DEFAULT steer adapter — refuses. With no injected :steer_adapter, the
turn hooks are the identity function (they never touch steer_state, which
stays nil), and resolve/2 answers {:error, :no_steer_channel} — an
honest refusal: no live steering owner is wired.
The per-connection DynamicSupervisor for Raxol.AgentClientProtocol.Session
processes.
Ephemeral per-turn state, held by a Raxol.AgentClientProtocol.Session only
while a session/prompt turn is in flight. outcome is written once by the
root leg; the cancel leg overwrites it.
The classified registry of every :telemetry event this package emits.
Behaviour for pluggable ACP message carriers.
A pure, process-free sequencing envelope for unordered-carrier
transports (no shipped transport uses it; see
Raxol.AgentClientProtocol.Transport.Reassembly for the receive-side
counterpart).
A pure, process-free NDJSON (newline-delimited JSON) line framer.
An in-process, zero-copy pair of Raxol.AgentClientProtocol.Transport
handles. This is the test backbone for the rest of the library and the
BEAM-local wiring for an agent/client pair that live in the same VM.
A pure, process-free reorder buffer for unordered-carrier transports
(pairs with Raxol.AgentClientProtocol.Transport.Envelope on the send
side; no shipped transport uses it).
Newline-delimited JSON (NDJSON) over a stdio pipe — either our OWN
process's real stdin/stdout (:self mode, when this BEAM process IS the
ACP agent/client speaking on its own stdio), or a spawned peer command's
stdio (:spawn mode, when we launch and speak to a subprocess).
The package OTP application — the single shared supervision tree that the per-connection subtrees and the reattach extension depend on.
Mix Tasks
Recomputes the SHA256 of the vendored ACP (Agent Client Protocol) schema
oracle files under priv/schema-oracle/v1/ and compares them against the
hashes recorded at pin time (see priv/schema-oracle/PINNED.md).