首页
/ spec-kit 扩展系统实战指南:Extension 的搜索、安装、目录信任模型与 Hooks 机制

spec-kit 扩展系统实战指南:Extension 的搜索、安装、目录信任模型与 Hooks 机制

2026-09-04 14:54:28作者:丁柯新Fawn

本文围绕 spec-kit(Spec Kit 扩展包管理工具)的官方参考文档 docs/reference/extensions.md 展开,系统讲解 specify extension 命令族的完整用法(search / add / remove / list / info / update / enable / disable / set-priority)、扩展目录(Catalog)的分层信任模型、四层配置合并机制以及 .specify/extensions.yml 中扩展注册与 Hook 系统的底层实现。读完本文,你可以独立完成扩展的发现、安装、治理与安全审计,并理解命令优先级、Hook 条件表达式在 src/specify_cli/extensions/init.py 中的实际执行逻辑。

一、扩展是什么:给 Spec Kit 增加领域能力

扩展(Extension)为 Spec Kit 添加新的能力——领域专属命令、外部工具集成、质量门禁等。它们引入超出内置 Spec-Driven Development 工作流的新命令与新模板。从源码结构看,扩展管理由 src/specify_cli/extensions/init.py 中的 ExtensionManagerExtensionManifestExtensionCatalog 等类实现:扩展以 extension.yml 清单描述自身(命令、脚本、模板、Hook、配置默认值),安装后其命令会自动注册到当前已安装的 AI 编码代理集成中。

一个真实的官方扩展例子是 git 扩展 extensions/git/extension.yml:它声明了 5 个命令(speckit.git.featurespeckit.git.validatespeckit.git.remotespeckit.git.initializespeckit.git.commit),要求 speckit_version: ">=0.2.0",并声明了覆盖 before_* / after_* 全部核心命令事件的 Hook(如 before_specify 创建特性分支、before_implement 可选自动提交)。清单还包含 requires.tools(本例中 git 为可选依赖)、tagsconfig.defaults 等字段。

注意: 所有扩展命令都要求项目已经过 specify init 初始化(源码中对应 _require_specify_project 守卫,见 src/specify_cli/extensions/_commands.py)。

二、扩展生命周期:搜索与安装

2.1 搜索可用扩展

specify extension search [query]
选项 说明
--tag 按标签过滤
--author 按作者过滤
--verified 仅显示已验证扩展

不带 query 时列出所有可用扩展。该命令会在所有激活目录(active catalogs)中搜索匹配项。对应实现是 ExtensionCatalog.search(query, tag, author, verified_only),搜索前会经过 _get_merged_extensions() 合并各目录条目并做缓存(缓存有效期为 CACHE_DURATION = 3600 秒,缓存目录位于 .specify/extensions/.cache/)。

2.2 安装扩展

specify extension add <name>
选项 说明
--dev 从本地目录安装(用于开发)
--from <url> 从自定义 URL 安装,而非从目录安装
--force 已安装时覆盖
--priority <N> 解析优先级(默认 10;数值越小优先级越高)

安装来源可以是目录、URL 或本地目录三种之一,命令在 src/specify_cli/extensions/_commands.pyextension_add 处理器中定义。从源码结构看,安装链路还包含若干安全加固:

  • install_from_directory / install_from_archive 会先校验 extension.yml 清单(ExtensionManifest 要求 schema_versionextensionrequiresprovides 必填字段,命令名必须匹配 ^speckit\.([a-z0-9-]+)\.([a-z0-9-]+)$,且不得与内置核心命令冲突——核心命令集合 CORE_COMMAND_NAMES 来自 templates/commands/ 目录发现);
  • --from <url> 下载路径强制 HTTPS(本地回环除外)、限制响应体大小、检测归档格式(ZIP 或 tar.gz/tgz),并做 TOCTOU 安全的临时文件处理(见 src/specify_cli/_download_security.pyinstall_extension_from_url);
  • 安装后调用 _register_commands_for_active_agent 把命令写入当前激活代理的命令目录;卸载/禁用时会 unregister_agent_artifacts 反向清理。

2.3 卸载、更新与启停

卸载:

specify extension remove <name>
选项 说明
--keep-config 移除时保留配置文件
--force 跳过确认提示

配置文件默认会被备份;--keep-config 让配置留在原处,--force 跳过确认。

列出已安装扩展(含状态、版本、命令数量):

specify extension list
选项 说明
--available 显示可用(未安装)扩展
--all 同时显示已安装与可用扩展

查看详情(描述、版本、命令、配置):

specify extension info <name>

更新(不指定名称时更新全部已安装扩展):

specify extension update [<name>]

启停(不删除,仅停用——被禁用的扩展不会被加载,其命令不可用):

specify extension enable <name>
specify extension disable <name>

设置解析优先级(多个扩展提供同名命令时,数值最小的优先):

specify extension set-priority <name> <priority>

三、目录(Catalog)管理:发现与安装的安全边界

3.1 信任模型:discovery-only vs. install sources

目录分两种,二者的区分是安全边界而非功能限制:

  • Install sourcesinstall_allowed: true)——你信任的、可从中安装的目录。内置的 default(官方)目录属于此类,你自己编写并审核过的目录也可以。
  • Discovery-only 目录(install_allowed: false)——只用于发现扩展的搜索面,不可安装。内置的 community 目录就是 discovery-only,开箱即用于 search,无需手动添加。

community 被刻意设计为只发现,因为它是一个开放的、未经审核的列表;若把其中所有条目变成一条命令可安装,就等于在没有任何审查的情况下拉取任意第三方代码。

切勿把 discovery-only 目录改成 install_allowed 那会破坏"发现与安装分离"的全部意义。正确做法有两种:

  1. --from 直接安装单个已审核的扩展(无需自建目录)。通过 specify extension info <name> 获取候选归档 URL(discovery-only 条目会打印 "Candidate archive" URL),审核该发布归档后再安装:
    specify extension info <name>          # 查看候选归档 URL
    specify extension add <name> --from <archive-url>
    
    在你审核之前,应视该 URL 为不可信——它来自未审核目录。
  2. 策展一个自己控制并审核的目录,并把那个目录标记为 install_allowed: true——适用于需要受治理、可复用安装源的场景(例如组织级)。

3.2 目录增删查

列出当前目录栈(含优先级与安装权限):

specify extension catalog list

添加目录(写入项目的 .specify/extension-catalogs.yml):

specify extension catalog add <url>
选项 说明
--name <name> 必填。目录唯一名称
--priority <N> 优先级(默认 10;数值越小优先级越高)
--install-allowed / --no-install-allowed 将目录标记为受信安装源。仅对你拥有并审核的目录启用;发现类目录保持关闭(默认)。绝不对未审核的公开目录启用
--description <text> 可选描述

移除目录:

specify extension catalog remove <name>

从源码结构看,catalog_add 处理器(src/specify_cli/extensions/_commands.py)强制 URL 必须使用 HTTPS(localhost 的 HTTP 除外),URL 校验逻辑在 src/specify_cli/catalogs.pyCatalogStackBase._validate_catalog_url 中实现——它还显式校验端口语法与 hostname 非空,避免畸形 URL 在拉取阶段才以晦涩错误暴露。

3.3 目录解析顺序

目录按以下顺序解析(首个命中者生效),对应 ExtensionCatalog.get_active_catalogs() 的实现:

  1. 环境变量SPECKIT_CATALOG_URL 覆盖所有目录(此时返回单一 custom 条目,install_allowed=True,且使用非默认目录时会向 stderr 打印信任警告);
  2. 项目配置.specify/extension-catalogs.yml
  3. 用户配置~/.specify/extension-catalogs.yml
  4. 内置默认 — 官方 default 目录(允许安装,priority 1)+ community 目录(discovery-only,priority 2)。

拥有并审核的目录在 .specify/extension-catalogs.yml 中的示例:

catalogs:
  - name: "my-org-catalog"
    url: "https://example.com/catalog.json"
    priority: 5
    install_allowed: true
    description: "Our approved extensions"

每个目录条目由 CatalogEntry 数据类描述(字段:urlnamepriorityinstall_alloweddescription),拉取时每个 URL 独立缓存并校验 payload 形状(_validate_catalog_payload 要求 JSON 对象且含 schema_versionextensions 字段,防止被污染缓存导致崩溃)。

四、扩展配置:四层合并模型

大多数扩展在安装目录中携带配置文件:

.specify/extensions/<ext>/
├── <ext>-config.yml           # 项目配置(纳入版本控制)
├── <ext>-config.local.yml     # 本地覆盖(被 gitignore)
└── <ext>-config.template.yml  # 模板参考

配置按以下顺序合并(优先级从低到高,后者覆盖前者):

  1. 扩展默认值(来自 extension.ymlconfig.defaults
  2. 项目配置<ext>-config.yml
  3. 本地覆盖<ext>-config.local.yml
  4. 环境变量SPECKIT_<EXT>_*

为新安装的扩展初始化配置,复制模板即可:

cp .specify/extensions/<ext>/<ext>-config.template.yml \
   .specify/extensions/<ext>/<ext>-config.yml

这一模型由 ConfigManager 类实现(src/specify_cli/extensions/init.pyConfigManager,含 _get_extension_defaults_get_project_config_get_local_config_get_env_config 逐层 _merge_configs)。以 git 扩展为例,其 extensions/git/config-template.yml 展示了典型的可用配置项:

  • branch_numberingsequential(001、002…)或 timestamp(YYYYMMDD-HHMMSS);
  • branch_template:分支名模板,支持 {author}app{number}{slug} 令牌,要求 {slug} 不得出现在 {number} 之前;
  • branch_prefix:简写命名空间,如 features/{app}
  • init_commit_message:仓库初始化时的提交信息(默认 [Spec Kit] Initial commit);
  • commit_stylefixed(使用固定提交信息)或 conventional(让代理检查 diff 生成 Conventional Commit 消息);
  • auto_commitdefault 全局开关 + 按命令(before_clarifybefore_planbefore_implementafter_specify 等)的 enabled 与自定义 message

扩展默认值同样声明在清单里,git 扩展的 extensions/git/extension.ymlconfig.defaultsbranch_numbering: sequentialbranch_template: ""branch_prefix: ""init_commit_message: "[Spec Kit] Initial commit"

五、项目级扩展注册与 Hooks:.specify/extensions.yml

Spec Kit 把项目级扩展注册与 Hook 配置保存在 .specify/extensions.yml 中,包含已安装扩展列表、全局设置与在 Spec Kit 命令前后触发的 Hook:

installed:
  - git
  - my-extension

settings:
  auto_execute_hooks: true

hooks:
  before_implement:
    - extension: git
      command: speckit.git.commit
      enabled: true
      optional: true
      priority: 10
      prompt: "Commit outstanding changes before implementation?"
      description: "Auto-commit before implementation"

  after_implement:
    - extension: my-extension
      command: speckit.my-extension.verify
      enabled: true
      optional: false
      priority: 5
      description: "Run verification after implementation"

5.1 配置字段说明

顶层 installed 列表记录项目内已安装的扩展;settings 映射保存项目级扩展设置;hooks 按事件分组 Hook 注册。auto_execute_hooks 默认 true,但当前保留未用——Hook 呈现与调用时并不读取它。

每个 Hook 条目支持的字段:

字段 说明
extension 注册该 Hook 的扩展 ID
command 与 Hook 关联的扩展命令
enabled Hook 是否激活;enabled: false 的 Hook 被跳过
optional 是否可选。true 时 Hook 连同 prompt 一起呈现、可跳过;false 时作为自动 Hook 发出(含 EXECUTE_COMMAND 标记)
priority Hook 优先级元数据。注册条目使用 >= 1 的整数;从 manifest 安装的条目未声明时默认 10。当前命令模板按 YAML 配置顺序呈现 Hook,不按 priority 排序
prompt 询问是否运行可选 Hook 时显示的消息
description 人类可读的 Hook 作用说明
condition 可选表达式,由 HookExecutor 求值(使用 config.<path>env.<VAR>,配合 is set==!=)。当前命令模板不求值 condition,带有非空 condition 的 Hook 会被跳过

Hook 事件名标识触发时机,通常形如 before_<command> / after_<command>,例如 before_implementafter_implementbefore_tasksafter_tasks。git 扩展的清单即为范例:before_constitution 自动初始化仓库、before_specify 创建特性分支(两者 optional: false),其余 before_* / after_* 事件挂载可选的 speckit.git.commit 自动提交 Hook。

5.2 源码印证:优先级归一化与条件求值

优先级处理由 src/specify_cli/extensions/init.pynormalize_priority() 实现:布尔值、int() 无法转换的非数字值、小于 1 的值都回落到默认值 DEFAULT_HOOK_PRIORITY = 10;数字字符串与有限浮点数经 int() 强制转换,非有限浮点数则可能直接报错而非回落。扩展清单在安装时即拒绝非法 Hook 优先级。

HookExecutor.get_hooks_for_event() 返回按 priority 升序排列(数值小者在前、稳定排序保持插入顺序)的启用 Hook 列表;但正如文档所述,当前命令模板直接读取 Hook 列表并按其配置的 YAML 顺序呈现,并不使用优先级排序——理解这一差异有助于解释为什么手动调整 YAML 顺序比改 priority 更直接影响呈现顺序。

条件求值 _evaluate_condition() 支持的正则模式与文档描述一致:config.<key.path> is setconfig.<key.path> == 'value' / != 'value'(布尔值会归一化为小写 true/false 再比较)、env.<VAR_NAME> is setenv.<VAR_NAME> == 'value' / != 'value';求值失败时默认不执行(should_execute_hook 捕获异常返回 False)。

此外,扩展 add / remove / enable / disable 之后会调用 refresh_integration_events 刷新原生事件配置;若刷新失败,CLI 会打印警告并提示重跑 specify integration upgrade <key>(见 _refresh_events_and_warn),以避免"被禁用扩展的 Hook 仍然残留生效"。

六、常见问题(FAQ)

为什么 search 找不到某个扩展? 检查扩展名拼写。扩展可能尚未发布,或位于你未添加的目录中。用 specify extension catalog list 查看当前激活的目录。

为什么扩展命令没有出现在我的 AI 编码代理中?specify extension list 确认扩展已安装且启用。如果显示已安装,重启你的 AI 编码代理——它可能需要重新加载才能生效。

如何设置扩展配置? 复制扩展自带的配置模板:

cp .specify/extensions/<ext>/<ext>-config.template.yml \
   .specify/extensions/<ext>/<ext>-config.yml

各配置层与覆盖规则见上文"扩展配置:四层合并模型"。

如何解决版本不兼容错误? 把 Spec Kit 更新到扩展所要求的版本(由清单 requires.speckit_version 约束,如 git 扩展要求 >=0.2.0)。

扩展由谁维护? 大多数扩展由各自作者独立创建与维护。Spec Kit 维护者不审查、不审计、不背书、不支持扩展代码。安装前请审查扩展源码,使用风险自负;针对特定扩展的问题请联系其作者或在其仓库中提交 issue。

七、小结

spec-kit 的扩展体系由三块组成:命令层(specify extension search/add/remove/list/info/update/enable/disable/set-priority)、目录信任层(install_allowed 区分安装源与发现面,四级解析顺序,HTTPS 强制)与项目注册层(.specify/extensions.ymlinstalled / settings / hooks + 四层配置合并 + 条件化 Hook)。实践中的关键纪律是:保持 community 目录只读发现、用 --from 安装单个已审核扩展或自建受信目录,并在安装任何第三方扩展前审查其 extension.yml 与命令模板——这也是官方文档在 FAQ 中明确给出的使用建议。

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

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
904
1.82 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
889
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.52 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
982
502
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384