A standalone service that encapsulates messaging-platform connectors behind a unified API. Agents reach outbound capabilities through a per-mailbox MCP server; inbound messages flow to the agent's harness via webhook. Owns the focal-attention paradigm so a single agent can hold one focus across many chats and platforms — entirely transparent to the harness.
Phase 1 ships: service core, Signal connector, MCP proxy, templated webhook delivery.
Phase 2 ships: focus mechanism (switch_chat, list_chats, recap rendering, per-event-type templates).
Phase 3 ships: Telegram connector — same abstraction, second platform.
Phase 4 ships: delivery health + retry, HMAC webhook signing, Prometheus metrics, operator CLI.
Phase 5 ships: per-account admin MCP server — agents administer their own messaging surface (mute chats, update templates, inspect health) via /mcp/admin/{account_id}.
Phase 6 ships: service events / webhook subscriptions — integrators listen for new_chat, delivery_failed, mailbox_paused. Fire-and-forget delivery never blocks the primary inbound flow.
Phase 7 ships: Discord connector — built fresh against the connector contract (no AIOS source), validating the contract is usable cold.
Phase 8 ships: Slack connector — second fresh build, providing strong evidence the abstraction is sound rather than retroactively shaped to existing implementations.
Phase 9 ships: ephemeral ride-along templates — optional ephemeral template key in delivery_templates produces a sibling field on the webhook body, unblocking AIOS-style cache-stable prompt assembly without introducing any mode discriminator.
Phase 10 ships: CMA integration adapter (examples/cma_adapter.py) + CMA_INTEGRATION.md walkthrough — closes the loop on the original CMA-first design goal.
387 tests passing across the service core (161), Signal connector (44), Telegram connector (57), Discord connector (66), and Slack connector (59).
┌─────────────────────┐
│ chatbox API │ FastAPI, stateless
│ (chatbox api) │ HTTP + per-mailbox MCP server (/mcp/{id})
└──────────┬──────────┘
│ Postgres
┌──────────┴──────────┐
│ Connector procs │ one per platform; HTTP client to API,
│ (chatbox-signal, │ MCP server for outbound tools
│ chatbox-telegram) │
└──────────┬──────────┘
│
┌───────────────┼───────────────────┐
│ │ │
Signal/Telegram/etc network Webhook → integrator's harness
(e.g. CMA session inbound URL)
- account — tenant key (multi-tenant in code; v1 ships single-tenant via bootstrap).
- mailbox — attention surface. Has a webhook URL, an MCP URL, delivery templates, and (in phase 2) a focal chat.
- connection — platform integration within a mailbox. At most one per platform per mailbox.
- chat — a single conversation thread on a connection. Identified to the agent as
<connector>:<external_handle>. - credential — encrypted secret (webhook auth, MCP proxy auth, optional HMAC signing key).
At any moment, a mailbox has zero or one focal chat. Inbound on the focal chat renders via the focal_message template; inbound on a non-focal chat renders via the notification template (which by default includes a $CHAT_LIST footer). Agents shift focus by calling switch_chat(chat_id) on the per-mailbox MCP server, which mutates focal state and returns a recap of the chat's recent history.
The focal paradigm prose lives in InitializeResult.instructions of the per-mailbox MCP server, so it lands in the agent's system prompt without harness involvement.
# Postgres
docker run -d --name chatbox-pg -p 5434:5432 \
-e POSTGRES_USER=chatbox -e POSTGRES_PASSWORD=chatbox -e POSTGRES_DB=chatbox \
postgres:16-alpine
# Configure
cp .env.example .env
echo "CHATBOX_VAULT_KEY=$(python3 -c 'import base64,secrets; print(base64.b64encode(secrets.token_bytes(32)).decode())')" >> .env
# Install + migrate + bootstrap
uv sync
set -a && source .env && set +a
uv run alembic upgrade head
uv run chatbox bootstrap # prints the API key once — save it
# Run
uv run chatbox api &
# Health
curl http://localhost:8000/healthSee SMOKE_TEST.md for the full operator runbook including connector setup.
All endpoints except /health, /metrics, and inbound require Authorization: Bearer <api_key>. Inbound endpoint uses a per-connection inbound_token (returned once at connection creation).
| Method | Path | Purpose |
|---|---|---|
| GET | /health |
Service health |
| GET | /metrics |
Prometheus metrics |
| POST | /v1/mailboxes |
Create mailbox; returns mcp_url, mcp_token |
| GET | /v1/mailboxes |
List |
| GET | /v1/mailboxes/:id |
Get |
| PUT | /v1/mailboxes/:id |
Update (webhook URL, templates, signing credential) |
| DELETE | /v1/mailboxes/:id |
Archive |
| GET | /v1/mailboxes/:id/health |
Delivery health snapshot |
| POST | /v1/mailboxes/:id/unpause |
Clear paused state |
| POST | /v1/mailboxes/:id/connections |
Add platform integration |
| GET | /v1/mailboxes/:id/connections |
List |
| GET | /v1/connections/:id |
Get |
| DELETE | /v1/connections/:id |
Archive |
| POST | /v1/credentials |
Create encrypted credential |
| GET, PUT, DELETE | /v1/credentials/:id |
Manage |
| POST | /v1/connections/:id/messages |
Connector → chatbox: inbound message |
(MCP) |
/mcp/:mailbox_id |
Per-mailbox MCP server |
chatbox migrate # Run alembic migrations
chatbox bootstrap # Create first account + API key
chatbox api # Start the API server
chatbox operator mailbox-list # List mailboxes (status, last delivery)
chatbox operator mailbox-health <id> # Show delivery health
chatbox operator mailbox-unpause <id> # Clear paused state
chatbox operator mailbox-regenerate-mcp-token <id> # Rotate the MCP token
chatbox operator connection-list <mailbox_id> # List connections on a mailbox
chatbox operator connection-archive <conn_id> # Archive a connection
chatbox operator tail-deliveries <mailbox_id> # Recent message delivery recordsEach connector is a separate process that:
- Calls chatbox's inbound endpoint (
POST /v1/connections/:id/messages) when it receives a platform message. - Exposes its own MCP server with platform-specific outbound tools (
signal_send,telegram_send, etc.) — chatbox's per-mailbox MCP server proxies tool calls to it.
Available:
chatbox-signal— Signal viasignal-cli(ported from AIOS).chatbox-telegram— Telegram bot via long-polling (ported from AIOS).chatbox-discord— Discord bot viadiscord.py(built fresh against the contract).chatbox-slack— Slack bot viaslack_sdksocket mode (built fresh against the contract).
The contract every connector implements: CONNECTOR_CONTRACT.md.
# All service tests (requires Docker for testcontainers Postgres).
# On macOS with Docker Desktop, testcontainers may need DOCKER_HOST set;
# discover the socket path with `docker context inspect | jq -r '.[0].Endpoints.docker.Host'`.
CHATBOX_VAULT_KEY=$(python3 -c "import base64,secrets; print(base64.b64encode(secrets.token_bytes(32)).decode())") \
uv run pytest tests/
# Connector tests (no DB)
( cd connectors/signal && uv run pytest )
( cd connectors/telegram && uv run pytest )
( cd connectors/discord && uv run pytest )
( cd connectors/slack && uv run pytest )| Env var | Required | Default | Description |
|---|---|---|---|
CHATBOX_DB_URL |
yes | — | Postgres URL, e.g. postgresql://chatbox:chatbox@localhost:5434/chatbox |
CHATBOX_VAULT_KEY |
yes | — | Base64-encoded 32-byte master key for AEAD credential storage |
CHATBOX_API_HOST |
no | 0.0.0.0 |
Bind host |
CHATBOX_API_PORT |
no | 8000 |
Bind port |
CHATBOX_LOG_LEVEL |
no | INFO |
Log level |
- DESIGN.md — locked terminology, architecture, data model
- CONNECTOR_CONTRACT.md — connector ABI
- CMA_INTEGRATION.md — wire chatbox to a Claude Managed Agents session
- PHASE_1_PLAN.md, PHASE_2_PLAN.md — built phases
- PHASE_2_SCOPE.md, PHASE_3_SCOPE.md, PHASE_4_SCOPE.md — phase scopes
- SMOKE_TEST.md — operator runbook
- CHANGELOG.md — phase-by-phase deliverables
(unlicensed for now)