Back to writing

/ Skills

[Skills-05] Maintaining Agent-Friendly Codebases: Deep Modules, Architecture, and Triage

Distilling codebase-design, architecture improvement, research, triage, and TypeScript module boundaries.

2 minSkill · Architecture · Deep Modules · Triage

Agent 友好的代码库不是“文件越小越好”,而是关键行为集中、接口清楚、事实来源可靠、进入系统的工作已经被验证和分类。本篇覆盖五个围绕代码库健康度的 skill,其中 setup-ts-deep-modules 仍处于 in-progress。

1. codebase-design:深度是调用者获得的杠杆#

这个 skill 采用一套严格词汇,避免 componentserviceAPIboundary 在不同人嘴里不断漂移。

  • Module:任何具有 interface 与 implementation 的东西,可以是函数、类、package 或跨层纵向切片;
  • Interface:调用者正确使用 module 必须知道的一切,不只 type signature,还包括 invariant、顺序、错误和性能特征;
  • Seam:可以替换行为而不在调用处修改代码的位置;
  • Adapter:在 seam 上满足 interface 的具体角色;
  • Depth:调用者每学习一单位 interface 能获得多少行为;
  • Leverage:一个实现服务多个调用者和测试;
  • Locality:变化、故障与知识集中在一个位置。
Deep module                 Shallow module
┌──────────────┐            ┌──────────────────────┐
│ small iface  │            │ large, fussy iface   │
├──────────────┤            ├──────────────────────┤
│              │            │ thin pass-through    │
│ rich behavior│            └──────────────────────┘
│              │
└──────────────┘

深度不是 implementation lines / interface lines 的比值,否则堆废代码反而能“变深”。它是调用杠杆。Deletion test 很直观:删掉 module 后,如果复杂度消失,它可能只是 middleman;如果复杂度重新散落到 N 个 caller,它就在提供价值。

1.1 Interface 同时是测试面#

好的 module 接受 dependency,而不是内部偷偷创建;返回 result,而不是只制造不可观察的 side effect;以更少方法和参数表达更多行为。

只有一个 adapter 时,seam 可能只是想象中的扩展点;出现第二个真实 adapter 后,变化才证明 seam 有价值。不要为“以后也许”引入 interface。

2. improve-codebase-architecture:寻找 deepening opportunity#

架构改进不是全仓库漫游式找茬。skill 先按 YAGNI 缩小扫描区域,优先最近频繁变化、持续制造摩擦的模块。

扫描结果写成视觉 HTML report。每个候选项包含涉及区域、当前 friction、改进方向、locality/leverage 收益、测试改善、before/after 图,以及 Strong / Worth exploring / Speculative 推荐等级。

此时只报告候选,不急着设计 interface。用户选中一个后,才通过 grilling 深入;需要多种 interface 时再调用 codebase-design 的 design-it-twice 方法。

如果候选违反现有 ADR,只有当真实摩擦足以值得重开决定时才展示,并清楚标注冲突。用户用有长期价值的理由拒绝候选时,可以把理由写成 ADR,防止下一次扫描重复建议。

3. research:每个事实追到第一方来源#

Research skill 很短,纪律却很强:

  1. 优先 official docs、source code、spec、first-party API;
  2. 每个重要 claim 都能追到拥有这个事实的 source;
  3. 结果写成单一、有引用的 Markdown,放进项目已有的研究目录;
  4. 研究作为 background work,不替代产品决策。

这与“让 Agent 凭参数知识写一段分析”不同。持久文件让后续 spec 或 wayfinder ticket 可以引用证据,也让信息随着依赖升级而重新审计。

4. triage:把原始请求变成可领取工作#

Triage 用两个正交维度标记 issue 或外部 PR:

  • Category:bugenhancement
  • State:needs-triageneeds-infoready-for-agentready-for-humanwontfix

每项工作必须恰好有一个 category 和一个 state。状态冲突时先询问维护者,不能自行覆盖。

处理单个 issue 的流程是:

  1. 读完整 body、comments、labels 与相关代码;
  2. 搜索是否已经实现,并检查 .out-of-scope/ 是否有既往拒绝;
  3. 向维护者给出 category/state 建议和依据;
  4. bug 先复现,PR 先验证 diff 声称的行为;
  5. 信息不足才进入 grilling;
  6. 输出 agent brief、human brief、needs-info notes 或 wontfix 记录。

Agent brief 描述行为、复现、验收和领域背景,不绑定很快失效的 file path。对于外部 PR,“PR 是带代码的 issue”:同样先判断请求是否成立,再决定 Agent 继续修改还是交给人 merge。

一个重要边界是:to-tickets 生成的 ticket 已经是 agent-ready,不应再次 triage。Triage 只处理未经加工的外部输入。

5. setup-ts-deep-modules:用工具强制 package 边界#

这个 in-progress skill 把 deep-module 原则落到 TypeScript monorepo。它使用 dependency-cruiser 建立约束:

  • package 外部只能通过 entry point 导入;
  • implementation 隐藏在子目录,禁止跨 package 深层 import;
  • 测试也从公开 interface 驱动,而不是绕过 seam;
  • 循环依赖和越层依赖由 CI 自动拒绝。

价值不只是“import 看起来整齐”。如果任意 caller 都能触碰内部文件,interface 就只是一份建议;工具化规则把 seam 变成可执行契约,也降低 Agent 为理解变化而遍历的文件数量。

迁移时需要先盘点 workspace layout、现有 entry points、测试路径和构建工具,再逐个 package 收紧。一次性开启所有限制,常会产生海量噪声,反而无法判断真正的设计问题。

6. 把健康度看成四个可维护面#

进入系统的工作 -> triage 验证、分类、写 brief
外部知识       -> research 固化证据
内部结构       -> codebase-design 定义深模块语言
持续治理       -> architecture scan 找机会,工具守住 seam

Agent 提高了变化速度,也提高了熵增速度。维护代码库健康的目标不是多加规范,而是让请求、知识、接口和自动检查都拥有清晰的单一入口。

参考#