Codex Telegram bot and remote UI for local OpenAI Codex App Server, built in Go.
codex-tg turns a Telegram bot into a mobile control surface for local Codex threads: it watches Codex GUI/CLI activity, keeps thread identity visible, routes replies back to the right thread, and exposes high-signal controls such as Plan Mode prompts, Stop, Steer, Details, Tools file, and Get full log.
- Codex Telegram remote UI for local OpenAI Codex App Server.
- Control and observe Codex threads from Telegram without exposing App Server to the internet.
- Reuse your existing Codex setup: skills, MCP servers, plugins, repo instructions, and local workflows.
- Thread-first routing keeps replies, tools, Plan Mode, Details, and Final cards attached to the right run.
- Built for long-running local coding-agent work from a phone.
Current release: v0.4.0.
The demo flow is documented in docs/demo/telegram-plan-mode-demo.md.
- Keep local Codex work observable from a phone without exposing Codex App Server to the internet.
- Continue supervising long-running coding tasks while away from the workstation.
- Use Telegram as a low-friction fallback surface on unreliable or constrained networks.
- Preserve local-first ownership: Codex sessions, workspaces, SQLite state, and tokens stay on your machine.
1. User request and Plan Mode
2. Tool execution and output
3. Final answer and Details
- Thread-first routing over local
codex app-serverstdio. - Global observer for foreign GUI/CLI runs, with polling fallback through
thread/read. - Telegram-origin live current tool rendering from App Server
item/*events, while foreign GUI/CLI panels stay completed-tool only. - Stable visual identity per thread: emoji marker plus project/thread/run chips.
- Explicit
New run -> [User] -> [commentary] -> [Tool] -> [Output] -> [Final]chronology with status on the live commentary/final card. - Low-noise Telegram notifications: only
New run(configurable),[Plan], and[Final]are audible; live progress and exports are sent silently. - Plan Mode starts from Telegram via
/planor/reply --plan; if a thread remains in Plan Mode, the Plan Final Card offersTurn off Planand/stopalso arms the next normal turn to leave Plan Mode.[Plan]prompt-cards keep reply-first routing and structured buttons when Codex provides choices. - Final Card with Details pagination and on-demand Tools file export.
- On-demand full log archive from Codex session JSONL.
- SQLite-backed durable state for bindings, routes, callbacks, observer target, panels, and delivery metadata.
- macOS service installer with friendly first-run setup, user LaunchAgent management, and menu bar tray control.
- Cross-platform Go daemon foundation for Windows, macOS, and Linux.
- Windows: actively tested with the local Codex App Server, Telegram Bot API, observer flows, and live E2E demo.
- macOS:
v0.4.0is verified stable on macOS 26.3.1 arm64 with Go 1.26.2, user LaunchAgent service setup, local build, package dry-run, Details binding validation, Telegram command-menu readback, real Chat folder creation, low-noise notification validation, Plan Mode reset validation, and live Telegram readback E2E. - Linux: CI runs tests/builds on Ubuntu; full local daemon/runtime validation is still pending.
Prerequisites:
- OpenAI Codex CLI with
codex app-server. - A Telegram bot token from BotFather.
- Your Telegram numeric user id.
On macOS, download the latest .pkg from
GitHub Releases,
install it, then run:
ctr-go service install --start --start-at-login
ctr-go doctorctr-go service install starts a friendly first-run setup wizard when required.
The same values can be passed with flags for scripted installs. It writes a
private local config file at ~/.codex-tg/config.env by default, creates a
user LaunchAgent, and starts the daemon when --start is present.
If your shell uses proxy variables such as HTTPS_PROXY or NO_PROXY, the
installer preserves them in the private config so the LaunchAgent can reach the
same network without putting secrets or user ids into the plist.
For Linux, Windows, or manual macOS setup, download the latest ctr-go archive,
unpack it, then run:
ctr-go init
ctr-go doctor
ctr-go daemon runUse CTR_GO_CONFIG to point at another config file. Explicit environment
variables still override config file values.
Build from source:
git clone https://github.com/mideco-tech/codex-tg.git
cd codex-tg
go run ./cmd/ctr-go init
go run ./cmd/ctr-go doctor
go run ./cmd/ctr-go daemon runEnvironment-only setup remains supported:
$env:CTR_GO_TELEGRAM_BOT_TOKEN = "<telegram-bot-token>"
$env:CTR_GO_ALLOWED_USER_IDS = "<telegram-user-id>"
$env:CTR_GO_DEFAULT_CWD = "C:\Users\you\Projects\Codex"In Telegram:
/start
/observe all
/threads
/context
Start or continue a Codex thread from Codex GUI/CLI. codex-tg should create a New run card, a [User] card, live progress cards, and then send a final answer card with Details while cleaning up transient live cards.
Set CTR_GO_NOTIFY_NEW_RUN=off to keep New run visible but silent. [Plan] prompts and [Final] cards still use normal Telegram notifications.
ctr-go init
ctr-go service install
ctr-go service start
ctr-go service stop
ctr-go service restart
ctr-go service status
ctr-go doctor
ctr-go status
ctr-go repair
ctr-go daemon runSource-build equivalents:
go run ./cmd/ctr-go init
go run ./cmd/ctr-go service install
go run ./cmd/ctr-go doctor
go run ./cmd/ctr-go status
go run ./cmd/ctr-go repair
go run ./cmd/ctr-go daemon runTelegram commands:
/start,/help/threads,/projects,/new,/newchat,/newthread,/show,/bind,/reply,/plan/settings,/model,/effort/context,/whereami/observe all,/observe off/status,/repair,/stop,/approve,/deny
/projects opens cached project/workspace navigation sorted by the latest
thread activity. Codex UI Chats from Documents/Codex are grouped under
Chats: the main projects view shows recent Chat previews, Open Chats opens
the full paginated Chat list, and choosing a Chat opens and binds its thread.
Use New thread in a normal project menu to create a new thread in that
project cwd. Use /newchat <prompt> to create a Codex UI Chat under
Documents/Codex/<date>/<prompt-slug>. Use /newthread <prompt> when you need
a thread without choosing a project or creating a Chat folder; App Server may
still attach the daemon default cwd.
Primary environment variables:
CTR_GO_HOMECTR_GO_CONFIG(~/.codex-tg/config.envby default)CTR_GO_CODEX_BINCTR_GO_APP_SERVER_LISTENCTR_GO_TELEGRAM_BOT_TOKENCTR_GO_ALLOWED_USER_IDSCTR_GO_ALLOWED_CHAT_IDSCTR_GO_DEFAULT_CWDCTR_GO_CODEX_CHATS_ROOT(~/Documents/Codexby default)CTR_GO_NOTIFY_NEW_RUN(trueby default; setfalse/off/0to sendNew runsilently)CTR_GO_LOG_ENABLED(trueby default; setfalse/off/0to discard daemon stdout logs)CTR_GO_DIAGNOSTIC_LOGS(trueby default; setfalse/off/0to keep normal bot logs but suppress structureddaemon_eventdiagnostics)CTR_GO_OBSERVER_POLL_SECONDSCTR_GO_REQUEST_TIMEOUT_SECONDSCTR_GO_PROJECTS_PROJECT_PREVIEW_LIMIT(7by default)CTR_GO_PROJECTS_CHAT_PREVIEW_LIMIT(3by default)CTR_GO_CHATS_PAGE_SIZE(8by default)CTR_GO_INDEX_REFRESH_SECONDSCTR_GO_ATTACH_REFRESH_SECONDSCTR_GO_DELIVERY_RETRY_SECONDSCTR_GO_DELIVERY_MAX_ATTEMPTS
Compatibility fallbacks:
CTR_TELEGRAM_BOT_TOKENCTR_ALLOWED_USER_IDSCTR_ALLOWED_CHAT_IDS
go test ./...
go build -buildvcs=false ./...Live Telegram readback E2E is documented in
tests/live_e2e/README.md. It is intentionally
gated by local env and is not part of go test ./....
Live demo for a screenshot:
$env:CTR_DEMO_TELEGRAM_E2E = "1"
$env:CTR_DEMO_TELEGRAM_CHAT_ID = "<telegram-chat-id>"
$env:CTR_GO_TELEGRAM_BOT_TOKEN = "<telegram-bot-token>"
$env:CTR_DEMO_KEEP_MESSAGES = "true"
go test -tags demo_e2e ./tests -run TestTelegramPlanModeScreenshotDemo -count=1 -vSee docs/demo/telegram-plan-mode-demo.md for the screenshot checklist.
Suggested repository description:
Codex Telegram bot and remote UI for local OpenAI Codex App Server. Observe, approve, and steer Codex from Telegram.
Suggested topics:
codex telegram telegram-bot telegram-ui openai-codex codex-cli
codex-app-server ai-agents coding-agent remote-control developer-tools
local-first go golang macos windows linux plan-mode agent-observer json-rpc
- Architecture
- Quickstart
- Telegram UX
- Plan Mode
- Security
- Operations
- Demo
- Changelog
- Contract matrix
- Validation notes
- ADRs
Apache License 2.0. This keeps the project permissive for the community while also providing an explicit patent grant that large companies usually expect from infrastructure and developer-tooling projects.
- Telegram long polling returns
409 Conflictwhen another process consumes the same bot token. - Do not expose Codex App Server on a public interface.
codex-tgis designed around local stdio. - Keep bot tokens, Telegram sessions, SQLite databases, logs, and
.envfiles out of git.



