# Codex Telegram Bot Hybrid Host/App-Server Plan ## Summary Create `codex-telegram-bot/` as a Docker Compose managed Go Telegram bot that connects to a **host-launched Codex CLI app-server**. Codex is not containerized: it runs from the installed host `codex` binary, using the host user's `~/.codex`, sandboxing, and workspace paths. The bot runs in Docker Compose, stores state in SQLite, and communicates with Codex through a bind-mounted Unix socket. ## Research Before implementation, carefully read the official docs and check against the guidelines below. Create/Update them properly if discrepancies or new findings occur. If you are not sure, ask the user for advice/instruction. - Codex App Server official docs: https://developers.openai.com/codex/app-server - App-server is intended for rich clients with authentication, conversation history, approvals, and streamed agent events. - Protocol is JSON-RPC 2.0 with the `jsonrpc` field omitted. - Important: `unix://` transport is WebSocket over Unix socket using HTTP Upgrade, not raw newline JSON. - Start flow: connect, send `initialize`, send `initialized`, then `thread/start` and `turn/start`. - Generate version-matched protocol schemas with `codex app-server generate-json-schema --out ./schemas`. - Telegram Bot API official docs: https://core.telegram.org/bots/api - `sendMessage` and `editMessageText` are limited to 1-4096 chars after entity parsing. - Callback buttons require `answerCallbackQuery`. - `getFile` downloads are limited to 20 MB via cloud Bot API. - `sendDocument` supports bot-sent files up to 50 MB via cloud Bot API. - Use long polling for MVP unless webhook deployment is explicitly needed. - Telegram bot feature docs: https://core.telegram.org/bots/features - Validate commands server-side regardless of BotFather command scopes. - Reject group/supergroup/channel updates in code even if group joining is disabled. - Use inline keyboards for approve/deny/details actions. ## Key requirements - Scaffold a Go bot project: - `cmd/bot` for the bot process. - `internal/telegram` for commands, callbacks, message rendering, and Telegram file downloads. - `internal/codexapp` for app-server WebSocket-over-Unix-socket JSON-RPC. - `internal/store` for SQLite state and migrations. - `scripts/start-codex-app-server`, `scripts/allow-user`, `scripts/remove-user`, `scripts/list-users`, `scripts/add-workspace`, `scripts/list-workspaces`. - Docker Compose runs only the bot: - Build the Go bot image locally. - Mount persistent SQLite data. - Bind-mount the host socket path into the bot container. - Bind-mount an upload staging directory at the same absolute path visible to host Codex. - Do not install or run Codex CLI inside the bot container. - Host Codex app-server: - Started outside Compose with `scripts/start-codex-app-server`. - Default command: `codex app-server --listen unix://$HOST_CODEX_SOCKET`. - Uses host `~/.codex`, host workspaces, and host sandbox behavior. - Socket defaults to an absolute path under the project, e.g. `$PROJECT/run/codex.sock`. - Telegram UX: - One-to-one chats only; reject groups, supergroups, and channels. - Allowlisted Telegram user IDs only. - Commands: `/start`, `/help`, `/new`, `/threads`, `/resume`, `/fork`, `/archive`, `/status`, `/cancel`, `/workspaces`, `/workspace`, `/model`, `/sandbox`, `/diff`. - Plain text continues the active Codex thread, creating one if needed. - Send assistant messages and rendered tool/status blocks as separate Telegram messages; chunk only when a single message exceeds Telegram limits. - Send long output, logs, and diffs as chunked messages. - Consider using HTML to render if markdown is weak/awkward. - Render Codex approval requests as inline keyboards with approve, deny, and details actions. - SQLite state: - `allowed_users`, `workspaces`, `sessions`, `threads`, `pending_approvals`, `audit_log`. - Workspace paths are host absolute paths used as Codex `cwd`. - The bot does not need direct workspace access except for upload staging. ## Test Plan Any interactive related test that requires user action should be done properly - ask the user to do X in telegram, then verify. - Unit tests: - Allowlist enforcement and group-chat rejection. - Workspace path validation. - Telegram escaping, chunking, document fallback, and callback validation. - WebSocket-over-Unix-socket JSON-RPC request correlation and reconnect behavior. - SQLite migrations and admin scripts. - Integration tests: - Use a low/mini model in codex for testing. - Verify initialize, thread start, turn start, streamed output, approval, and cancellation. - Verify `/start`, `/new`, `/threads`, `/resume`, `/workspace`, `/cancel`, image input, and document staging. - Verify non-allowlisted users are rejected and logged. - Manual acceptance: - Start host Codex app-server with `scripts/start-codex-app-server`. - Run `docker compose up --build`. - Add an allowlisted user and workspace with scripts. - In a one-to-one Telegram chat, run `/start`, select workspace, create a thread, send a prompt, approve a Codex request, inspect output, and cancel a running turn. ## Assumptions - Bot runtime is Docker Compose. - Codex CLI app-server is launched from the installed host binary, outside Docker. - The Unix socket is the only v1 connection between bot and Codex. - Go is used for the bot. - SQLite is used for state and admin-managed allowlist/workspaces. - Codex-in-container and `codex exec` are both out of scope for MVP. - This computer is resource limited. Use docker/docker compose for large tools/SDKs to avoid installing locally.