Multi-runtime teams
Choose Claude Code, Codex, OpenCode or Gemini CLI for each agent. Mix runtimes or use several sessions of the same one; all connect to the same team mailbox. Roles and relationships remain your choice.
Declaring runtimes
Each runtime lives in runtimes/<name>.yaml:
binary: claudesupports_mcp: truedefault_model: claude-opus-4-8Reference one from an agent spec:
workers: dev1: runtime: codex model: gpt-5-codex reports_to: managerThe agent-wrapper.sh dispatches on $RUNTIME and calls the matching binary with the right flags.
Delivery parity
Agents on any runtime react to new mail on arrival β only the mechanism differs. Claude Code agents get each message pushed into their session as a <channel source="team"> event; Codex, OpenCode, and Gemini agents get a short note typed into their tmux pane by the team mailbox β π¬ sender: "short previewβ¦" (+N more) β which sends them to inbox_peek / inbox_read / inbox_ack. Because the note is typed as keystrokes, the preview is sanitized: collapsed to a single line with all control characters stripped, so a message body can never submit input or drive the agentβs TUI. The mailbox is the source of truth in both cases, so mixing runtimes never changes what a message means β just how it knocks.
What each runtime supports
Not every agent-spec field applies to every runtime:
| Capability | Claude Code | Codex | OpenCode | Gemini |
|---|---|---|---|---|
MCP (mcps: + built-in team mailbox) | β | β | β | β |
model | β | β | β | β |
effort | β | β | β | β |
permission_mode (incl. attended, bypassPermissions) | β | β | β * | β |
| Compaction on rate limit | β | β | β | β |
| Telegram slash passthrough | β | β | β | β |
hooks | β | β | β | β |
subagents | β | β | β | β |
skills | β | β | β | β |
* permission_mode: bypassPermissions on opencode degrades to --auto β opencode has no full-bypass upstream, so deny rules stay enforced; teamctl validate prints a warning naming the downgrade.
A capability declared on a runtime that doesnβt support it is ignored at render time. teamctl validate prints a warning for each such mismatch (validation still succeeds).
One subtlety on MCP env: ${VAR} placeholders in mcps: env values are Claude-Code-only β Claude Code expands them at launch, but Codex and OpenCode pass the literal ${VAR} string to the server. For codex and opencode agents, give servers literal values or put the secret in the operator environment the MCP server process inherits.
Choose for the role
Check the tools, permission controls, model availability and account limits the role needs. Test a representative interaction before assigning ongoing work. For OpenCode, pin model: in provider/model form instead of relying on its default selection.
Cost
Each runtime reports usage differently. teamctl budget sums its recorded ledger, but runtime cost parsers are not wired today, so its USD column does not measure actual spend. Use provider usage records and spending controls; see Cost and rate limits.
Example
See Product team for Claude Code and Codex agents, or Newsletter office for Claude Code, Codex and Gemini CLI across two projects.