Decision — coding agents as Bus sessions, over ACP
Status: accepted 2026-10-30.
Context
Coding agents (Claude Code, Gemini CLI, Codex, OpenCode) were driven by a separate hand-made path each, and none was a Bus citizen. A running turn could not be watched, steered, answered or stopped from the Bus. Agents already reached into MixOS through mixos-mcp; the missing half was MixOS reaching out to them.
The Agent Client Protocol (ACP, Apache-2.0) is the open standard for that: JSON-RPC 2.0 over an agent's stdio, spoken by all of those agents directly or through a small adapter.
The decision
- ACP is a vocabulary, not a wire format. The Bus keeps its own framing. ACP messages never travel raw in a Bus body; one gateway maps them onto ordinary Bus commands and topics.
- One gateway: agentd, a Mix Bus citizen
(Bus name
agent), one per user session. It is the only process that holds ACP pipes, runs each agent as a child on a two-way pipe, and adds no transport or addressing of its own. It starts as a Mix script, per "Mix before another Rust daemon". - The loop: ACP → Bus ← MCP. agentd speaks ACP to the agent and
republishes its updates on
agent.session.updated; it gives every session a mixos-mcp server, so the agent acts back on the Bus asmcp-s-<session>-…. - The client side of ACP is MixOS's.
- Files (
fs/*) are confined to the session'scwdandadditional_dirs, which must lie under the instance's configured roots (paths resolved, no symlink or..escape). - Terminals (
terminal/*) run on pipes with a bounded output tail on the headless path; on a desk they are to move onto Term. - Permission requests go to a human through notifyd, or to an instance
policy that may answer only
allow_once. No answer is never yes, and a cancel answers every open requestcancelled. - This confines what the agent asks agentd for. The agent's own tools (its shell, its built-in file tools) are not confined by agentd, and the decision does not claim a sandbox.
- Files (
- Agent rules still bind. Agents run with the user's real
HOMEand normal configuration, so their own hooks and instructions apply. - The broker owns the sender. agentd recognises a session's own agent
by the Bus name the broker stamps on its requests. A session's own agent
cannot act on that session (
AGENT_SELF); a session started by an agent is a child, and a child cannot start or resume sessions (AGENT_DEPTH); a hard cap on live sessions (AGENT_LIMIT) holds for everyone. - Every
agent.*command answers every caller, per the open Bus. What makes a call safe is the instance: its roots, its permission policy, its caps, and the log. Capability tokens were considered and rejected: they refuse honest callers and leave self-approval one hop away. - Durable intent. agentd writes every acting command and every mapped
update to an append-only SQLite log before it runs or publishes it.
Command ids are scoped per session; a retry with the same id gets the
first reply and never runs again. Sessions outlive agentd in the log,
and
agent.session.resumebrings one back through the agent's ownsession/resumeorsession/load. - Versions. ACP v1 is required; v2 is to be negotiated when both sides offer it, behind the same Bus vocabulary.
- Foreign code. ACP agents are external programs at the edge, called
through Mix process primitives. No ACP SDK enters
mix.
Known residuals
- An agent with a shell can open a Bus client of its own, or register under another name. The sender check catches the honest MCP path only; the cap and the human in the loop catch the rest.
- The asking agent can reach notifyd through mixos-mcp and answer its own permission question: an accepted consequence of the open Bus.
- agentd checks a path and then reads or writes it in a separate step; an agent that swaps the path for a symlink in between can lead it out, but doing so takes the agent's own tools, which reach the same files anyway.
Not doing
- Replacing the Bus wire format with JSON-RPC, or speaking ACP to outside editors directly. An ACP server face for editors could come later, on top of agentd, as its own decision.
- Merging mixos-mcp into agentd: mixos-mcp serves outside agents too.
Where it stands
agentd, its session log, resume, fs/*, headless terminals and the
mix agent command line are in place, tested with
Claude (claude-agent-acp), Gemini CLI, OpenCode and Codex (codex-acp).
Open: terminals through Term on a desk, ACP v2, and a Workshop front end.