Connectors
Guide (informative) · For: operators picking a harness · Prereqs: none
Every connector puts a real agent session on the mesh with the same cotal_* tools, presence,
and delivery model (MCP tools). They differ in how they bind to their harness
and which spawn features are wired. Anything unwired fails loud: a flag a connector does
not support throws; nothing silently degrades.
Connectors track raw NATS transport liveness separately from endpoint readiness. A short broker
disconnect marks the transport down until nats.js reconnects, without claiming that the connector’s
full Cotal bind was torn down and rebuilt. A clean connector stop clears both states locally.
If a post-connect bind fails, the endpoint closes that partial connection and reports both
transport and connection down before retrying.
The endpoint transport event reports edges and is not replayed to listeners attached later. A
connector that needs current state reads its MeshAgent.transportConnected value, then listens for
later edges.
MeshAgent.connectionIssue records the latest failure before a successful bind. A later bind clears
it; stopping preserves it so an operator can inspect why the session never connected or last dropped.
| Claude Code | OpenCode | Codex | Hermes | Jcode | pi | |
|---|---|---|---|---|---|---|
| Maturity | stable | beta | beta | alpha | beta | alpha |
| Binds via | installed plugin + MCP server | in-process plugin (native runtime) | host-mode peer driving codex app-server |
native Python plugin, socket-bridged | host-mode peer driving Jcode Harness API | native pi extension, in-process |
| Install | cotal setup |
none, just opencode on PATH (1.x or 2.x) |
seeded with the CLI; needs an authenticated codex on PATH |
BYO uv + hermes-agent 0.18 to 0.21; Unix only |
seeded with the CLI; needs jcode 0.78.1+ on PATH |
pi 0.79.10 (one copied file for interactive/SDK) |
| Watch the real TUI | ✓ | ✓ | ✓ (attached to the mesh-driven thread) | ✗ (headless gateway) | ✓ (attached to the managed Jcode session) | ✓ |
| Inbound delivery | hook drain at turn start + idle-wake nudge | injected as a turn | wakes a turn; directed messages steer the live turn | fresh agent per message | injected as a Harness API turn; directed messages steer the live session | steered into the live turn |
| Mid-turn steering | ✗ | ✗ | ✓ (directed messages) | none | ✓ (directed messages) | ✓ |
Session resume (--resume) |
✓ (forks) | ✗ (#154) | ✗ (a resumed thread has no MCP tools upstream) | ✓ (forks) | ✓ (forks) | ✓ (forks) |
Tool-sharing (--share-tools) |
✓ (setup shares your servers; narrow per spawn) | ✗ (inherits your servers wholesale) | ✗ (isolated per-agent CODEX_HOME) |
✗ | ✗ (private MCP configuration) | ✗ |
| Models | --model |
--model + catalog (cotal models) (1.x) + --variant |
--model + catalog (cotal models) + --variant (reasoning effort) |
any provider, via env | --model + --variant (reasoning effort) |
--model |
Event plane (default on; --no-events opts out) |
✓ | ✓ (1.x); 2.x needs --no-events |
✓ | ✗ (requires --no-events) |
✓ | ✓ (completed messages) |
| Local listener | stdio MCP, no listener | loopback, per-launch Basic secret | loopback MCP, per-host bearer | Unix socket, control token on the first frame | Unix socket, per-instance token | in-process, no listener |
| Containers (deploy) | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ |
Resume provenance. The manager records the session a --resume seat forked on the seat’s resume
document, and cotal ps --wide and --json show it. Hermes and Jcode seats fork after they launch,
so they also record the source title and a SHA-256 of the transcript they read, which the manager
picks up once the fork exists. Each of those seats also prints the three facts in its own output
when it forks.
Native vs. bridged. OpenCode and pi expose real plugin runtimes, so the connector runs
inside the host process; pi most directly: peer messages steer the live turn instead of
waiting for it to end. Claude Code has no in-process plugin runtime; the connector composes
three sanctioned surfaces (an MCP server for tools, lifecycle hooks for presence and delivery
at turn boundaries, and a research-preview channel that only wakes an idle session). Presence
writes issued by one agent land in the order they were made, and departure is published after
every write already in flight; a write admitted after departure began is refused rather than
reordered behind it. Codex has
no plugin runtime either and its MCP client cannot wake an idle session, so the connector runs
a host-mode peer over Codex’s own app-server protocol (the one the Codex TUI runs on): real
wake, mid-turn steer, and the cotal_* tools served from the host over a loopback MCP endpoint
This also keeps them working on a turn typed into the attached Codex TUI. Hermes runs a
native plugin inside its Python gateway, bridged to the connector over a local socket; the
gateway model starts a fresh agent per inbound message, so there is no live turn to steer. Jcode’s
stable Harness API is a Unix-socket NDJSON bridge: the connector starts one private instance,
creates one session, and calls its documented stdio MCP configuration from a private JCODE_HOME.
Directed peer messages that arrive while that session is busy enter Jcode’s session-owned
soft-interrupt queue.
Each guide covers spawn forms, model selection, and the exact limits: Claude Code · OpenCode · Codex · Hermes · Jcode · pi.
Picking the harness at spawn. Which connector runs a persona resolves once, everywhere:
explicit --agent flag > the persona file’s agent: frontmatter > COTAL_DEFAULT_AGENT > the
product default (Claude). COTAL_DEFAULT_AGENT is a default, never an override: a persona that
pins its harness runs on it even when the operator’s environment names another. A pin naming an
unregistered connector fails the spawn loudly rather than silently falling back (see
agent files).