acp_runtime provides supervised, application-facing sessions for coding
agents that speak the Agent Client Protocol (ACP). It builds on
ex_mcp and adds:
- a long-lived session process that survives UI disconnects;
- prompt, cancellation, permission, event, and diagnostic state management;
- an
ExMCP.Transportimplementation backed by a pluggable process runner; - interactive-shell startup isolation for remote execution environments;
- optional notification and persistence callbacks;
- a reusable Phoenix LiveView conversation component; and
- a loopback-only web playground for launching local ACP agent commands.
Host applications remain responsible for authorization, agent records, credentials, and persistence schemas. They can provide an action adapter to the shared conversation component while retaining their own authorization boundary.
The repository includes a runnable Phoenix application that launches an ACP agent as a local stdio process and renders the same conversation component that can be embedded in another Phoenix application.
mix setup
mix phx.serverOpen http://127.0.0.1:4000, then enter:
- the ACP agent executable;
- one command argument per line;
- the repository working directory; and
- any additional
NAME=valueenvironment entries.
The launch form can be prefilled from application configuration instead of typing these values on every launch:
config :acp_runtime,
agent_process: [
executable: "opencode",
args: ["acp"],
working_directory: "/absolute/path/to/project",
environment: %{}
]Values set in the form override the configured defaults, and unconfigured fields fall back to their previous behavior (blank fields, server working directory).
For the locally installed OpenCode ACP server, use opencode as the executable
and acp as its single argument.
The spawned process inherits the environment of the Phoenix server. Commands are represented as an executable plus an argument list and are not evaluated as a shell command string.
The development endpoint binds to 127.0.0.1 and the playground route uses
only the Phoenix browser pipeline. It has no authentication and should not be
exposed on a public interface without adding an authentication boundary.
ACPRuntimeWeb.ConversationComponent owns the prompt form, streamed events,
permission controls, session status presentation, and safe Markdown rendering
for agent messages. A parent LiveView passes the initial state and forwards
{:acp_status, state} and
{:acp_event, event} messages with Phoenix.LiveView.send_update/3.
<.live_component
module={ACPRuntimeWeb.ConversationComponent}
id="acp-conversation"
session_id={@session_id}
session_state={@session_state}
agent_name={@agent_name}
action_adapter={ACPRuntimeWeb.SessionActions}
action_context={@session_pid}
/>Custom adapters implement ACPRuntimeWeb.ConversationActions. This lets a
host authorize prompt, cancellation, permission, and termination operations
before delegating to the runtime.
The component's stylesheet is shipped at
priv/static/assets/acp_runtime.css. A Tailwind host can include it in its own
application bundle:
@import "../../deps/acp_runtime/priv/static/assets/acp_runtime.css";Add one runtime supervisor to the host application's supervision tree:
{ACPRuntime.Supervisor,
name: MyApp.ACP.RuntimeSupervisor,
registry: MyApp.ACP.Registry,
session_supervisor: MyApp.ACP.SessionSupervisor,
task_supervisor: MyApp.ACP.TaskSupervisor}Start sessions through ACPRuntime.Session or through an application-specific
facade that supplies the callback modules and supervisor names.
The configured runner module starts and controls the process hosting the ACP
agent. See ACPRuntime.ProcessRunner for the required contract. This permits
the same runtime to operate against local ports, containers, VMs, or remote
execution services without depending on their SDKs.
ACPRuntime.LocalProcessRunner is the built-in implementation for the local
web playground. It uses an Erlang port and leaves agent stderr attached to the
Phoenix server's stderr so it cannot corrupt the ACP messages on stdout.
This project is currently consumed as a sibling path-dependency prototype.
Public Hex publishing requires an explicit license decision, package metadata,
and independent CI before the version is changed from 0.1.0-dev.