cli-hub 的矩阵机制与本地渲染:装完不等于能力齐了
cli-hub 这个包管理器最容易被略过的一层是 matrix。装单个 CLI 的那条路径很直白,一条 install 就完了;矩阵这层则是在单个 CLI 之上,把「做一件事需要哪些能力、每种能力有谁能提供」写成一张表,然后按能力去装。cli-hub-meta-skill/SKILL.md 第 34 到 38 行给的定义很短:一个 CLI 是一个工具,matrix 是打包成 capabilities × providers 的整条工作流。
这层抽象带来一个很具体的后果,也是本篇要讲透的那一处:matrix install 跑完并返回,不代表这条矩阵声明的能力你本机都有了。 原因不在于安装失败,而在于矩阵表里大部分 provider 从设计上就不归它管。
矩阵表里有什么
我们采集时(2026-08-10,对应仓库快照 39634a6)读仓库根的 matrix_registry.json,里面有 5 个矩阵,meta.updated 是 2026-06-11,描述里标了 “capability-based, v2 schema”,5 个矩阵的 schema_version 都是 2。规模如下:
| 矩阵 | CLI 数 | capabilities | recipes | known_gaps |
|---|---|---|---|---|
| video-creation | 14 | 19 | 7 | 4 |
| knowledge-research | 13 | 12 | 6 | 4 |
| 3d-cad | 6 | 12 | 6 | 4 |
| game-development | 9 | 10 | 6 | 3 |
| image-design | 7 | 9 | 7 | 3 |
这张表里最该先看的一列是 known_gaps。5 个矩阵每一个都自带 3 到 4 条已知缺口,也就是说矩阵作者自己就在表里写明了「这几件事这套组合做不了」。这一列在 skill 渲染时会被单独渲染成一节,后面会说到。
矩阵注册表的拉取路径是 https://hkuds.github.io/CLI-Anything/matrix_registry.json,本地缓存在 ~/.cli-hub/matrix_registry_cache.json,TTL 3600 秒(cli-hub/cli_hub/matrix.py 13 到 15 行)。它比普通 registry 多一级兜底:网络和缓存都失败时,还会从当前目录向上遍历父目录去找本地的 matrix_registry.json(matrix.py 52 到 62 行、85 到 87 行)。这意味着你在仓库 checkout 里跑 cli-hub,读到的可能是仓库里那份文件而不是线上那份——排查「为什么我看到的矩阵和别人不一样」时,这是第一个要确认的点。
8 种 kind,只有 2 种归 install 管
matrix.py 26 到 35 行列出了 provider 的 kind 枚举标签,一共 8 种:harness-cli、public-cli、python、native、api、agent-skill、agent-native、web-search。
紧挨着它的第 20 行是 INSTALLABLE_KINDS,集合里只有两个值:harness-cli 和 public-cli——只有这两类被 matrix install 管理。八种里的其余六种,从这个集合的定义上就被排除在安装器的管辖之外了。
剩下六种怎么办?第 420 行的 unmanaged_providers() 把 install 管不到的 provider 分成 5 个桶:python、native、api、agent-skill、public-unmanaged。这是一个纯陈述性的分类输出,不是待办清单——它只负责把管不到的部分按类别摆出来,怎么解决是你自己的事,源码这一层没有再往下接任何动作。
所以回到开头那句话。以 video-creation 为例,矩阵里 14 个 CLI 对应 19 个 capability,但一条 capability 底下挂的 provider 可能是 api 或 native 的。matrix install 装完那些归它管的,退出后剩下的部分需要你另外处理,而这一步没有任何自动化。
这里还得说清一件事:matrix install 对归它管的那两类,走的是 cli-hub 的通用安装器,也就是会在你本机真的执行 pip / npm 一类的安装命令(cli-hub/cli_hub/installer.py 184 到 192 行是 harness 的 pip 路径)。这类工具本身的定位就是在本机安装并驱动第三方软件,装之前先看清它要动哪些目录,这一点没法回避。
capability 的「覆盖」是怎么算的
matrix.py 269 到 275 行是整个矩阵机制里语义最需要留意的一段。这段汇总算法的口径是:一条 capability 只要满足「至少有一个可用 provider,或者存在 agent-installable 兜底」两者之一,就计为覆盖;其余的一律算硬 gap,而硬 gap 的存在会驱动退出码 3。两个条件是「或」的关系,这一点是下面所有反直觉之处的来源。
反直觉的地方在后半个条件。第 17 行的 AGENT_INSTALLABLE_KINDS 只含 agent-skill 一种 kind,而 173 到 188 行对这类 provider 是直接短路返回的:preflight 结果里 available 写死 False,状态标成 agent-installable,三类依赖的检查结果两组都是空的——它根本不去检查这个 provider 有没有条件运行。
也就是说,同一条 provider 记录在 preflight 的明细里是 available: False,在汇总里却把它所在的 capability 记进了覆盖。这两个数看的是两回事:明细回答「现在能不能用」,汇总回答「有没有路子」。你如果只看汇总那行覆盖数,会得到一个偏乐观的印象。判断本机现状要看明细里的 available,判断退出码要看汇总。这也解释了为什么退出码 3 会在你以为「装完了」的时候冒出来。
对照着看非 agent-skill 的那条分支就更清楚了。150 到 198 行按三类依赖逐一检查:环境变量 env、可执行文件 binary 查 shutil.which、Python 包 package 走 importlib.util.find_spec 与 importlib.metadata.version。这三类是真检查,结果分成已具备与缺失两组。
顺带一个细节:matrix.py 303 行的 provider.cli 字段,注释标的是 “forward-compatible with schema v2.1 (F4.2)“。当前注册表是 v2,这个字段指向的是还没落地的 schema 版本,原样记在这里。同一段(309 到 312 行)还有一条命名规则:provider 名带 cli-anything- 前缀时会剥掉前缀再去 clis[] 里匹配。
preflight 和收窄安装范围
矩阵这组子命令一共 7 个(grep -c "@matrix.command" = 7):list / search / info / preflight / install / doctor / recipes。
preflight 就是上面那套依赖检查的入口,cli-hub-meta-skill/SKILL.md 40 到 50 行给 agent 的标准动作序列里把「preflight before you install」写成硬性要求。同一份文件 52 到 57 行还有一条明确警告:不要为了一个 capability 就整装一个 14-CLI 的矩阵,要用 --capability / --recipe / --only / --dry-run 把范围收窄。
matrix install 的选项在 cli-hub/cli_hub/cli.py 823 到 836 行:--capability/-c、--recipe、--only、--dry-run、--resume、--skill-only、--json。其中三个是互斥的——--capability / --recipe / --only 三选一,同时给多个直接返回用法错误(matrix.py 363 到 365 行);--resume 也不能和这三个混用,混用同样是用法错误(installer.py 476 到 479 行)。
--skill-only 值得单独拎出来:它只渲染矩阵 skill,不装任何成员 CLI(cli.py 830 到 855 行)。这条路径是下一节的引子。
退出码契约写在 cli.py 60 到 65 行:0 成功、1 失败或未找到、2 用法错误、3 部分失败或存在 gap。meta-skill 里复述的 0/3/1/2 与这里一致。注意 3 不是失败——它是「跑完了,但有缺口」,脚本里按非零就当失败处理会把这种情况一并吞掉。
本地渲染:SKILL.md 是怎么落到你机器上的
矩阵的另一半是 matrix_skill.py(397 行),它负责把矩阵内容渲染成一份 agent 能读的 SKILL.md,落点是 ~/.cli-hub/matrix/<name>/SKILL.md,同目录并排放 references/ 和 scripts/(matrix_skill.py 5 到 8 行、31 行、40 行)。还兼容一种旧的扁平布局 ~/.cli-hub/matrix/<name>.SKILL.md,仅当新路径不存在时才回落(68 到 79 行)。矩阵的安装状态则单独记在 ~/.cli-hub/matrix_state.json(installer.py 15 到 16 行)。
内容从哪来,是一条四级查找链(matrix_skill.py 10 到 19 行):
- 仓库 checkout 里的
cli-hub-matrix/<name>/ - wheel 内置的
cli_hub/_matrix_data/<name>/ - 发布 URL
https://hkuds.github.io/CLI-Anything/matrix/<name>/SKILL.md - 都没有就生成一份 stub
第二级那份内置数据是打包时塞进去的:cli-hub/setup.py 12 到 48 行在 build_py / sdist 阶段把上一级目录的 cli-hub-matrix 整个复制进 cli_hub/_matrix_data/,注释里说明 editable 安装不需要这份 vendored 拷贝。MANIFEST.in 里也只有一条 recursive-include cli_hub/_matrix_data * 加一条 global-exclude。第一级的仓库根定位优先用 git rev-parse --show-toplevel(超时 5 秒),失败再向上找 .git(45 到 65 行)。
这条链上有一个必须知道的行为:走到第三级只能拿到 SKILL.md 正文,拿不到它引用的 references/ 和 scripts/。 这种情况下渲染出来的文件里会追加一段说明,原文是 “No local copy … relative links above will not resolve locally”(135 到 142 行)。文件是渲染成功的,agent 读到的正文也是完整的,但正文里那些相对链接指向的文件在你机器上并不存在。所以在 ~/.cli-hub/matrix/<name>/ 下看到 SKILL.md 不等于资产齐了,得看这段说明在不在,以及旁边有没有真的多出 references/。
渲染出来的内容除了原始正文,还会注入几节。注入段落用 <!-- MATRIX_SKILL_PATHS:START --> 和对应的 :END 注释包裹(146 行),中间是一张表,列是 CLI / Entry Point / Canonical Skill / Local Skill / Status(238 到 250 行)。除此之外还会渲染 Capability Provider Overview、Recipes、Known Gaps、Stage Tooling Overview 四节(299 到 392 行)——前面说的那些 known_gaps 就是从这里进到 agent 视野里的。
有一个函数值得原样记下来:_render_discovery_section()(395 到 397 行)存在,但直接返回空串,注释写的是 registry search hints 属于元数据,生成的 skill 只列具体 provider。你在渲染产物里找不到 discovery 这一节,不是渲染出了问题。
矩阵内容本身:只有一个是全的
渲染链第一级读的 cli-hub-matrix/ 目录,我们采集时共 13 个文件、4893 行。5 个矩阵子目录里,只有 video-creation/ 带 references/ 和 scripts/(9 个文件),其余 4 个各自只有一个 SKILL.md。
各 SKILL.md 的行数:video-creation 536 行、knowledge-research 241、3d-cad 232、image-design 218、game-development 213。
video-creation/references/ 下有 7 篇:captions 206 行、sound-design 137、source-triage 123、story-structure-audio 117、render-doctor 116、art-direction-review 92、nle-shotcut-kdenlive 82。scripts/video_doctor.py 2580 行,是整个目录最大的单文件。这份脚本的文件头(2 到 7 行)有一段自我定位很克制:它自述”intentionally non-binary”,只报事实与调查信号,不判定视频是否合格;非零退出表示 doctor 自己跑不起来,而不是素材有问题。它的默认 flag 词表里含 "TODO"、"DEBUG" 这类占位/调试词(21 到 26 行,689 行与 696 行用到),用于揪出字幕里没替换掉的占位文本。
顺带一处命名上的落差:video-creation/SKILL.md frontmatter 的 name 是 cli-hub-matrix-video-creation,而正文第 12 行的标题写的是 “Video Creation Matrix (v3 — capability-based)“,注册表 meta 那边写的是 v2 schema。这两处版本表述不一致,我们只陈述到这里。
一处文档指向不存在的路径
matrix_registry.json 的 meta.schema_doc 指向 docs/cli-matrix/matrix_registry.schema.md,但我们采集时 ls docs/ 的结果里没有 cli-matrix/ 这个目录——docs/ 下是 FREECAD_VIDEO_REFERENCE.md、PREVIEW_MECHANISM_PROGRESS.md、PREVIEW_PROGRESS.md、PREVIEW_PROTOCOL.md、hub/ 和 scripts/。想照着 schema 文档去理解 v2 字段定义的话,这条路走不通,只能回去读 matrix.py 里对字段的实际取用。两处各自可核对,我们只说到这里。
你可以自己核对的几件事
不需要安装任何 harness,clone 下来读文件就能把上面的说法逐条对上:
- 数矩阵规模:读仓库根
matrix_registry.json,逐个矩阵数clis/capabilities/recipes/known_gaps的长度,和上面那张表比。 - 确认 install 的管辖边界:看
cli-hub/cli_hub/matrix.py第 17 行和第 20 行两个集合,再看第 420 行unmanaged_providers()那 5 个桶的名字。 - 确认覆盖率的算法:读 269 到 275 行那段汇总逻辑,对照 173 到 188 行 agent-skill 的短路返回,看清
available=False的 provider 是怎么被记进覆盖的。 - 确认矩阵内容的齐整度:
find cli-hub-matrix -type f数一遍,看references/和scripts/只出现在哪个子目录下。 - 确认 schema 文档:把
matrix_registry.json里meta.schema_doc的值和ls docs/的输出摆在一起。
如果你已经装了 cli-hub,那么 cli-hub matrix preflight <矩阵名> 与 cli-hub matrix doctor <矩阵名> 是这层的两个只读入口,前者查依赖、后者逐个检查矩阵成员是否已记录安装、entry_point 是否在 PATH,并给出 cli-hub install <name> 形式的修复命令(installer.py 565 到 589 行)。要收窄安装范围时,选项按 cli.py 823 到 836 行的语义组合,例如加 --dry-run 先看计划、或用 --skill-only 只渲染 skill。以上为按仓库中的参数语义组合的示例,未经实测,以官方文档与 --help 的实际输出为准。
最后回到那句话:矩阵这层解决的是「一条工作流需要哪些能力」的表达问题,不是「一条命令把环境配齐」的执行问题。表里 8 种 kind 只有 2 种归安装器管,覆盖率的算法把没检查过的 agent-skill 也算作覆盖,5 个矩阵每个都自带 3 到 4 条 known_gaps——这三件事凑在一起,指向同一个结论:把它当成一份能力清单来读,比当成一个安装器来用要合适。至于具体某条工作流跑起来是什么样,我们没有装过也没有跑过其中任何一个 harness,给不出结论。
本文依据 CLI-Anything 官方仓库(github.com/HKUDS/CLI-Anything)的 README、registry.json、
docs/ 与各 agent-harness/ 下的源码整理,核对日 2026-08-10,对应仓库快照 39634a6。
本文内容为仓库源码与文档口径,我们没有安装或运行过其中任何一个 harness,
也没有在本机驱动过任何一款宿主软件,因此不涉及实际操控效果的任何描述。
这类 harness 会在本机执行外部程序与脚本,是否使用请结合自身环境评估。
注册表与 harness 内容随上游更新而变动,请以仓库最新内容为准。
安全相关做法请结合自身环境评估,本文不构成安全方案建议。