Agents¶
Plexus drives three coding agents — Claude Code, Codex, and OpenCode — through one registry and one
injection contract. It's agent-agnostic by design: every agent goes through the same two plexus calls
(register + spawn a terminal) and the same edc /inject contract. What differs is where registration
is wired and how the injected turn is received. (See Concepts for the terms.)
Support matrix¶
| Capability | Claude Code | Codex | OpenCode |
|---|---|---|---|
| Register in Plexus | ✅ hook | ✅ plugin | ✅ plugin |
| Live terminal (attach) | ✅ | ✅ | ✅ |
Launch via plexus |
✅ | ✅ | ✅ decoupled |
| External turn injection | ✅ channel | ✅ app-server | ✅ HTTP |
| Injected turn is visible | ✅ native | ✅ | ✅ TUI mode |
Native source=system marker |
✅ | framed¹ | framed¹ |
| Interrupt a running turn | ✅ | ✅ | ✅ /abort |
¹ framed — the trust boundary is reconstructed as text (SYSTEM EVENT (untrusted data)) since the
agent has no native system marker.
How each is wired¶
Claude Code¶
- Registration: hooks in
plexus/hooks/—session-start.shrunsplexus ttyd spawn+plexus register(agent=claude);session-end.shderegisters; a keepalive heartbeats idle sessions. - Injection: the
edcchannel — an MCP stdio server declaringclaude/channel. Events arrive as nativenotifications/claude/channelturns withmeta.source="system". - Install: two supported paths (see Setup) — the combined
Plexus plugin (
plexus@jjuanrivvera-plexus, registration hooks + injection channel in one), or à la carte (theevent-driven-claude@jjuanrivvera-edcplugin for the channel + the plexus hooks for registration). Either way the hooks live in~/.claude/settings.json; the channel allowlist lives in the OS managed-settings file (notsettings.json) — Setup has the exact snippets.
Codex¶
- Registration: the
.codex-pluginshipped inedc— itsSessionStarthook registers interactive Codex sessions (agent=codex,inject_port=0) and spawns the web terminal. The always-on injectable session is theedc codex servedaemon, which self-registers with a real inject port. - Injection:
edc codex servedrives acodex app-serverthread over JSON-RPC; each event becomes aturn/start. Pinned to approval-never + read-only sandbox so an injected turn can't act on its own. - Trust: no native system marker → framed as text.
OpenCode¶
- Registration: the
.opencode-pluginshipped inedc(plexus.ts→~/.config/opencode/plugins/). Onsession.createdit runsplexus ttyd spawn+plexus register(agent=opencode), reading the inject port from$EDC_INJECT_PORT. - Injection:
edc opencode serve. OpenCode is client-server, soplexus opencodelaunches a decoupled stack — an addressableopencode serve, a TUI-modeedcsidecar on a fixed inject port, and theopencode attachyou interact with. Injected turns are typed into the attached session via/tui/*so they render (working around sst/opencode#8564). - Trust: no native system marker → framed as text.
Adding another agent¶
The pattern to support a new agent:
- Register it — a session-start hook/plugin that calls
plexus ttyd spawn+plexus register --agent <name>(and a session-end that deregisters).plexusaccepts any lowercase agent name. - Receive injection — an
edc <name> serveadapter that runs the/injectlistener and translates each event into that agent's "start a turn" primitive, reconstructing the trust boundary if the agent has no native system marker.
plexus needs no change to add an agent — only a hook and an adapter.