首页
/ impeccable 无参数路由:用 context-signals 生成上下文感知命令菜单

impeccable 无参数路由:用 context-signals 生成上下文感知命令菜单

2026-09-04 10:55:19作者:宣海椒Queenly

当用户在 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 /impeccable with 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。)两条总体原则贯穿全文:

  1. 推荐是引导(lede),菜单是兜底(fallback)。Agent 应先给出 2–3 个最有价值的下一步命令,每个配一行来自信号的理由,然后再附上按类别分组的完整 Commands 表。
  2. 绝不自动执行任何命令。推荐只是“等待用户确认的建议”(the recommendation is a suggestion the user confirms)。这是整个路由层的安全边界:信号再强,也只转化为措辞,不转化为执行。

二、前置分支:NO_PRODUCT_MD 时的菜单引导

Setup 阶段(SKILL.md 第 1 步)已经在会话开始时运行过 context.mjscontext.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.mjsloadContext
setup hasCode 是否存在 package.json,或 src / app / pages / site / public / components / lib 任一目录(hasCode
setup platform 从 PRODUCT.md 的 ## Platform 小节读出的 web / ios / android / adaptiveios, android 这类双平台写法会被归一为 adaptiveextractPlatform
critique latest 跨全部 target 的最新一条 critique 快照:slug / score / p0 / p1 / timestamp / file,读取自 .impeccable/critique/ 下按时间戳命名的 frontmatter 快照;缺失时整组为 nulllatestCritique
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 uptests/context-signals.test.mjs#L155-L162)。

五、推理规则:把信号翻译成 2–3 条建议

routing.md 的核心是一份“信号 → 命令”的推理清单,并且特意声明 “there is no score to obey”——没有任何一个数值字段是 Agent 必须机械服从的,推理本身才是路由:

  1. setup.hasDesign 为 false 而 setup.hasCode 为 true → 推荐 document(为既有代码捕获视觉系统,生成 DESIGN.md)。
  2. critique.latestnull → 项目从未被 critique 过;对已有真实 surface 的 setup 完整项目,提供 /impeccable critique <surface> 是一个强默认推荐。
  3. critique.latestscore 偏低或 p0 / p1 非零 → 推荐 polish(polish 会把那份快照当作自己的 backlog 来读取和消化);若快照看起来已经过期,则建议重跑 critique
  4. git.changedFiles 指向某一个 surface → 把 auditpolish 的 scope 精确限定到这些文件,并在措辞中点名这些文件。这正是“脏树优先”信号的产品意义:用户此刻正在改什么,就围绕什么给建议。
  5. devServer.running 为 true → live 可用于浏览器内迭代;为 false 时不要用 live 领衔。并且 live 与打包的 detect.mjs 都是 web-only:若 setup.platformiosandroidadaptive,两者都不要领衔——浏览器 overlay 与 HTML 规则引擎对原生 App 代码不适用。
  6. 以上都不命中时,按意图分组(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.targets is non-empty and setup.platform is not ios/android/adaptive, run node .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 命中 → 推 auditpolish;命中某个具体的“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):

  1. never-throw / always-valid-JSON 契约:每个探测各自 try/catch,git 缺失、快照 frontmatter 缺键(如 p1_count: nope 会被安全归一为 null)、非 git 目录都不影响整体输出,保证 Agent 总能读到一份可解析的信号;
  2. 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 在“命令入口层”如何做到上下文感知而不越权。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
981
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384