/decide
你是单一架构决策记录(ADR)的作者,该记录存放在 ai-docs/decisions/ 下。决策注册表是使先前推理可追溯的底层基础——每一个限制未来工作、明确排除某个替代方案或设定有效期的有意义的选择都会被记录下来,以便未来的工程师和AI代理能够追溯。
你在此技能中不编辑生产代码。你唯一要写的制品是新的或修改后的ADR文件。建议在你的总结中添加对 canonical-patterns.md / architectural-smells.md 的反向引用,但不由你执行(一个明确的编辑任务会在人工审查后添加这些反向引用)。
成功标准
- 新的/修改后的ADR通过了第3阶段验证:
.venv/bin/python scripts/decisions.py audit和link-check运行结果干净,并报告实际输出。 - 第1阶段确认没有现有的决策已经涵盖该主题——重复的ADR会被中止,转而使用
--amend或替代,绝不会为同一选择创建第二个ADR。 - 在适用的情况下设置了
related_smell/related_pattern反向引用,并且总结建议添加Decided in: NNNN行——这是建议,而非自行执行。 - 除了
ai-docs/decisions/之外,没有写入任何内容。 从第0阶段开始就朝着这些门控编写。
核心理念
- 决策的阈值是真实的。 任何满足以下条件的选择:(a) 限制未来的技能或重构,(b) 明确排除一个替代方案,或 (c) 设定一个有效期,都是候选。惊喜、调试笔记和项目状态不是决策——这些内容应放入
.claude/tasks/lessons.md、提交消息或任务列表中。 - 一个选择对应一个ADR。 如果工作跨越两个耦合的选择,则编写两个ADR。一个记录了两个独立分支的单一ADR很难被替代,难以链接,并且最终会变成一个墓地条目。
- 反向引用使注册表可导航。 每个ADR在适用时应设置
related_smell和/或related_pattern前置元数据,并且你的总结应建议向匹配的canonical-patterns.md/architectural-smells.md条目添加Decided in: NNNN反向引用。没有反向引用,注册表就成了只写存储器。 - 替代优于删除。 被替代的决策保留在注册表中,状态为
superseded,并带有superseded_by: NNNN。永远不要删除ADR——这个链条就是审计追踪。 - 目标节奏:每季度2-5个。 在单个项目中超过这个数量意味着过度记录——登记簿会变成一个杂物抽屉。如果你发现自己一周内起草了第三个ADR,停下来问问后面的那些是否真的是决策,或者仅仅是不偏好。
- 追溯编写的ADR是有效的。 一个长期存在的约束未来工作的约定,即使早于注册表,也值得拥有一个ADR。在正文中将其标记为这样的形式(
> 追溯编写的ADR。)。
参数解析
四种形式——选择恰好一种。
形式A — 新的ADR(默认)
/decide <slug>
<slug> 是一个简短的短横线分隔的主题标识符(例如 textchoices-for-state、spec-first-refactor、celery-safe-dispatch)。协调器选择下一个可用的4位数字 id(最低未使用的整数,零填充),从slug中衍生出标题,并搭建一个状态为 proposed 的ADR。
形式B — 替代一个现有的ADR
/decide --supersede <existing-id> --slug <new-slug>
编写一个新的ADR(下一个id,状态 proposed),并带有 supersedes: [<existing-id>]。同时,暂存对被替代ADR前置元数据的编辑(status: superseded,superseded_by: <new-id>),但不提交——必须先由人工批准新的ADR。
形式C — 修改一个现有的ADR
/decide --amend <id>
编辑以下字段之一:status、superseded_by、applies_to、tags、related_smell、related_pattern。正文编辑不在范围内(对于这些编辑,直接打开文件——修改ADR的决策本身就是一个决策,因此通常应该使用替代而不是修改)。
形式D — 列出
/decide --list
是 .venv/bin/python scripts/decisions.py list 的简写形式。不写入新文件。
将解析后的规范展示给用户(意图 + 目标id + 从 canonical-patterns.md / architectural-smells.md 中找出的 related_smell/related_pattern 候选),并在形式A和B中等待批准后再写入。形式C/D立即执行。
批准令牌合约与 /extract-enum 和 /fix-workflow 相同:第一个非空白令牌必须是 approved、approve、go、lgtm、proceed 或 yes。
流程
第0阶段 — 设置
前: 参数已解析。后: 下一个id已确定(形式A,B);目标文件路径已确定(形式C);${REPO_ROOT}/ai-docs/decisions/ 存在。
# 查找下一个id(形式A,B)
NEXT_ID=$(.venv/bin/python -c "
import pathlib, re
ids = []
for p in pathlib.Path('ai-docs/decisions').glob('[0-9][0-9][0-9][0-9]-*.md'):
m = re.match(r'(\d{4})-', p.name)
if m: ids.append(int(m.group(1)))
print(f'{(max(ids)+1) if ids else 1:04d}')
")
NEW_PATH="ai-docs/decisions/${NEXT_ID}-${SLUG}.md"
如果slug在任何id下已经存在,则中止并建议使用 --amend 修改现有的ADR。
第1阶段 — 上下文收集
前: 目标id已知。后: 找到了相关的模式候选和相关的坏味道候选。
读取这些文件(小巧、快速、范围限定于主题):
ai-docs/decisions/README.md— 注册表约定.claude/docs/canonical-patterns.md— 搜索与决策主题匹配的模式名称(对slug单词进行大小写不敏感的grep).claude/docs/architectural-smells.md— 对坏味道名称进行相同搜索.venv/bin/python scripts/decisions.py list --json— 完整的注册表(这样你就不会不小心重新决定一个已经决定过的问题)
对于形式B(替代),还要读取被替代ADR的正文,以便新ADR可以说明哪些内容发生了变化。直接引用被替代决策的决策句子,然后解释分歧。
第2阶段 — 起草ADR
前: 上下文已收集。后: ${NEW_PATH} 已写入(形式A,B)或 --amend 的字段已更新(形式C)。
使用注册表脚本搭建形式A/B,然后编辑生成的文件。脚手架是前置元数据形状的可执行真相来源:
.venv/bin/python scripts/decisions.py init "${SLUG}"
由 scripts/decisions.py init 发出的ADR形状——保持这些前置元数据字段存在,即使某个值为空:
---
id: "<NNNN>"
namespace: core
title: "<大写开头的标题句子——如果可能的话以动词开头>"
status: proposed # proposed | accepted | superseded | deprecated
date: <YYYY-MM-DD 今天>
deciders: [] # 如果不确定则询问再填写
supersedes: [] # 仅在形式B中填充
superseded_by: null
applies_to: []
embodied_by: [] # 一旦接受则必需;参见 ADR 0033
tags: []
related_smell: <smell-anchor 或 null> # 来自 architectural-smells.md
related_pattern: <pattern-anchor 或 null> # 来自 canonical-patterns.md
---
# <标题>
<可选的追溯编写免责声明>
## 上下文
<2-4段,解释之前的状态、反复出现的问题以及此决策的触发因素。要具体——引用真实文件、真实事件、真实故障模式。模糊的上下文 = 以后无法被替代。>
## 决策
<一个简短的段落陈述规则,然后如果有多个子规则则使用项目符号列表。