# What Is the ACP (Agent Communication Protocol) Runtime in Routa?

> Discover the ACP runtime in Routa, the core subsystem hosting Agent Communication Protocol sessions. Learn how it launches, supervises, and communicates with external agent processes using JSON-RPC.

- Repository: [Fengda Huang/routa](https://github.com/phodal/routa)
- Tags: deep-dive
- Published: 2026-05-26

---

**The ACP runtime in Routa is the core subsystem that hosts Agent Communication Protocol sessions, responsible for launching, supervising, and communicating with external agent processes via JSON-RPC over stdio.**

Routa’s ACP runtime serves as the bridge between the application’s orchestration layer and external AI agents like Claude-code, Opencode, or Codex. According to the phodal/routa source code, this runtime spans both the Next.js web backend and Rust desktop backend, exposing a unified HTTP/SSE interface while managing process lifecycles, session persistence, and health monitoring.

## Architecture and Core Responsibilities

The ACP runtime is more than a simple process wrapper—it is a stateful subsystem that handles session management, transport encoding, and provider abstraction.

### Session Lifecycle and Persistence

At the heart of the runtime sits the `AcpSessionManager` in [`src/core/acp/acp-session-manager.ts`](https://github.com/phodal/routa/blob/main/src/core/acp/acp-session-manager.ts), which maintains a registry of active sessions, their IDs, providers, and status. This manager coordinates with [`src/core/acp/session-db-persister.ts`](https://github.com/phodal/routa/blob/main/src/core/acp/session-db-persister.ts) to store chat history in SQLite, enabling session replay and debugging across restarts. When the orchestrator requests an agent, the session manager instantiates a new context and delegates process spawning to the process manager.

### Process Management and JSON-RPC Transport

The `AcpProcessManager` (located in [`src/core/acp/acp-process-manager.ts`](https://github.com/phodal/routa/blob/main/src/core/acp/acp-process-manager.ts)) maps session IDs to live `AcpProcess` objects and implements start, stop, and reconnection semantics. Each `AcpProcess` instance in [`src/core/acp/acp-process.ts`](https://github.com/phodal/routa/blob/main/src/core/acp/acp-process.ts) manages the low-level JSON-RPC read/write loop over stdio, encoding messages to the agent binary and forwarding notifications back to the `AcpSessionManager`. This layer handles health checks and error recovery when agent processes crash or become unresponsive.

### Provider Abstraction Layer

Routa supports multiple ACP-compatible agents through a uniform adapter interface. Provider-specific logic resides in `src/core/acp/provider-adapter/` (including [`claude-adapter.ts`](https://github.com/phodal/routa/blob/main/claude-adapter.ts) and [`opencode-adapter.ts`](https://github.com/phodal/routa/blob/main/opencode-adapter.ts)), translating Routa’s internal event model into provider-specific JSON-RPC calls. This abstraction allows the runtime to treat Claude-code, Opencode, Docker-based agents, or custom binaries identically, regardless of their individual CLI quirks.

### HTTP Bridge and Health Verification

The runtime exposes REST endpoints and Server-Sent Events (SSE) via [`src/app/api/acp/runtime/route.ts`](https://github.com/phodal/routa/blob/main/src/app/api/acp/runtime/route.ts), implementing `GET /api/acp/runtime` for status checks and `POST /api/acp/runtime` for initialization. To verify connectivity before user interaction, [`src/core/acp/acp-warmup.ts`](https://github.com/phodal/routa/blob/main/src/core/acp/acp-warmup.ts) executes a lightweight “ping” session when the UI calls `/api/acp/warmup`, confirming that the selected provider binary is reachable and functional.

## Integration with Routa's Orchestration

The ACP runtime connects to Routa’s task orchestration through the `Orchestrator` class in [`src/core/orchestration/orchestrator.ts`](https://github.com/phodal/routa/blob/main/src/core/orchestration/orchestrator.ts). When an orchestrated task requires agent assistance, the orchestrator requests a session from `AcpSessionManager`, which triggers `AcpProcessManager` to spawn the appropriate provider process. The frontend then communicates with this session via [`src/client/acp-client.ts`](https://github.com/phodal/routa/blob/main/src/client/acp-client.ts), a typed façade that abstracts HTTP calls into methods like `createSession`, `sendMessage`, and `streamEvents`.

## Working with the ACP Runtime: Code Examples

The following patterns demonstrate how to interact with the runtime using the TypeScript client library.

### Warm-Up the Runtime

Verify that the ACP subsystem is functional before creating user-facing sessions:

```typescript
import { AcpClient } from '@/client/acp-client';

async function initializeRuntime() {
  await AcpClient.warmup();
  console.log('ACP runtime ready');
}

```

This invokes `POST /api/acp/warmup`, internally handled by [`acp-warmup.ts`](https://github.com/phodal/routa/blob/main/acp-warmup.ts) to spawn a temporary validation session.

### Create a New Session

Instantiate a session with a specific provider adapter and system prompt:

```typescript
const session = await AcpClient.createSession({
  provider: 'opencode',
  systemPrompt: 'You are a helpful coding assistant.',
});
console.log('Session ID:', session.id);

```

The client calls `POST /api/acp`, triggering `AcpSessionManager.createSession` and ultimately spawning the process via `AcpProcessManager`.

### Stream Messages and Responses

Send user input and subscribe to SSE events for agent responses:

```typescript
async function chat(sessionId: string, message: string) {
  await AcpClient.sendMessage(sessionId, { 
    role: 'user', 
    content: message 
  });

  const eventSource = AcpClient.subscribe(sessionId);
  eventSource.onmessage = (ev) => {
    const update = JSON.parse(ev.data);
    console.log('ACP update:', update);
  };
}

```

This routes to `POST /api/acp/{sessionId}/message` and `GET /api/acp/{sessionId}/events`, with [`acp-process.ts`](https://github.com/phodal/routa/blob/main/acp-process.ts) handling the JSON-RPC translation layer.

### Terminate a Session

Clean up resources when the conversation completes:

```typescript
await AcpClient.terminateSession(sessionId);

```

This triggers `DELETE /api/acp/{sessionId}`, signaling `AcpProcessManager` to kill the underlying process and update persistence via [`session-db-persister.ts`](https://github.com/phodal/routa/blob/main/session-db-persister.ts).

## Summary

- The **ACP runtime** is Routa’s unified backend for hosting JSON-RPC agent sessions, spanning Next.js and Rust implementations.
- **Process management** in [`acp-process-manager.ts`](https://github.com/phodal/routa/blob/main/acp-process-manager.ts) handles spawning, health checks, and reconnection for child agent processes.
- **Session state** is tracked by [`acp-session-manager.ts`](https://github.com/phodal/routa/blob/main/acp-session-manager.ts) and persisted to SQLite via [`session-db-persister.ts`](https://github.com/phodal/routa/blob/main/session-db-persister.ts).
- **Provider abstraction** allows the runtime to communicate with Claude-code, Opencode, or Docker agents through adapter implementations in `src/core/acp/provider-adapter/`.
- **HTTP/SSE bridge** exposes the runtime via `/api/acp/runtime` endpoints, consumed by the front-end `AcpClient` and the orchestration layer.

## Frequently Asked Questions

### What is the difference between ACP runtime and a simple agent process?

The **ACP runtime** encompasses state persistence, lifecycle notifications, and health monitoring in addition to the child process itself. While a simple process only executes the agent binary, the runtime includes [`session-db-persister.ts`](https://github.com/phodal/routa/blob/main/session-db-persister.ts) for SQLite storage, [`lifecycle-notifier.ts`](https://github.com/phodal/routa/blob/main/lifecycle-notifier.ts) for UI updates, and MCP integration for tool invocation, making it an observable, extensible environment rather than just a process wrapper.

### How does the ACP runtime handle different agent providers?

The runtime uses a **provider adapter pattern** located in `src/core/acp/provider-adapter/`. Each adapter (e.g., [`claude-adapter.ts`](https://github.com/phodal/routa/blob/main/claude-adapter.ts), [`opencode-adapter.ts`](https://github.com/phodal/routa/blob/main/opencode-adapter.ts)) implements a uniform interface that translates between the provider’s specific JSON-RPC dialect and Routa’s internal `SessionUpdateNotification` events, allowing the core runtime to remain provider-agnostic.

### What happens if an ACP agent process crashes during a session?

The `AcpProcessManager` monitors process health through the stdio pipe in [`acp-process.ts`](https://github.com/phodal/routa/blob/main/acp-process.ts). If an agent exits unexpectedly, the manager triggers reconnection logic or marks the session as failed, notifying the UI via the lifecycle notifier. Session history remains available in SQLite via [`session-db-persister.ts`](https://github.com/phodal/routa/blob/main/session-db-persister.ts), though the specific crashed process is terminated and cleaned up.

### Can external tools interact with the ACP runtime outside the Routa UI?

Yes. The runtime exposes **HTTP endpoints** in [`src/app/api/acp/runtime/route.ts`](https://github.com/phodal/routa/blob/main/src/app/api/acp/runtime/route.ts) and SSE streams that any HTTP client can consume. The `AcpClient` in [`src/client/acp-client.ts`](https://github.com/phodal/routa/blob/main/src/client/acp-client.ts) serves as a reference implementation, but external scripts or CLI tools can directly call `POST /api/acp` to create sessions and `GET /api/acp/{sessionId}/events` to stream responses without using the React frontend.