Skip to content
Agent Workspaces
Agent

acp-runtime

The ACP runtime is the domain service that serves the ACP API contract. It owns the host-scoped dependencies needed to run provider ACP sessions, but it should not mix cross-session routing with per-session state projection.

From plugin
emdash
6.2k33 skills33 agents

Agent definition

acp-runtime.md

ACP Runtime Architecture

The ACP runtime is the domain service that serves the ACP API contract. It owns the host-scoped dependencies needed to run provider ACP sessions, but it should not mix cross-session routing with per-session state projection.

Ownership

  • `AcpRuntime` is the composition root. It wires the ACP API contract to shared

ports, the resource-cached connection source, and the session manager.

  • `SessionManager` is the conversation directory and cross-conversation coordinator. It owns the

handle map, suspended-intent index, process-close fan-out, lifecycle-chassis wiring, and the composition of the router, materializer, and list projector. Activity tracking, idle sweeping, intent persistence, lifecycle reports, and eviction sequencing remain delegated to the shared session-lifecycle chassis (`packages/core/src/services/session-lifecycle/`). Its explicit `inspect()` seam exposes identifier-only lifecycle snapshots for deterministic ownership and leak assertions without revealing the directory maps.

  • `ConversationHandle` is the aggregate root for one conversation. It owns the wake descriptor,

desired configuration, retained presentation snapshot, conversation-lifetime projection, explicit lifecycle state and epoch, current `SessionRecord`, activation snapshot construction, and its single-key `LifecycleCell`. Descriptor and retained-presentation changes write through one intent-persistence seam, while killed/disposed state and the epoch invalidate stale asynchronous materialization and command work before directory removal.

  • `LifecycleCell` provides coalesced starts, leases, interrupt-before-drain teardown, and bounded

draining for one handle. The multi-key `LifecycleRegistry` remains available to other runtimes.

  • `SessionMaterializer` is stateless. It acquires a connection, loads or creates the provider

session, creates the record's machine-state binding, applies retained configuration and mode, and returns a `SessionRecord` for the handle to adopt. Provisional loading registration and replay setup share one cleanup path so failures cannot leave routing residue.

  • `SessionRouter` owns ACP `sessionId` routing and one scoped provisional load route per process

generation. The materializer serializes `loadSession` handshakes for each generation, so a provider that reports a rebound session ID still resolves unambiguously. Unknown or stale updates outside that scope are dropped rather than retained across activations; generation invalidation drops provisional and registered routes. Its maps stay private; identifier-only queries support lifecycle leak assertions. `SessionsListProjector` composes live handle summaries with lightweight suspended-intent rows.

  • `SessionCell` owns one live activation: the state machine, transcript reducer, permission broker,

prompt queue effects, turn quiescence, and whether the provider's config catalog is pending or ready. It does not own the conversation-lifetime projection or retained rematerialization descriptor.

  • The ACP connection source owns provider processes through `createResourceCache`.

Cache identity includes provider, cwd, and an opaque fingerprint of the requested environment; the process route id stays provider/cwd plus generation and can host multiple ACP sessions with the same environment.

  • Models under `packages/core/src/acp/models/` are the shared vocabulary for

reducer output, live model state, and the public ACP API contract.

  • Runtime implementation code lives under `packages/core/src/runtimes/acp/node/`; the portable

contract and client models stay under `packages/core/src/runtimes/acp/api/`.

  • The Node surface exports `createAcpComponent()`. App-owned worker entries call

`runWireComponentWorker(createAcpComponent(...))`; `@emdash/core` does not export process bootstrap helpers.

flowchart TD
  subgraph api [ACP API]
    commands[Commands]
    liveModels[LiveModels]
    queries[Queries]
  end
  subgraph runtime [Runtime]
    root[AcpRuntime]
    manager[SessionManager Directory]
    router[SessionRouter]
    materializer[SessionMaterializer]
    intentIndex[Suspended Intent Index]
    listProjector[SessionsListProjector]
  end
  subgraph conversation [Conversation Aggregate]
    handle[ConversationHandle]
    lifecycle[LifecycleCell]
    projection[Conversation Projection]
  end
  subgraph session [Live Activation]
    record[SessionRecord]
    machine[SessionMachine]
    reducer[Transcript Reducer]
  end
  subgraph connection [Connection]
    source[ConnectionSource]
    ports[AgentPorts]
  end
  agent[ACP Agent]

  commands --> root --> manager --> handle
  manager --> intentIndex --> listProjector --> liveModels
  handle --> lifecycle --> materializer --> source --> agent
  materializer --> record --> machine
  agent --> ports --> router --> record
  record --> reducer --> handle --> projection --> liveModels
  handle --> listProjector
  reducer --> queries

Command and Read Paths

Commands enter through the API and are routed by `AcpRuntime` to the `SessionManager`. The manager locates or lazily creates a `ConversationHandle`; wake commands ask the handle's lifecycle cell to ensure an activation and acquire the appropriate lease. Session commands then reach the `SessionCell`, where the pure `SessionMachine` decides whether the command is valid and emits effects for the cell to interpret.

Provider updates move in the opposite direction. The connection handler receives ACP callbacks, normalizes raw `SessionUpdate`s through the provider's enrich hook, and asks the `SessionRouter` to resolve the owning conversation. The cell folds the event through the reducer; its handle republishes the resulting activation snapshot through the conversation-keyed projection.

The public API separates session startup from observation. Desktop resolves the authoritative conversation configuration and provider environment. `attach` creates or refreshes

Read more
@generalaction
Ships withemdash

Emdash is the Open-Source Agentic Development Environment (🧡 YC W26). Run multiple coding agents in parallel. Use any provider.

Stars on GitHub

Momentum

stars in total
6.2k
Star history of generalaction/emdash on GitHub, a chart by star-history.com

Other agents on emdash.

core-modules

core-modules

Agent

This page defines the target organization of `packages/core/src/`. Core is organized by module type so that shared domain APIs…

git-runtime

git-runtime

Agent

Git is split into a transport contract and a host-scoped runtime. Renderer, desktop, and workspace-server code share the Wire…

main-process

main-process

Agent

The main process is organized into domain modules under `src/main/core/`. Each domain typically has a `controller.ts` (RPC…

path-system

path-system

Agent

`@emdash/core/primitives/path/api` is the source of truth for portable file identity and lexical path operations. The detailed…

More agents from other plugins.

api-builder

api-builder

Agent

Deprecated placeholder. Do not use; follow root AGENTS.md and package instructions instead.

happier2d2.2k
@happier-dev@happier-devInstall Agent

Questions about acp-runtime.

Which coding agents can use acp-runtime?
acp-runtime installs in Claude Code and Cursor: each loads subagents from .claude/agents, so copy the file there. Flowy's auto-invocation runs in Claude Code only.