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

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

2026-09-05 15:25:38作者:董斯意

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/ 包中,按职责分层:

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 源码)

BundleManifestfrom_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,防止路径穿越
组件版本 pin extensions、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.pysearch() 看,匹配是对 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.pycomponents_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]
选项 说明
--path bundle 目录或 bundle.yml(默认当前目录)
--offline 只对照 bundled/已安装组件校验引用

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

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

specify bundle build [--path <bundle目录>] [--output <输出目录>]
选项 说明
--path bundle 目录(默认当前目录)
--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>]
选项 说明
--policy install-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.pyInstalledBundleRecord(bundle_id、version、contributed_components、installed_at)写入 .specify/bundle-records.json,schema 版本 1.0。文件读取路径带防符号链接/路径穿越的收敛检查;schema 主版本不匹配时快速失败而不是错误解析——这是 remove/update 能"精确只碰本 bundle 组件"的数据基础。

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

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

执行与回滚installer.pyinstall_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.pyrecords.py

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

项目优选

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