| 1 | # Telegram Bridge |
| 2 | |
| 3 | This bridge lets a Telegram chat control a local `codewhale serve --http` |
| 4 | runtime from a phone. It uses Telegram Bot API long polling, so the first |
| 5 | version does not need a public webhook URL or inbound port. |
| 6 | |
| 7 | Security model: |
| 8 | |
| 9 | - `codewhale serve --http` stays bound to `127.0.0.1`. |
| 10 | - `/v1/*` runtime calls use `CODEWHALE_RUNTIME_TOKEN`. Legacy |
| 11 | `DEEPSEEK_RUNTIME_TOKEN` is accepted only as a compatibility fallback. |
| 12 | - Telegram chats must be allowlisted unless `TELEGRAM_ALLOW_UNLISTED=true` is |
| 13 | set for first pairing. |
| 14 | - Direct messages are the intended MVP control surface. Group chat control is |
| 15 | disabled unless `TELEGRAM_ALLOW_GROUPS=true`. |
| 16 | - Tool approvals are text commands: `/allow <approval_id>` or `/deny <approval_id>`. |
| 17 | - The bridge also sends inline button controls for common actions. Text |
| 18 | commands remain the fallback. |
| 19 | |
| 20 | ## Setup |
| 21 | |
| 22 | Create a bot with Telegram's `@BotFather`, then configure the bridge: |
| 23 | |
| 24 | ```bash |
| 25 | cd /opt/codewhale/telegram-bridge |
| 26 | npm install --omit=dev |
| 27 | cp .env.example /etc/codewhale/telegram-bridge.env |
| 28 | sudoedit /etc/codewhale/telegram-bridge.env |
| 29 | node src/index.mjs |
| 30 | ``` |
| 31 | |
| 32 | Validate env files before starting the service: |
| 33 | |
| 34 | ```bash |
| 35 | npm run validate:config -- \ |
| 36 | --env /etc/codewhale/telegram-bridge.env \ |
| 37 | --runtime-env /etc/codewhale/runtime.env \ |
| 38 | --workspace-root /opt/whalebro \ |
| 39 | --check-filesystem |
| 40 | ``` |
| 41 | |
| 42 | For first pairing, temporarily set `TELEGRAM_ALLOW_UNLISTED=true`, send the bot |
| 43 | `/status`, copy the returned `chat_id` or `user_id` into |
| 44 | `TELEGRAM_CHAT_ALLOWLIST`, then turn `TELEGRAM_ALLOW_UNLISTED=false`. |
| 45 | |
| 46 | ## Commands |
| 47 | |
| 48 | - `/menu` |
| 49 | - `/status` |
| 50 | - `/threads` |
| 51 | - `/new` |
| 52 | - `/resume <thread_id>` |
| 53 | - `/model <name|default>` |
| 54 | - `/interrupt` |
| 55 | - `/compact` |
| 56 | - `/allow <approval_id> [remember]` |
| 57 | - `/deny <approval_id>` |
| 58 | |
| 59 | Anything else is sent as a prompt. If group control is explicitly enabled, |
| 60 | messages must start with `/cw` by default, for example: |
| 61 | |
| 62 | ```text |
| 63 | /cw check git status and tell me what is dirty |
| 64 | ``` |
| 65 | |
| 66 | The `/menu`, `/status`, `/threads`, active-turn, and approval messages include |
| 67 | tap targets for common actions. Approval buttons map to the same runtime API as |
| 68 | `/allow` and `/deny`; they do not enable blanket auto-approval unless you tap |
| 69 | the explicit "Allow + remember" button. |
| 70 |