Interfaces
An interface is a pluggable human-facing channel. Telegram is the shipping adapter; Discord, iMessage, CLI, and webhook are planned.
Telegram lives directly on the manager and is set up by teamctl bot setup (one bot per user-facing manager — DM the bot, the message goes to the matching manager). Other adapters use the top-level interfaces: array shape.
# projects/news.yaml — Telegram on the manager itselfmanagers: head_editor: runtime: claude-code role_prompt: roles/head_editor.md interfaces: telegram: bot_token_env: TEAMCTL_TG_HEAD_EDITOR_TOKEN chat_ids_env: TEAMCTL_TG_HEAD_EDITOR_CHATS# team-compose.yaml — non-Telegram adaptersinterfaces: - type: discord name: discord-home-lab config: bot_token_env: TEAMCTL_DISCORD_TOKEN server_id: "…"
- type: imessage name: imsg config: my_number: "+31…"
- type: cli name: local # No config. Reachable via `teamctl chat <project>:<manager>`.Approvals are routed to every attached interface until one of them decides.
What interfaces do
| Interface | Inbound DMs | Approval buttons | Notes |
|---|---|---|---|
| telegram | ✓ | ✓ | Shipping adapter. |
| discord | ✓ | ✓ | Slash commands + buttons. |
| imessage | ✓ | ✗ (reply “approve 3”) | macOS host only. |
| cli | ✓ | ✓ | teamctl chat / teamctl pending. |
| webhook | ✓ | ✓ | For web dashboards or IFTTT-style. |
Adapter contract
An adapter is a process that:
- Reads new messages for subscribed managers (
inbox_peek/inbox_watch, scoped via--managerfor the Telegram adapter). - Surfaces them to the human.
- Writes human replies back as
sender=user:<handle>via SQL insert or team-mcp. - Listens for approval notifications and renders inline decision UI.
Adapters ship as small standalone binaries next to teamctl — team-interface-telegram, team-interface-discord, etc.