首页
/ Spec Kit agent-context 扩展深度解析:如何让 CLAUDE.md、AGENTS.md 与 Plan 自动保持同步

Spec Kit agent-context 扩展深度解析:如何让 CLAUDE.md、AGENTS.md 与 Plan 自动保持同步

2026-09-06 16:46:50作者:贡沫苏Truman

Spec Kit 的 agent-context 扩展负责管理编码智能体(Claude Code、Copilot、Cursor、Gemini 等)的上下文/指令文件,例如 CLAUDE.mdAGENTS.md.github/copilot-instructions.md。它是一个显式安装(opt-in)的可选扩展:安装后,它会在这些文件中维护一段由可配置标记包围的"受管区块",并自动把区块内容指向当前最新的 plan.md 路径;不安装则 Spec Kit 的任何流程都不会改动这些文件。读完本文,你将掌握该扩展的安装/禁用方式、全部配置项含义、受管区块的 upsert 算法、plan 路径的解析优先级,以及 .mdc 文件的 frontmatter 修复机制。

为什么做成一个扩展,而不是内置功能

不是每个 Spec Kit 用户都希望 Spec Kit 去写编码智能体的上下文文件。把这一行为放进一个独立的 opt-in 扩展(见 extensions/agent-context/README.md)带来四个直接好处:

  • 可选择是否安装——specify init 默认不会安装它。想要 Spec Kit 托管 agent 上下文文件时才显式添加;未安装时该文件绝不会被修改,已禁用时其自动钩子也不会运行。
  • 可自定义标记——编辑项目内的 .specify/extensions/agent-context/agent-context-config.yml,脚本会遵循其中 context_markers 的取值。
  • 可同步多个 agent 锚点——当项目同时使用多份上下文文件(如 AGENTS.mdCLAUDE.md)时,配置 context_files 列表即可一次更新全部文件。
  • 可按需刷新——在 agent 中运行 speckit.agent-context.update 命令,或依赖 extension.yml 中声明的 after_specifyafter_plan 钩子自动刷新。

从源码结构看,这一"完全交给扩展自己"的设计在 CLI 侧有对应约束:specify_cli 的集成初始化代码(如 src/specify_cli/integrations/_helpers.py)明确注释"agent 上下文文件完全由 opt-in 的 agent-context 扩展拥有,该函数从不触碰扩展及其配置",并且测试 tests/extensions/test_extension_agent_context.py 中的 test_cli_does_not_resolve_context_placeholder 专门验证了 CLI 不再解析模板中的 __CONTEXT_FILE__ 占位符——当扩展未安装或被禁用时,模板里的 __CONTEXT_FILE__ 会原样保留。

受管区块的生命周期:只动标记之间的内容

该扩展的核心职责是拥有由 start/end 标记(默认 <!-- SPECKIT START --> / <!-- SPECKIT END -->)分隔的受管 section 的完整生命周期:

  • 只写标记之间:区块外的任何内容都不受影响;
  • .mdc 文件额外保证文件顶部 YAML frontmatter 中包含 alwaysApply: true(Cursor 只自动加载带此字段的 .mdc 规则文件);
  • 幂等:重复运行只会替换旧区块,不会叠加。

受管区块的固定内容由 _build_section 生成:

<!-- SPECKIT START -->
For additional context about technologies to be used, project structure,
shell commands, and other important information, read the current plan
at specs/001-login/plan.md
<!-- SPECKIT END -->

即一句提示语加上"当前 plan 的路径"。这样当编码 agent 读取 CLAUDE.md 时,就能被引导去读最新的实现计划。

安装、禁用与命令

安装

在已初始化的 Spec Kit 项目根目录运行:

specify extension add agent-context

禁用 / 重新启用

specify extension disable agent-context

# 重新启用
specify extension enable agent-context

禁用(或未安装)期间,Spec Kit 中没有任何流程会创建、更新或删除受管区块,模板中的 __CONTEXT_FILE__ 占位符保持原样,扩展自身的配置也永远不会被读取。

提供的命令

命令 说明
speckit.agent-context.update 用当前 plan 路径刷新 agent 上下文文件中的受管区块

命令 ID 是规范的(canonical)写法;实际调用语法取决于你的集成方式:

集成类型 调用写法
dot-command 集成 /speckit.agent-context.update
hyphen/skills 集成(含 Forge、Cline 等) /speckit-agent-context-update
Codex、ZCode(skills 模式) $speckit-agent-context-update
Kimi /skill:speckit-agent-context-update

对应的命令模板见 extensions/agent-context/commands/speckit.agent-context.update.md,其声明的执行入口为:

  • Bash.specify/extensions/agent-context/scripts/bash/update-agent-context.sh [plan_path]
  • PowerShell.specify/extensions/agent-context/scripts/powershell/update-agent-context.ps1 [plan_path]

当省略 plan_path 参数时,脚本会自动探测最新的 specs/**/plan.md

配置参考:agent-context-config.yml

所有配置都集中在项目内的 .specify/extensions/agent-context/agent-context-config.yml。仓库中的模板(extensions/agent-context/agent-context-config.yml)完整注释了每个字段的用途,可逐项对照理解:

# 单个 agent 上下文文件路径(相对项目根,即 .specify/ 所在目录)。
# 拒绝绝对路径、反斜杠分隔符和 `..` 路径段。
# 留空时使用你所选编码 agent 的默认上下文文件
# (见 agent-context-defaults.json)。
# 例: context_file: CLAUDE.md
context_file: ""

# 多个 agent 上下文文件列表(相对项目根)。
# 当 context_file 与 context_files 同时存在时,context_files 优先生效。
# 例:
# context_files:
#   - AGENTS.md
#   - CLAUDE.md
context_files: []

# 受管区块的起止标记。扩展只在这两个标记之间注入信息。
# 仅在希望自定义标记名时修改。
# 例:
# context_markers:
#   start: "<!-- AGENT SPEC KIT CONTEXT START -->"
#   end: "<!-- AGENT SPEC KIT CONTEXT END -->"
context_markers:
  start: "<!-- SPECKIT START -->"
  end: "<!-- SPECKIT END -->"

要点归纳:

配置项 类型 行为
context_file 字符串(可选) 指定单个受管文件;留空则回退到集成默认映射
context_files 字符串列表(可选) 多个受管文件;非空时优先于 context_file,逐一遍历更新
context_markers.start / .end 字符串(可选) 受管区块分隔符;缺失时使用默认 <!-- SPECKIT START --> / <!-- SPECKIT END -->

路径安全约束

_validate_context_fileextensions/agent-context/scripts/python/update_agent_context.py#L112-L138)对每个候选路径做硬性校验,违反即报错退出(退出码 1):

  • 必须以项目根为相对路径——绝对路径(/...)与 Windows 盘符路径(C:\...)被拒绝;
  • 不得包含反斜杠分隔符;
  • 不得包含 .. 路径段;
  • 最终解析(含符号链接解引用)后仍必须落在项目根之内,防止通过 symlink 逃逸出项目目录。bash 脚本中的 test_bash_script_rejects_symlink_escape 对应测试(tests/extensions/test_extension_agent_context.py)专门覆盖了这一逃逸场景。

未配置时的"自播种"(self-seed)

context_filecontext_files 都为空时,脚本并不会报错,而是执行自播种逻辑:读取 .specify/init-options.json 中的 integration(或 ai)键,再通过 extensions/agent-context/agent-context-defaults.json 中的映射得到默认上下文文件。该映射覆盖了全部 36 个支持的集成,摘选如下:

集成 key 默认上下文文件
claude CLAUDE.md
copilot .github/copilot-instructions.md
gemini GEMINI.md
cursor-agent .cursor/rules/specify-rules.mdc
codex / copilot 之外的多数 CLI(codexgoosegrokopencodeqwen 等) AGENTS.md
junie .junie/AGENTS.md
kilocode .kilocode/rules/specify-rules.md
trae .trae/rules/project_rules.md
qwen / qodercli / shai / tabnine / zcode QWEN.md / QODER.md / SHAI.md / TABNINE.md / ZCODE.md

源码注释明确指出,这一映射"按设计独立于 Specify CLI"——扩展自己管理自己的生命周期,脚本内部不 import 任何 specify_cli 模块。若集成在映射表中不存在默认值,脚本会打印"no default context file is known for integration …"的提示,要求用户显式设置 context_file。此外,在 Windows/Cygwin/MSYS 环境下,context_files 的去重比较采用大小写不敏感(casefold)策略,与 bash 脚本中 MINGW/MSYS/CYGWIN 分支的行为一致。

底层实现:Plan 路径如何被解析

这是扩展最有技术含量的部分。受管区块的价值完全取决于 plan_path 是否指向"当前"计划,因此解析采用两级优先策略(见 _resolve_plan_path):

  1. 优先读取 .specify/feature.json——该文件由 /speckit-specify 写入,其中 feature_directory 字段指明当前功能目录;脚本在 feature_directory/plan.md 存在时以它为准。解析时做了几处细节处理:
    • 先把路径中的反斜杠(PowerShell 在 Windows 上写入的格式)规范化为正斜杠;
    • 支持相对路径、绝对路径与 C:/ 盘符路径三种形态;
    • resolve() 解引用符号链接再做 relative_to 比较,使 macOS 上 /var/…/private/var/… 被判定为同一路径;
    • 若 plan 落在项目根外,则直接输出解析后的 POSIX 绝对路径。
  2. 回退到 mtime 探测——仅当 feature.json 不存在或其 plan 尚未生成时,递归遍历 specs/ 下所有 plan.mdrglob 而非旧的单层 specs/*/plan.md 通配),选出修改时间最新的一个。递归搜索保证了通过 SPECIFY_FEATURE_DIRECTORY 创建的作用域化布局(如 specs/<scope>/<feature>/plan.md)也能被发现。同样,候选文件在比较前先做符号链接解引用,避免指向项目外的 specs/ symlink 被误选。

这条解析链有专门的回归测试:tests/extensions/test_update_agent_context_feature_json.py 覆盖 feature.json 路径,test_bash_script_discovers_nested_plan / test_bash_script_finds_nested_plan 等用例覆盖嵌套布局的 mtime 回退。

底层实现:区块 upsert 的四分支算法

_upsert_section(bash/PowerShell 版本逻辑等价)按文件中现有标记的组合分四种情况处理:

现有文件状态 行为
start 与 end 标记均存在 整体替换标记之间的旧区块(保留标记后的换行)
只有 start 标记 从 start 标记处开始截断,写入新区块(丢弃残缺尾部)
只有 end 标记 保留 end 标记之后的内容,在其前面插入新区块
都没有标记 若文件已有内容则追加到文件末尾(先补齐换行);文件不存在则直接创建,父目录不存在时自动 mkdir -p

写入前还会把全文 CRLF/CR 统一规范化为 LF(读取时以 utf-8-sig 编码容忍 BOM),保证跨平台换行稳定。bash 入口脚本还负责解释器选择:依次尝试 $SPECKIT_PYTHON 环境变量、python3python,并要求该解释器可 import yaml 且为 Python 3(见 update-agent-context.sh 第 29-55 行),任何一个不可用则降级为打印警告并跳过更新,而不是让钩子失败。

.mdc 文件的 frontmatter 修复

ensure_mdc_frontmatterupdate_agent_context.py 第 216-256 行)只对 .mdc 后缀文件生效,处理三种情形:

  1. 文件无 frontmatter → 在头部整体前置 ---\nalwaysApply: true\n---\n\n
  2. frontmatter 已有 alwaysApply: true → 原样返回(幂等);
  3. frontmatter 存在但 alwaysApply 缺失或值不是 true → 原地修复该行、保留原有注释与格式;若完全没有该键则在 frontmatter 末尾追加一行。

对应测试 test_bash_script_prepends_mdc_frontmattertest_bash_script_mdc_frontmatter_is_idempotenttest_bash_script_repairs_existing_mdc_frontmatter 以及"非 .mdc 文件不做 frontmatter 处理"的负向用例,都在 tests/extensions/test_extension_agent_context.py 中可查证。

钩子驱动的自动化

extension.yml 声明了两个可选钩子:

hooks:
  after_specify:
    command: speckit.agent-context.update
    optional: true
    description: "Refresh agent context after specification"
  after_plan:
    command: speckit.agent-context.update
    optional: true
    description: "Refresh agent context after planning"

也就是说,每次执行 /speckit.specify/speckit.plan 之后,事件系统会自动触发 speckit.agent-context.update,使上下文文件中的 plan 路径始终跟上最新进度——无需手动干预。根据 extensions/EXTENSION-API-REFERENCE.md,钩子挂在 after_specifyafter_plan 等由核心命令定义的生命周期事件上,同一事件的多个钩子按 priority 升序执行(默认 10)。extension.yml 同时声明了元信息:schema_version: "1.0"、要求 speckit_version: ">=0.2.0"、标签 agent/context/core,且该扩展以捆绑(bundled)形式随仓库分发,catalog 中将其列为 bundled 条目(测试 test_catalog_lists_agent_context_as_bundled 守护此约定)。

环境要求与故障排查

捆绑的更新脚本要求 Python 3 + PyYAML 做 YAML 解析/写入(PowerShell 侧在可用时也可用 ConvertFrom-Yaml)。PyYAML 随 specify CLI 一起分发,正常情况下同一个 python3 解释器即可满足。如果钩子报告 "PyYAML is required … not available in the current Python environment",说明系统 python3 与安装 Spec Kit 所用的解释器不是同一个,解决方式:

pip install pyyaml
# 或者针对 Spec Kit 实际使用的那个解释器:
/path/to/speckit-python -m pip install pyyaml

脚本在 PyYAML 缺失时的行为是优雅降级:打印指引信息后以退出码 0 跳过本次更新(上下文文件不被修改),避免破坏宿主命令流程;测试 test_bash_script_falls_back_from_invalid_speckit_python 验证了无效 SPECKIT_PYTHON 会被自动回退到 PATH 上其他可用解释器。

验证与测试入口

该扩展的行为有相当完整的测试护栏,均位于 tests/extensions/ 目录,可作为"实现是否符合文档"的一手证据:

bash、PowerShell、Python 三个运行时的脚本(scripts/bash/update-agent-context.shscripts/powershell/update-agent-context.ps1scripts/python/update_agent_context.py)在语义上互为孪生实现,配置解析、自播种、路径校验、plan 解析与 upsert 逻辑逐条对齐,跨平台行为以测试为准绳。

小结

agent-context 是 Spec Kit 扩展体系中一个边界清晰、职责单一的范本:它以 opt-in 的方式接管编码 agent 上下文文件,把"让 agent 知道最新 plan 在哪"这件容易被遗忘的小事变成 after_specify/after_plan 钩子驱动的自动行为。对使用者的实际收益是——在 Claude Code、Copilot、Cursor 等工具中始终有一份指向当前 specs/**/plan.md 的新鲜指引,而标记之外的文件内容(团队手写的规则、项目约定)永远不会被覆盖;若你更倾向自行维护该文件,不安装扩展即可,Spec Kit 的其余部分对此完全无感。

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