扩展 Spec Kit:插件架构之扩展与预设
前置知识
- ›第 1 篇:架构与项目导航
- ›第 3 篇:集成系统(了解 CommandRegistrar)
- ›第 4 篇:命令模板与工作流引擎
- ›YAML 语法与 JSON Schema 基础概念
扩展 Spec Kit:插件架构之扩展与预设
9 个内置命令覆盖了 SDD 工作流的核心场景,但实际项目往往需要更多。团队可能希望在每个工作流步骤中集成 git 分支管理,或者需要一套医疗合规预设,在规格模板中强制添加 HIPAA 必填章节。Spec Kit 通过两套并行的扩展机制来满足这些需求:extensions 用于添加新命令和生命周期钩子,presets 用于覆盖现有模板。两套系统共享相同的校验模式、目录发现机制以及面向 AI agent 的输出格式化逻辑。
扩展清单 Schema 与校验
每个扩展都通过一个 extension.yml 清单文件来定义,并由 ExtensionManifest 进行校验。Schema 要求包含四个顶级字段:
schema_version: "1.0"
extension:
id: my-ext # ^[a-z0-9-]+$ regex validated
name: "My Extension"
version: "1.0.0" # semver validated via packaging.version
description: "..."
requires:
speckit_version: ">=0.2.0" # PEP 440 specifier
provides:
commands: [...] # At least one command OR hook required
hooks: {...} # Optional lifecycle hooks
命令名称必须符合 EXTENSION_COMMAND_NAME_PATTERN 正则表达式:speckit.{extension}.{command}。这套命名空间约定——例如 speckit.git.feature 或 speckit.git.commit——有效避免了扩展之间以及扩展与核心命令之间的命名冲突。
extensions.py#L148-L231 中的校验逻辑相当严格:
- 扩展 ID 只能包含小写字母、数字和连字符
- 版本号必须能通过
packaging.version.Version解析为合法的 semver speckit_version指定符会与当前运行的 CLI 版本进行校验- 每个命令必须同时包含
name和file字段 - 每个钩子必须包含
command字段 - 扩展至少需要提供一个命令或钩子
提示: 校验错误信息足够具体,可以直接指导修复——例如 "Invalid command name 'git.feature': must follow pattern 'speckit.{extension}.{command}'",而不是笼统的 "validation failed"。开发扩展时,在扩展目录下运行
specify extension add .,可以立即获得校验反馈。
Git 扩展:典型案例分析
内置的 git 扩展位于 extensions/git/extension.yml,是了解扩展能力的最佳参考。它提供了:
5 个命令:
| 命令 | 用途 |
|---|---|
speckit.git.feature |
创建功能分支,支持顺序编号或时间戳编号 |
speckit.git.validate |
校验分支是否符合命名规范 |
speckit.git.remote |
检测 git 远程 URL,用于 GitHub 集成 |
speckit.git.initialize |
初始化 git 仓库并创建初始提交 |
speckit.git.commit |
在工作流步骤完成后自动提交变更 |
18 个生命周期钩子,覆盖每个工作流阶段:
flowchart LR
subgraph "before_ hooks"
BC["before_constitution<br/>(git.initialize)"]
BS["before_specify<br/>(git.feature)"]
BCl["before_clarify<br/>(git.commit)"]
BP["before_plan<br/>(git.commit)"]
BT["before_tasks<br/>(git.commit)"]
BI["before_implement<br/>(git.commit)"]
BCh["before_checklist<br/>(git.commit)"]
BA["before_analyze<br/>(git.commit)"]
BTI["before_taskstoissues<br/>(git.commit)"]
end
subgraph "after_ hooks"
AC["after_constitution<br/>(git.commit)"]
AS["after_specify<br/>(git.commit)"]
ACl["after_clarify<br/>(git.commit)"]
AP["after_plan<br/>(git.commit)"]
AT["after_tasks<br/>(git.commit)"]
AI["after_implement<br/>(git.commit)"]
ACh["after_checklist<br/>(git.commit)"]
AA["after_analyze<br/>(git.commit)"]
ATI["after_taskstoissues<br/>(git.commit)"]
end
before_constitution 钩子会执行 speckit.git.initialize(optional: false,强制执行),确保在创建 constitution 之前 git 仓库已经存在。before_specify 钩子会执行 speckit.git.feature(同样强制),用于创建功能分支。所有 after_* 钩子则以 optional: true 的方式执行 speckit.git.commit,并向用户展示类似 "Commit specification changes?" 的确认提示。
此外,该扩展还在 extensions/git/scripts/ 目录下包含了配置模板以及 bash 和 PowerShell 两种版本的 shell 脚本。
钩子系统架构
钩子在清单文件的 hooks 部分定义,每个钩子的结构如下:
hooks:
before_specify:
command: speckit.git.feature
optional: false
description: "Create feature branch before specification"
after_specify:
command: speckit.git.commit
optional: true
prompt: "Commit specification changes?"
description: "Auto-commit after specification"
flowchart TD
A["Extension installed"] --> B["Hooks merged into<br/>.specify/extensions.yml"]
B --> C["AI reads command template"]
C --> D["Template says: check hooks.before_specify"]
D --> E["AI reads .specify/extensions.yml"]
E --> F{"Hook found?"}
F -->|No| G["Continue normally"]
F -->|Yes| H{"optional?"}
H -->|false| I["AI executes /speckit.git.feature"]
H -->|true| J["AI presents prompt to user"]
J --> K{"User approves?"}
K -->|Yes| I
K -->|No| G
I --> L["Hook result"] --> G
这里有一个关键的设计决策:钩子由 AI agent 执行,而非 CLI。extensions.yml 是一份声明式配置文件,AI 在运行时读取并解释其内容。命令模板中包含了检查钩子的逻辑——而所谓的"运行时",其实是 LLM 在阅读 Markdown 指令。这意味着钩子的执行可靠性取决于 AI agent 对指令的理解能力。这是一种权衡:以此换来系统的简洁性,同时充分发挥 AI 对自然语言的理解优势。
ExtensionRegistry 与目录栈
已安装的扩展记录在 .specify/extensions/.registry 中,这是一个由 ExtensionRegistry 管理的 JSON 文件:
{
"schema_version": "1.0",
"extensions": {
"git": {
"id": "git",
"version": "1.0.0",
"enabled": true,
"installed_at": "2026-04-12T10:30:00+00:00",
"priority": 10
}
}
}
扩展可以在不卸载的情况下启用或禁用,每个扩展还有一个优先级值,当多个扩展提供同一钩子点时,用于决定模板解析的顺序。
在扩展发现方面,Spec Kit 采用多目录系统。官方目录位于 extensions/catalog.json,列出了所有内置扩展:
{
"schema_version": "1.0",
"extensions": {
"git": {
"name": "Git Branching Workflow",
"bundled": true,
"tags": ["git", "branching", "workflow", "core"]
}
}
}
bundled: true 标志告诉 CLI 从 core_pack/extensions/ 目录加载该扩展,而不是从网络下载。社区目录 extensions/catalog.community.json 以及组织级别的私有目录可以叠加使用,通过基于优先级的合并策略进行解析。
CommandRegistrar 桥接层
当扩展命令需要写入各 agent 对应的目录时,扩展系统本身不处理格式转换,而是委托给 CommandRegistrar。
sequenceDiagram
participant Ext as ExtensionManager
participant Reg as CommandRegistrar
participant Dir as Agent Directories
Ext->>Reg: register_commands_for_all_agents(commands, source_id, ...)
Reg->>Reg: _ensure_configs() — load from INTEGRATION_REGISTRY
loop For each detected agent
Reg->>Reg: Check if agent_dir exists in project
alt Markdown agent
Reg->>Dir: Write speckit.git.feature.md
else TOML agent
Reg->>Dir: Write speckit.git.feature.toml
else Skills agent
Reg->>Dir: Write speckit-git-feature/SKILL.md
end
end
agents.py#L503-L540 中的 register_commands_for_all_agents() 方法会扫描项目中已有的 agent 目录(.claude/skills/、.github/agents/、.gemini/commands/ 等),并以每个 agent 对应的格式写入扩展命令。这意味着在 init 完成后再安装扩展,其命令会自动同步到所有已配置的 agent。
CommandRegistrar 内部的 AGENT_CONFIGS 字典采用懒加载方式,从 INTEGRATION_REGISTRY 填充——这与第 1 篇介绍的单一数据源模式一脉相承。_ensure_configs() 类方法在导入失败时会自动重试,以应对模块加载时的循环导入问题。
针对 Copilot,register_commands() 还会额外调用 write_copilot_prompt(),生成 Copilot 所需的配套 .prompt.md 文件,将格式专属逻辑集中管理。
预设系统:模板覆盖层
预设是第二种扩展机制。extensions 负责添加命令和钩子,而 presets 则负责替换现有模板。PresetManifest 的校验逻辑与 ExtensionManifest 高度相似——相同的 schema 版本、相同的 ID 格式规则、相同的 semver 校验。
内置的 "lean" 预设位于 presets/lean/preset.yml,用精简版本替换了 5 个核心命令:
provides:
templates:
- type: "command"
name: "speckit.specify"
file: "commands/speckit.specify.md"
description: "Lean specify - create spec.md from a feature description"
replaces: "speckit.specify"
replaces 字段指明该模板要覆盖哪个核心命令。模板解析的优先级顺序如下:
本地项目文件(最高优先级)
↓
预设模板
↓
扩展提供的模板
↓
核心模板(最低优先级)
预设与扩展共享相同的注册表模式(.specify/presets/.registry)、相同的目录发现系统,以及相同的 CommandRegistrar 桥接层来处理各 agent 的输出格式。
提示: 预设和扩展可以同时使用。你可以在使用 git 扩展管理分支钩子的同时,应用 lean 预设来简化命令模板。当多个来源提供同一模板时,优先级系统能确保解析结果可预期。
下一步
至此,我们已经介绍了架构、初始化流程、集成系统、命令模板以及扩展机制。还有最后一块拼图:Spec Kit 如何确保这一切真正可靠地运转?第 6 篇将深入测试套件——涵盖 25+ 个 agent 的集成测试、扩展与预设的校验测试、CI 流水线,以及贡献新集成的实用指南。