用于在内网单机环境中,通过 Telegram Bot 绑定指定工作目录(workdir),自动寻找其中最新 Codex Session,与本地 Codex CLI 实时交互的 Python 服务。
- Telegram 实时对话与流式输出
- 任务运行状态提示与取消
- 指令排队与重试
- 本地 SQLite 记录会话与运行日志
- Python 3.11+
- 本地可执行的 Codex CLI
- 为避免
The cursor position could not be read within a normal duration,运行 Codex CLI 时默认设置PROMPT_TOOLKIT_NO_CPR=1与TERM=xterm-256color。 - 默认使用
resume_id="auto"(按codex_workdir自动选择最新会话);当可解析到会话时,通过codex exec resume <id>(非交互模式)以保证 Telegram 场景可稳定输出。
python -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt准备配置后启动:
python -m src.main系统会优先读取 config.toml;不存在时回退到 .env(单 bot 兼容)。
base:基础设置(全局共享)bots:每个 bot 一条记录,必须包含name / token / allowed_user_ids / codex_workdir;resume_id可选(默认auto)- 支持
${ENV:KEY}占位符,便于把敏感信息放到.env
- 未配置:默认
"auto"(按codex_workdir自动选择最新会话)。 - 固定值:直接填 Codex Session ID(用于“稳定绑定同一个会话”的场景)。
"auto":自动跟随codex_workdir目录树下最新的主会话(读取~/.codex/sessions/**.jsonl的session_meta.payload.cwd,匹配codex_workdir或其子目录;会对路径做realpath/normpath归一化)。- 会自动忽略 subagent 会话(
session_meta.payload.source含subagent的记录)。 - 用途:当某个会话运行很久导致无法继续 compact,需要在 Codex CLI 中
/new开新对话时,本系统可自动切换到新 Session。 - 运行中切换:当
CODEX_JSONL_STREAM_EVENTS=1且运行中检测到同目录树下出现更新的主会话时,JSONL tailer 会自动切换到最新会话(同样忽略 subagent),避免长任务因会话切换导致“没有输出/拿不到最终结果”。
- 会自动忽略 subagent 会话(
示例(可参考 config.toml.example):
[base]
db_path = "data/app.db"
lock_path = "data/app.lock"
codex_cli_cmd = "codex"
codex_cli_args = []
codex_cli_input_mode = "stdin"
codex_cli_skip_git_check = true
jsonl_sync_interval_seconds = 3
message_chunk_limit = 3500
[[bots]]
name = "stock"
token = "${ENV:TELEGRAM_BOT_TOKEN_STOCK}"
allowed_user_ids = [123456789]
codex_workdir = "${ENV:CODEX_WORKDIR_STOCK}"
[[bots]]
name = "gateway"
token = "${ENV:TELEGRAM_BOT_TOKEN_GATEWAY}"
allowed_user_ids = [123456789]
codex_workdir = "${ENV:CODEX_WORKDIR_GATEWAY}"至少需要配置:
TELEGRAM_BOT_TOKENTELEGRAM_ALLOWED_USER_IDS
可选配置:
CODEX_WORKDIR:工作目录(未配置时默认使用当前工作目录,通常为 systemd 的WorkingDirectory)CODEX_CLI_RESUME_ID:固定 Session ID 或"auto";未配置时默认"auto"(按CODEX_WORKDIR自动选择最新会话)
其余基础设置可参考 .env.example(与 base 字段一致)。
CODEX_CLI_CMD:Codex CLI 命令(默认codex)CODEX_CLI_ARGS:Codex CLI 额外参数(可选)CODEX_CLI_INPUT_MODE:stdin或arg(默认stdin)CODEX_CLI_APPROVALS_MODE:审批模式(默认3,等价于输入/approvals 3)CODEX_CLI_SKIP_GIT_CHECK:是否跳过 Git 仓库检查(1/0,默认1,用于codex exec)CODEX_CLI_USE_PTY:是否使用伪终端(1/0,默认0,用于解决stdin is not a terminal)DB_PATH:SQLite 路径(默认data/app.db)LOCK_PATH:进程锁文件路径(默认data/app.lock,用于防止多重启动)STREAM_FLUSH_INTERVAL:输出节流间隔秒数(默认1.5)STREAM_INCLUDE_STDERR:是否显示 stderr(1/0,默认0)PROGRESS_TICK_INTERVAL:进度心跳已废弃,当前版本忽略该配置RUN_TIMEOUT_SECONDS:单次运行超时秒数(示例10800,约 3 小时)CONTEXT_COMPACTION_IDLE_TIMEOUT_SECONDS:检测到Context compacted后无新输出的等待秒数(示例10800,约 3 小时,用于防止进程卡住)NO_OUTPUT_IDLE_TIMEOUT_SECONDS:长时间无任何输出时的自动结束秒数(示例10800,约 3 小时,用于防止僵死进程)FINAL_RESULT_IDLE_TIMEOUT_SECONDS:检测到最终结果后无输出的自动结束秒数(示例10800,约 3 小时,用于防止任务卡住)JSONL_SYNC_INTERVAL_SECONDS:JSONL 同步轮询间隔秒数(默认3,用于同步本地 CLI 的结果)CODEX_JSONL_STREAM_EVENTS:是否从 Codex JSONL 实时推送事件到 Telegram(1/0,默认1,agent_reasoning内容会被隐藏)CODEX_JSONL_REASONING_THROTTLE_SECONDS:推送agent_reasoning占位提示的最小间隔秒数(默认10)CODEX_JSONL_REASONING_MODE:推理事件展示模式,hidden(不推送)或summary(安全摘要,默认summary)MESSAGE_CHUNK_LIMIT:单条消息最大长度(默认3500,实际会被限制在 4096 以内,并自动拆分)
/new <内容>:新建会话并提交指令(等效 Codex CLI/new <内容>)/session:查看会话绑定(只读)/stop:停止当前任务/status:查看状态/retry:重试上一次指令/lastresult:查看最近一次结果/whoami:查看用户与聊天 ID/help:查看帮助
项目内提供服务文件模板:deploy/codex-session-gateway.service。请按实际路径修改后安装(默认使用 .venv 里的 Python)。
如需在 Codex 指令中调用 systemctl --user,请确保用户 DBus 可用(服务模板已设置 XDG_RUNTIME_DIR 与 DBUS_SESSION_BUS_ADDRESS)。
若仍提示 Failed to connect to bus: No medium found,请启用用户常驻:loginctl enable-linger <用户>。
安装示例:
sudo cp deploy/codex-session-gateway.service /etc/systemd/system/codex-session-gateway.service
sudo systemctl daemon-reload
sudo systemctl enable --now codex-session-gateway查看日志:
sudo journalctl -u codex-session-gateway -f在受限环境中可能出现“有权限但无法联网/无法重启”的情况,常见表现与处理建议如下:
sudo: The "no new privileges" flag is set:容器启用了no-new-privileges,即使允许提权也无法执行sudo/systemctl。
处理:在宿主机执行重启命令,或调整容器配置关闭该标志;必要时改用用户级服务。Failed to connect to bus: No medium found:用户级 DBus 不可用。
处理:启用用户常驻loginctl enable-linger <用户>,并确保XDG_RUNTIME_DIR与DBUS_SESSION_BUS_ADDRESS已设置。Could not resolve hostname github.com或 Git 推送失败:运行环境无外网/DNS 被限制。
处理:在具备外网的主机上执行git push,或确保运行环境允许外网访问与 DNS 解析。- 若需让 Codex CLI 在非交互环境下自动执行审批相关操作:
处理:在.env或config.toml的base.codex_cli_args中配置--dangerously-bypass-approvals-and-sandbox(请谨慎使用)。
- 安全与敏感信息规范:
docs/security.md - 最近一次审计报告:
docs/audits/2026-01-16-security-audit.md - 默认禁用
httpx/httpcore的 INFO 请求日志,避免 Telegram Bot Token 出现在日志(URL 内嵌 token)。
- 重复发送结果、JobQueue 警告、如何确认运行版本等:
docs/troubleshooting.md
- 全量索引:
docs/INDEX.md - 规划与历史记录:
docs/plans/
.venv/bin/python -m pytest -q