| name | support-acp |
| description | Guide for building external clients (IDE plugins, agents) that integrate with RARA via the Agent Client Protocol (ACP). Use when adding ACP support to an external system, debugging ACP transport issues, or extending RARA's control plane for new protocol clients. |
Support ACP โ RARA Agent Client Protocol Integration
Use this skill when integrating an external system with RARA over the Agent Client Protocol
(ACP) via stdio transport, or
when extending RARA's control-plane surface for new protocol adapters.
Goals
- Provide a complete, working reference for ACP clients connecting to RARA.
- Document the control-plane protocol that external clients use to manage sessions, submit
prompts, register sources, and subscribe to events.
- Cover event translation, provenance, and trust boundaries.
Architecture Overview
RARA implements ACP through these modules:
src/acp.rs โ ACP agent impl (stdio transport, session create/prompt)
src/acp_consumer.rs โ subscribes to RuntimeEventBus, translates AgentEvent โ SessionNotification
src/control_plane.rs โ routes RuntimeControlEnvelope โ domain handlers
src/runtime_control.rs โ full control-plane type system (requests, events, provenance)
src/runtime_event_bus.rs โ event bus with raw (AgentEvent) and structured (RuntimeControlEvent) channels
src/protocol_sources.rs โ protocol-registered prompt/skill/memory sources
Runtime Architecture
External Client (stdio)
โ
โผ
acp.rs โโโโโโโบ RuntimeEventBus (send AgentEvent) โโโบ agent loop
โฒ โ
โ โผ
โ acp_consumer.rs (subscribe_control)
โ โ
โ โผ
โโโโโโโโโ SessionNotification (AgentEvent translated)
The control-plane channel (subscribe_control) carries structured RuntimeControlEvent values and
RuntimeEvent values for protocol-native events (MCP, hooks, etc.).
1. Transport
RARA starts ACP in stdio mode:
rara acp
The protocol uses the agent-client-protocol crate (version 0.11, feature unstable) over
stdin/stdout with JSON-RPC framing.
Clients spawn rara acp as a child process and communicate over its stdin/stdout.
2. Session Lifecycle
2.1 Create a Session
Send session/create with an optional cwd and session_id:
{
"method": "session/create",
"params": {
"cwd": "/path/to/project",
"session_id": "optional-session-id"
}
}
RARA responds with a session/created notification containing the session context (provider,
model, working directory, bash approval policy).
2.2 Resume a Session
{
"method": "session/resume",
"params": {
"session_id": "existing-session-id"
}
}
2.3 Cancel / Interrupt
Cancel the current turn or interrupt an in-progress operation:
control plane request: SessionControlRequest::CancelCurrentTurn
control plane request: SessionControlRequest::InterruptCurrentTurn
3. Prompt Submission
Send a user prompt via session/prompt:
{
"method": "session/prompt",
"params": {
"prompt": "user message text"
}
}
This translates to an AgentEvent::UserMessage pushed through the event bus.
4. Event Translation
The acp_consumer.rs subscribes to the structured control bus and translates AgentEvent
variants into ACP SessionNotification values:
| AgentEvent | SessionNotification | Notes |
|---|
AgentEvent::AssistantMessage | assistant/message | Streaming text is flushed on turn boundary |
AgentEvent::ToolCall | tool/progress | Tool name, args, status sent as tool progress |
AgentEvent::ThinkingDelta | assistant/thinking | Thinking/reasoning content sent separately |
AgentEvent::PlanStep | plan/step | Plan step updates |
AgentEvent::PlanApprovalNeeded | plan/approval_needed | Blocking approval request |
AgentEvent::ShellApprovalNeeded | approval/shell | Bash command approval |
AgentEvent::GoalStatus | goal/status | Goal progress |
AgentEvent::Warning | warning | Runtime warnings |
AgentEvent::Error | error | Runtime errors |
Tool Events
Tool lifecycle events are published as structured ToolEvent values:
ToolEvent::Started โ tool invocation begins
ToolEvent::Progress โ incremental output (e.g. streaming shell output)
ToolEvent::Completed โ tool finished (contains ToolResult)
ToolEvent::Errored โ tool invocation failed
Tool output streams are tagged with ToolStream variants: Stdout, Stderr, System.
5. Control Plane Protocol
External clients that need deeper integration can use the control-plane request/event protocol
via the structured bus.
5.1 RuntimeControlEnvelope
All control-plane requests are wrapped in a RuntimeControlEnvelope:
struct RuntimeControlEnvelope {
request_id: String,
provenance: RuntimeProvenance,
request: RuntimeControlRequest,
}
5.2 Provenance and Trust
struct RuntimeProvenance {
controller: RuntimeControllerKind,
adapter: Option<String>,
session_id: Option<String>,
source_id: Option<String>,
trust: RuntimeSourceTrust,
authorship: RuntimeSourceAuthorship,
}
ACP adapters connect as RuntimeControllerKind::Acp with RuntimeSourceTrust::Untrusted.
Trust elevation for specific operations is handled through the approval flow.
5.3 Request Categories
RuntimeControlRequest
โโโ Session(SessionControlRequest) โ create, resume, cancel, interrupt, query
โโโ Input(InputControlRequest) โ submit prompt, answer pending input,
โ answer plan approval, answer shell approval
โโโ Output(OutputSubscriptionRequest) โ subscribe/unsubscribe to output stream
โโโ PromptSource(PromptSourceControlRequest) โ register/unregister prompt sources
โโโ SkillSource(SkillSourceControlRequest) โ register skill roots/skills
โโโ Mcp(McpControlRequest) โ query status, refresh, reconnect
โโโ Memory(MemoryControlRequest) โ add/update/delete records, list labels
โโโ Hook(HookControlRequest) โ hook lifecycle management
โโโ Approval(ApprovalControlRequest) โ approval policy management
5.4 Event Categories
RuntimeEvent
โโโ Session(SessionEvent) โ session created, resumed, ended
โโโ Input(InputEvent) โ prompt received, input answered, follow-up received
โโโ Assistant(AssistantEvent) โ assistant message, thinking, plan steps
โโโ Tool(ToolEvent) โ tool started, progress, completed, errored
โโโ Approval(ApprovalEvent) โ shell approval requested/answered
โโโ Plan(PlanEvent) โ plan explanation, steps, completed
โโโ PromptSource(PromptSourceEvent) โ registered, unregistered
โโโ Skill(SkillEvent) โ skill registered, loaded, disabled
โโโ Mcp(McpEvent) โ mcp status changed
โโโ Memory(MemoryEvent) โ memory created, updated, deleted
โโโ Hook(HookEvent) โ hook lifecycle
โโโ Context(ContextEvent) โ context observability, budget updates
โโโ Todo(TodoEvent) โ todo list changes
โโโ Warning(WarningEvent) โ runtime warnings
โโโ Error(ErrorEvent) โ runtime errors
6. Protocol-Registered Sources
External clients can register prompt sources, skill sources, and memory records through the
control plane. These sources participate in normal precedence resolution alongside local sources.
6.1 Prompt Sources
PromptSourceControlRequest::Register(PromptSourceRegistration {
source_id: String,
scope: SourceScope,
layer: SourceLayer,
budget_hint_tokens: Option<u32>,
lifetime: PromptSourceLifetime,
content: String,
})
- Turn-limited sources are automatically expired after the specified number of turns.
- Session sources expire when the session ends.
- Persistent sources need explicit unregistration.
6.2 Skill Sources
SkillSourceControlRequest::RegisterSkill {
source_id: String,
name: String,
content: String,
precedence_hint: Option<i32>,
}
Protocol-registered skills can shadow or extend local skills based on precedence.
6.3 Memory Records
MemoryControlRequest::AddRecord {
memory_id: String,
scope: MemoryScope,
content: String,
metadata: Value,
}
Protocol-registered memory records participate in normal memory retrieval and selection.
7. Output Subscription
External clients subscribe to the output stream to receive structured events:
OutputSubscriptionRequest::Subscribe { subscriber_id }
OutputSubscriptionRequest::Unsubscribe { subscriber_id }
Subscribed clients receive all RuntimeEvent values published through the control bus.
8. Implementation Reference: Building an ACP Client
8.1 Spawn RARA
use std::process::{Command, Stdio};
let mut child = Command::new("rara")
.arg("acp")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::inherit())
.spawn()?;
8.2 Create a Session
Write JSON-RPC to stdin:
{"jsonrpc":"2.0","id":1,"method":"session/create","params":{"cwd":"/path/to/project"}}
Read the session/created notification from stdout.
8.3 Send a Prompt
{"jsonrpc":"2.0","id":2,"method":"session/prompt","params":{"prompt":"Explain this code"}}
8.4 Handle Events
Read SessionNotification values from stdout as JSON-RPC notifications:
{"jsonrpc":"2.0","method":"notifications/send","params":{"sessionNotification":"assistant/message","message":"..."}}
8.5 Approve a Plan
When the agent enters planning mode:
- Receive
plan/approval_needed
- Send approval or rejection through the input control path:
{"jsonrpc":"2.0","id":3,"method":"input/answer","params":{"type":"plan_approval","approved":true}}
8.6 Approve a Shell Command
When the agent requests shell approval:
- Receive
approval/shell with command details
- Send decision:
{"jsonrpc":"2.0","id":4,"method":"input/answer","params":{"type":"shell_approval","decision":"once"}}
Valid decisions: once, prefix, always, suggestion.
9. Current Limitations
- MCP resource references are not yet wired into the
/context prompt assembly.
- Tool search for MCP tools is scaffolded but not yet injecting discovered tools into the prompt.
- The
support-acp integration skill (this file) documents the protocol surface; full end-to-end
IDE integration demos are not yet available.
10. Testing ACP Integration
Run RARA in ACP mode with a test session:
echo '{"jsonrpc":"2.0","id":1,"method":"session/create","params":{"cwd":"."}}' | rara acp
For interactive testing, pipe JSON-RPC commands and observe responses.