Local Telegram control surface for Codex sessions.
This project runs a Telegram bot on your own machine so an allowlisted Telegram user can start, resume, monitor, and respond to local Codex work. It uses the local Codex CLI and the host machine's existing Codex login. It does not add a second LLM layer.
The bridge is a working local prototype with tests and operator docs. It is useful for real testing, but it should still be reviewed carefully before being used as an always-on service.
This repo is intended as a GitHub source project, not an npm-published package.
- Telegram access is restricted to numeric user IDs in
TELEGRAM_ALLOWED_USER_IDS. - Codex control/write access is restricted to
ALLOWED_PROJECT_ROOTS. - Read-only session monitoring is restricted to
MONITORED_PROJECT_ROOTS. .env, Codex auth files, Codex sessions, logs, dependencies, and build output are ignored by Git.- Voice input and file uploads are disabled by default.
- Group chats, Telegram-initiated login, assistant-output previews, and raw error details are disabled by default. Automatic artifact delivery is also disabled by default.
danger-full-accessstyle launch profiles should be treated as explicit opt-in only.
- Windows, macOS, or Linux host with shell access.
- Node.js 22 or newer.
- npm.
- Git.
- Codex CLI installed and authenticated locally.
- A Telegram bot token from
@BotFather.
Check the local toolchain:
node --version
npm --version
git --version
codex --version
codex login statusClone the repo from your fork or chosen remote:
git clone <repo-url> codex-telegram-bridge
cd codex-telegram-bridgeInstall dependencies:
npm installCreate local configuration:
Copy-Item .env.example .envOn macOS or Linux:
cp .env.example .envEdit .env with real local values:
TELEGRAM_BOT_TOKEN=<token from BotFather>
TELEGRAM_ALLOWED_USER_IDS=<numeric Telegram user id>
CODEX_HOME=<absolute path to your Codex home>
CODEX_WORKSPACE=<absolute path to the default workspace>
ALLOWED_PROJECT_ROOTS=<comma-separated absolute paths Codex may control>
MONITORED_PROJECT_ROOTS=<comma-separated absolute paths to monitor>
CODEX_SESSION_BACKEND=app-server
CODEX_MODEL=<optional default model>
CODEX_SANDBOX_MODE=workspace-write
CODEX_APPROVAL_POLICY=on-request
ENABLE_GROUP_CHATS=false
ENABLE_TELEGRAM_LOGIN=false
SHOW_ASSISTANT_OUTPUT_IN_TELEGRAM=false
SHOW_ERROR_DETAILS_IN_TELEGRAM=false
AUTO_SEND_ARTIFACTS=false
Build and test:
npm test
npm run buildRun:
npm start- In Telegram, open
@BotFather. - Run
/newbot. - Choose a display name and bot username.
- Copy the bot token into
.envasTELEGRAM_BOT_TOKEN. - Find the numeric Telegram user ID for each allowed operator.
- Put those IDs in
.envasTELEGRAM_ALLOWED_USER_IDS.
One way to find your user ID is to send /start to the bot, then inspect:
https://api.telegram.org/bot<TELEGRAM_BOT_TOKEN>/getUpdates
Use the message.from.id value. Treat that URL like a secret while it contains
the bot token.
The bridge sets its Telegram command menu on startup, so BotFather command menu configuration is optional.
Use absolute paths.
Example:
CODEX_WORKSPACE=C:\Users\YourName\Projects\example-app
ALLOWED_PROJECT_ROOTS=C:\Users\YourName\Projects\example-app,C:\Users\YourName\Projects\another-repo
MONITORED_PROJECT_ROOTS=C:\Users\YourName\Projects\example-app,C:\Users\YourName\Projects\another-repo
ALLOWED_PROJECT_ROOTS controls where Telegram may cause Codex to work.
MONITORED_PROJECT_ROOTS controls what appears in /active and /watch.
Use monitored roots for visibility. Use allowed roots only for repos where Telegram-triggered Codex writes are acceptable.
The Telegram menu shows the main commands. /help shows the full command list.
Core:
/startchecks that the bot is reachable./helpshows all commands./newcreates a new Codex session in the default workspace./sessionshows the active session./sessionsbrowses recent main sessions./sessions allincludes related sessions./attach <session_id>attaches a chat or topic to an existing Codex session./statuschecks the current session state and latest saved output.
Monitoring:
/activelists currently active Codex sessions in monitored roots./watchlets you choose an active session to watch./watcheslists watched sessions with current run, total work, tokens, and cost when available./unwatchstops watching a session.
Usage:
/usageshows token totals, estimated cost, and total work time./usage <project>filters usage by project when multiple roots are configured./costis an alias for/usage./limitsshows the latest observed Codex rate-limit snapshot.
Live turn controls:
/answer <text>answers a Codex input request when the bridge can observe it./steer <text>sends extra input to a running app-server turn./abortinterrupts the active bridge-owned turn./retryresends the last prompt in the active chat binding.
Configuration:
/modelviews or changes the model for new turns./effortsets reasoning effort./launch_profilesselects a launch profile./authchecks local Codex auth./loginstarts Codex login whenENABLE_TELEGRAM_LOGIN=true./logoutsigns out whenENABLE_TELEGRAM_LOGIN=true./voiceshows whether voice input is enabled.
If you want another coding agent to configure the bridge for you, use:
The agent should ask you for secrets and local paths, write them only to .env,
run the verification commands, and never commit private configuration.
See Operations for foreground/background runs, restart commands, smoke tests, and troubleshooting.
Track:
- TypeScript source under
src/. - Tests under
test/. - Documentation under
docs/. package.json,package-lock.json,tsconfig.json, and.env.example.
Do not track:
.envnode_modules/dist/logs/.telecodex/- Codex auth or session files.
Before committing:
git status --short
npm test
npm run build
git diff --checkBefore making a fork or repo public:
- Rotate any Telegram bot token used during local testing.
- Confirm
.env, logs,.telecodex,dist, Codex auth files, and Codex session files are not tracked. - Run
git status --ignored --shortand verify ignored local files are not part of the release archive. - Run
npm test,npm run build,npm audit --omit=dev, andnpm pack --dry-run. - Check Git history for private paths, project names, tokens, and chat IDs. If anything private appears in history, publish from a fresh clean repository instead of making that history public.
- Review package metadata, license/provenance, and setup docs.
