Host Integrations
One AgenticMail dispatcher per LLM host. Currently shipping for Claude Code and OpenAI Codex CLI, with two more on the roadmap.
The @agenticmail/claudecode package was the reference implementation; @agenticmail/codex shipped on 2026-05-14 with ~90% architectural reuse. Grok Build and Hermes Agent follow the same shape, each adjusting only for the target host's plugin/hook conventions.
Co-installation: one machine, multiple hosts
As of 0.9.20, a single machine can run both agenticmail-claudecode and agenticmail-codex side-by-side. Each host:
- Has its own bridge account (
claudecode@localhost,codex@localhost) withrole='bridge'andmetadata.hostmatching its name - Has its own PM2 dispatcher daemon (
agenticmail-claudecode-dispatcher,agenticmail-codex-dispatcher) - Has its own MCP server config block, lifecycle hooks, and subagent directory
- Watches only the accounts it owns (per
metadata.host), so a reply to a Codex-owned teammate fires exactly one worker (under@openai/codex-sdk), and a reply to a Claude-owned teammate fires exactly one worker (under@anthropic-ai/claude-agent-sdk).
The MCP server auto-stamps metadata.host on every new account from the AGENTICMAIL_MCP_HOST env var that each installer writes into its MCP server's env block. Legacy accounts that predate this can be retro-tagged with agenticmail-<host> claim --all.
What every integration needs
Every host package implements the same five primitives:
- MCP server registration — write into the host's config so the MCP toolbelt becomes available to the model.
- Sub-agent registration — surface every AgenticMail account as a host-native subagent the model can call directly.
- Lifecycle hooks —
SessionStart(capabilities blurb),UserPromptSubmit(mail context),Stop(autonomous-mode awareness). - Headless dispatcher — long-running daemon that wakes one fresh model turn per new-mail / new-task event.
- Installer + uninstaller —
agenticmail-<host>-install/-uninstallthat patches/cleans up the host's config files idempotently.
If a host doesn't support one of these as a first-class primitive, the package documents the workaround.
Status matrix
| Host | Package | MCP | Subagents | Hooks | Headless | Status |
|---|---|---|---|---|---|---|
| Claude Code (Anthropic) | @agenticmail/claudecode |
✅ native | ✅ native | ✅ native | ✅ SDK | Shipping (0.2.13) |
| Codex CLI (OpenAI) | @agenticmail/codex |
✅ native (TOML) | ✅ spawn_agent |
✅ native (8 events, byte-compat with Claude Code) | ✅ @openai/codex-sdk |
Shipping (0.1.5) |
| Grok Build (xAI) | @agenticmail/grok-build (planned) |
✅ announced | ✅ native | ✅ native (17 events) | ✅ ACP / -p |
Researched |
| Hermes Agent (Nous Research) | @agenticmail/hermes (planned) |
✅ native | ✅ delegate_task |
✅ native (richer than CC) | ✅ Python SDK | Researched |
How host ownership is enforced
The three layers that keep co-installed hosts from stepping on each other:
| Layer | Where | Behavior |
|---|---|---|
| MCP auto-stamp | packages/mcp/src/tools.ts's create_account reads process.env.AGENTICMAIL_MCP_HOST |
Every account created through MCP gets metadata.host pre-filled with the env var's value. Each host installer writes this var into its own MCP server's env block, so accounts created from a Claude Code session are stamped 'claudecode' and accounts created from a Codex session are stamped 'codex'. |
| Install-time filter | selectExposableAgents() in install.ts (both host packages) |
A teammate appears in the host's subagent roster (~/.claude/agents/, ~/.codex/agents/) ONLY if metadata.host === ownHost. Legacy unclaimed accounts are skipped — the operator must claim them explicitly. |
| Dispatcher-time filter | shouldWatch() in dispatcher.ts (both host packages) |
The dispatcher's per-account SSE channel opens only if metadata.host === ownHost, OR if metadata.host is unset (legacy back-compat). Bridge accounts (role='bridge' or metadata.bridge===true) are always skipped regardless of host. |
The claim subcommand
agenticmail-<host> claim <name> [--unclaim] [--all] [--json] is the operator-facing tool for transferring ownership:
# Take ownership of every unclaimed teammate
agenticmail-claudecode claim --all
# Hand a specific teammate to the other host
agenticmail-claudecode claim vesper --unclaim
agenticmail-codex claim vesper
# Audit-friendly output
agenticmail-codex claim --all --json
--all deliberately refuses to steal accounts already owned by another host — you have to unclaim first, then re-claim, so cross-host transfers are intentional rather than accidental.
Architectural overlap
Across all four planned hosts, roughly 70% of the dispatcher code is identical: SSE channel management, per-agent serialization, wake-coalesce, wake-budget, catch-up scan, state persistence, activity reporting, host-ownership filter. The host-specific bits are:
- Spawning a model turn. Claude Code uses
@anthropic-ai/claude-agent-sdk'squery(). Codex CLI's headless mode is TBD (likelycodex -p). Grok Build uses ACP-over-stdio orgrok -p. Hermes Agent usesfrom run_agent import AIAgent. - Config-file layout. Each host stores its settings + hooks + MCP servers in a different path/shape.
- Subagent definition format. Claude Code: markdown with YAML frontmatter in
~/.claude/agents/. Grok: JSON entries insubAgents[]. Hermes: plugin entry-points. Codex: TBD.
To keep the four packages DRY, the plan is to factor out @agenticmail/host-toolkit — a shared library with:
Dispatcherbase class (everything except thespawnWorkerandinstallerslots).DispatcherState(persistence, already isolated).runCatchUp(mail + task backlog).composeWakePrompt(thread cache + agent memory injection).WakeBudget,WakeCoalesce(rate limiter + debounce).- The capabilities-blurb generator.
Each host package then becomes a thin layer (~500 lines) that supplies host-specific spawnWorker, Installer, and event-name mappings.
Read next
- Integration: Codex CLI — OpenAI's Codex agent, deliberate Claude Code clone of hook surface
- Integration: Grok Build — xAI's freshly-released agent CLI
- Integration: Hermes Agent — Nous Research's Python-native agent runtime