Skip to content

Commit 18a91d2

Browse files
committed
feat: add codex sdk backend
1 parent c13877d commit 18a91d2

File tree

10 files changed

+1018
-88
lines changed

10 files changed

+1018
-88
lines changed

.env.example

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,19 @@ ALLOWED_USER_IDS=123456789,987654321
55
PROACTIVE_USER_IDS=123456789
66
STATE_FILE=.codex-telegram-claws-state.json
77

8+
CODEX_BACKEND=sdk
89
CODEX_COMMAND=codex
910
CODEX_ARGS=
1011
WORKSPACE_ROOT=.
1112
CODEX_WORKDIR=.
13+
CODEX_SDK_CONFIG={}
14+
CODEX_SDK_SKIP_GIT_REPO_CHECK=true
15+
CODEX_SDK_SANDBOX_MODE=
16+
CODEX_SDK_APPROVAL_POLICY=
17+
CODEX_SDK_REASONING_EFFORT=
18+
CODEX_SDK_NETWORK_ACCESS_ENABLED=
19+
CODEX_SDK_WEB_SEARCH_MODE=
20+
CODEX_SDK_ADDITIONAL_DIRECTORIES=[]
1221
SHELL_ENABLED=false
1322
SHELL_READ_ONLY=true
1423
SHELL_ALLOWED_COMMANDS=["pwd","ls","git status","git diff --stat","npm test","npm run check"]

AGENTS.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
- `src/index.ts`: application entrypoint and subsystem wiring.
66
- `src/bot/`: Telegram handlers, formatting, command parsing, i18n, middleware.
77
- `src/orchestrator/`: routing, MCP client, skill registry, GitHub/MCP skills.
8-
- `src/runner/`: Codex PTY/exec management and restricted shell execution.
8+
- `src/runner/`: Codex SDK/CLI runner management, PTY fallback handling, and restricted shell execution.
99
- `src/cron/`: scheduled proactive jobs.
1010
- `tests/`: Node built-in test suite, one `*.test.js` file per module area.
1111

@@ -14,6 +14,7 @@
1414
- `npm install`: install dependencies.
1515
- `npm run start`: start the Telegram bot with the current `.env`.
1616
- `npm run dev`: run the bot in watch mode for local development.
17+
- Use `CODEX_BACKEND=sdk` for the preferred SDK-backed runner; keep `CODEX_BACKEND=cli` only when you specifically need the legacy PTY/CLI path.
1718

1819
## Test Commands
1920

README.md

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@
33
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
44
[![Node.js 20+](https://img.shields.io/badge/node-20%2B-green.svg)](https://nodejs.org/en/download/current)
55

6-
A Telegram bot that gives you remote access to `@openai/codex` through a PTY-backed Node.js runtime.
7-
It is strictly inspired by `RichardAtCT/claude-code-telegram`, but this project is implemented for Codex CLI + MCP + Subagent routing.
6+
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.
7+
It is strictly inspired by `RichardAtCT/claude-code-telegram`, but this project is implemented for Codex SDK/CLI + MCP + Subagent routing.
88

99
## What Is This?
1010

11-
This bot connects Telegram to Codex CLI and routes tasks to the right execution surface:
11+
This bot connects Telegram to Codex and routes tasks to the right execution surface:
1212

13-
- **Coding tasks** -> Codex CLI in `node-pty` (real TTY, stable interactive behavior)
13+
- **Coding tasks** -> Codex SDK threads or Codex CLI/PTy sessions
1414
- **Explicit tool tasks** -> Subagents (`/mcp`, `GitHub Skill`)
1515
- **Proactive automation** -> Cron scheduler for daily summaries and push notifications
1616

@@ -19,6 +19,7 @@ Key design goals:
1919
- Keep Codex interactive sessions smooth and stream-safe on Telegram
2020
- Enforce zero-trust access with whitelist-only users
2121
- Avoid duplicate MCP calls by separating Codex MCP vs Bot MCP responsibilities
22+
- Prefer the SDK backend for new installs, while keeping the CLI backend as a fallback
2223

2324
## Quick Start
2425

@@ -50,6 +51,7 @@ ALLOWED_USER_IDS=123456789
5051
STATE_FILE=.codex-telegram-claws-state.json
5152
WORKSPACE_ROOT=.
5253
CODEX_WORKDIR=.
54+
CODEX_BACKEND=sdk
5355
```
5456

5557
Optional safe shell:
@@ -104,7 +106,7 @@ npm run healthcheck
104106
Telegram Message
105107
-> src/bot/handlers.ts
106108
-> src/orchestrator/router.ts
107-
-> src/runner/ptyManager.ts (coding tasks -> Codex CLI)
109+
-> src/runner/ptyManager.ts (coding tasks -> Codex SDK or Codex CLI)
108110
-> src/orchestrator/skills/*.js (general tasks -> MCP/GitHub subagents)
109111
-> src/bot/formatter.js
110112
-> Telegram sendMessage/editMessageText
@@ -116,7 +118,7 @@ Core modules:
116118
- `src/config.ts`: env parsing and validation
117119
- `src/bot/`: auth middleware, formatting, command handlers
118120
- `src/orchestrator/`: routing + MCP client + skills
119-
- `src/runner/ptyManager.ts`: Codex PTY process + streaming
121+
- `src/runner/ptyManager.ts`: Codex runner abstraction for SDK threads, CLI/PTy sessions, and CLI exec fallback
120122
- `src/cron/scheduler.js`: proactive scheduled push
121123

122124
Enterprise target architecture: [docs/enterprise-architecture.md](/Users/ding/Documents/Code/Github/codex-telegram-claws/docs/enterprise-architecture.md)
@@ -126,7 +128,7 @@ Enterprise Phase 1 roadmap: [docs/phase-1-roadmap.md](/Users/ding/Documents/Code
126128

127129
To avoid duplicated context fetch:
128130

129-
- **Coding requests** are sent directly to Codex CLI (Codex can use its own MCP stack)
131+
- **Coding requests** are sent directly to Codex (SDK or CLI backend; Codex can use its own MCP stack)
130132
- **Bot-side MCP** is only used by explicit `/mcp ...` commands
131133

132134
This prevents:
@@ -150,7 +152,7 @@ How they are triggered:
150152
- `/gh ...` -> GitHub skill
151153
- `/mcp ...` -> MCP skill
152154
- Plain text may also route to a subagent when the router sees a supported GitHub-style request such as `git push`, `commit`, or `run test`
153-
- Everything else falls back to Codex CLI
155+
- Everything else falls back to Codex
154156

155157
Where this happens:
156158

@@ -175,8 +177,8 @@ General:
175177
- `/repo recent` - show recent projects for the current chat
176178
- `/repo -` - switch back to the previous project
177179
- `/new` - clear the saved Codex conversation for the current project and start fresh on the next message
178-
- `/exec <task>` - force a one-off `codex exec`
179-
- `/auto <task>` - force a one-off `codex exec --full-auto`
180+
- `/exec <task>` - force a one-off Codex run without saving project context
181+
- `/auto <task>` - force a one-off fully automatic Codex run without saving project context
180182
- `/plan <task>` - ask Codex for a plan only, without direct file modification intent
181183
- `/model [name|reset]` - show or set the model override for the current chat
182184
- `/language [en|zh|zh-HK]` - show or set the system language for the current chat
@@ -188,8 +190,8 @@ General:
188190
- `/sh <command>` - run a safe allowlisted Linux command in the current project (disabled by default)
189191
- `/sh --confirm <command>` - confirm a dangerous command when writable mode is enabled
190192
- `/restart` - restart the bot process explicitly from Telegram
191-
- `/interrupt` - send `Ctrl+C` to current PTY session
192-
- `/stop` - terminate current PTY session
193+
- `/interrupt` - interrupt the active Codex run
194+
- `/stop` - terminate the active Codex run
193195
- `/cron_now` - trigger daily summary immediately
194196

195197
MCP skill:
@@ -212,9 +214,9 @@ GitHub skill:
212214

213215
Telegram adaptation notes:
214216

215-
- Plain text messages behave like `codex "task description"`
216-
- `/exec` behaves like `codex exec "task"`
217-
- `/auto` behaves like `codex exec --full-auto "task"`
217+
- Plain text messages behave like a normal Codex conversation turn
218+
- `/exec` runs a one-off Codex task and does not overwrite the saved project conversation slot
219+
- `/auto` runs a one-off Codex task with `approvalPolicy=never` on the SDK backend, or `codex exec --full-auto` on the CLI backend
218220
- `/new` is implemented by the bot and resets the current chat session
219221
- `/new` only clears the current project's saved Codex conversation slot
220222
- `/status` is implemented by the bot and reports local runtime state
@@ -228,27 +230,58 @@ Telegram adaptation notes:
228230

229231
## Streaming and Reasoning Visualization
230232

231-
PTY output is streamed with throttled `editMessageText` updates.
233+
Codex output is streamed with throttled `editMessageText` updates.
232234

233235
- Throttle: controlled by `STREAM_THROTTLE_MS` (default `1200`)
234236
- Long output: auto-chunked to Telegram-safe message sizes
235237
- MarkdownV2: escaped to avoid parse failures
236238
- Reasoning tags: `<think>...</think>` extracted and rendered as:
237239
- spoiler (`||...||`, default)
238240
- quote block (if `REASONING_RENDER_MODE=quote`)
239-
- If `node-pty` cannot spawn on the current host, the runner falls back to `codex exec` for per-request execution
240-
- In `codex exec` fallback mode, Telegram output is cleaned to hide the Codex banner, raw tool trace, `mcp startup`, and duplicate `tokens used` footer
241-
- On macOS, startup now auto-repairs `node-pty` helper execute permissions before the first PTY session
241+
- On `CODEX_BACKEND=sdk`, Telegram streams structured Codex SDK events and persists thread IDs per project
242+
- On `CODEX_BACKEND=cli`, the bot prefers PTY sessions; if `node-pty` cannot spawn on the current host, it falls back to `codex exec`
243+
- In CLI exec fallback mode, Telegram output is cleaned to hide the Codex banner, raw tool trace, `mcp startup`, and duplicate `tokens used` footer
244+
- On macOS, startup auto-repairs `node-pty` helper execute permissions before the first PTY session
242245

243246
## Project-Scoped Conversation State
244247

245248
Conversation state is now tracked per `chat + project`, not just per chat.
246249

247250
- When you switch with `/repo <name>`, the bot keeps that project's last Codex session id in runtime state
248-
- When you switch back to the same project later, the next plain-text task resumes that project's Codex conversation
251+
- When you switch back to the same project later, the next plain-text task resumes that project's Codex thread/session
249252
- `/new` clears only the current project's saved conversation slot; other projects in the same Telegram chat are untouched
250253
- `/exec`, `/auto`, and `/plan` stay one-off by design and do not replace the saved project conversation
251-
- On hosts where PTY is unavailable, project restore still works through `codex exec resume`
254+
- On the SDK backend, project restore uses `resumeThread(threadId)`
255+
- On the CLI backend, project restore uses PTY resume or `codex exec resume`
256+
257+
## Backend Selection
258+
259+
Choose the execution backend with `CODEX_BACKEND`:
260+
261+
- `sdk` - preferred for new installs; avoids PTY fragility and uses persistent Codex SDK threads
262+
- `cli` - legacy backend; uses PTY when available and falls back to `codex exec`
263+
264+
SDK-related options:
265+
266+
```bash
267+
CODEX_BACKEND=sdk
268+
CODEX_SDK_CONFIG={}
269+
CODEX_SDK_SKIP_GIT_REPO_CHECK=true
270+
CODEX_SDK_SANDBOX_MODE=workspace-write
271+
CODEX_SDK_APPROVAL_POLICY=never
272+
CODEX_SDK_REASONING_EFFORT=high
273+
CODEX_SDK_NETWORK_ACCESS_ENABLED=true
274+
CODEX_SDK_WEB_SEARCH_MODE=live
275+
CODEX_SDK_ADDITIONAL_DIRECTORIES=["/abs/path/extra-worktree"]
276+
```
277+
278+
CLI-related options:
279+
280+
```bash
281+
CODEX_BACKEND=cli
282+
CODEX_COMMAND=codex
283+
CODEX_ARGS=
284+
```
252285

253286
## Event-Driven Automation
254287

@@ -277,6 +310,15 @@ Common options:
277310
```bash
278311
CODEX_COMMAND=codex
279312
CODEX_ARGS=
313+
CODEX_BACKEND=sdk
314+
CODEX_SDK_CONFIG={}
315+
CODEX_SDK_SKIP_GIT_REPO_CHECK=true
316+
CODEX_SDK_SANDBOX_MODE=
317+
CODEX_SDK_APPROVAL_POLICY=
318+
CODEX_SDK_REASONING_EFFORT=
319+
CODEX_SDK_NETWORK_ACCESS_ENABLED=
320+
CODEX_SDK_WEB_SEARCH_MODE=
321+
CODEX_SDK_ADDITIONAL_DIRECTORIES=[]
280322
WORKSPACE_ROOT=/Users/yourname/projects
281323
STATE_FILE=/path/to/codex-telegram-claws-state.json
282324
SHELL_ENABLED=false
@@ -389,7 +431,8 @@ Telegram can manage runtime usage of Bot-side MCP and skills, but not install ar
389431
## Troubleshooting
390432

391433
- **Bot not responding**: verify `BOT_TOKEN` and `ALLOWED_USER_IDS`
392-
- **Codex not producing output**: verify `CODEX_COMMAND` and `CODEX_WORKDIR`
434+
- **Codex not producing output**: verify `CODEX_BACKEND`, `CODEX_COMMAND`, and `CODEX_WORKDIR`
435+
- **SDK backend cannot resume**: verify the host still has access to `~/.codex/sessions` and that the saved thread id belongs to the same working directory
393436
- **Markdown parse errors**: reduce output size/context; check special characters in tool output
394437
- **MCP failures**: run `/mcp tools <server>` first to validate server availability
395438
- **GitHub API failures**: verify `GITHUB_TOKEN` scope (`repo`) and account permissions
@@ -399,4 +442,5 @@ Telegram can manage runtime usage of Bot-side MCP and skills, but not install ar
399442
## Reference
400443

401444
- Inspired by: https://github.com/RichardAtCT/claude-code-telegram
402-
- This implementation: Codex-first Node.js stack (`telegraf`, `node-pty`, `node-cron`, MCP SDK)
445+
- Codex SDK reference: https://github.com/coleam00/codex-telegram-coding-assistant
446+
- This implementation: Codex-first Node.js stack (`@openai/codex-sdk`, `telegraf`, `node-pty`, `node-cron`, MCP SDK)

package-lock.json

Lines changed: 127 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "codex-telegram-claws",
33
"version": "0.1.0",
4-
"description": "A super Telegram bot that securely orchestrates Codex CLI with PTY streaming, MCP routing, and GitHub automation skills.",
4+
"description": "A super Telegram bot that securely orchestrates Codex via SDK or CLI/PTy streaming, MCP routing, and GitHub automation skills.",
55
"type": "module",
66
"main": "src/index.ts",
77
"scripts": {
@@ -34,6 +34,7 @@
3434
"dependencies": {
3535
"@modelcontextprotocol/sdk": "^1.13.2",
3636
"@octokit/rest": "^22.0.0",
37+
"@openai/codex-sdk": "^0.114.0",
3738
"dotenv": "^16.4.7",
3839
"lodash.throttle": "^4.1.1",
3940
"node-cron": "^4.0.5",

0 commit comments

Comments
 (0)