Skip to main content
Glama
flake-verbs

flake-verbs

by bdelanghe

flake-verbs

Flake 结构动词,以类型化的 verbspec 规范编写一次,并投射到 CLI、MCP、Anthropic tool-use 和 OpenAPI。

这个工具回答了两个问题,而这两个问题过去都需要人工通读 flake 才能弄清:

动词

问题

inputs

我那些输入中,到底有哪些被真正用到?

input-drift

每个锁定的输入相对上游漂移了多远——它还能不能被获取到?

运行

bun install
bun run src/cli.ts inputs ~/.config/home-manager
bun run src/cli.ts input-drift ~/.config/home-manager --problemsOnly
bun run src/cli.ts --mcp-tools          # the agent-facing surface, derived

两个动词都把 flake 根目录当作位置参数(默认 .)并输出 JSON; CLI 渲染为文本视图,其他所有出口都补充消费 output。

Related MCP server: mcp-supply-guard

inputs — 使用 vs. 提到

最直接的做法是执行 grep <input-name> *.nix,而它会报告每个输入都被使用。 有三种情况只是“提到”某个输入,却不依赖它:

  • outputs = { a, b, ... }: 参数列表——只是“点名”每个输入

  • 注释

  • 路径和字符字面量——./program/lnzr.nix、".../.keep"

字符串 插值 是一个例外,必须通过过滤器保留,因为 ${"${dx-compose}/path/to/module"} 是真正的引用。这种不对称,正是它无法用 grep 实现的原因。

扫描还会记下 _module.args 别名。一个 flake 若绑定 synoptic = config._module.args.synopic-github,实际就在另一个不同名称之下使用该输入, 遗漏这一层,就是一个还在活跃的输入被误剪掉的方式。

三种判定

referenced 和 unused 的意思符合字面。module-import-only 才是有意思的那个, 而且它刻意不叫“unused”,因为引入一个 home-manager 模块,既可能是完全承载的(模块本身 自己配置 config,也可能完全无效(每一个选项都默认为 false,无人打开它)。

用 --deep(默认为开)时,该动词在能判定的地方去判定:把输入通过 nix flake archive 解析为 store path,读取被导入的模块,恢复它声明的选项命名空间,并检查消费 flake 是否有内容 设置到它。这让一种无法置评的态度变成事实:

DEAD dx-compose          github:bdelanghe/dx-compose
     imports a module declaring programs.devcontainers-cli, which nothing in this flake sets

下面再说过程中无法解析命名空间时,就保持 module-import-only,而不是去猜测。 一个误报的 unused 是代价不菲的错误——它删除的是一个可用输入 —— 因此每一步都在向 退化的方向「就该由人来看看」。

input-drift — 那一个能回本

太 (behind) 属于正常状态,不算失败。另外有有两个状态:

  • unportable — 即 path: 输入。Nix 在求值时重新读取磁盘上的 path 输入,因此 一个只指向作者机器上才有目录的锁,会让 flake 在其他机器上完全无法 evaluate。 此引导式的死角,只有你试图在第二台机器上 build 时才会看不出来。

  • orphaned — 锁定的 revision 中带上一些提交,它们不在远程默认分支,或者远程完全 不予以;这个 commit 只存在于某个本地 checkout 里——是尚未推送的工作,重建机器后 会被悄无声息丢丢弃。

这两个状态退出码是一非零,所以 CI 上会把它们挡下来。behind 则不影响。

上游查询都是通过 gh api 进行的,因此私有输入也不需要这个工具处理令牌。

它为什么存在

它写于一次真正的损失之后。一个 home-manager flake 带有四个 path: 输入,全部指向 ~/.local 目录;换了一台干净机器后,flake 完全无法求值最大问题。当把这些输入改成指向 GitHub 后发现,其中 lnzr 这个输入在本地 checkout 领先其远端 main 三个月——那三行 右工作只存在本地检出里,不存在于任何其他地方,现在跟着旧磁盘一起没了。

锁定文件自始至终一直记录着这两个事实。但其间没有任何工具能向它提问。

值得注意的限制

  • 引用扫描是文本层面上的,不是一套求值。它读的是 .nix 源码,并不 evaluate flake,所以 那些只通过生成、动态构建的 attrpath 才能触达的输入仍然有被漏掉。

  • --deep 单独负责 cfg = config.<ns> 和 options.<ns> 这两种惯用法。 如换个方式写模块,就退回 module-import-only。

  • input-drift 只针对 github: 输入与其上游比较。gitL: 或 tarball: 输入 报为 unknown,而非输出一个错误值。

  • 只检查直接输入。传递式输入是别人的决定,应当由相应的人模块在自己的仓库中自行审计。

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables MCP-compatible clients to inspect Next.js codebases, analyze App Router and Pages Router structure, discover API routes, and audit build performance through controlled tools.
    10 npm
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables supply-chain integrity for MCP tools by locking tool-definition hashes after review and detecting added, removed, modified, or risky tool definitions.
    MIT