Repository navigation
Releases: xwfe/ccnm
Release list
ccnm v0.11.0
这一版补的是真机验收(P62)最后查出来的几处,以及受管 Codex 会话的命令审批。
P62 在 2026-10-04 完成:两个 Provider 的受管闭环、外部 MCP、Machine API、
候选包的安装升级回退都在真机(macOS Agent → Debian 13 Runtime)上过了。
两台机器要一起升。 内部协议号没变(仍是 10),但两端版本号不同时
doctor 和起会话照样会报 CCNM_E_VERSION。ccnm.machine/1(ccnm rpc)
和 ccnm.workspace-mcp/1 仍是冻结的契约,这一版没有不兼容的改动。
受管 Codex 会话执行命令前问你(P71)
- 以前 Codex 会话里模型调
exec_command直接执行(Claude 会话每次都问)。
现在 Agent 启动 Codex 前先问 Runtime 哪些工具要人确认,给它们单独设
approval_mode="prompt":每次exec_command前弹 "Allow / Cancel",
取消的调用到不了 Runtime。其余工具和--print不受影响。 - 和 Claude 的区别:Codex 会话里的人用
/permissions切到 Full Access 就
不再问。workspace 的allow_unattended_exec对两边一样生效。 - 只用 Codex 0.154.0 零额度实测过(本机假模型),没用真实模型跑过。
Machine API(P68,真机复验过)
- Agent 上管运行的监督进程被杀,几秒内就是
unknown,failure写明
"监督进程没留下结局、Agent 可能还在跑"和它的 pid;以前要等满运行超时
加 30 秒(默认 15 分半),这期间一直是running。 - 跑过的会话原始输出在第一次被读之前就没了,
session.result给旧尾部并带
unavailable_reason: agent_refused,不再回"空且完整"。
doctor(P69、P70)
- 对着旧版本的 Agent,先报版本不一致,不再只说"身份不符"。
- Agent 是别的构建时,
Reverse SSH不再把它转述丢掉的字段算到 Runtime
头上(旧 Agent 会让 Runtime 看起来"不是同一个构建")。 - 版本行写实际的 Agent 节点名(以前写死
work)。 Command approval一行按 Provider 说实话。
人用的 CLI(P69)
ccnm workspace add按配置里的节点名写runtime_node和 Agent 节点,
不再写死agent/runtime;候选不止一个时用新参数--agent-node指定。
Two downloads, for the two halves of ccnm.
macos-universal— arm64 + x86_64. This is the one an Agent Node
needs, and it also works as a Runtime.linux-x86_64— the Runtime half only (internal mcp-serveand its
tools). The Agent half is a launchd LaunchAgent and does not run on
Linux. Needs glibc >= 2.39; Debian 13 has 2.41.
Both machines need the same ccnm version.
Take the one for that machine -- a glob here would match both:
tar -xzf ccnm-<version>-<platform>.tar.gz
mv ccnm ~/.local/bin/ccnm.new && mv ~/.local/bin/ccnm.new ~/.local/bin/ccnm
Two things that bite:
- Never
cpover a ccnm that has already run. On Apple Silicon the next
exec of it dies with SIGKILL (exit 137) while the running one carries on
with the old code. Rename over it, as above. - Downloaded through a browser it arrives quarantined and macOS refuses to
run it:xattr -d com.apple.quarantine ccnm.curldoes not set that.
Setup, the doctor table and troubleshooting: README.md
ccnm v0.10.1
v0.10.0 的 tag 打了,但发布流程在 macOS 门禁上被一条测试的时序问题挡住,
没有产出下载。这一版就是它,只多了修好的那条测试和版本号。
这一版主要是把"会话控制"和"出了事说得清"补扎实:停得准、结果拿得全、
写锁先看再起、结束的会话能清,以及第一轮真机验收(P62)查出来的问题。
两台机器要一起升。 内部协议从 v0.9.0 的 6 升到了 10,混装时 doctor 和
起会话都会报 CCNM_E_VERSION。ccnm.machine/1(ccnm rpc)和
ccnm.workspace-mcp/1 仍是冻结的契约,这一版没有不兼容的改动。
Machine API(ccnm rpc)
session.stop按会话精确停止,停得到--print运行,不会误停同项目的
交互会话;停止标志先落盘,Agent 发 SIGTERM 后最多等 5 秒确认。- 客户端断开不再连累已经接受的会话:每个会话由自己的 owner 进程跑完,
回来用 session id 照样查得到。ssh 在认证前就失败的记failed,不再是
unknown。 session.result的输出完整保留(每个流最后 32 MiB)、倒序分页、能取
stderr;会话没起来时多一个failure,给出原因(第 10 节同一套错误码)。session.start先问一次写锁:有人正写回-32008,残留或读不了回
-32007并给原因。只是观察,不是预留。
人用的 CLI
ccnm cleanup <项目>:先预览会删什么、留什么,再凭预览给的令牌删;
Operator、Agent、Runtime 执行账号各删各的,项目、写锁、凭据和还在跑的
会话都不碰。- 交互会话的 stop 会等通道退出再确认;
ccnm log把被停掉的会话记成
"被停止",时长是真的。 ccnm status <项目>显示写锁的状态;终端被别的实例占着时会指出来。ccnm controller install会把--config/CCNM_CONFIG和
XDG_CONFIG_HOME、XDG_STATE_HOME写进 LaunchAgent(以前不写,装完
Controller 在默认目录监听)。- 中文帮助补全;
--print末尾写实际的 Agent 节点名。
doctor
- 版本号相同、内部协议不同的两个构建会被认出来(
not the same build)。
只有新的那一端看得出:以后在 v0.10.1 之后自己从 main 编的构建也叫
0.10.1,两台都跑一遍 doctor,以新的那台为准。 - Agent 拒绝所选实例时,第一行就是 Agent 给的原因(比如 profile 目录
权限不对),不再误报身份不符或"在同一台机器上"。 - Codex 登录那一行写明只看了本地登录状态——令牌被吊销它看不出来。
Linux Runtime
- 项目可以放在执行账号的家目录里,哪怕你(Operator)进不去(Debian 12
起家目录默认 0700):不再误报"不在这台机器上",由执行账号回答。
可靠性
- MCP relay 的 leader 退出后,同进程组里留下的子进程会被整组清掉并确认,
清不掉就不交出写权。 apply_patch两处并发误判:两次检查撞在一起时不再放过一次被打断的提交;
同账号几个项目同时改文件时,不再删掉别人正在写的日志、让那一次无故失败。- 后台命令两处高负载下的竞态(server 死后的 run 被报成"还在跑"、取消调用
白等 10 秒)。
验到了哪一步
macOS Agent → Debian 13 Runtime 的真机轮里,Claude 那一半(受管会话、外部
Claude Code、Machine API)跑通;Codex 那一半当时被账号额度挡住,正在补。
真机轮查出的问题在 P63–P67 修好,那些修复目前只有离线证据。逐项证据见
docs/support-matrix.md,已知限制见 README。
Two downloads, for the two halves of ccnm.
macos-universal— arm64 + x86_64. This is the one an Agent Node
needs, and it also works as a Runtime.linux-x86_64— the Runtime half only (internal mcp-serveand its
tools). The Agent half is a launchd LaunchAgent and does not run on
Linux. Needs glibc >= 2.39; Debian 13 has 2.41.
Both machines need the same ccnm version.
Take the one for that machine -- a glob here would match both:
tar -xzf ccnm-<version>-<platform>.tar.gz
mv ccnm ~/.local/bin/ccnm.new && mv ~/.local/bin/ccnm.new ~/.local/bin/ccnm
Two things that bite:
- Never
cpover a ccnm that has already run. On Apple Silicon the next
exec of it dies with SIGKILL (exit 137) while the running one carries on
with the old code. Rename over it, as above. - Downloaded through a browser it arrives quarantined and macOS refuses to
run it:xattr -d com.apple.quarantine ccnm.curldoes not set that.
Setup, the doctor table and troubleshooting: README.md
ccnm v0.9.0
推送后把 P50 记录里没验的五项逐条补了,结论和原话写进 P50 记录的补验一节,
支持矩阵那一行跟着改。
配置说明多了一条会咬人的:受管会话里的 Claude / Codex 是 launchd 起的
Controller 带起来的,拿不到 shell 里 export 的变量,Codex 更是只交 4 个,所以
Agent 配置里 ${VAR} 引用 shell 变量的 server 在受管会话里会报缺。之前那句只说了
Codex,读起来像 Claude 会话没问题。
Two downloads, for the two halves of ccnm.
macos-universal— arm64 + x86_64. This is the one an Agent Node
needs, and it also works as a Runtime.linux-x86_64— the Runtime half only (internal mcp-serveand its
tools). The Agent half is a launchd LaunchAgent and does not run on
Linux. Needs glibc >= 2.39; Debian 13 has 2.41.
Both machines need the same ccnm version.
Take the one for that machine -- a glob here would match both:
tar -xzf ccnm-<version>-<platform>.tar.gz
mv ccnm ~/.local/bin/ccnm.new && mv ~/.local/bin/ccnm.new ~/.local/bin/ccnm
Two things that bite:
- Never
cpover a ccnm that has already run. On Apple Silicon the next
exec of it dies with SIGKILL (exit 137) while the running one carries on
with the old code. Rename over it, as above. - Downloaded through a browser it arrives quarantined and macOS refuses to
run it:xattr -d com.apple.quarantine ccnm.curldoes not set that.
Setup, the doctor table and troubleshooting: README.md
ccnm v0.8.0
模型在远端能做的事,从七个工具变成十一个。 新增 load_skill(读项目
自带的 skills)、view_image(看 workspace 里的图片)、read_notebook
(Jupyter notebook 按 cell 读)、stop_command(停掉后台命令)。另外
search_text 加了三种输出模式、跨行匹配和文件类型过滤,apply_patch 加了
整文件覆盖 write 和 edit_notebook,exec_command 加了一行 shell 和
后台运行 run_in_background,read_output 加了 wait_ms。
两处行为收紧,升级前请看。
一、有副作用的三个工具(exec_command、apply_patch、stop_command,
连同 files[] 里的嵌套结构)现在拒绝它们没声明的字段,超上限的
timeout_ms 和 preview_bytes 也是拒,不再悄悄钳到上限。以前这些都被
静默忽略——一个编出来的 sandbox: false 照样把命令跑了。只读的七个工具
不受影响,照常回答,只在结果末尾写一行忽略了什么。tools/list 里每个
工具的 additionalProperties 现在和服务端真实解析一致。
二、会话结束时如果有命令停不掉(离开了进程组又攥着管道,信号够不着),
写入互斥不再被标成可用。以前这种情况会放锁,下一个 coding 会话就和那个
还在跑的东西并排写同一棵树。现在 marker 留成 held 加一行 abandoned,
点名还剩哪个 output_ref,ccnm status 也分得清「故意留着的」和「异常
退出留下的」。
每条命令可以套一层 OS 沙箱(opt-in,workspace 写 exec_sandbox = "codex")。用的是 Codex 0.154.0 发给自己命令的那份权限对象,一字不改。
实测 warm cache 的 cargo build/test 编译耗时无差别,每条命令多约 40 ms
(macOS)/ 14 ms(Linux);挡住工作区外写、HOME 写、.git 写和网络。
四个时钟写进协议第 6 节:单次等待、命令运行期限、会话、输出保留。
取消一次带 wait_ms 的 read_output 只停等待、命令照跑;断线后同名会话
重连,旧 output_ref 报 CCNM_E_INVALID_ARGS。
握手失败的诊断不再被盖住。 以前 Runtime 在握手时的拒绝一律报成
CCNM_E_RUNTIME_UNREACHABLE(退出码 21),真正的错误码只在 stderr:
后面。
真机验证:macOS 双机上,真实 Claude Code 2.1.272 用上了 read_notebook、
view_image、load_skill 和 exec_command 的 shell,参数校验的收紧
没有咬到它。run_in_background 没有拿到真实模型用它的证据;Linux
Runtime 上这批新工具一次都没跑过。 范围见 docs/support-matrix.md。
协议号没变(ccnm.workspace-mcp/1,open 4、external 5)。但工具表变了,
而 Claude 的 settings 放行清单和 Codex 的 enabled_tools 都按它生成,所以
两台机器必须装同一个版本。升级前先停会话,见 docs/operations.md
「升级前先把会话停掉」。
Two downloads, for the two halves of ccnm.
macos-universal— arm64 + x86_64. This is the one an Agent Node
needs, and it also works as a Runtime.linux-x86_64— the Runtime half only (internal mcp-serveand the
seven tools). The Agent half is a launchd LaunchAgent and does not run on
Linux. Needs glibc >= 2.39; Debian 13 has 2.41.
Both machines need the same ccnm version.
Take the one for that machine -- a glob here would match both:
tar -xzf ccnm-<version>-<platform>.tar.gz
mv ccnm ~/.local/bin/ccnm.new && mv ~/.local/bin/ccnm.new ~/.local/bin/ccnm
Two things that bite:
- Never
cpover a ccnm that has already run. On Apple Silicon the next
exec of it dies with SIGKILL (exit 137) while the running one carries on
with the old code. Rename over it, as above. - Downloaded through a browser it arrives quarantined and macOS refuses to
run it:xattr -d com.apple.quarantine ccnm.curldoes not set that.
Setup, the doctor table and troubleshooting: README.md
Full Changelog: v0.7.0...v0.8.0
ccnm v0.7.0
Two downloads, for the two halves of ccnm.
macos-universal— arm64 + x86_64. This is the one an Agent Node
needs, and it also works as a Runtime.linux-x86_64— the Runtime half only (internal mcp-serveand the
seven tools). The Agent half is a launchd LaunchAgent and does not run on
Linux. Needs glibc >= 2.39; Debian 13 has 2.41.
Both machines need the same ccnm version.
Take the one for that machine -- a glob here would match both:
tar -xzf ccnm-<version>-<platform>.tar.gz
mv ccnm ~/.local/bin/ccnm.new && mv ~/.local/bin/ccnm.new ~/.local/bin/ccnm
Two things that bite:
- Never
cpover a ccnm that has already run. On Apple Silicon the next
exec of it dies with SIGKILL (exit 137) while the running one carries on
with the old code. Rename over it, as above. - Downloaded through a browser it arrives quarantined and macOS refuses to
run it:xattr -d com.apple.quarantine ccnm.curldoes not set that.
Setup, the doctor table and troubleshooting: README.md
Full Changelog: v0.6.0...v0.7.0
ccnm v0.6.0
Two downloads, for the two halves of ccnm.
macos-universal— arm64 + x86_64. This is the one an Agent Node
needs, and it also works as a Runtime.linux-x86_64— the Runtime half only (internal mcp-serveand the
seven tools). The Agent half is a launchd LaunchAgent and does not run on
Linux. Needs glibc >= 2.39; Debian 13 has 2.41.
Both machines need the same ccnm version.
Take the one for that machine -- a glob here would match both:
tar -xzf ccnm-<version>-<platform>.tar.gz
mv ccnm ~/.local/bin/ccnm.new && mv ~/.local/bin/ccnm.new ~/.local/bin/ccnm
Two things that bite:
- Never
cpover a ccnm that has already run. On Apple Silicon the next
exec of it dies with SIGKILL (exit 137) while the running one carries on
with the old code. Rename over it, as above. - Downloaded through a browser it arrives quarantined and macOS refuses to
run it:xattr -d com.apple.quarantine ccnm.curldoes not set that.
Setup, the doctor table and troubleshooting: README.md
Full Changelog: v0.5.0...v0.6.0
ccnm v0.5.0
Two downloads, for the two halves of ccnm.
macos-universal— arm64 + x86_64. This is the one an Agent Node
needs, and it also works as a Runtime.linux-x86_64— the Runtime half only (internal mcp-serveand the
seven tools). The Agent half is a launchd LaunchAgent and does not run on
Linux. Needs glibc >= 2.39; Debian 13 has 2.41.
Both machines need the same ccnm version.
Take the one for that machine -- a glob here would match both:
tar -xzf ccnm-<version>-<platform>.tar.gz
mv ccnm ~/.local/bin/ccnm.new && mv ~/.local/bin/ccnm.new ~/.local/bin/ccnm
Two things that bite:
- Never
cpover a ccnm that has already run. On Apple Silicon the next
exec of it dies with SIGKILL (exit 137) while the running one carries on
with the old code. Rename over it, as above. - Downloaded through a browser it arrives quarantined and macOS refuses to
run it:xattr -d com.apple.quarantine ccnm.curldoes not set that.
Setup, the doctor table and troubleshooting: README.md
Full Changelog: v0.4.1...v0.5.0
ccnm v0.4.1
Two downloads, for the two halves of ccnm.
macos-universal— arm64 + x86_64. This is the one an Agent Node
needs, and it also works as a Runtime.linux-x86_64— the Runtime half only (internal mcp-serveand the
seven tools). The Agent half is a launchd LaunchAgent and does not run on
Linux. Needs glibc >= 2.39; Debian 13 has 2.41.
Both machines need the same ccnm version.
Take the one for that machine -- a glob here would match both:
tar -xzf ccnm-<version>-<platform>.tar.gz
mv ccnm ~/.local/bin/ccnm.new && mv ~/.local/bin/ccnm.new ~/.local/bin/ccnm
Two things that bite:
- Never
cpover a ccnm that has already run. On Apple Silicon the next
exec of it dies with SIGKILL (exit 137) while the running one carries on
with the old code. Rename over it, as above. - Downloaded through a browser it arrives quarantined and macOS refuses to
run it:xattr -d com.apple.quarantine ccnm.curldoes not set that.
Setup, the doctor table and troubleshooting: README.md
Full Changelog: v0.4.0...v0.4.1
ccnm v0.4.0
Two downloads, for the two halves of ccnm.
macos-universal— arm64 + x86_64. This is the one an Agent Node
needs, and it also works as a Runtime.linux-x86_64— the Runtime half only (internal mcp-serveand the
seven tools). The Agent half is a launchd LaunchAgent and does not run on
Linux. Needs glibc >= 2.39; Debian 13 has 2.41.
Both machines need the same ccnm version.
Take the one for that machine -- a glob here would match both:
tar -xzf ccnm-<version>-<platform>.tar.gz
mv ccnm ~/.local/bin/ccnm.new && mv ~/.local/bin/ccnm.new ~/.local/bin/ccnm
Two things that bite:
- Never
cpover a ccnm that has already run. On Apple Silicon the next
exec of it dies with SIGKILL (exit 137) while the running one carries on
with the old code. Rename over it, as above. - Downloaded through a browser it arrives quarantined and macOS refuses to
run it:xattr -d com.apple.quarantine ccnm.curldoes not set that.
Setup, the doctor table and troubleshooting: README.md
Full Changelog: v0.3.0...v0.4.0
ccnm v0.3.0
Two downloads, for the two halves of ccnm.
macos-universal— arm64 + x86_64. This is the one an Agent Node
needs, and it also works as a Runtime.linux-x86_64— the Runtime half only (internal mcp-serveand the
seven tools). The Agent half is a launchd LaunchAgent and does not run on
Linux. Needs glibc >= 2.39; Debian 13 has 2.41.
Both machines need the same ccnm version.
Take the one for that machine -- a glob here would match both:
tar -xzf ccnm-<version>-<platform>.tar.gz
mv ccnm ~/.local/bin/ccnm.new && mv ~/.local/bin/ccnm.new ~/.local/bin/ccnm
Two things that bite:
- Never
cpover a ccnm that has already run. On Apple Silicon the next
exec of it dies with SIGKILL (exit 137) while the running one carries on
with the old code. Rename over it, as above. - Downloaded through a browser it arrives quarantined and macOS refuses to
run it:xattr -d com.apple.quarantine ccnm.curldoes not set that.
Setup, the doctor table and troubleshooting: README.md
Full Changelog: v0.2.0...v0.3.0