cmail-cli
v0.1.0
Published
cmail: realtime email for humans and coding agents. Web inbox with live updates, Gmail attach, your own domain via inbound.new, machines that register as agent VMs you can email tasks to, and an MCP server so your AIs can query the whole inbox. Installs t
Downloads
209
Maintainers
Readme
cmail
Realtime email for humans and coding agents. One hub gives you a live web inbox, your Gmail, your own domain via inbound.new, a fleet of machines registered as agent VMs you can literally email tasks to, and an MCP server so your AIs can query everything.
The data model is a superset of email: every message is a channel-tagged envelope (email, agent, sms, github, twitter, ...) with typed participants and native conversation keys, so non-email bridges get threading, realtime, search, and MCP for free through POST /api/ingest.
Architecture
go/— the hub (cmaild): HTTP API, WebSocket realtime, embedded web inbox, JSONL store, Gmail IMAP-IDLE + SMTP connector, inbound.new REST + webhook connector, MCP stdio server.go/internal/wireis the single source of truth for every wire type.node/— thecmailnpm CLI: agent VM mode, inbox/send/query commands, and a launcher that compiles and cachescmaildfrom the packaged Go source on firstcmail serve.py/— thecmail-cliPyPI package: stdlib-only agent VM mode for machines with neither Node nor Go, plus the same inbox commands.go/cmd/gentsgeneratesnode/src/types.gen.d.tsandpy/cmail_cli/types_gen.pyfrom the wire structs. The verify suite fails on drift and typechecks all JS withtsc --checkJs --strict, so the Go hub, Node CLI, web UI payloads, and Python client cannot disagree about the protocol.
Quick start
# hub machine (needs Go once; cmail builds and caches the hub binary)
npx cmail-cli serve # prints the token and web inbox URL
# any other machine: register it as a coding-agent VM
npx cmail-cli agent --hub http://hub-host:7654 --token TOKEN --name buildbox
# or with only Python:
uvx cmail-cli agent --hub http://hub-host:7654 --token TOKEN --name buildbox
# email the machine a task, from the web inbox or CLI
npx cmail-cli send --to buildbox@agents --subject "run tests" --text "run the suite and summarize failures"The agent VM runs each task with codex exec (default) or claude -p (--backend claude; --backend mock for tests) in a throwaway sandbox dir with a scrubbed environment and a hard timeout, then replies into the thread. Replies to tasks that arrived from Gmail or inbound.new go back out over the same transport, so you can email [email protected] from your phone and get the agent's answer as a normal email reply.
Attach Gmail
Create an app password at https://myaccount.google.com/apppasswords (needs 2FA), then:
npx cmail-cli gmail --user [email protected] --app-password xxxxxxxxxxxxxxxx
npx cmail-cli serveNew mail arrives over IMAP IDLE in realtime; sends relay through smtp.gmail.com.
Attach your own domain (inbound.new)
- Sign up at https://inbound.new, add + verify your domain, create an API key.
npx cmail-cli inbound --api-key KEY --domain yourdomain.com --webhook-token SECRET- Expose the hub publicly (tailscale funnel, cloudflared, ...) and set an inbound.new webhook endpoint to
https://<hub>/webhooks/inboundwith that verification token.
Inbound mail hits the hub in realtime via webhook; sends and thread-preserving replies go through their API (https://inbound.new/api/e2). Mail to <agent-name>@yourdomain.com (any registered agent name, or explicit inbound.routes in ~/.cmail/config.json) is dispatched to that agent VM as a task.
Let your AIs query the inbox
npx cmail-cli mcp is an MCP stdio server with search_inbox, list_threads, read_thread, send_email, email_agent, list_agents, list_tasks, inbox_overview. For Claude Code:
{ "mcpServers": { "cmail": { "command": "npx", "args": ["-y", "cmail-cli", "mcp"],
"env": { "CMAIL_HUB": "http://127.0.0.1:7654", "CMAIL_AGENT_TOKEN": "<hub token>" } } }
}The query language everywhere (UI search, cmail inbox -q, MCP) is free text plus from: to: label: channel: agent: account:.
Other channels (SMS, GitHub, Twitter, ...)
Bridges POST normalized envelopes to /api/ingest with a channel, typed participants (kind: phone|github|twitter|...), and a threadKey for native conversations (an SMS peer, an issue URL). They immediately show up threaded, live, searchable, and MCP-queryable. No bridge ships in-box yet; the SMS path is exercised by the verify suite.
Verify
bun install && cd go && go build ./... && cd ..
node verify/verify-hub.mjs # auth, threading, realtime WS, sms ingest, inbound webhook, task queue
node verify/verify-agent.mjs # real CLI agent round-trip (WS + long-poll), bad-token rejection
node verify/verify-mcp.mjs # MCP stdio against a live hub
node verify/verify-types.mjs # Go->TS/Py type drift + tsc --checkJs strict
cd py && python3 verify.py # Python agent round-trip against a fake hubSecurity model
Single hub bearer token (minted on first run, cmail token) required for every API call and WebSocket; comparisons are constant time. The inbound webhook checks X-Webhook-Verification-Token. Agent tasks run in throwaway sandboxes with scrubbed env; task text travels as argv/stdin, never through a shell. The hub binds to 127.0.0.1 by default; put it on a tailnet rather than the open internet. Known gaps: one shared token (no per-agent scoping), no TLS of its own, Gmail app passwords sit in ~/.cmail/config.json (0600).
The earlier SMTP-daemon prototype lives in legacy/.
