Expand description
The first-party Agent Client Protocol (ACP) adapter for Aion.
This crate implements the aion-integrations AgentHarness / AgentSession seam against
any agent that speaks ACP over its stdio. Where
aion-integration-norn adapts one specific harness and aion-integration-cli adapts the
observability-only tier, this one adapts a protocol: a single implementation reaches every
agent that has an ACP mode — Claude Code, Codex, Gemini CLI, OpenCode, and whatever ships next.
§The invariant this crate exists to preserve
The aion platform crates (aion-core, aion-worker, aion-server, …) stay ACP-blind:
everything ACP-specific — the method namespace, the session/update shapes, the permission
handshake — is confined to protocol, translate, and messages here, behind the neutral
trait. Nothing above this adapter references an ACP type.
§Shape
AcpHarnessimplementsAgentHarness:AgentHarness::startspawns the configured agent command with piped stdio (stderr inherited), performs theinitializehandshake gating on ACP protocol version1, creates a session withsession/new, issues the one long-runningsession/promptrequest carrying the spec’s input as atextcontent block, and returns anAcpSession.AcpSessionimplementsAgentSession:AgentSession::eventsstreams translatedaion_core::ActivityEvents and ends the moment the turn is answered,AgentSession::capabilitiesreturns the negotiated set,AgentSession::intervenemaps a neutral command onto real ACP (capability-gated), andAgentSession::wait_resultinterprets the id-matchedsession/promptResponse as the terminalaion_core::Payloadand then shuts the agent process down.protocolnames the wire contract,translateis the pure translation between it and the neutral types,messagesreassembles the streamed message text, andpermissionis the required policy for answeringsession/request_permission.
§Four rulings worth knowing before you use it
Cancelis the only intervention primitive advertised. It is the only one ACP v1 can actually deliver; the other four have no protocol mechanism, and advertising a control that silently does nothing would be worse than advertising none. A live session gates ontranslate::negotiated_capabilities; a composition root advertising this adapter at worker REGISTRATION — before any agent process exists — publishes the same ceiling throughregistration_capabilities, which is documented with why the two coincide for ACP and pinned against whattranslate::intervention_to_notificationcan actually build.- The permission policy is required, with no default. An unanswered
session/request_permissionblocks the agent until the activity times out, and an Aion activity is unattended, so the answer is decided when the harness is built. Seepermission. - No filesystem or terminal callbacks are offered. Those exist for editors with unsaved
buffers and embedded panels; a worker has neither, and the agent has direct disk access. An
inbound
fs/*orterminal/*request is still ANSWERED (with-32601) and recorded, because an unanswered peer request wedges the run. Seeprotocol. - The event stream ending is the end-of-run signal, and it does not wait for the process.
A real ACP agent is a persistent stdio server: it answers
session/promptand keeps running. The platform’s agent driver takes the terminal result only once the event stream yieldsNone, so the adapter closes the transcript at the answer rather than at the child’s exit. Seepump.
§Two limitations to read before you rely on this
- The session working directory is per-HARNESS, not per-attempt. Two agent activities running
concurrently through one
AcpHarnessshare a workspace root and can overwrite each other’s files. Per-attempt workspace provisioning is a separate design; seeharnessfor the full statement and why nothing is invented here. - A completed turn may legitimately carry no text. An agent that ends
end_turnhaving emitted only tool calls yields a SUCCESSFUL result whosetextis"". That is honest, not a bug: the agent finished and said nothing, and its work is on the transcript as tool events. Seeoutcome.
§Wire types
The ACP request/response/notification types come from the published
agent-client-protocol-schema crate, pinned
exactly. That is deliberate: a hand-written mirror of a moving external protocol is a fossil
waiting to happen, and a protocol bump should be a compile error rather than a silent wire
mismatch. Only the schema is taken — not the full agent-client-protocol SDK, which carries its
own async stack and would drag a second runtime into this tokio codebase.
Re-exports§
pub use catalogue::CATALOGUE;pub use catalogue::CatalogueHarness;pub use containment::ProcessGroup;pub use harness::AcpHarness;pub use harness::registration_capabilities;pub use mcp::McpServerSpec;pub use outcome::PromptOutcome;pub use permission::PermissionPolicy;pub use session::AcpConfigValue;pub use session::AcpSession;pub use session::TurnHandle;
Modules§
- catalogue
- The agents this build knows how to launch, as data — id, launch line, install hint. The harness catalogue: which ACP agents this build knows how to launch.
- containment
- Process-group containment for a spawned agent, so a session takes its whole tree with it. Process-group containment for a spawned ACP agent.
- harness
- The ACP adapter implementing
aion_integrations::AgentHarness.AcpHarness— theAgentHarnessimplementation that drives any ACP agent subprocess. - mcp
- The MCP servers an agent is handed when a session opens.
The MCP servers this adapter hands an agent on
session/newandsession/load. - messages
- Reassembly of ACP’s per-chunk message stream into durable messages and the run’s final text.
The streamed-message accumulator: turns ACP’s per-chunk
session/updatestreams into a transcript that is both live and durable, and into the run’s final text. - outcome
- Interpretation of the terminal
session/promptResponse as the activity’s result. Interpretation of the terminalsession/promptResponse as the activity’s result. - permission
- The required policy for answering
session/request_permission. The permission policy anAcpHarnessmust be constructed with — how this adapter answerssession/request_permission. - protocol
- ACP’s on-wire contract — the ONLY module naming its method strings and protocol version. The Agent Client Protocol wire contract — the ONLY module naming ACP’s method strings, its protocol version, and the client capabilities this adapter advertises.
- pump
- The reader pump that handles every inbound frame for a live session. The reader pump: the one task that owns the connection’s reader and handles every inbound frame.
- session
- The live ACP session implementing
aion_integrations::AgentSession.AcpSession— a live ACP prompt turn behind theAgentSessionseam. - translate
- The pure translation between ACP’s wire shapes and the neutral
aion-coretypes. The translation point — the single place ACP’s native shapes meet the neutralaion-coretypes.