A Telegram bot that gives you remote access to @openai/codex through a Node.js runtime with two Codex backends: the Codex SDK and the legacy CLI/PTy path.
It is strictly inspired by RichardAtCT/claude-code-telegram, but this project is implemented for CodeX SDK/CLI + MCP + Subagent routing.
- installs a Telegram-facing Codex runtime
- keeps Codex live sessions scoped to
chat + repo - manages bot-side MCP and GitHub subagents
- exposes repo switching, status, and minimal frontend dev-server control from Telegram
Dex Agent is the runtime package in the Dex ecosystem. The companion workflow package is auto-fluxo-flow, a phased workflow skill/plugin for Codex agents. The operational memory contract is published as dex-memoria, a documental package for memory lifecycle rules and sanitized templates. See docs/ecosystem.md for the current map of runtime, skills, project instances, and governance files.
$DexAgentHome = Join-Path $env:USERPROFILE ".dex-agent"
git clone https://github.com/dex-agent/dex-agent.git $DexAgentHome
Set-Location $DexAgentHome
npm install
Copy-Item .env.example .envOn Windows, the recommended operational install path is %USERPROFILE%\.dex-agent.
Keep development clones and project repositories outside that folder to avoid mixing
the bot runtime with normal GitHub workspaces.
BOT_TOKEN=123456789:telegram-token
ALLOWED_USER_IDS=123456789
STATE_FILE=.codex-telegram-claws-state.json
WORKSPACE_ROOT=%USERPROFILE%/.dex-agent
CODEX_WORKDIR=%USERPROFILE%/.dex-agent
CODEX_BACKEND=sdknpm run start/status
/admin
/repo
/skill
/dev status
/agora revisar a regra urgente antes de continuar
/gh create repo my-new-app
For agent-oriented setup, see SKILL.md.
For child project installs, use the canonical Dex Install guide: skills/dex-install/README.md.
This bot connects Telegram to Codex and routes tasks to the right execution surface:
- Coding tasks -> Codex SDK threads or Codex CLI/PTy sessions
- 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
- Prefer the SDK backend for new installs, while keeping the CLI backend as a fallback
- Node.js 20.19+ or 22.13+ -- https://nodejs.org/en/download/current
- Codex CLI -- https://github.com/openai/codex
- Telegram Bot Token -- from
@BotFather
$DexAgentHome = Join-Path $env:USERPROFILE ".dex-agent"
git clone https://github.com/dex-agent/dex-agent.git $DexAgentHome
Set-Location $DexAgentHome
npm installCopy-Item .env.example .envMinimum required:
BOT_TOKEN=123456789:telegram-token
ALLOWED_USER_IDS=123456789
STATE_FILE=.codex-telegram-claws-state.json
WORKSPACE_ROOT=%USERPROFILE%/.dex-agent
CODEX_WORKDIR=%USERPROFILE%/.dex-agent
CODEX_BACKEND=sdkOptional safe shell:
SHELL_ENABLED=true
SHELL_READ_ONLY=true
SHELL_ALLOWED_COMMANDS=["pwd","ls","git status","git diff --stat","npm test","npm run check"]
SHELL_DANGEROUS_COMMANDS=["git add","git commit","git push","rm","mv","cp","npm publish"]npm run startDevelopment mode:
npm run devValidation:
npm run check
npm run lint
npm run format:check
npm test
npm run healthcheck
npm run healthcheck:liveFor live checks, configure your own local .env values after startup and keep the output local.
- do not commit or paste live output containing bot usernames, chat IDs, thread IDs, or other environment-specific identifiers
- use your own
BOT_TOKEN,ALLOWED_USER_IDS, and Codex credentials locally - for GitHub Actions, set
TELEGRAM_BOT_TOKEN,TELEGRAM_EXPECTED_USERNAME, andTELEGRAM_SMOKE_CHAT_IDin repository secrets instead of hardcoding them
npm run start- start the botnpm run dev- watch mode for local developmentnpm run check- TypeScript type and syntax validation for the repositorynpm run typecheck- run the TypeScript compiler in--noEmitmodenpm run lint- ESLint for source, tests, scripts, and local JS/CJS config filesnpm run lint:fix- apply safe lint fixesnpm run format- format repository files with Prettiernpm run format:check- verify formattingnpm test- run the full test suitenpm run healthcheck- static runtime readiness checknpm run healthcheck:strict- stricter production-oriented health checknpm run healthcheck:live- live Codex + Telegram probe against the configured backend and bot tokennpm run telegram:smoke- live Telegram API smoke test when a real bot token is available
Telegram text/audio/image
-> src/bot/handlers.ts
-> explicit command handlers (/project, /admin, /repo, /queue, /memory, /inbox, ...)
-> src/runner/ptyManager.ts (free-text execution -> Codex SDK or Codex CLI)
-> src/orchestrator/skills/*.ts (explicit bot-side capabilities)
-> src/bot/formatter.ts
-> Telegram sendMessage/editMessageText
Finalized responses do not offer follow-up action buttons by default. If an operator explicitly enables FINAL_ACTIONS_AUTO_OFFER=true, the bot can surface a compact follow-up keyboard with optional audio summary buttons, a short suggested reply prompt, and focused actions: the exact extracted next step, a contextual route that is either transform into planning or send to specialist, dynamic support buttons such as review/quick meeting/inbox when the text calls for them, finish whole block, autopilot, and autopilot x3. The short action button mirrors the concrete next step already stated in the finalized response, planning uses $sprinter, and specialist handoff appears only when the finalized response names one non-planning Proximo especialista indicado.
When FINAL_ACTIONS_AUTO_OFFER=true and a finalized response includes both Proximo passo and Proximo Passo Recomendado, the follow-up keyboard prioritizes the recommended step as the primary button and keeps the panel compact: Recomendado, Sugestao curta, and the -> marker. Example: Proximo Passo Recomendado: Tereza Testa, execute o near_term_slot_duplo_lu_souza. becomes the primary -> action instead of falling back to a generic /plan.
The /project prompts built-ins must stay anchored to the current workspace contract. Do not hardcode a domain flow from another repo into a generic preset; prompts like end-to-end testing should tell Codex to identify the project's own main flow first.
Core modules:
src/index.ts: bootstrap and lifecyclesrc/config.ts: env parsing and validationsrc/bot/: auth middleware, formatting, command handlers, deterministic menu/catalogsrc/orchestrator/: memory, project understanding, MCP client, explicit skillssrc/runner/ptyManager.ts: Codex runner abstraction for SDK threads, CLI/PTy sessions, queueing, and resume statesrc/cron/scheduler.ts: proactive scheduled push
Enterprise target architecture: docs/enterprise-architecture.md Enterprise Phase 1 roadmap: docs/phase-1-roadmap.md Project memory system v1: docs/memory-system/README.md
If you are using this repository as the dedicated workspace of the bot, the canonical recovery path is:
- open INDEX.md
- follow the surfaced pointer into
.agents/PROJECT.md,.agents/ACTIVE.md,.agents/HANDOFF.md, or.codex/napkin.md - only then open deeper docs, sprint notes, skills, or archives
Current operational rules:
- the local autostart validated on this machine is the Windows Startup folder, not Task Scheduler
/projectnow readsINDEX.md,.agents/PROJECT.md, and.agents/HANDOFF.md -> Current block statusas primary recovery surfaces instead of relying only onACTIVE/HANDOFF.agents/HANDOFF.md -> Current block statusis the canonical place to answer what just closed, how much is complete, what comes next, which specialists are suggested for the live session, and how to fall back if review or replanning is neededskills/README.mdis the authoritative inventory for local skills versus mirrored global skills
Governance principle:
- every action or event should point to a method
- every method should be guided by a contract
- if a recurring flow still has no clear method or no explicit contract, it should not be treated as a stable standard yet
- each working phase should have a named specialist assisting by default:
pensamento->questionadorplanejamento->sprinterconstruir->mapeador-implementacaorevisar->revisor-codigo(Renata Review)testar->tio-testadorveredito->validador-pronto(Vera Veredito)
- when a phase uses its specialist, the close-out should explicitly credit the collaboration of that specialist
The bot now follows a deterministic split:
- free text, transcribed audio, and images go directly to Codex
- structured actions happen only through commands, menu buttons, or inline callbacks
- bot-side MCP and GitHub actions are explicit only
That means:
/gh ...goes to the GitHub skill/mcp ...goes to the MCP skill/memory ...and/inbox ...go to the project memory control plane- normal messages stay a Codex conversation turn
This prevents:
- accidental intent capture from heuristic routing
- duplicate MCP work across bot and Codex
- control-plane actions being mixed with free-text execution
The bot now has a file-based reuse loop on top of project memory:
- finalized Codex responses can become durable memory candidates
- finalized Codex responses now auto-capture only in strict cases: explicit memory/promotion asks or structured lines like
Decision:andRule: - repeated or explicit reusable flows can become
skill_candidate - strong and clear cases can auto-promote into a reusable skill
- global skills born from this repo are mirrored back into
skills/
What changes in practice:
- the main UX stays in chat; the bot can tell you it learned a reusable flow
/inboxremains the review surface for candidates and proposals/memoryremains the technical inspection surface/projectnow exposes aReuso Rapidoblock with recent promoted skills and pending skill candidates- recall now uses one shared retrieval query plus live operational context instead of separate ad hoc query strings per caller
- finalized runtime closeouts, verdict wrappers, meeting wrappers, and phase-labelled narration are now filtered before they can become
skill_candidate
skills/README.md is the authoritative inventory for how this repository classifies reusable skills.
Current rule of the repo:
dex-agent-audio-summaryis the canonical global skill for summary and explanatory audio viaDex Agent; the reusable home lives in the machine-wide vault and this repo keeps a faithful mirror underskills/refinador-intencaois a local product skill for weak or ambiguous captures before deciding between durable memory, local skill, global skill, or live state onlypromocao-memoria-para-skillis a faithful mirror of the canonical global skill and must stay aligned with the machine-wide vault contract- when the local-vs-global decision is obvious and strong, the agent should update the canonical home plus the repo mirror directly and only report what changed; user consultation becomes the exception for materially ambiguous cases
Practical consequence:
- if a repo-specific workflow diverges from the canonical audio-skill contract, give it a new local name instead of changing the mirrored global skill in place
- when a capture is still vague, refine it first through
refinador-intencaoinstead of forcing/rememberor a premature skill promotion
General:
/start- bootstrap message/menu- deterministic dashboard with clickable shortcuts/admin [show|link|prompts|prompts add ...|prompts remove ...|history|history explain ...|history discard ...|history propose ...|history cancel ...]- show the internal admin dashboard snapshot, open a real local dashboard link, manage custom admin prompts, or inspect and mutate the focused history module for the current project/help- command summary/status- show current chat status, active runner mode, workdir, model override, reasoning-effort override, MCP servers, the internal superpowers workflow phase, and the derived operational posture (working,queued,awaiting closeout,prolonged silence, etc.)/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 <keyword>- fuzzy match projects; switch if only one match, otherwise list candidates/repo <typo>- suggests the closest project name when there is no direct match/repo recent- show recent projects for the current chat/repo -- switch back to the previous project/project- show the current project card with deterministic action buttons/project [default|executive|next|sources|steps|commands|prompts|queue]- open a specific project card variant; the card now readsINDEX,PROJECT, andCurrent block status, keeps the primary surface focused on action and navigation, and leaves raw file inspection to/memory view .../inbox- show the durable memory inbox for the current project, includingskill_candidate/inbox [candidates|proposals|promote|discard|why|confirm|cancel|help]- review and promote durable memory or reusable-skill candidates/memory- inspect project memory usage, operational memory state, and the surfaced filesINDEX,PROJECT,ACTIVE,HANDOFF,napkin, orledger/memory [show|help|candidates|promote|discard|why|remember <text>]- technical memory surface backed by the same inbox/new- clear the saved Codex conversation for the current project and start fresh on the next message/exec <task>- force a one-off Codex run without saving project context/auto <task>- force a one-off fully automatic Codex run without saving project context/autopilot [status|resume|off|<count>|on <count>]- arm, resume, or disable the special autopilot for a fixed number of finalized responses in the current chat/plan <task>- ask Codex for a plan only, without direct file modification intent/continue- replay the last blocked same-workdir Codex request once/agora <message>- interrupt the active Codex run in this same chat and send an urgent instruction with a safe resume prompt; example:/agora antes de continuar, verifique a regra de permissao da aba Consultas/inject <message>- alias of/agora/model [name|reset]- show or set the model override for the current chat/reasoning [low|medium|high|xhigh|reset]- show or set the reasoning-effort override for the current chat; PT-BR aliases likebaixa,media,alta, andaltissimoalso work/language [en|zh|zh-HK]- show or set the system language for the current chat/verbose [on|off]- show or toggle system notices for the current chat/skill list- show skill switches for the current chat/skill status- alias of/skill list/skill on <name>- enable a skill for the current chat/skill off <name>- disable a skill for the current chat/dev start- start the current repo frontend server (dev, thenstart)/dev stop- stop the current repo frontend server/dev status- show the current repo frontend server status/dev logs- show the current repo frontend server log tail/dev url- show the detected local frontend URL/sh <command>- run a safe allowlisted Linux command in the current project (disabled by default)/sh --confirm <command>- confirm a dangerous command when writable mode is enabled/restart- restart the bot process explicitly from Telegram/interrupt- interrupt the active Codex run/stop- terminate the active Codex run/cron_now- trigger daily summary immediately
MCP skill:
/mcp list/mcp status [server]/mcp reconnect <server>/mcp enable <server>/mcp disable <server>/mcp tools <server>/mcp call <server> <tool> {"query":"..."}
GitHub skill:
/gh commit "feat: message"-> explicit GitHub write action/gh push-> explicit push for the current branch/gh create repo my-new-repo-> explicit sibling repo creation underWORKSPACE_ROOT/gh confirm-> confirm the pending GitHub write action and execute it- plain-text write requests such as
create repo ...,commit, orpushare intercepted and converted into guidance; they no longer execute GitHub writes directly /gh run tests-> launch test job/gh test status <jobId>-> read test status/output tail
Telegram adaptation notes:
- Plain text messages behave like a normal Codex conversation turn
- Audio and image inputs also go directly to Codex after bot-side preprocessing
- Structured bot actions are deterministic: command, menu, or button only
/execruns a one-off Codex task and does not overwrite the saved project conversation slot/autoruns a one-off Codex task withapprovalPolicy=neveron the SDK backend, orcodex exec --full-autoon the CLI backend/autopilot <count>arms a persistent per-chat test mode that automatically follows thePiloto automaticopath after each finalized response until the configured counter reaches zero or you run/autopilot off/autopilot resumeasks the armed autopilot to continue from the last saved finalized response after a restart, consuming one configured auto-followup only if the resume run actually starts- the
Piloto x3final-action button arms a short three-step autopilot run and starts it from the current finalized context; it decrements the counter only when the first run actually starts - the armed autopilot stops instead of spending remaining steps when the finalized response says there is no open block or sprint, the line is already at
100%, or the safe next step is explicitly to stay closed - when the armed autopilot stops, it sends a useful stop card with the reason, blind spot, golden tip, and safe options instead of silently leaving the chat without direction
/newis implemented by the bot and resets the current chat session/newonly clears the current project's saved Codex conversation slot/statusis implemented by the bot and reports local runtime state/statusalso surfaces the internalsuperpowersworkflow system, the last detected workflow phase, and observability hints from the live operational continuation state so the bot can distinguish active work, queue, waiting, and prolonged silence more honestly/repois implemented by the bot and switches the per-chat working directory insideWORKSPACE_ROOT/skillis implemented by the bot and keeps per-chat skill switches in runtime state/skillonly lists toggleable bot skills;superpowersis shown as an internal workflow, not a toggleable skill- after startup or restart, if this chat still has a recoverable prompt queue, the bot now describes the real boot source, auto-runs the next queued item when possible, and skips the generic "ready" notice for that same chat
- reusable-flow learning is file-based and auditable; there is no hidden state, embeddings, or vector DB behind it
/devis implemented by the bot and manages one frontend server per repo workdir, shared across chats/dev startpreferspackage.jsonscriptdevand falls back tostart/shis implemented by the bot, never invokes a shell interpreter, and only accepts configured command prefixes/shis read-only by default; dangerous prefixes can be configured and require--confirmwhen writable mode is enabled/plantranslates to a planning-only prompt instead of passing a raw/planslash command to Codex- contextual
/planrequests such as "em cima daqui", "achados", "findings", or "consolidar tudo que ja foi levantado" attach the latest finalized action text as the primary planning source before falling back to durable project memory - If another chat already has an active Codex run in the same workdir, the bot blocks the new request and requires
/continuefor a one-shot override - The default bot language is
pt-BR; use/languageto switch the chat locale /verbose offkeeps Telegram output quiet by hiding fallback, startup, and session-exit notices for the current chat
Codex 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 (
- On
CODEX_BACKEND=sdk, Telegram streams structured Codex SDK events and persists thread IDs per project - On
CODEX_BACKEND=cli, the bot prefers PTY sessions; ifnode-ptycannot spawn on the current host, it falls back tocodex exec - In CLI exec fallback mode, Telegram output is cleaned to hide the Codex banner, raw tool trace,
mcp startup, and duplicatetokens usedfooter - On Unix-like hosts, startup auto-repairs
node-ptyhelper execute permissions before the first PTY session; on Windows, the preflight validates the nativenode-ptyartifact instead
Conversation state is now tracked per chat + project, not just per chat.
- When you switch with
/repo <name>, the bot keeps that project's last Codex session id in runtime state - When you switch back to the same project later, the next plain-text task resumes that project's Codex thread/session
/newclears only the current project's saved conversation slot; other projects in the same Telegram chat are untouched/exec,/auto, and/planstay one-off by design and do not replace the saved project conversation- On the SDK backend, project restore uses
resumeThread(threadId) - On the CLI backend, project restore uses PTY resume or
codex exec resume
The bot now blocks a second Codex run when another bot-managed chat already has an active Codex task in the same workdir.
- the warning is strong by default because simultaneous writes in the same workdir are easy to corrupt
/continuereplays the most recently blocked request once for the current chat- switching projects clears the pending blocked request
- this guard only sees bot-managed chats in this process; if you also use Codex directly in a terminal, use a separate git worktree to avoid conflicts
The bot includes a minimal repo-scoped frontend runtime layer:
/dev startstarts the current repo's frontend command/dev stopstops it/dev statusshows whether it is running/dev logsreturns the recent output tail/dev urlreturns the first detected local URL from logs
Selection rules:
- prefer
package.jsonscriptdev - if
devis missing, fall back tostart - keep only one active frontend server per repo workdir
- do not expose arbitrary shell execution through
/dev
Choose the execution backend with CODEX_BACKEND:
sdk- preferred for new installs; avoids PTY fragility and uses persistent Codex SDK threadscli- legacy backend; uses PTY when available and falls back tocodex exec
SDK-related options:
CODEX_BACKEND=sdk
CODEX_SDK_CONFIG={}
CODEX_SDK_SKIP_GIT_REPO_CHECK=true
CODEX_SDK_SANDBOX_MODE=danger-full-access
CODEX_SDK_APPROVAL_POLICY=never
CODEX_SDK_REASONING_EFFORT=high
CODEX_SDK_NETWORK_ACCESS_ENABLED=true
CODEX_SDK_WEB_SEARCH_MODE=live
CODEX_SDK_ADDITIONAL_DIRECTORIES=["/abs/path/extra-worktree"]If CODEX_SDK_SANDBOX_MODE is unset, the bot now defaults SDK threads to Full Access: danger-full-access with approvalPolicy=never. Set it explicitly to workspace-write or read-only only if you want a more restricted mode.
CLI-related options:
CODEX_BACKEND=cli
CODEX_COMMAND=codex
CODEX_ARGS=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
STATE_FILE=.codex-telegram-claws-state.json
WORKSPACE_ROOT=%USERPROFILE%/.dex-agent
CODEX_WORKDIR=%USERPROFILE%/.dex-agentCommon options:
TELEGRAM_API_BASE=https://api.telegram.org
TELEGRAM_PROXY_URL=
CODEX_COMMAND=codex
CODEX_ARGS=
CODEX_BACKEND=sdk
CODEX_SDK_CONFIG={}
CODEX_SDK_SKIP_GIT_REPO_CHECK=true
CODEX_SDK_SANDBOX_MODE=
CODEX_SDK_APPROVAL_POLICY=
CODEX_SDK_REASONING_EFFORT=
CODEX_SDK_NETWORK_ACCESS_ENABLED=
CODEX_SDK_WEB_SEARCH_MODE=
CODEX_SDK_ADDITIONAL_DIRECTORIES=[]
WORKSPACE_ROOT=%USERPROFILE%/.dex-agent
STATE_FILE=.codex-telegram-claws-state.json
SHELL_ENABLED=false
SHELL_READ_ONLY=true
SHELL_ALLOWED_COMMANDS=["pwd","ls","git status","git diff --stat","npm test","npm run check"]
SHELL_DANGEROUS_COMMANDS=["git add","git commit","git push","rm","mv","cp","npm publish"]
SHELL_TIMEOUT_MS=20000
SHELL_MAX_OUTPUT_CHARS=12000
STREAM_THROTTLE_MS=1200
STREAM_BUFFER_CHARS=120000
CODEX_FINALIZE_HOOK_TIMEOUT_MS=120000
FINAL_ACTIONS_AUTO_OFFER=false
REASONING_RENDER_MODE=spoiler
CRON_DAILY_SUMMARY=0 9 * * *
CRON_TIMEZONE=America/Sao_Paulo
PROACTIVE_USER_IDS=123456789MCP:
MCP_SERVERS=[]GitHub:
GITHUB_TOKEN=ghp_xxx
GITHUB_DEFAULT_WORKDIR=%USERPROFILE%/.dex-agent
GITHUB_DEFAULT_BRANCH=main
E2E_TEST_COMMAND=npx playwright test --reporter=lineRecommended local Windows baseline for this repository:
STATE_FILE=.codex-telegram-claws-state.json
WORKSPACE_ROOT=%USERPROFILE%/.dex-agent
CODEX_WORKDIR=%USERPROFILE%/.dex-agent
GITHUB_DEFAULT_WORKDIR=%USERPROFILE%/.dex-agentUse npm run env:check to verify the active .env against this baseline before startup.
Use these scripts when moving a configured Dex Agent install to a fresh
%USERPROFILE%\.dex-agent install or when copying local child-project settings.
Safe export, without tokens:
npm run config:export -- -OutputPath "$env:USERPROFILE\Desktop\dex-agent-config.zip"Full local backup, including .env secrets:
npm run config:export -- -IncludeSecrets -OutputPath "$env:USERPROFILE\Desktop\dex-agent-config.full.zip"Import into a new install:
npm run config:import -- -ArchivePath "$env:USERPROFILE\Desktop\dex-agent-config.zip" -ForceImporting .env requires the explicit secret flag:
npm run config:import -- -ArchivePath "$env:USERPROFILE\Desktop\dex-agent-config.full.zip" -IncludeSecrets -ForceThe bundle can include local network registry files, .agents/CONTACTS.local.json,
.agents/PROMPTS.json, DEX_PAI/DEX_REDE handoff docs, child
skills/dex-agent/instance.json, and .env only when -IncludeSecrets is set.
Do not commit exported ZIP files.
GitHub Actions now includes:
CIworkflow on push and pull requestTelegram Smokemanual workflow for live bot-token validation when repository secrets are configuredReleaseworkflow onv*tags, which reruns validation and publishes a GitHub Release
Repository secrets for live smoke checks:
TELEGRAM_BOT_TOKENTELEGRAM_EXPECTED_USERNAME(optional)TELEGRAM_SMOKE_CHAT_ID(optional)
Keep live verification output out of git history and release notes. Bot usernames, thread IDs, and chat IDs are environment-specific operator data and should be configured by each user locally or through GitHub secrets.
Recommended local release gate:
BOT_TOKEN=dummy-token ALLOWED_USER_IDS=1 npm run release:check
npm run healthcheck:live
npm run telegram:smokev1.0.0 should only be tagged after the full release gate, Telegram smoke checks, and repository metadata sync are complete. The detailed checklist and topic sync command live in release.md.
Release references:
- operations.md
- release.md
- ecosystem.config.cjs - PM2 compatibility shim
- 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- Keep
SHELL_READ_ONLY=trueunless you have a strong reason to allow write commands - If you allow write commands, mark high-risk prefixes in
SHELL_DANGEROUS_COMMANDSand require/sh --confirm ... - Prefer least-privilege GitHub PAT
Current local Windows baseline:
- operational parent installed at
%USERPROFILE%\.dex-agent - single parent autostart via the current user's Windows Startup folder:
start-dex-agent.cmd -> scripts/boot-dex-agent-autostart.ps1 -> scripts/start-dex-agent.ps1 - optional network boot via
scripts/boot-dex-agent-network-autostart.ps1 -> config/dex-agent-network.local.json -> <instance>\scripts\start-dex-agent.ps1 - hidden restart via
restart-dex-agent-hidden.vbs -> restart-dex-agent-hidden.ps1 -> start-dex-agent.ps1 - one polling process per bot token
PM2 remains a supported supervisor for server-style or always-on hosts, but it is not the only valid deployment path.
ecosystem.config.ts is the canonical PM2 config file. Start PM2 with ecosystem.config.cjs, which only bridges PM2 into the TypeScript source.
PM2 flow when that is your target environment:
pm2 start ecosystem.config.cjs
pm2 status dex-agent
pm2 logs dex-agent
pm2 restart dex-agentRun exactly one polling process per bot token.
Windows autostart for the current user:
Set-Location "$env:USERPROFILE\.dex-agent"
powershell -ExecutionPolicy Bypass -File .\scripts\register-dex-agent-autostart.ps1
Get-Content "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup\start-dex-agent.cmd"
Get-Content .\config\dex-agent-network.example.jsonThe parent autostart script refuses to register from a non-canonical clone by default; the expected operational root is %USERPROFILE%\.dex-agent. The network boot script reads the local ignored registry at config\dex-agent-network.local.json before starting each registered instance through its own scripts\start-dex-agent.ps1. Registry paths may use %USERPROFILE%, and the boot script expands them before resolving each instance root.
Remove autostart:
Set-Location "$env:USERPROFILE\.dex-agent"
powershell -ExecutionPolicy Bypass -File .\scripts\unregister-dex-agent-autostart.ps1scripts/start-dex-agent.ps1 is the canonical singleton entrypoint for local Windows operation: it clears stale src/index.ts processes for this repo before starting a fresh one. The hidden restart path now reuses that same script, and scripts/status-dex-agent.ps1 warns when multiple polling processes are still alive instead of silently picking one.
Keep these local-only artifacts out of the initial publish baseline:
.env.codex-telegram-claws-state.json.runtime/.agents/.codex/
The local continuity layer and runtime logs are useful for operating this machine, but they are not part of the public product contract.
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.
Telegram can manage runtime usage of Bot-side MCP and skills, but not install arbitrary new servers from chat.
- MCP servers are process-level runtime resources: list, inspect, reconnect, enable, disable
- Skills are chat-level routing switches: each chat can enable or disable
githubandmcpindependently - Codex's own MCP remains separate and is not managed through these bot commands
- Runtime state is persisted to
STATE_FILE, so/mcp enable|disable,/skill on|off,/language,/verbose,/reasoning, and per-project Codex conversation slots survive bot restarts
- Bot not responding: verify
BOT_TOKENandALLOWED_USER_IDS - Telegram API blocked: set
TELEGRAM_PROXY_URL(HTTP proxy likehttp://127.0.0.1:7890) or run a local Bot API server and setTELEGRAM_API_BASE - Codex not producing output: verify
CODEX_BACKEND,CODEX_COMMAND, andCODEX_WORKDIR - SDK backend cannot resume: verify the host still has access to
~/.codex/sessionsand that the saved thread id belongs to the same working directory - 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 failedon macOS/Linux: this usually means thenode-ptyhelper lost execute permissions; startup now auto-repairs it, andnpm run healthcheckreports the result- CLI/PTy warnings on Windows: verify
npm run healthcheck; the Windows preflight checks the nativenode-ptyartifact instead of the Unixspawn-helper
- Inspired by: https://github.com/RichardAtCT/claude-code-telegram
- Codex SDK reference: https://github.com/coleam00/codex-telegram-coding-assistant
- This implementation: Codex-first Node.js stack (
@openai/codex-sdk,telegraf,node-pty,node-cron, MCP SDK)
