前缀器:先限定范围,命中失败再扩大,并记录变化
一个对整个仓库进行搜索的智能体会为每个不相关的结果付出令牌成本。而一个命名空间映射(只需十几行代码,说明什么内容在哪里)就能让智能体从第一次调用开始就在正确的区域内搜索。本技能负责构建该映射、保持其更新,并强制智能体执行“先限定范围再搜索”的策略。它的唯一职责是:更便宜、更好的代码库搜索。
规模门槛。 当文件数量大致低于一百个,或仓库的结构一目了然时,跳过映射,按目录名限定搜索范围;只有超过这个规模,映射方案才值得投入。
<重要> 如果当前搜索即使只有很小的可能性可以被限定范围,就应限定范围。不限定范围的搜索正是本技能要阻止的失败。“就一次 grep”正是令牌流失的开始。 </重要>
工作方式
- 一次性定位。 检查是否存在
.prefixer/namespaces.md。如果不存在,且当前任务需要进行超过两次搜索,则为正在处理的代码段建立映射(§1 至 §3),然后在其内部搜索。如果映射已存在,则读取它并开始限定范围的搜索。 - 限定范围搜索,命中失败再扩大。 第一次搜索应指向最可能的命名空间,而不是仓库根目录(§4 至 §6)。
- 记录日志。 在任务结束时,向
.prefixer/metrics.jsonl添加一行记录;当基线存在时,还需记录变化(§7 至 §8)。此为必需输出,非可选。
何时体现价值
- 在大型或不熟悉的仓库中的首次会话。 读取十二行映射而非扫描整个目录树;第一次搜索就已经是限定范围的。
- 单体仓库。 每个包一个命名空间:搜索不会将兄弟包的信息噪音带入上下文。
- 多个代码库。 组织级别的映射用于选择代码库,仓库级别的映射用于选择其内部的命名空间。两个级别,绝不会进行联合扫描。
- 重复探索。 “X 在哪里?”、重构、不熟悉的功能区域;首次尝试命中率正是映射方案体现价值的地方。
- 你会再次访问的仓库。 映射会跨会话持久化;每个未来的智能体都将以“已定位”状态开始,而不是重新扫描。
A. 命名空间映射
1. 映射代码段,而非整个代码库
规则: 当仓库没有 .prefixer/namespaces.md 且工作需要超过两次搜索时,仅映射 此任务涉及的那部分仓库:三到五个命名空间;而不是整个目录树。一个能限定当前搜索范围的局部映射,胜过花费一小时构建的完整映射。当一次真实的搜索落到映射范围之外时才扩展它,永远不要提前扩展。运行 bash scripts/init_namespaces.sh(位于本技能目录)以获取一个脚手架,然后修正其猜测:说明每个命名空间的用途。
原因: 本设计有意采用增量采纳方式。映射是一个工作文件,而非清单;当一次搜索需要某行时,它才体现价值。
草稿不是映射。 任何前缀或 contains 列仍为 TODO 的行均未完成;在依赖该映射之前,请完成或删除这些行。脚手架会报告剩余多少行草稿。
优先使用现有文档。 如果 AGENTS.md、CLAUDE.md 或 README 已经描述了布局,则从中为 contains 列提供种子(脚手架会这么做),并将 namespaces.md 视为搜索范围的权威来源;不要维护两个内容可能渐行渐远的目录。
会话开始时阅读优于事后记忆。 每会话读取一次映射是最容易被跳过的一步。如果工具链能在会话开始时注入文件,让它输出 namespaces.md:这样每次搜索自然就从限定范围开始,无需任何纪律约束。已提供的集成方式:scripts/install_hook.sh 为您写入钩子(scripts/session_start.sh 输出映射及健康状态判决);代码片段位于 integrations/ 中。配方和原理参见 references/namespaces.md。
2. 保持映射小巧并使用 glob 表达式
规则: 5 到 12 个命名空间。每行由一个简短前缀、一个路径 glob 以及一行用于消除歧义的用途说明组成。如果两行匹配同一搜索的频率相同,则合并它们。如果某行从未限定过真实的搜索,则删除它。
格式:
# 命名空间
repo: acme-payments
| 前缀 | 范围 | 包含 |
|--------|--------------------|-----------------------------|
| api: | src/api/** | REST 处理程序、路由 |
| auth: | src/auth/** | 登录、会话、令牌 |
| sso: | src/auth/sso/** | SSO 子团队区域 |
| test: | tests/**, **/*.test.* | 测试套件、测试夹具 |
repo: 头部是此代码库的唯一限定符(来自 git 远程仓库);它使得在组织运行多个代码库时每个前缀全局唯一:acme-payments:auth: 永远不会与 checkout-service:auth: 冲突。
行可以嵌套:缩进行的上级命名空间,用于模块内的子团队或服务内的包。标签会组合,如 auth:sso:,因此相同名称在不同父级下保持独立(orders:checkout: 与 payments:checkout: 不同)。
名称是推导出来的,而非声明的。 前缀和 contains 文本来自代码库自身的词汇:目录名、命名空间所限定的文件中的主导术语,永远不要使用你凭空创造的类别。推导出的名称会随代码库的演进而演变;发明的名称则会漂移。脚手架会为您完成此工作:修正其错误,保留其正确之处。
格式详情及其他仓库形状的映射:references/namespaces.md。
3. 更新,绝不重新生成
规则: 当映射过时时,编辑过时的行。不要重写文件。整体重新生成会丢失使其有价值的累积细节。删除无用的行,添加缺失的行,保持其余部分字节一致;重写的映射还会破坏加载它的每个会话的提示缓存前缀。整理完成后,运行 bash scripts/check_namespaces.sh:如果某行的 glob 解析后没有文件,则说明该行在向每个未来会话传达错误信息。当映射感觉过时或日志已经增长时,运行 bash scripts/suggest_map.sh:它会读取 metrics.jsonl 和目录树,并建议真实搜索已经请求过的行。
多个代码库: 相同的技巧可以叠加。组织级映射用于选择代码库(pay: services/payments/**),仓库级映射用于选择其内部的命名空间。每个映射的 repo: 头部保持前缀跨代码库唯一;四十个服务都可以有一个 auth/,因为限定标签 payments:auth: 唯一地标识了一个。永远不要将所有仓库合并为一个搜索,那正是组织规模下根目录 grep 失败的根本原因。参见 references/namespaces.md。
B. 搜索范围限定
4. 从最窄范围开始
规则: 每次搜索从最有可能包含答案的命名空间开始。grep "expire" src/auth/ 优于 grep "expire" .。一次未命中消耗一次调用;一次广泛搜索则消耗整个命中列表的令牌。
让脚本承载规则: bash scripts/search.sh auth "expire" 将标签解析为其 glob,在内部搜索,未命中时向上一级扩大,并记录指标行;§4 至 §8 自动运行。--scope <ns> 打印 glob 列表,--paths <ns> 打印解析出的文件,--list 打印所有标签;将映射作为其他命令可查询的索引。
注意: “以防万一”搜索仓库根目录;无路径约束的 glob 模式如 **/*;在命名空间 glob 就够用时使用 find。
5. 未命中时向上一级扩大
规则: 在命名空间内未命中?向上一级扩大:命名空间,然后其父区域,然后是整个仓库,然后才是第三方库和生成代码目录。不要从一次未命中直接跳到全仓库扫描,也不要搜索 node_modules、vendor、dist、build 或锁文件,除非任务本身涉及它们。
6. 使用命名空间标签回答
规则: 使用 prefix:path:line(例如 auth:src/auth/session.ts:42)格式报告结果。这样,你的下一次搜索或未来会话的搜索,就已经从限定范围开始了。当一个文件不属于任何现有命名空间时,说明映射存在缺口;应提及这一点,而不是发明一个标签。
C. 追踪
7. 在进行断言前先建立基线
规则: 在推荐搜索变更之前,先统计当前行为:每任务搜索次数、每次搜索工具调用次数、首次尝试命中率。没有基线,就没有变化,只有故事。通过运行固定的探查来记录一个基线:在仓库根目录执行 bash scripts/measure_search.sh --baseline orientation -- grep -rn "TODO" .,或在映射存在前统计最初几个任务的数据。关于记录内容和评分方式,参见 references/metrics.md。
8. 记录每个任务
规则: 在每个任务结束时,向 .prefixer/metrics.jsonl 追加一行 JSON:
{"ts":"2026-10-26T14:03:11Z","task":"find-session-expiry","searches":3,"tool_calls":4,"first_try_hit":true,"est_tokens":1400}
est_tokens 为 字符数/4,是一个估计值;即使无法精确测量,也要保留该字段。会话结束时,报告与基线的变化。scripts/measure_search.sh 封装一次搜索并在仓库根目录记录每搜索一行(hits、scope;--baseline 标记探查,--hit|--miss 记录 first_try_hit)。手动编写的任务行添加 tool_calls 和 first_try_hit。使用同一 schema,字段可选;references/metrics.md 列出了所有字段。scripts/report_metrics.sh 读取日志:命中率、每个命名空间的消耗、限定范围与基线的变化。
Git 处理。 提交 namespaces.md:它是每个未来会话都能受益的共享前缀。metrics.jsonl 是本地遥测数据;脚手架会为其编写一个 .prefixer/.gitignore。仅当团队希望查看趋势数据时才提交它。
危险信号
出现以下想法时请停止。你在找理由。
| 想法 | 现实 |
|---|---|
| “一次广泛的 grep 不会有什么坏处” | 广泛的 grep 正是本技能要消除的成本。限定范围。 |
| “我知道它大概在哪里” | 在命名空间中验证。错误的猜测比一次限定范围的检查成本更高。 |
| “先映射整个仓库” | 映射你所在的代码段。其余的行在搜索需要时才会体现价值。 |
| “对这个任务来说,映射是多余的” | 一个部分映射到第三次搜索时仍能带来回报。 |
| “跳过基线,直接应用” | 没有基线就没有证据。先测量。 |
| “我会重新生成整个映射,这样更快” | 重新生成会丢弃精心整理的内容并破坏缓存。编辑过时的行。 |
| “脚手架生成的映射就算数” | 充满 TODO 行的映射是草稿,不是映射。完成或删除它们。 |
| “搜索 vendor 目录以求全面” | 生成代码是令牌的坟场。只有当它是任务主体时才搜索。 |
何时不使用前缀
- 单文件脚本和一次性仓库:没有需要限定范围的内容。
- 只有一个明确文件的任务:打开它,不要为它构建基础设施。
- 当路径已经说明一切时:在
src/auth/内部搜索不需要用auth:做装饰。 - 第三方库或生成代码,除非它们是任务的主题。
- 小于约 100 个文件且结构清晰的仓库:按目录名限定范围,跳过映射。
参考
references/namespaces.md:映射格式、仓库形状、多仓库堆叠references/metrics.md:指标定义、JSONL schema、变化报告scripts/init_namespaces.sh:为当前仓库搭建命名空间映射脚手架scripts/check_namespaces.sh:检查映射:无效范围、重复标签、草稿scripts/search.sh:将限定范围搜索作为命令执行:解析、搜索、扩大、记录scripts/suggest_map.sh:读取日志和目录树,建议映射编辑scripts/measure_search.sh:一步完成搜索并记录scripts/report_metrics.sh:读取日志:命中率、范围消耗、变化scripts/session_start.sh:输出映射(及健康状态)用于会话启动钩子scripts/install_hook.sh:为 devin/claude 配置 SessionStart 钩子scripts/doctor.sh:检查仓库设置的健康状态:映射、检查、钩子、安装标记scripts/eval_scope.sh:测量限定范围搜索与根搜索的令牌变化scripts/eval_repo.sh:检查并评估映射中每个命名空间,平均节省百分比scripts/visualize.py:在文件树上渲染映射及测量到的节省,生成 HTML 报告SPEC.md:namespaces.md 格式合同,供读取或写入映射的工具使用integrations/:会话启动钩子代码片段 + 消费者仓库的 PR 检查工作流
为流水线和提示作者保留的相关手册(超出本技能核心职责):references/index-prefixes.md、references/prefix-library.md、references/cache-ordering.md。