A Telegram bot that gives you remote access to @openai/codex through a PTY-backed Node.js runtime.
It is strictly inspired by RichardAtCT/claude-code-telegram, but this project is implemented for Codex CLI + MCP + Subagent routing.
This bot connects Telegram to Codex CLI and routes tasks to the right execution surface:
- Coding tasks -> Codex CLI in
node-pty(real TTY, stable interactive behavior) - Explicit tool tasks -> Subagents (
/mcp,GitHub Skill) - Proactive automation -> Cron scheduler for daily summaries and push notifications
Key design goals:
- Keep Codex interactive sessions smooth and stream-safe on Telegram
- Enforce zero-trust access with whitelist-only users
- Avoid duplicate MCP calls by separating Codex MCP vs Bot MCP responsibilities
- Node.js 20+ -- https://nodejs.org/en/download/current
- Codex CLI -- https://github.com/openai/codex
- Telegram Bot Token -- from
@BotFather
git clone https://github.com/MackDing/codex-telegram-claws.git
cd codex-telegram-claws
npm installcp .env.example .envMinimum required:
BOT_TOKEN=123456789:telegram-token
ALLOWED_USER_IDS=123456789
WORKSPACE_ROOT=.
CODEX_WORKDIR=.Optional safe shell:
SHELL_ENABLED=true
SHELL_ALLOWED_COMMANDS=["pwd","ls","git status","git diff --stat","npm test","npm run check"]npm run startDevelopment mode:
npm run devSanity check:
npm run check
npm testTelegram Message
-> src/bot/handlers.js
-> src/orchestrator/router.js
-> src/runner/ptyManager.js (coding tasks -> Codex CLI)
-> src/orchestrator/skills/*.js (general tasks -> MCP/GitHub subagents)
-> src/bot/formatter.js
-> Telegram sendMessage/editMessageText
Core modules:
src/index.js: bootstrap and lifecyclesrc/config.js: env parsing and validationsrc/bot/: auth middleware, formatting, command handlerssrc/orchestrator/: routing + MCP client + skillssrc/runner/ptyManager.js: Codex PTY process + streamingsrc/cron/scheduler.js: proactive scheduled push
To avoid duplicated context fetch:
- Coding requests are sent directly to Codex CLI (Codex can use its own MCP stack)
- Bot-side MCP is only used by explicit
/mcp ...commands
This prevents:
- duplicate queries against the same MCP server
- extra latency/token/tool cost
- context drift from two independent MCP execution surfaces
General:
/start- bootstrap message/help- command summary/status- show current chat status, active runner mode, workdir, model override, MCP servers/pwd- show the current project directory for this chat/repo- list switchable git projects underWORKSPACE_ROOT/repo <name>- switch the current chat to another project/repo recent- show recent projects for the current chat/repo -- switch back to the previous project/new- close current session and start fresh on the next message/exec <task>- force a one-offcodex exec/auto <task>- force a one-offcodex exec --full-auto/plan <task>- ask Codex for a plan only, without direct file modification intent/model [name|reset]- show or set the model override for the current chat/sh <command>- run a safe allowlisted Linux command in the current project (disabled by default)/interrupt- sendCtrl+Cto current PTY session/stop- terminate current PTY session/cron_now- trigger daily summary immediately
MCP skill:
/mcp tools <server>/mcp call <server> <tool> {"query":"..."}
GitHub skill:
/gh commit "feat: message"->git add .+ commit + push/gh push-> push current branch/gh create repo my-new-repo-> create repo and bind origin/gh run tests-> launch test job/gh test status <jobId>-> read test status/output tail
Telegram adaptation notes:
- Plain text messages behave like
codex "task description" /execbehaves likecodex exec "task"/autobehaves likecodex exec --full-auto "task"/newis implemented by the bot and resets the current chat session/statusis implemented by the bot and reports local runtime state/repois implemented by the bot and switches the per-chat working directory insideWORKSPACE_ROOT/shis implemented by the bot, never invokes a shell interpreter, and only accepts configured command prefixes/plantranslates to a planning-only prompt instead of passing a raw/planslash command to Codex
PTY output is streamed with throttled editMessageText updates.
- Throttle: controlled by
STREAM_THROTTLE_MS(default1200) - Long output: auto-chunked to Telegram-safe message sizes
- MarkdownV2: escaped to avoid parse failures
- Reasoning tags:
<think>...</think>extracted and rendered as:- spoiler (
||...||, default) - quote block (if
REASONING_RENDER_MODE=quote)
- spoiler (
- If
node-ptycannot spawn on the current host, the runner falls back tocodex execfor per-request execution
node-cron is built in for proactive behavior:
- Daily summary schedule:
CRON_DAILY_SUMMARY(default0 9 * * *) - Target users:
PROACTIVE_USER_IDS - Summary includes commit count, changed files, insertions/deletions, and recent commits
Use /cron_now for manual trigger during debugging.
Required:
BOT_TOKEN=...
ALLOWED_USER_IDS=123456789,987654321
WORKSPACE_ROOT=.
CODEX_WORKDIR=.Common options:
CODEX_COMMAND=codex
CODEX_ARGS=
WORKSPACE_ROOT=/Users/yourname/projects
SHELL_ENABLED=false
SHELL_ALLOWED_COMMANDS=["pwd","ls","git status","git diff --stat","npm test","npm run check"]
SHELL_TIMEOUT_MS=20000
SHELL_MAX_OUTPUT_CHARS=12000
STREAM_THROTTLE_MS=1200
STREAM_BUFFER_CHARS=120000
REASONING_RENDER_MODE=spoiler
CRON_DAILY_SUMMARY=0 9 * * *
CRON_TIMEZONE=Asia/Shanghai
PROACTIVE_USER_IDS=123456789MCP:
MCP_SERVERS=[]GitHub:
GITHUB_TOKEN=ghp_xxx
GITHUB_DEFAULT_WORKDIR=.
GITHUB_DEFAULT_BRANCH=main
E2E_TEST_COMMAND=npx playwright test --reporter=line- Whitelist-only access (
ALLOWED_USER_IDS) is mandatory - Do not commit
.env, tokens, or session artifacts - Run bot under a restricted OS user in production
- Keep
CODEX_WORKDIRscoped to a safe workspace root - Keep
WORKSPACE_ROOTlimited to a parent directory that only contains projects you want the bot to access - Keep
/shdisabled unless you need it; when enabled, only expose read-only or narrowly scoped command prefixes /shusesspawn(..., { shell: false }), rejects pipes/redirection/subshell syntax, and runs inside the current project directory- Prefer least-privilege GitHub PAT
Usually not for general users. Codex itself can run commands as part of a coding task, so /sh is not required for normal code-edit workflows.
It is useful when you need deterministic operator actions from Telegram, such as:
pwdgit statusgit diff --statnpm test
Treat it as an admin-only ops channel, not a general-purpose remote shell.
- Bot not responding: verify
BOT_TOKENandALLOWED_USER_IDS - Codex not producing output: verify
CODEX_COMMANDandCODEX_WORKDIR - Markdown parse errors: reduce output size/context; check special characters in tool output
- MCP failures: run
/mcp tools <server>first to validate server availability - GitHub API failures: verify
GITHUB_TOKENscope (repo) and account permissions - Duplicate MCP suspicion: ensure coding tasks are routed directly to Codex, and bot MCP is used only for
/mcp posix_spawnp failed: this means PTY spawn is blocked on the host; the runner will fall back tocodex exec
- Inspired by: https://github.com/RichardAtCT/claude-code-telegram
- This implementation: Codex-first Node.js stack (
telegraf,node-pty,node-cron, MCP SDK)