BMad 安装生命周期管理:setup / doctor / update 三命令的完整运维指南
【免费下载链接】BMAD-METHODBreakthrough Method for Agile Ai Driven Development项目地址: https://gitcode.com/gh_mirrors/bm/BMAD-METHOD
BMad(Breakthrough Method for Agile AI-Driven Development)把「安装、体检、升级」拆成三条互不越界的命令流:bmad setup负责物化_bmad运行时,bmad doctor只修复已存在的运行时,bmad update仅做只读的版本检查。本文以 skills/bmad/references/setup.md 为骨架,结合 skills/bmad/scripts/setup.py 的源码实现,完整讲解三条命令的调用方式、JSON 报告语义、模块配置问题的问答流程,以及底层物化与合并机制,读完即可独立完成 BMad 的安装、修复与版本核对。
命令分发:三条流,互不串线
BMad 的安装运维入口由 hub skill 负责路由。当用户以命令名或自然语言表达「setup、update、doctor」意图时,Agent 必须加载 skills/bmad/references/setup.md 并严格按对应流程执行(见 skills/bmad/SKILL.md 的分发规则)。
三条命令的定位差异是本文全部内容的前提:
bmad update—— 纯检查(inspection only),只报告安装状态,不做任何修改;bmad doctor—— 修复(repairs an existing runtime),只针对已经存在的_bmad运行时;bmad setup—— 安装(performs setup),负责从零物化或整体重建运行时。
三条流绝不互相代跑:update 请求不会触发 setup,doctor 请求也不会被路由到 setup。此外,所有脚本调用都依赖uv:如果环境中缺少uv或无法运行,Agent 必须明确告知用户先安装uv并停止执行,绝不使用其他方式绕行编写_bmad。
bmad update:只读的版本体检
调用命令
update 是纯检查命令,运行时不允许创建任何答案文件或临时文件,直接执行 skill 内的脚本:
uv run --no-cache "{skill-root}/scripts/setup.py" --project-root "{project-root}" --skill "{skill-root}" --update其中{skill-root}是 bmad skill 在宿主环境中的实际路径,{project-root}是目标项目根目录。在源码层面,--update分支会拒绝与--list-config-questions或--module-answers组合使用(见 setup.py),保证检查路径纯粹只读。
JSON 报告与状态语义
脚本以 JSON 形式输出报告,每个 module 一个状态,并列出该 module 的每一份已安装副本(按 skill id 与版本标识)。顶层current字段为true仅当所有 module 都处于current状态。报告中的状态取值必须原样转述,共七种:
| 状态 | 含义 |
|---|---|
current | 已安装版本与源版本一致,无需更新 |
newer-available | 源版本比已安装版本更新,存在可升级版本 |
ahead | 已安装版本领先于源版本 |
differing-unordered | 两版本无法按 SemVer 排序比较(如含-dev或非 SemVer 版本) |
could-not-check | 无法读取源清单(如网络失败),必须附上 source 特定的失败原因 |
version-spread | 同一 module 的多份副本版本不一致 |
source-disagreement | 多份副本各自可检查但状态结论不一致 |
模块级的汇总逻辑可在 setup.py 的 update_report 中看到:先判断是否version-spread(多版本),其次是否could-not-check,再检查状态是否单一,否则归为source-disagreement。单副本的版本判定由version_state完成:可比较且相等为current,低于源为newer-available,高于源为ahead,不可比较为differing-unordered(setup.py)。
报告纪律
- 出现
version-spread时必须逐一列出每一份副本; could-not-check必须包含该次检查失败的原因;- 必须说明本次使用的 bmad 副本及其版本(
bmad_copy字段); - 顶层
current不为true时,严禁宣称安装已是最新。
update 的边界
update 只做两件事:重新扫描已安装的 skills,以及读取每个源的module-manifest.toml。它不会安装、移动、修复或删除任何 skill,不会写项目或写 lockfile,也不会执行npx skills update。如果报告显示有可用更新,正确做法是把「更新已安装 skill 文件夹」这件事交给npx skills update负责——这正是 update 分支在源码中刻意保持只读 的设计意图。
update 的版本比较基于严格的 SemVer 解析:SEMVER正则覆盖 major.minor.patch、预发布与构建元数据,且显式排除含-dev的版本(setup.py);预发布比较遵循「无预发布 > 有预发布、数字段按数值、字母段按字典序」的规则(compare_prerelease)。源清单的读取支持四种update_source前缀——github:、https://、file:、plugin:——其中github:会被展开为 raw 源地址,plugin:直接标记为plugin-managed并提示通过插件市场更新,file:则解析为相对或绝对本地路径(update_copy_report)。
bmad doctor:对既有运行时做精准修复
前置条件与状态机
doctor 要求{project-root}/_bmad已存在。当该目录缺失时,两条 doctor 子命令都会返回顶层status: setup-required,Agent 必须转告用户先运行bmad setup并停止,不得自行创建 staging 目录或任何项目输出(对应源码中的missing_bmad_report,见 setup.py)。若_bmad存在但不是普通目录,同样报错终止;若_bmad是符号链接,脚本会提示用链接指向的真实目录作为--project-root重新执行(reject_symlinked_bmad)。
第一步:列出新声明的配置问题(只读)
uv run --no-cache "{skill-root}/scripts/setup.py" --project-root "{project-root}" --skill "{skill-root}" --doctor --list-config-questions该命令输出一个 JSON 数组,每个元素形如{"module": ..., "key": ..., "prompt": ..., "default": ...}。问答纪律:
- 数组中的每个问题只问一次,且严格按数组顺序,必须展示其
default; - 已有答案的问题不会出现在数组中,不得重问,更不得覆盖;
- 用户接受默认值时,必须原样使用脚本输出的默认值。
第二步:写入临时答案文件
当数组非空时,仅将返回的模块答案写入一个新的临时 TOML 文件,路径记录为{module-answers-path}。写入时必须遵循与 setup 完全一致的引用、转义、避撞规则和[modules."..."]结构(详见下文「已安装模块问题」一节),例如:
[modules."example"] "simple_key" = "selected answer" "nested.key" = "selected answer"第三步:执行修复
# 无新声明的配置问题 uv run --no-cache "{skill-root}/scripts/setup.py" --project-root "{project-root}" --skill "{skill-root}" --doctor # 带新声明的答案 uv run --no-cache "{skill-root}/scripts/setup.py" --project-root "{project-root}" --skill "{skill-root}" --doctor --module-answers "{module-answers-path}"成功结束后,只删除本次 doctor 运行创建的临时答案文件。
doctor 报告字段
doctor 报告顶层status有三种取值:
current—— 无需任何修复;repaired—— 完成了修复;reconciled-with-warnings—— 仍有 module 处于版本分散(spread)或被阻塞(blocked)状态。
报告中还必须包含:共享脚本的修复结果(shared_scripts)、新增的答案(answers_added)、每个 module 的选中或阻塞状态(modules[].state)、module 脚本修复的精确结果(scripts: repaired/current/unchanged)、剩余的版本分散(version_spreads)与过期(remaining_staleness),以及本次使用的 bmad 副本/版本(bmad_copy)。顶层current字段为false当且仅当存在阻塞或版本分散(见 doctor 函数)。
doctor 的修复边界
- 当
legacy_leftovers非空时,必须说明「经典 BMad 安装器遗留的文件仍然存在,且未被触碰」;这些文件定义在源码的LEGACY_LEFTOVERS常量中(setup.py),包括_config/manifest.yaml、_config/bmad-help.csv、core/config.yaml等旧安装器产物; - 本地修复成功不等于项目级 skill 副本已更新:只要
version_spreads或remaining_staleness非空,就不得宣称整个安装为最新,并应告知用户协调被阻塞或分散 module 的已安装副本是npx skills update的职责; - doctor保留既有配置答案、
custom/、用户层以及非脚本的 module 文件;它只把共享脚本树与选中的 module 脚本树修到与源完全一致(byte 级),因此可能删除这些脚本目录下过期的文件; - 遇到畸形配置、非法 manifest 或答案、不可读脚本、来源歧义时,必须指名出错来源并停止,绝不尝试第二条修复路径。
doctor 的 module 选择逻辑(select_doctor_modules)值得单独说明:单副本直接选中;多副本时先剔除不可排序的 dev/非 SemVer 版本——若剩余副本内容完全一致则仍可选中,否则标记blocked;在可排序副本中选取最高 release,若并列最高版本的多个副本 manifest 或脚本负载不一致,同样标记blocked。这保证了 doctor 只会从「可信的最高版本副本」物化脚本,杜绝在冲突状态下盲目修复。
bmad setup:物化与重建_bmad运行时
行为契约
setup 自身不提出任何问题——唯一的问题来源是已安装 module 的 manifest。其契约要点:
- 重复运行幂等且保留团队答案:第二次运行会保留既有团队答案(包括非字符串值),只询问新声明的 module 问题;
- 经典安装器文件永不触碰:经典 BMad 安装器在
_bmad下遗留的文件(LEGACY_LEFTOVERS所列)不会被修改或删除; - 修复
_bmad/scripts:当该路径是符号链接、或是一份与打包 bmad skill 的scripts/并非 byte 完全一致的拷贝时,setup 会将其修复——每个符号链接都被替换为普通拷贝,byte 一致的拷贝原样保留,成功完成的 setup 永远不会创建符号链接(对应 stage_bmad / ensure_scripts 的实现:tree_matches先做整树逐字节比对,不匹配才重建); - 永不触碰
custom/与既有*.user.toml。
setup 的物化流程(源码视角)
setup()(setup.py)的执行链如下:
- 拒绝符号链接形式的
_bmad; - 从 skill 取
scripts/与assets/config.template.toml作为负载(payload()),并校验resolve_config.py等关键文件存在; - 用项目目录名填充模板中的
{directory_name}占位符(fill_team_config),解析出团队配置模板; - 读取既有
_bmad/config.toml,通过fill_keep做「模板为骨架、既有值为优先」的递归合并——既有的键全部保留且覆盖模板默认值,模板新增的键才保留模板值(fill_keep); - 发现已安装 modules,找出尚未回答的配置问题(
find_pending_questions按modules.<module>.<key>路径探测是否已存在); - 校验答案文件与待答问题集合完全一致(不多不少,
validate_module_answers); - 在
_bmad的兄弟 staging 目录(_bmad.setup-*)中物化:先拷贝现有_bmad(保留custom/、额外的*.user.toml与遗留物),再写入scripts/、config.toml、每个 module 的scripts/与custom/,最后通过replace_dir原子替换(materialize_bmad); - 依据配置中的
output_folder确保输出目录存在(默认_bmad-output,见 output_folder)。
replace_dir的三步换位(dest 改名备份 → staging 改名就位 → 删备份)保证了即便中途失败也能回滚,是「setup 永不破坏既有运行时」的底层保障(setup.py)。
已安装模块问题:配置问答与 TOML 答案文件
这是 setup 与 doctor 共用的核心交互协议。
发现待答问题(只读)
uv run --no-cache "{skill-root}/scripts/setup.py" --project-root "{project-root}" --skill "{skill-root}" --list-config-questions输出 JSON 数组,元素含module、key、prompt、default四个字段。规则:
- 数组中的每个问题只问一次、按数组顺序、展示
default; - 数组里没有的问题不问;
- 接受默认值时原样使用脚本输出——脚本已经将
{directory_name}展开为项目目录名,同时保留{project-root}与未知占位符的字面量(见 find_pending_questions 中的 default 替换)。
答案文件的写法
当数组非空时,用 Write 工具(而不是 shell)把选定的答案写入{project-root}/.bmad-help-setup-modules.toml;若该路径已存在,另选一个临时路径以避免覆盖任何既有文件,并把实际路径记录为{module-answers-path}。不要把这些答案放进config.user.toml或其他*.user.toml。
写入要点:
- 只把答案放在其所属 module 之下;
- 每个返回的 key 都作为一个 TOML key 加引号写入,使点分 key 保持无歧义:
[modules."example"] "simple_key" = "selected answer" "nested.key" = "selected answer"- 所有值必须是 TOML 基础字符串(basic strings),反斜杠、双引号、换行、回车、制表符及其他控制字符必须正确转义。源码中的
toml_string/toml_control函数(setup.py)正是这套转义规则的实现:\、"、\b、\t、\n、\f、\r显式映射,其余0x20以下与0x7F的控制符转成\uXXXX; load_module_answers会校验答案文件只含modules表,扁平化后逐值必须是字符串,且同一(module, key)不得重复定义(setup.py);validate_module_answers进一步要求答案与待答问题严格一一对应:多了报is not a pending question,少了提示先运行--list-config-questions(setup.py)。
执行 setup
# 无模块答案 uv run --no-cache "{skill-root}/scripts/setup.py" --project-root "{project-root}" --skill "{skill-root}" # 带模块答案 uv run --no-cache "{skill-root}/scripts/setup.py" --project-root "{project-root}" --skill "{skill-root}" --module-answers "{module-answers-path}"出错即停,不留残余
若发现或安装过程报告:团队 TOML 畸形、manifest 冲突或无效、答案无效、声明的脚本不可读——必须指名出错来源并停止,不尝试其他物化路径。setup 成功后,只删除本次 setup 期间创建的实际临时答案路径(包括写了模块答案时的{module-answers-path})。
底层支撑:manifest 解析与安全问题
setup/doctor/update 三条命令共享同一套 manifest 解析管线(parse_packaged_manifest,见 setup.py),其对输入的安全校验值得关注:
- module 名称:必须匹配
[A-Za-z0-9][A-Za-z0-9_-]*,且不能落入保留目录集{_config, custom, modules, scripts}(大小写不敏感),防止路径穿越与保留名冲突; - update_source:必须是
github:、https://、file:、plugin:前缀之一且前缀后非空;github:要求 owner/repo/path 三段齐全,https://不允许含空白; - config_questions:每个问题必须且只能含
key、prompt、default三个字符串字段;key必须是非空点分 key 且不能以 module 名为前缀,同一清单内互不冲突(含前缀冲突,见conflicting_question_key); - scripts:每个条目必须是相对路径、首段为
scripts、至少两段、不含..、.或反斜杠,且最终解析结果必须落在 skill 根目录之内(read_declared_script用resolve(strict=True)后做relative_to校验,防符号链接逃逸); - 多副本一致性:
discover_installed_modules要求同一 module 的多份 manifest 字节完全一致,否则直接报冲突;module id 仅大小写不同的情况也会被group_installed_copies拒绝。
与配置模板及 manifest 的对应关系
setup 物化的_bmad/config.toml源自 skills/bmad/assets/config.template.toml,其结构展示了「模块配置 + Agent 角色」的双层组织:
[core] project_name = "{directory_name}" output_folder = "{project-root}/_bmad-output" [modules.bmm] planning_artifacts = "{project-root}/_bmad-output/planning-artifacts" implementation_artifacts = "{project-root}/_bmad-output/implementation-artifacts" project_knowledge = "{project-root}/docs" [agents.bmad-agent-analyst] module = "bmm" team = "software-development" name = "Mary" title = "Business Analyst" icon = "📊"{directory_name}由 setup 在写盘前替换为项目目录名;{project-root}作为字面量保留,由后续的resolve_config.py解析。配置的合并层级可参考 skills/bmad/scripts/tests/test_config_utils.py 的验证:_bmad/config.toml→_bmad/custom/config.toml→_bmad/custom/*.user.toml层层覆盖,而_bmad/config.user.toml被明确视为经典安装器遗留物(LEGACY_LEFTOVERS之一),既不被写入也不参与合并——测试断言其中的stray键永远不会出现在最终配置里。
而 bmad skill 自身的 skills/bmad/module-manifest.toml 正是被上述管线解析的典型 manifest:
module = "toolbox" version = "6.13.0-next" update_source = "github:bmad-code-org/BMAD-METHOD/skills" knowledge = "`references/help.md` in the `bmad` skill"其module值为toolbox,版本号为6.13.0-next(含-next后缀,属于不可排序的 dev 形态),update_source采用github:前缀,knowledge指向 skills/bmad/references/help.md 作为该模块的路由文档。
常见故障与处置速查
| 现象 | 处置 |
|---|---|
环境无uv | 停止执行,告知用户安装uv,不得改用其他方式写_bmad |
doctor 报告setup-required | 先运行bmad setup,doctor 不自行补建运行时 |
update 报告newer-available/version-spread | 按报告列出每份副本,交由npx skills update更新已安装 skill 文件夹 |
_bmad是符号链接 | 用--project-root指向链接的真实目标目录执行 setup/doctor |
| 团队 TOML 畸形、manifest 冲突或答案无效 | 指名出错来源并停止,不尝试第二条修复路径 |
doctor 的legacy_leftovers非空 | 说明经典安装器遗留文件存在且未被触碰 |
| 需要临时答案文件 | 写入.bmad-help-setup-modules.toml(冲突则换名),结束后只删自己创建的临时文件 |
三条命令的设计哲学一以贯之:update 只观察、doctor 只修运行时、setup 才物化,且每一步都通过 staging 目录、byte 级比对、严格 manifest 校验和「出错即停」来保证_bmad的可恢复性与安全性。理解这套生命周期管理,是团队稳定运行 BMad 工作流、平滑升级 v6 及后续版本的基础。
【免费下载链接】BMAD-METHODBreakthrough Method for Agile Ai Driven Development项目地址: https://gitcode.com/gh_mirrors/bm/BMAD-METHOD
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考