Router Skill:大型 Skill 仓库的规模化组织方法

原始 GitHub 文件:

ask-matt 不是拿来直接产出代码、文档或原型的。它做的是另一层工作:当这套仓库里的 user-invoked skills 变多以后,用户已经不可能记住每一条 skill 的名字、边界和顺序,于是需要一个总入口来判断"我现在该走哪条 flow"。

这正是 writing-great-skills 里那句判断的落地版本:当 user-invoked skills 多到用户记不住时,就用一个 router skill 解决 cognitive load

1. 完整可复制中文 ask-matt/SKILL.md

md 复制代码
---
name: ask-matt
description: 询问当前情形适合哪条 skill 或哪条 flow。它是这个仓库里所有用户手动触发 skill 的路由入口。
disable-model-invocation: true
---

# Ask Matt

你不可能记住每一条 skill,所以就来问。

**flow** 指的是一条穿过多条 skill 的路径。大多数路径都沿着一条**主线 flow**运行,另外有两个**并入主线的入口**会汇入它。其余 skill 则是独立使用的。

## 主线 flow:idea → ship

这是大多数工作真正会走的路径。你有一个想法,并且想把它做出来。

1. **`/grill-with-docs`**:通过追问式访谈把想法打磨清楚。当你**已经有代码库**时,从这里开始。它是有状态的,会把过程中学到的东西保存在 `CONTEXT.md` 和 ADR 中。(没有代码库?用 `/grill-me`,见"独立使用"一节。)
2. **分支:是不是每个问题都能在对话里直接定下来?** 如果某个问题必须靠一个可运行的答案来确定(例如状态、业务逻辑、必须亲眼看到的 UI),就先绕到 prototype;两个方向都用 **`/handoff`** 作为桥(见"跨会话切换"):
   - 先用 **`/handoff`** 导出,
   - 然后围绕那个文件开启一个全新的会话,
   - 用 **`/prototype`** 写一次性代码来回答这个问题,
   - 再用 **`/handoff`** 把学到的内容带回去,并从原始想法线程引用它。
3. **分支:这是不是一个会跨多轮会话的构建?**
   - **是** → 先用 **`/to-prd`**(把当前线程整理成 PRD),再用 **`/to-issues`**(把 PRD 拆成可独立领取的 issue)。因为这些 issue 彼此独立,**每做一个 issue 都要清空上下文**:每个 issue 都开启一条新会话,把 PRD 和单个 issue 一起传给 **`/implement`**。
   - **否** → 直接在当前上下文里运行 **`/implement`**。

### 上下文卫生

第 1 到第 3 步要保持在**同一个连续的上下文窗口**里完成。在 `/to-issues` 之前不要 compact,也不要清空上下文。这样 grilling、PRD 和 issues 才能建立在同一轮思考上。之后的每次 `/implement` 再从一个干净上下文出发,只围绕那一张 issue 工作。

这里的上限是 **[smart zone](https://www.aihero.dev/ai-coding-dictionary/smart-zone)**:也就是模型仍能保持锋利推理的上下文范围(当前最强模型大约在 120k tokens 左右)。如果会话在 `/to-issues` 之前就逼近这个上限,不要硬撑到性能退化;改用 `/handoff`,并在一条新线程里继续。

## 并入主线的入口

所谓入口,是指一种起始局面:它会先生成工作,再并入主线。

- **Bug 和需求越积越多** → 用 **`/triage`**。它会让 issue 经过 triage 角色流转,并产出 agent-ready issues;后面的 **`/implement`** 再来领取这些问题。

  Triage 只用于**不是你自己创建的** issue,例如 bug report、外部进来的 feature request,以及任何原始流入的问题。`/to-issues` 产出的 issue 已经是 agent-ready,因此**不要再 triage 一遍**。

## 代码库健康

这不是功能开发,而是日常维护。

- **`/improve-codebase-architecture`**:只要有空就跑,用来持续保持代码库对 agents 友好。它会浮现出值得继续深化的机会;挑中其中一个之后,就会生成一个新的 idea,而这个 idea 可以带回主线 flow,从 `/grill-with-docs` 开始推进。

## 跨会话切换

- **`/handoff`**:当一条线程快满了,或者你需要分叉出去(例如开一条 `/prototype` 会话),它会把当前对话压缩成一个 markdown 文件。你不会在原地继续,而是**开启一条新会话,并引用那个文件**,借此把上下文带过去。它是上下文窗口之间的桥,而且两个方向都能用。只要你想要一个**新会话**,但又必须保留**当前对话内容**,就用它。
- **`/compact`**(内建能力):继续留在**同一条对话**里,只是让更早的内容变成摘要。适合在**阶段之间的有意切口**使用,只要你不介意失去逐字历史即可。不要在阶段进行中途 compact;Agent 很容易丢方向。`/handoff` 是分叉到新会话,`/compact` 是继续留在原会话。

## 独立使用

这些不走主线 flow。

- **`/grill-me`**:和 `/grill-with-docs` 一样,是不留情面的追问式访谈;但适用于**没有代码库**的时候。它是无状态的:不会在本地保存任何内容,也不会构建 `CONTEXT.md`。当你只是想把一个不在仓库里的计划或设计问清楚时,用它。
- **`/teach`**:围绕某个概念进行跨多轮会话的学习,并把当前目录当成一个有状态工作区来使用。
- **`/writing-great-skills`**:用于写好和改好 skills 的参考。

## 前置条件

**`/setup-matt-pocock-skills`**:在第一次运行工程 flow 之前先执行它,用来配置其他 skills 默认依赖的 issue tracker、triage labels 和文档布局。自定义 issue tracker 也可以接入。

2. 它其实是 writing-great-skills 里 router skill 的实例

ask-matt 最有价值的地方,是它把一条抽象原则写成了真实入口。

writing-great-skills 里,有一个很关键的判断:如果一组 skill 都是 user-invoked,那么它们不会常驻上下文,节省了 context load;但代价是用户得自己记住它们,承担 cognitive load。当这个负担变大时,就应该引入一条 router skill

ask-matt 就是这条 router skill:

  • 它自己也是 user-invoked;
  • 它不承担具体执行;
  • 它只负责把当前处境路由到正确的 flow 或 skill。

所以这条 skill 的核心不是"多懂一点仓库",而是"把整套 skill 的入口秩序建立起来"。

3. 为什么它必须 disable-model-invocation: true

这条 skill 如果允许模型自动触发,反而会损失它最重要的边界。

因为 ask-matt 不是一个具体工作模式,而是"请先帮我决定该用哪种工作模式"。如果它常驻可自动触发状态,模型在很多本来已经明确的场景里都可能绕回来先做一次路由,等于多加一层不必要的判断。

把它做成 user-invoked,效果反而更干净:

  • 当用户真的"不知道该走哪条 flow"时,再显式调用它;
  • 一旦 flow 已经明确,后续就应该直接进入目标 skill,而不是不断回到路由层。

所以它的禁用自动触发,不是因为它不重要,而是因为它太上层了。

4. 主线 flow 真正想控制的是"从想法到交付"的相位切换

ask-matt 最容易被读浅的地方,是把它当成一张 skill 导航表。其实它更像一张相位图

主线 idea → ship 不是随便把 skill 串起来,而是在控制同一类问题应该在哪个阶段被解决:

  • grill-with-docs 解决"想法和设计有没有压实"
  • prototype 解决"哪些问题必须靠可运行答案才能定下来"
  • to-prd / to-issues 解决"什么时候该把长线程压成稳定交付物"
  • implement 解决"什么时候进入真正实现"

所以它不只是路由"该用哪条 skill",而是在路由"当前卡住的问题属于哪一种问题"。

5. 为什么它反复强调上下文卫生

这条 skill 的一个高价值判断,是把"何时连续保留上下文、何时故意切断上下文"说得非常清楚。

它的原则是:

  • grill-with-docsto-prdto-issues 这几步必须放在同一个连续上下文里,因为它们共享同一轮设计推理;
  • 每个 /implement 则应该从干净上下文开始,因为 issue 已经是压实过的工作包,不再需要背整条上游讨论。

也就是说,它把上下文当成一种工程资源来管理,而不是默认"上下文越长越好"。这和你前面一直强调的 information hierarchycontext load 是同一类思路。

6. /handoff/compact 的区别,是这条 skill 里最实用的一个判断

很多人会把两者都理解成"压缩上下文",但 ask-matt 刻意把它们拆开:

  • /handoff:换线程,保留结构化上下文,是跨会话的桥。
  • /compact:不换线程,只在原会话里继续,只保留摘要。

这两个动作看起来接近,实际作用完全不同。ask-matt 把它们并排写出来,是为了防止用户在阶段中途误用 compact,导致推理链条断裂;或者本来应该换线程时,却还在原地硬撑。

这也是它作为总路由器的职责之一:不仅告诉你"去哪",还告诉你"什么时候该切线程"。

7. 这条 skill 为什么要把仓库里的 skill 分成主线、入口、独立使用、前置条件

这种分类法不是排版问题,而是注意力控制。

它把整套仓库里的 skill 分成四类:

  • 主线:大多数 feature work 真正会走的标准路径
  • 入口:不是从想法出发,而是从积压问题出发的场景
  • 独立使用:不汇入主线的独立能力
  • 前置条件:其他 flow 默认依赖的初始化步骤

这样一来,用户不会把 skill 仓库看成平铺菜单,而会先知道:

  • 哪些是默认路径
  • 哪些是特殊起点
  • 哪些根本不在主线里
  • 哪些必须先配置

这正是 router skill 应该做的事:先建立地图,再让人决定下一步。

8. 快速复习关键思想

关键思想压缩:

  • ask-matt 不是执行 skill,而是总路由 skill。
  • 它是 writing-great-skills 中 router skill 原则的具体实现。
  • 它必须是 user-invoked;如果自动触发,反而会污染清晰场景。
  • 它真正路由的是"当前属于哪一类问题、该进入哪一个阶段"。
  • 它把上下文视为一种要管理的资源,而不是默认越长越好。
  • /handoff/compact 的边界,是这条 skill 的实用核心之一。

快速回忆:

  1. ask-matt 解决的根本问题是什么?
  2. 为什么它不应该自动触发?
  3. 为什么 /grill-with-docs/to-issues 要保持在同一个上下文里?
  4. 为什么 /implement 要一张 issue 一条新会话?
  5. /handoff/compact 的差别到底是什么?

答案要点:

  • 它解决的是 user-invoked skill 变多以后,用户记不住入口和 flow 的认知负担。
  • 因为它是路由层,不是执行层;场景已经明确时,不该再额外加一层路由判断。
  • 因为这些步骤共享同一轮设计推理,提前切断会让 PRD 和 issues 失去上游语义。
  • 因为 issue 已经是压实后的独立工作包,不需要背整条长线程进入实现。
  • /handoff 是跨会话带文件继续;/compact 是留在原会话里继续,只保留摘要。