impeccable 无参数路由:用 context-signals 生成上下文感知命令菜单
当用户在 Agent 中裸敲 /impeccable 而不带任何子命令时,项目如何回答“我现在该做什么”?impeccable(一个让 AI harness 更懂设计的 skill 套件)并没有给出一张静态命令清单,而是通过一份名为 routing.md 的路由 playbook,结合 context-signals.mjs 收集的实时项目信号,动态生成一份“2–3 个最高价值建议 + 完整菜单兜底”的上下文感知菜单。读完本文,你将理解这套无参数路由的完整决策链:从 NO_PRODUCT_MD 分支、五大类信号采集,到 detect.mjs 深度扫描信号的融入规则,以及“只建议、绝不自动执行”的安全边界。
一、路由 playbook 的触发时机与总体原则
routing.md 开头就界定了自己的定位:
Read this when the user invokes
/impeccablewith no argument. They are asking "what should I do?" Make the menu context-aware instead of static.
也就是说,它专门服务于无参数调用这一入口。这份文档由 SKILL.md 的路由规则直接挂接:
No argument: read routing.md and present its context-aware menu; never auto-run a command.
(见 SKILL.src.md 的 Routing 小节,rule:skill-routing。)两条总体原则贯穿全文:
- 推荐是引导(lede),菜单是兜底(fallback)。Agent 应先给出 2–3 个最有价值的下一步命令,每个配一行来自信号的理由,然后再附上按类别分组的完整 Commands 表。
- 绝不自动执行任何命令。推荐只是“等待用户确认的建议”(the recommendation is a suggestion the user confirms)。这是整个路由层的安全边界:信号再强,也只转化为措辞,不转化为执行。
二、前置分支:NO_PRODUCT_MD 时的菜单引导
Setup 阶段(SKILL.md 第 1 步)已经在会话开始时运行过 context.mjs。context.mjs 负责加载 PRODUCT.md、DESIGN.md、匹配的 surface brief 以及原生平台指引;当它在任何位置都找不到 PRODUCT.md 时,会向 stdout 打印一条显式的 NO_PRODUCT_MD: 消息(见 context.mjs#L1131-L1162)。routing.md 要求 Agent 据此走第一个分支:
- 以
/impeccable init作为菜单头条推荐,并用一句话说明原因(项目还没有捕获的产品上下文); - 仍然展示其余完整菜单,不能因为缺 PRODUCT.md 就静默跳进 init 流程(don't silently jump into init)。
值得注意的是,NO_PRODUCT_MD 在实际实现中有两种措辞变体,都出现在 context.mjs#L1131-L1185:
| 变体 | 触发条件 | 附加指令 |
|---|---|---|
| 无既有视觉实现 | 无 PRODUCT.md,且代码中未发现既有视觉实现 | PRODUCT_INIT_REQUIRED:新构建/重设计必须先完成 init |
| 有既有视觉实现 | 无 PRODUCT.md,但 hasVisualImplementation 探测到 token 化样式、成体系的组件等 |
SCOPED_EXISTING_ALLOWED:窄范围精修命令可直接以现有代码为上下文继续,之后再建议 init |
这个区分保证了裸调用在“有代码但没上下文”的项目上不会过度打断用户——窄范围命令可以继续,init 只是被置顶的建议,而不是强制门槛。
三、信号采集:context-signals.mjs 的 JSON 输出
当 PRODUCT.md 存在时,routing.md 指示 Agent 运行一次:
node .agent/skills/impeccable/scripts/context-signals.mjs
并读取其 JSON。该脚本(源文件 skill/scripts/context-signals.mjs)的设计契约写在文件头注释里,非常克制:
It does NOT score or rank. The agent reasons over the raw signals… Deliberately light: no LLM calls, no detector run, no file writes. Every probe is best-effort and never throws; the output is always valid JSON.
即:不打分、不排序(推理交给 Agent 的模型能力)、无 LLM 调用(不调用 detector、不写文件)、任何探测都是尽力而为且永不抛错,输出永远是合法 JSON。入口函数 gatherSignals 组装出五组信号:
| 信号组 | 字段 | 含义与采集方式 |
|---|---|---|
setup |
hasProduct / productPath / hasDesign / designPath |
PRODUCT.md / DESIGN.md 是否存在及其相对路径,来自 context.mjs 的 loadContext |
setup |
hasCode |
是否存在 package.json,或 src / app / pages / site / public / components / lib 任一目录(hasCode) |
setup |
platform |
从 PRODUCT.md 的 ## Platform 小节读出的 web / ios / android / adaptive;ios, android 这类双平台写法会被归一为 adaptive(extractPlatform) |
critique |
latest |
跨全部 target 的最新一条 critique 快照:slug / score / p0 / p1 / timestamp / file,读取自 .impeccable/critique/ 下按时间戳命名的 frontmatter 快照;缺失时整组为 null(latestCritique) |
git |
isRepo / branch / base / changedFiles / changedCount |
当前分支、diff 基分支、改动文件列表(截断到 50 条)与总数;非 git 仓库时返回 isRepo: false 与空列表 |
devServer |
running / ports |
探测本机 127.0.0.1 上的常见开发端口 [4321, 3000, 5173, 5174, 8080, 8000, 4200](COMMON_DEV_PORTS),每个端口 250ms 超时;只要任一端口可达即 running: true |
scan |
targets / via |
应交给 detector 扫描的本地文件(永不输出 URL)及其来源,见下一节 |
其中 git.changedFiles 的采集是这份信号里工程含量最高的部分。gitSignals 并不假设仓库一定有 main/master:它按“最具体优先”的顺序检测 diff 基分支——先取当前分支配置的 upstream(@{u} 全符号引用解析),再取 develop(git-flow 仓库的功能分支通常合入 develop),再取各 remote 的默认分支 symref(origin/HEAD),最后才落到 main / master 惯例名;如果当前分支本身就是一条集成分支(或处于 detached HEAD),则只对工作区做 scope 提示,不做分支 diff,避免两条集成分支互相 diff 出全量差异。源码注释明确指出这段逻辑修复的是 issue #302(develop 基线上特征分支的改动对扫描目标“隐身”),并有专门测试印证:diffs a feature branch against a develop integration branch (#302)(tests/context-signals.test.mjs#L231-L250)。
四、scan.targets:detector 扫描目标的四级优先级
scan 组是路由中“第二次深入”的输入。scanTargets 按固定优先级选出本地目标,scan.via 字段标明来源:
| 优先级 | via |
选择逻辑 |
|---|---|---|
| 1 | git-changes |
脏工作区(或特征分支相对 base 的 diff)中的 markup/style 文件。先用扩展名白名单过滤(.html .htm .css .scss .jsx .tsx .js .ts .vue .svelte .astro),再剔除 vendored 路径(以 . 开头的目录、node_modules / dist / build 等;例外保留 .vitepress / .vuepress / .storybook,因为那里面是真 UI 源码),最后校验文件仍存在。routing.md 称之为 “the markup/style files in your dirty tree, the most relevant set” |
| 2 | source-dir |
依次检查 src / app / components / pages / public,取存在的目录 |
| 3 | html |
根目录存在 index.html 时指向它 |
| 4 | root |
有代码但没有上述结构时,回退到 .(detector 的 walkDir 自身会跳过 node_modules / dist / build 与隐藏目录) |
源码注释解释了为什么目标永远是本地路径:URL 意味着昂贵的 Puppeteer 浏览器渲染,而被探测到的 dev-server 端口甚至可能不属于当前项目;本地 HTML 文件或源码树由无 jsdom 依赖的静态引擎扫描,成本极低。测试同样固定了这一契约:targets a local source dir (never a URL), even with a dev server up(tests/context-signals.test.mjs#L155-L162)。
五、推理规则:把信号翻译成 2–3 条建议
routing.md 的核心是一份“信号 → 命令”的推理清单,并且特意声明 “there is no score to obey”——没有任何一个数值字段是 Agent 必须机械服从的,推理本身才是路由:
setup.hasDesign为 false 而setup.hasCode为 true → 推荐document(为既有代码捕获视觉系统,生成 DESIGN.md)。critique.latest为null→ 项目从未被 critique 过;对已有真实 surface 的 setup 完整项目,提供/impeccable critique <surface>是一个强默认推荐。critique.latest的score偏低或p0/p1非零 → 推荐polish(polish 会把那份快照当作自己的 backlog 来读取和消化);若快照看起来已经过期,则建议重跑critique。git.changedFiles指向某一个 surface → 把audit或polish的 scope 精确限定到这些文件,并在措辞中点名这些文件。这正是“脏树优先”信号的产品意义:用户此刻正在改什么,就围绕什么给建议。devServer.running为 true →live可用于浏览器内迭代;为 false 时不要用live领衔。并且live与打包的detect.mjs都是 web-only:若setup.platform是ios、android或adaptive,两者都不要领衔——浏览器 overlay 与 HTML 规则引擎对原生 App 代码不适用。- 以上都不命中时,按意图分组(build new / improve what's there / iterate visually),并结合当前 surface 与
setup.platform做定制。
这套推理与 SKILL.md 的完整 Commands 表(即“完整菜单”)一一对应。按类别分组的菜单如下(源自 SKILL.src.md 的 Commands 表,路由文档要求“followed by the full menu… grouped by category”):
| 命令 | 类别 | 说明 |
|---|---|---|
craft [feature] |
Build | 普通 new-work 请求的弃用别名 |
shape [feature] |
Build | 写代码前先规划 UX/UI |
init |
Build | 将持久产品上下文捕获进 PRODUCT.md |
document |
Build | 从既有项目代码生成 DESIGN.md |
extract [target] |
Build | 抽取可复用 token 与组件进设计系统 |
critique [target] |
Evaluate | 带启发式打分的 UX 设计评审 |
audit [target] |
Evaluate | 技术质量检查(a11y、性能、响应式) |
polish [target] |
Refine | 发布前的最终质量打磨 |
bolder [target] |
Refine | 放大安全/平庸的设计 |
quieter [target] |
Refine | 收敛激进/过度刺激的设计 |
distill [target] |
Refine | 去繁就简,剥离到本质 |
harden [target] |
Refine | 生产就绪:错误、i18n、边缘情况 |
onboard [target] |
Refine | 首次运行流程、空状态、激活设计 |
animate [target] |
Enhance | 添加有目的的动画与动效 |
colorize [target] |
Enhance | 为单色 UI 添加策略性色彩 |
typeset [target] |
Enhance | 改善字体层级与字体选择 |
layout [target] |
Enhance | 修复间距、节奏与视觉层级 |
delight [target] |
Enhance | 注入个性与记忆点 |
overdrive [target] |
Enhance | 突破常规极限 |
clarify [target] |
Fix | 改进 UX 文案、标签与错误信息 |
adapt [target] |
Fix | 适配不同设备与屏幕尺寸 |
optimize [target] |
Fix | 诊断并修复 UI 性能 |
live |
Iterate | 视觉变体模式:在浏览器中选取元素、生成替代方案 |
六、可选深入:detect.mjs 的真实检测信号
在信号推理之上,routing.md 还允许一次可选的“实地取证”。条件与命令(以安装版 skill 路径表述)为:
If
scan.targetsis non-empty andsetup.platformis notios/android/adaptive, runnode .agent/skills/impeccable/scripts/detect.mjs --json <scan.targets joined by spaces>once
关键约束与取舍:
- 打包 detector,本地文件:detect.mjs 是一个薄壳,动态加载
detector/detect-antipatterns.mjs(不存在时回退到cli/engine下的同名实现),对本地 HTML/CSS 跑规则引擎——no network, no npx; - 命中的融入方式:大量 quality / contrast 命中 → 推
audit或polish;命中某个具体的“slop 家族”→ 推对应命令,文档举例:渐变文字或 eyebrow 式眉标 →quieter/typeset,扁平或灰色调板 →colorize,“and so on”; - 失败兜底:detect 报错或树太大太慢时,跳过它并建议用户自己跑
audit;“never block the suggestion on it”——建议流程永远不能被检测拖住。
routing.md 把这一步定性为 “a real, current signal that beats guessing”(真实的、当下的信号胜过猜测),但它仍是从属于信号推理的增强项,而非必经之路。
七、输出形态与质量护栏
routing.md 的收尾两句话定义了 Agent 呈现结果的形式:
Keep it to 2-3 pointed picks with the exact command to type. The menu stays the fallback; the recommendation is the lede.
即:2–3 条带精确可敲命令的锐利建议领衔,完整菜单作兜底。结合前文,一份合格的无参数响应应包含:推荐理由逐条挂接信号字段、每条建议给出可直接输入的命令(如 /impeccable polish src/pages/Checkout.tsx)、其后是完整的类别化 Commands 表——且全程不执行任何命令。
这套设计在实现层面有两条值得注意的质量护栏,都可在测试中验证(tests/context-signals.test.mjs):
- never-throw / always-valid-JSON 契约:每个探测各自 try/catch,git 缺失、快照 frontmatter 缺键(如
p1_count: nope会被安全归一为null)、非 git 目录都不影响整体输出,保证 Agent 总能读到一份可解析的信号; - vendored 路径过滤(#303):
.claude/skills/...、.cursor/等 vendored AI-harness 安装文件的改动不会混入git-changes扫描目标,避免“改 harness 触发对 harness 的扫描”这类自指噪声;测试用例filters harness-dir files out of git-changes scan targets (#303)固化了这一行为。
八、小结
impeccable 的无参数路由把“该做什么”这个模糊问题拆解成一条确定性流水线:context.mjs 判上下文是否就绪(NO_PRODUCT_MD 分支置顶 init)→ context-signals.mjs 产出五组轻量信号(setup / critique / git / devServer / scan)→ Agent 按六条推理规则把信号翻译成 2–3 条精确命令建议,可选地用一次本地 detect.mjs --json 扫描补足实证 → 完整 Commands 表兜底。全程无打分器、无 LLM 调用、无网络请求、无自动执行,推荐与执行之间始终隔着一道“用户确认”的边界。理解这套机制,也就理解了 impeccable 在“命令入口层”如何做到上下文感知而不越权。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00