Spec Kit Bundles 完全指南:bundle.yml 清单、specify bundle 命令体系与 Bundler 源码实现
2026/9/6 19:06:56 网站建设 项目流程

Spec Kit Bundles 完全指南:bundle.yml 清单、specify bundle 命令体系与 Bundler 源码实现

【免费下载链接】spec-kit💫 Toolkit to help you get started with Spec-Driven Development项目地址: https://gitcode.com/GitHub_Trending/sp/spec-kit

Bundle 是 Spec Kit 把已有组件(extensions、presets、workflows、steps)组合成一个版本化、可安装单元的分发层。读完本文,你将掌握specify bundle全部子命令(search / info / install / update / remove / list / init / validate / build / catalog)的参数与行为边界,理解bundle.yml清单的完整结构与校验规则,并能从源码层面弄清安装幂等性、集成(integration)冲突检测、来源记录(provenance)与目录栈(catalog stack)的底层实现。

1. Bundle 是什么:组合层而非运行时层

用 Bundles 参考文档 的表述:extensions 和 presets 是"原语"(primitives),而 bundle 是一层分发与组合(distribution and composition)机制——它声明一个团队或角色所需的全部组件,并通过每个组件自身的安装机制一次性装好。Bundle 本身不引入任何新的运行时行为。

一条 bundle 的完整生命周期可以概括为四个动作:

  1. 描述:由bundle.yml清单声明元数据、版本依赖与组件引用;
  2. 发现:与其他组件共用同一套目录栈(catalog stack)被发现;
  3. 解析:安装时把声明的组件按固定版本(pinned version)解析成具体的安装计划;
  4. 执行:检查唯一的跨 bundle 冲突点(活动集成),幂等地应用每个组件,并写入完整的来源记录,以便日后干净地移除或刷新。

从源码结构看,这套机制全部落在src/specify_cli/bundler/包中,按职责分层:

  • 模型层 models/:manifest.py(清单解析与结构校验)、records.py(已安装 bundle 的来源记录)、catalog.py(目录栈);
  • 服务层 services/:resolver.py(清单 → 安装计划)、installer.py(执行安装/卸载)、conflict.py(冲突检测)、catalog_stack.py(跨源解析与搜索)、packager.py(构建产物)、validator.py 与 references.py(校验);
  • CLI 层 commands/bundle/init.py:只负责参数解析与 Rich 输出渲染,业务逻辑全部委托给服务层(源码注释称之为 Principle I:"thin commands over services")。

2. bundle.yml 清单:结构与校验规则

2.1 一个真实的清单示例

仓库自带示例 examples/bundles/business-analyst/bundle.yml,完整展示了清单的全部顶层字段:

schema_version: "1.0" bundle: id: "business-analyst" name: "Business Analyst" version: "1.0.0" role: "business-analyst" description: "Spec-Driven Development setup for business analysts: requirements elicitation, traceability, and acceptance criteria." author: "spec-kit-examples" license: "MIT" requires: speckit_version: ">=0.9.0" tools: [] mcp: [] provides: extensions: - id: "agent-context" version: "1.0.0" presets: - id: "requirements-elicitation" version: "1.0.0" priority: 10 strategy: "append" steps: - id: "capture-requirements" - id: "trace-acceptance-criteria" workflows: - id: "requirements-to-spec" version: "1.0.0" tags: ["requirements", "traceability", "analysis"]

examples/bundles/下还有 developer、product-manager、security-researcher 三个同构示例,可对照阅读。

2.2 字段校验规则(来自 manifest.py 源码)

BundleManifest 在from_dict之后通过structural_errors()做结构校验,规则如下:

规则说明
schema_version必须在支持集合内,当前为{"1.0"}SUPPORTED_SCHEMA_VERSIONS
必填字段bundle.idbundle.namebundle.versionbundle.rolebundle.descriptionbundle.authorbundle.licenserequires.speckit_version
bundle.version必须是合法 semver
bundle.id必须是文件系统安全 slug:^a-z0-9?$(小写字母、数字、._-,禁止路径分隔符)。这是因为 id 会被直接拼进产物文件名<id>-<version>.zip,防止路径穿越
组件版本 pinextensions、presets、workflows 条目必须固定version;steps 可以不定版本
版本号一经声明必须是合法 semver
presets 额外要求必须声明整数prioritystrategy必须是replaceprependappendwrap之一

另外两个容易踩坑的解析细节(源码注释中明确记录):

  • YAML null 不会变成字符串 "None"author:后面留空在 YAML 中是 null,解析器通过_text()把它映射为空字符串,再由必填检查拒绝,而不是放行一个"None"的作者;
  • integration写成裸字符串会被拒绝:如果integration存在但不是 mapping(例如直接写integration: copilot),解析直接报错,而不是静默丢弃、把 bundle 错误地变成"集成无关"。

2.3 组件引用与集成声明

每个组件条目被解析为ComponentRefkind/id/version/source/priority/strategy)。可选的integration字段(mapping 形式,含id)声明该 bundle 目标集成;若清单不声明integration,则 bundle 是"集成无关"的(is_agnostic()为 True),安装时继承项目当前活动集成。

requires.toolsrequires.mcp是软依赖:解析安装计划时它们只产生警告("Requires external tools: ..."),不会阻断安装;而requires.speckit_version是硬门控——见下文 resolver。

3. 消费侧命令:search / info / install / update / remove / list / init

3.1 search:在目录栈中检索

specify bundle search [query]
选项说明
--offline不访问网络
--json输出机器可读 JSON

在所有活动目录中搜索匹配查询的 bundle。不带查询时列出全部可用 bundle,附版本、角色、来源和信任指标(org 维护目录中的条目为verified,其余为community),让你在安装前判断信任级别。

从 catalog_stack.py 的search()看,匹配是对 id、name、role、description、tags 做小写子串检索;更关键的是每个 bundle id 只会出现一次,且解析到最高优先级的来源——先按优先级占用 id,再过滤查询,避免低优先级的同 id 影子条目把"你装不到的那个版本"广告出来。--json输出中每条记录还包含install_policyinstall-allowed/discovery-only)与trust字段。

3.2 info:安装前的完整预览

specify bundle info <bundle_id>
选项说明
--offline不访问网络
--json输出机器可读 JSON

显示 bundle 的完整元数据以及它完全展开的组件集合——每个 extension、preset、step、workflow 及其固定版本,外加 preset 的 priority 与 strategy,并附信任指标。这个预览与install实际应用的计划是同一份:你可以精确看到将被添加什么。与已安装 bundle 的可预见重叠也会在这里被提示。

源码中这条命令刻意做到"要么完整、要么报错":bundle_info 会真正下载并解析远端清单,而不是退化成目录里的provides计数——否则用户可能把一个无法验证的 bundle 误认为已知可安装。清单下载失败会以非零码退出,而不是静默降级。

3.3 install:一条命令装完整个组件栈

specify bundle install <bundle_id | path>
选项说明
--integration覆盖初始化/安装时使用的集成
--offline不访问网络

参数既可以是目录中的 bundle id,也可以是本地路径:构建好的.zip产物、bundle 目录、或bundle.yml文件本身。本地源不经过目录栈,直接安装(_local_manifest_source()在目录解析之前处理这三类本地形态)。

安装语义的几个关键点(均与文档一致,并可在 installer.py 中逐条印证):

  • 自动初始化:当前目录还不是 Spec Kit 项目时,install会先初始化项目,让全新 checkout 一条命令进入可用状态。此时--integration用于选择集成(优先级:显式覆盖 → bundle 声明 → 默认值)。注意源码里有一道顺序保障:所有硬兼容门控(Spec Kit 版本、集成冲突)都在specify init之前解析,避免一个不兼容的 bundle 先初始化出项目状态、随后才在版本检查上失败而留下半截状态。
  • 不覆盖已初始化的项目--integration不能绕过已初始化项目的活动集成。若 bundle 目标集成与项目不一致,安装直接中止且不做任何改动;若项目活动集成无法确定(缺失或不可读的.specify/integration.json)而 bundle 又 pin 了集成,则用--integration确认目标。集成无关的 bundle 继承项目活动集成。
  • 幂等:已存在的组件被跳过。这里的"已存在"判断是按 id 而非版本的(见 3.4 的 pin 语义)。
  • 失败不留记录:安装失败时不写任何来源记录;本次运行中已装上的组件会被尽力回滚——回滚错误被吞掉,因此磁盘上可能残留部分状态。源码中回滚是"有界"的:只回滚本次调用新装的组件,事先就存在的组件永不被回滚;组件归属采用引用计数式逻辑,独立安装(未被任何 bundle 记录追踪)的组件绝不会被记到 bundle 名下,防止日后remove时误删(源码注释引用的 FR-022)。

3.4 update:重新解析并刷新组件

specify bundle update [<bundle_id>]
选项说明
--all更新所有已安装 bundle
--integration覆盖刷新组件时使用的集成;仅在项目活动集成无法确定时生效
--offline不访问网络

重新解析 bundle,并通过每个原语自己的 update 路径刷新组件:把已装组件提升到 bundle 新 pin 的版本,同时保留原语级覆盖(例如 preset priority)。update走的是install_bundle(..., refresh=True)路径:已安装组件不再被跳过而是重新应用;旧版本拥有、新清单不再提供的组件会被卸载(前提是其他已安装 bundle 不再需要它们);首次安装时间(installed_at)在跨刷新时保留。

Pin 只在安装时强制。幂等检查是按 id 的、版本无感的:已存在的组件在install期间被跳过,不会拿磁盘上的版本与清单 pin 比较。因此版本 pin 只有在 bundler 真正首次安装或刷新某个组件时才保证被应用。用specify bundle update可以把每个自有组件重新按其 pin 版本应用一遍。

3.5 remove / list / init

specify bundle remove <bundle_id> specify bundle list [--json] specify bundle init [<bundle_id>] [--integration ...] [--offline]
  • remove:只卸载该 bundle 贡献的组件;其他已安装 bundle 仍需要的组件会原样保留,不做连带删除。实现上由 records.py 的components_still_needed()算出"其他 bundle 仍需要的 (kind, id) 集合",再逐组件判定卸载或跳过;移除中途失败时,bundle 记录保持不动,错误信息会明确说明可能已部分卸载。
  • list:列出项目中已安装 bundle 的版本、组件数与安装时间。
  • init:先确保当前目录是 Spec Kit 项目(必要时幂等初始化),再可选地安装给定 bundle,适合作为新 checkout 的显式一步式引导。

4. 创建侧命令:validate / build / publish

4.1 validate:清单是否良构、引用能否解析

specify bundle validate [--path <bundle目录|bundle.yml>] [--offline]
选项说明
--pathbundle 目录或bundle.yml(默认当前目录)
--offline只对照 bundled/已安装组件校验引用

报告bundle.yml是否良构、以及每个声明的组件引用能否解析。引用依次对照 bundled 组件、项目已安装组件、以及(在线时)活动目录来检查。只有当引用在所有可查位置都确定不存在时校验才失败——即有活动目录可达且确认该组件缺失。无法验证的引用(离线校验、或目录不可达)被降级为警告,让作者可以继续编写,而不是直接跑挂。

4.2 build:产出单一版本化分发产物

specify bundle build [--path <bundle目录>] [--output <输出目录>]
选项说明
--pathbundle 目录(默认当前目录)
--output产物输出目录

从 bundle 目录生成一个版本化、可分发的.zip产物,命名<id>-<version>.zip,内嵌清单,可直接specify bundle install <artifact.zip>安装。packager.py 中的构建约束值得作者注意:

  • 缺少bundle.ymlREADME.md直接拒绝——每个 bundle 必须随附描述文档;
  • 清单结构无效时拒绝构建并指向validate
  • 所有文件读取被限制在 bundle 源目录内(路径收敛),排除.git__pycache__.DS_Store
  • 产物使用固定的 zip 时间戳(zip epoch),保证字节级可复现。

4.3 publish:托管产物与目录条目

Bundle 作者先在本地校验、打包,再把生成的产物和目录元数据托管到用户可访问的位置。目录条目指向 bundle 产物,但bundle.yml内部声明的组件仍会经过 bundled 组件、已安装组件,或活动的 extension / preset / workflow / step 目录来解析。

如果你的 bundle 引用了非默认目录中的组件,请在文档中写明这些目录 URL,并在一个添加了对应目录的干净项目上实测安装路径。提交社区 bundle 时,应把这份依赖解析证据附在 GitHub 仓库的 Bundle Submission issue 模板中。社区 bundle 的完整提交清单(公开仓库 + 合法bundle.yml、带specify bundle build产物的版本化 release、说明文档、目录条目建议、干净项目测试证据)与维护者的审核范围,见 Community Bundles 文档——维护者只核验提交元数据完整、格式正确、链接可达,不审计也不背书bundle 及其安装组件的行为,安装前请自行审查清单与组件来源。

5. 目录源管理:优先级、策略与信任

bundle 通过优先级有序的目录源栈(project、user、built-in 三级作用域)被发现。

# 查看活动目录栈(含各来源的作用域与安装策略) specify bundle catalog list # 添加一个项目作用域的目录源 specify bundle catalog add <url> [--policy install-allowed|discovery-only] [--priority <n>] [--id <id>]
选项说明
--policyinstall-alloweddiscovery-only
--priority来源优先级(越小越优先;默认 10)
--id显式指定来源 id
# 移除项目作用域的目录源 specify bundle catalog remove <id_or_url>

持久化在.specify/bundle-catalogs.yml中(见 catalog_config.py),磁盘形状为{schema_version, catalogs: [{id, url, priority, install_policy}]}。几个实现层面的约束:

  • 内置默认源不可删除;要用同 id 来源去覆盖它。
  • HTTPS-only:http(s) 目录 URL 只允许 https(localhost 可用 http),无主机的 URL 在写入时即被拒绝;本地路径会被规范化为绝对路径再存储,因此remove可以按当时添加的相对路径反查。
  • discovery-only 的来源只能 search/info,不能 installinstallupdate解析到 discovery-only 来源会直接报错。内置 community 源就是 discovery-only,按 id 安装需要先显式添加一个 install-allowed 目录(显式目录的默认优先级高于内置 community 源)。
  • 信任指标:org 维护目录条目显示verified,其余显示community_trust_level())。

注意命令的作用域差异:searchinfo在任何位置都可用——没有项目时回退到 built-in/user 目录栈。而改变状态的命令(listupdateremovecatalog)要求已用specify init初始化过的项目;installinit在目录未初始化时会按需自动初始化。

5.1 远端下载的安全约束

info/install走目录解析时,清单从条目的download_url下载。CLI 层 对此有一整套硬约束:file://、裸文件系统路径、无 scheme 的值一律拒绝(从磁盘安装请直接传路径参数);非 HTTPS 下载直接拒绝(重定向目标也要逐个校验);下载有字节上限(MAX_DOWNLOAD_BYTES);目录条目若带sha256则下载后逐字节校验。对 GitHub release 下载链接,会先解析为 REST API 资产 URL 以兼容私有/SSO 仓库。这些约束在--offline下依然先行检查,避免离线模式报出误导性的"网络已禁用"。

6. 底层机制速览:来源记录、解析门控与冲突检测

来源记录(provenance):每次成功安装后,records.py 把InstalledBundleRecord(bundle_id、version、contributed_components、installed_at)写入.specify/bundle-records.json,schema 版本1.0。文件读取路径带防符号链接/路径穿越的收敛检查;schema 主版本不匹配时快速失败而不是错误解析——这是 remove/update 能"精确只碰本 bundle 组件"的数据基础。

解析门控:resolver.py 的resolve_install_plan()把清单展开为InstallPlan,并执行两道硬门控:Spec Kit 版本门控(satisfies()检查requires.speckit_version,不满足即拒绝安装)与集成兼容性检查。info的预览与install的执行共享这同一个计划来源,保证"你看到的正是将装上的"。

冲突检测:conflict.py 确认文档的说法——唯一的跨 bundle 硬冲突点是活动集成:bundle pin 的集成与项目活动集成不一致即中止。组件级重叠(例如另一个 bundle 也提供了同名 preset)只是信息性提示,实际由原语机制自己的优先级规则裁决。install前打印的黄色!提示即来自这里。

执行与回滚:installer.py 的install_bundle()对计划逐组件执行is_installed → install/skip,全部成功后才 upsert 记录;任何异常触发_rollback(),逆序移除本次新装组件(尽力而为、吞掉移除错误),与文档"On failure, no provenance record is written"完全对应。

7. 实战走查:从示例 bundle 到安装

以仓库内置的 business-analyst 示例走一遍完整链路:

# 1. 检索并预览(任何位置可用) specify bundle search business specify bundle info business-analyst # 2. 在干净目录一条命令初始化 + 安装(目录未初始化时自动 init) specify bundle install business-analyst # 或从本地源安装(目录 / bundle.yml / .zip 均可,不查目录栈) specify bundle install ./examples/bundles/business-analyst specify bundle install ./business-analyst-1.0.0.zip # 3. 查看已安装与来源记录 specify bundle list # 4. 需要升级时,把组件刷新到清单新 pin 的版本 specify bundle update business-analyst # 5. 卸载(其他 bundle 仍需要的组件会保留) specify bundle remove business-analyst

作者侧则是对称的:

# 1. 校验清单良构与引用可达 specify bundle validate --path ./my-bundle # 2. 产出 <id>-<version>.zip specify bundle build --path ./my-bundle --output ./dist # 3. 托管 dist 下的产物 + 目录条目;非默认目录依赖需随提交附解析证据 # 4. 在干净项目上按 5.1 节的 HTTPS/策略约束实测安装

8. 小结

维度结论
定位分发与组合层,零新增运行时行为,复用各原语自身安装机制
清单bundle.yml,schema 1.0;id 为安全 slug;extensions/presets/workflows 必须 pin semver;presets 必须声明 priority + strategy
安装幂等(按 id);失败不留记录 + 有界回滚;集成冲突是唯一直止点
更新update才保证按 pin 版本重新应用所有自有组件
移除引用计数,无连带删除
发现project > user > built-in 优先级目录栈;install-allowed / discovery-only 策略;verified / community 信任指标
分发build 出可复现<id>-<version>.zip;HTTPS-only + sha256 校验;本地路径安装不走目录栈

本文所有行为描述均以当前仓库src/specify_cli/bundler/与 docs/reference/bundles.md 为准;清单字段级细节可对照 manifest.py,安装/回滚/引用计数逻辑可对照 installer.py 与 records.py。

【免费下载链接】spec-kit💫 Toolkit to help you get started with Spec-Driven Development项目地址: https://gitcode.com/GitHub_Trending/sp/spec-kit

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询