Skip to content

ops codex

lianlian edited this page Jul 18, 2026 · 3 revisions

/ops codex 跑长任务

最后更新:2026-07-18
交流群:点击加入 QQ 群【雪主任的工坊】

想在 QQ 里让服务器上的 Codex 帮你查目录、改代码、跑测试?用这个。

一句话版:

/ops codex <你的任务描述>

机器人会立刻回一个任务 ID,Codex 在固定工作目录和固定沙箱里异步干活。任务超过 45 秒还在跑时,会低频推送“仍在运行”;干完再把真实结果推回原会话。

先泼两盆冷水:

  • 权限很高,默认关闭
  • 只适合完全信任的管理员
  • 不是给普通聊天用户的功能
  • 通用权限、固定命令和安全模型,先看 /ops 在 QQ 里做运维

先确认本机 Codex 能跑

机器人实际运行账号执行:

command -v codex
codex --version
codex exec --help

command -v codex 打出来的绝对路径,后面填进 program。NVM 安装常见长这样:

/home/bot/.nvm/versions/node/v24.0.0/bin/codex

NVM 版 Codex 经常靠 /usr/bin/env node 启动,而 systemd 服务的 PATH 往往不带 NVM。
好消息:/ops codex 会把规范化后的固定 program 父目录塞到 Codex 子进程 PATH 最前面。
只要 nodecodex 在同一个 bin 目录,通常不用改机器人进程全局 PATH
这只影响 Codex,不影响普通 /ops 固定命令。

再多一句安全建议:Codex / Node 请装在工作区外面,比如独立的 NVM versions/<node版本>/bin
workspace-write 时,配置加载会拒绝 program 父目录落在 working_directory 里面的写法,包括靠 .. 或符号链接绕进去;路径关系搞不清时也会直接拒绝启动。

写配置

在部署运行目录:

cp config/ops.example.toml config/ops.toml
chmod 600 config/ops.toml

先把总开关和会话范围打开。私聊示例:

enabled = true

[private]
enabled = true
allowed_user_ids = ["从私聊 /ping 获取的稳定 user_id"]

[group]
enabled = false
allowed_group_ids = []

再写 Codex 段:

[codex]
enabled = true
program = "/absolute/path/to/codex"
working_directory = "/absolute/path/to/workspace"
timeout_seconds = 1800
max_prompt_bytes = 8000
max_stdout_bytes = 32768
max_stderr_bytes = 16384
profile = "qq-maid-ops"
sandbox = "workspace-write"
cancellable = true
max_concurrent_tasks = 1

字段怎么理解:

字段 人话解释
program Codex CLI 的绝对路径,聊天消息改不了
working_directory Codex 唯一固定工作根;可以是发布目录,也可以不是 Git 仓库
profile 固定 Codex profile,建议单独给机器人运维建一份
sandbox 只认 read-onlyworkspace-write
timeout_seconds 单任务最长跑多久
max_prompt_bytes 任务描述最多多长
max_stdout_bytes / max_stderr_bytes 最终回执保留多少输出
cancellable 能不能取消正在跑的任务
max_concurrent_tasks 并发上限,建议先从 1 开始

发布目录常常没有 .git。入口固定会带:

codex exec --skip-git-repo-check --ephemeral

所以没 Git 也能跑,而且这次任务不会持久化 Codex session。
这两个参数负责“跳过 Git 检查”和“不留 session”,不会放宽工作目录、profile 或沙箱。

重启后先自测

./botctl.sh restart
./botctl.sh status

然后在机器人会话里依次发:

/ops
/ops codex 只读取当前工作目录并概括它的用途,不修改文件
/ops list

受理回执大概长这样:

Codex 任务已受理
任务 ID:ops-a82f31c4
取消:/ops cancel ops-a82f31c4

任务结束后,你会收到成功、执行失败、超时、取消或启动失败这些真实状态
模型嘴里说“成功了”不算数,以进程退出状态为准。

长任务进度怎么推:

  • 45 秒内结束:不会多发过程通知
  • 超过 45 秒还在跑:先发第一条“仍在运行”
  • 之后最多每 120 秒一条
  • 进度里只有任务 ID、仍在运行、已运行时间、取消命令
  • 没有原始 stdout/stderr、命令参数、任务描述或文件内容
  • 进度和最终结果用不同的 Outbox 去重键;任务一结束会停掉进度,并取消还没发出去的旧快照
  • Outbox 重试只重发已保存快照,不会重新执行 Codex

补充几条体验细节:

  • Codex 正常跑时,进度、插件告警、工具日志常写到 stderr
  • 成功任务只把最终 stdout 推到聊天
  • 失败 / 超时 / 取消时,stderr 会落到权限受限的 logs/ops/<任务ID>.log,聊天只提示服务器日志路径
  • 如果独立日志写失败,最终结果会直接附带一段脱敏、限长的 stderr 摘要,不会硬叫你去看一份空日志
  • 写日志前会做任务描述的字面脱敏
  • 普通 /ops 固定命令还是 stdout + stderr 原样回

最终输出会走项目现有的 QQ 安全 Markdown 渲染:

  • http:// / https:// 链接可以保留
  • 指向 /root/... 这类服务器本地文件的 Markdown 链接,QQ 里打不开,所以只展示标签,不发内部绝对路径

查询和取消

/ops list
/ops cancel ops-a82f31c4

/ops list 只看当前机器人进程里还在跑的任务。
首期注册表不跨进程恢复;机器人一重启,重启前还在跑的任务不会继续帮你收结果。

stop / kill / close 只是 cancel 的兼容别名;帮助文案优先展示 /ops cancel <任务ID>

常见报错

Not inside a trusted directory

意思是:working_directory 不是 Git 工作树,而旧版本入口又没带 --skip-git-repo-check
换带这个参数的新版本再试。为了绕过报错在发布目录里临时 git init

/usr/bin/env: 'node': No such file or directory

多半是 NVM 版 codex 需要同目录的 node,但服务没加载交互式 Shell 的 NVM 环境。
部署会把 program 所在目录塞进 Codex 子进程 PATH 的版本后重试,并确认这两个文件真在同一目录:

ls -l "$(dirname "$(command -v codex)")/codex"
ls -l "$(dirname "$(command -v codex)")/node"

状态是“启动失败”

检查:

  • program 是不是现有文件的绝对路径
  • 机器人账号有没有执行权限
  • working_directory 是不是现有目录

启动失败不会把内部路径或系统错误详情甩到聊天里。必要时在服务器上用同一账号跑:

codex --version

状态是“执行失败”

先看回执里的退出码,再按提示去服务器读:

logs/ops/<任务ID>.log

如果独立日志写入失败,就看回执里那一段有限 stderr 摘要。

常见原因:

  • Codex profile 不存在
  • 认证不可用
  • 模型服务挂了
  • 任务里某条命令返回非零

stdout 里写了“成功”也不算成功。错误日志不会自动上传,清理策略你自己定。

服务器日志里有插件或 MCP 告警

可选插件、系统 keyring、MCP Server 初始化失败,不一定等于主任务失败。
以任务退出状态和最终 stdout 为准。
比如某个 MCP 报了 Python ModuleNotFoundError,任务仍可能直接读本地文件并成功退出。
成功回执不会把这些进度日志推到聊天;要不要修插件 / MCP 环境,看你服务器侧需要。

有受理回执,却一直没有最终通知

先发 /ops list 看任务是不是还在跑,再查 Notification Worker、平台连接、发送权限。
Outbox 重试只重发已保存结果,不会重新执行 Codex

安全边界,记这几条就够

  • 只给完全信任的管理员,优先私聊
  • working_directory 只指向你真的允许 Codex 读 / 写的目录
  • Codex / Node 装在工作区外;workspace-writeprogram 父目录不能落在工作区里
  • sandbox 不要配成 danger-full-access,框架也不接受
  • 任务描述里别塞 token、secret、API Key、真实用户 ID、群 ID、聊天记录
  • 任务描述始终作为 -- 后的单个 argv 传递,不经 Shell;精确的 - 会被拒绝,避免触发 stdin 语义
  • 错误诊断会替换任务描述完整文本及其非空行的字面匹配,但识别不了转义、变形或模型改写后的敏感内容
  • Unix 上超时 / 取消会终止独立进程组;Windows 当前只保证干掉直接子进程

部署后建议验收一遍

代码更新并按项目流程发布后,至少确认:

make deploy-remote
  1. 服务重启成功,botctl.sh status 显示进程还活着
  2. /ops codex 能返回任务 ID,不再卡在 Git 信任目录或 Node PATH
  3. 只读测试任务能收到真实成功结果
  4. 任务结束后,/ops list 不再显示它
  5. /ops cancel <任务ID> 能取消一个明确允许取消的测试任务

Clone this wiki locally