mcpField
G
github-sync

github-sync

github.com/bmad-labs开发1989 次安装6 天前更新
代码仓库

关于 github-sync

github-sync 是一项双向同步 BMAD 规划文件与 GitHub Projects v2 的技能。它按字段区分数据归属,并要求先展示变更报告、获得批准后再执行修改。

主要功能

  1. 01双向同步 BMAD 与 GitHub Projects
  2. 02初始化项目字段和配置
  3. 03将故事推送为 GitHub 问题
  4. 04拉取状态、负责人和任务完成情况
  5. 05变更需审批且同步具幂等性

适用场景

  1. 01为 BMAD 文件配置 GitHub Project
  2. 02根据规划故事创建 GitHub 问题
  3. 03用 GitHub 进展更新本地故事
  4. 04同步前审阅计划变更

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/bmad-labs/skills --skill github-sync

安装后在 Claude Code 中输入/github-sync确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
evals.json
references/
config-schema.md
content-mapping.md
gh-commands.md
scripts/
parse-artifacts.py

详细介绍

GitHub Sync — BMAD 到 GitHub Projects v2

在以 Markdown 文件存储的 BMAD 规划产物(史诗、用户故事、冲刺计划)与 GitHub Projects v2 之间双向同步,以便直观地跟踪项目。

快速导航

  • gh CLI 命令、GraphQL 查询 → references/gh-commands.md
  • Issue 正文模板、字段映射、标签、里程碑 → references/content-mapping.md
  • 配置文件格式 → references/config-schema.md
  • 产物解析脚本 → scripts/parse-artifacts.py

四条规则(绝不可违反)

  1. 绝不自动同步。 每项会修改数据的操作(创建 Issue、更新字段、修改文件)都必须先生成同步报告,展示给用户,并等待用户明确批准后才能执行。用户必须清楚看到将发生的所有变更。

  2. 字段级别的唯一事实来源。 每个字段只有一个归属方——BMAD 文件或 GitHub。同步时始终以归属方的数据为准。绝不覆盖归属方的数据。

    • 归 BMAD 所有: 用户故事正文、验收标准、任务、冲刺分配、史诗分组、依赖关系
    • 归 GitHub 所有: 状态、开发人员分配、任务复选框完成状态、故事点、优先级
  3. 幂等操作。 同一同步操作运行两次应产生相同结果。回链标识符(用户故事文件中的 H1 标题链接、规划 frontmatter 中的 gh_item_url)可防止重复创建。创建之前始终检查是否已有同步状态。

  4. 绝不使用脚本自动解析 Issue 正文。 生成 Issue 正文时,必须使用 Read 工具直接读取每个用户故事文件,并按照 references/content-mapping.md 中的模板手动撰写正文。自动解析脚本可能以难以察觉的方式静默失败:格式假设错误时会删掉任务列表,移除代码块时会大幅删减开发说明,还会生成空的章节标题。一次错误的推送就可能同时污染全部 27 个 Issue。读取文件。编写正文。不走捷径。


流程识别

用户说工作流是否需要配置?
“set up github project”、“onboard”、“initialize github”入门设置否(会创建配置)
“push to github”、“sync push”、“create issues”推送是
“pull from github”、“sync pull”、“update from github”拉取是
“sync status”、“what's out of sync”状态检查是

如果项目根目录中不存在 .github-sync.yaml,始终先进入入门设置。


前置条件检查(每个工作流运行前执行)

运行任何工作流前,按顺序验证以下内容。遇到第一个失败项时停止。

Step 1: gh --version
        → If missing: "Install GitHub CLI: https://cli.github.com/"

Step 2: gh auth status
        → If not authenticated: "Run: gh auth login"

Step 3: gh auth status (check for "project" in scopes)
        → If missing: "Run: gh auth refresh -s project"

Step 4: (For push/pull/status only) Check .github-sync.yaml exists
        → If missing: "Run onboarding first: say 'set up github project'"

入门设置工作流

这是首次设置流程。它会创建或连接到一个 GitHub Project,并创建自定义字段、标签和按阶段划分的里程碑。

步骤 1:检测 BMAD 产物

运行解析器以发现现有内容:

python3 .agents/skills/github-sync/scripts/parse-artifacts.py --mode scan \
  --stories-dir .artifacts/implementation-artifacts

同时检查以下文件是否存在:

  • .artifacts/planning-artifacts/epics.md
  • .artifacts/planning-artifacts/sprint-plan.md

注意: 产物路径 .artifacts/ 可能因项目而异。请检查实际目录结构——有些项目使用 _bmad-output/。与用户确认正确路径,并在整个流程中使用这些路径。相应更新配置中的 paths.*。

报告数量:“找到 N 个用户故事文件、M 个史诗、K 个冲刺。”

步骤 2:收集 GitHub 详情

自动检测当前仓库:

gh repo view --json owner,name --jq '.owner.login + "/" + .name'

列出现有项目,并询问用户是使用其中一个还是创建新项目:

gh project list --owner {owner} --format json

展示检测到的所有者/仓库和现有项目。继续之前请征求用户确认。

步骤 3:解析史诗和冲刺数据

现在阅读 references/content-mapping.md——第 7 节(标签方案)、第 8 节(里程碑方案)和第 12 节(史诗推导)。你需要这些内容来生成准确的入门设置报告。

然后解析实际产物:

python3 .agents/skills/github-sync/scripts/parse-artifacts.py --mode epics \
  --file .artifacts/planning-artifacts/epics.md

python3 .agents/skills/github-sync/scripts/parse-artifacts.py --mode sprints \
  --file .artifacts/planning-artifacts/sprint-plan.md
步骤 4:生成入门设置报告

展示报告,列出所有将要创建的内容:

=== GITHUB SYNC — ONBOARDING REPORT ===

Repository: {owner}/{repo}
Project: #{N} "{title}" (existing) OR new project "{title}"

Will create/verify:
  Custom fields (7):
    - Story ID      (TEXT)
    - Epic          (SINGLE_SELECT: 12 options, rainbow colors)
    - Sprint        (SINGLE_SELECT: Sprint 01–12, rainbow colors + sprint goal descriptions)
    - Dev           (SINGLE_SELECT: All, Dev 1, Dev 2, Dev 3, Dev 1+2)
    - Sprint Start  (DATE)
    - Sprint End    (DATE)
    - Story Points  (NUMBER)
  Built-in fields to set:
    - Start date    (DATE, pre-existing)   ← same dates as Sprint Start
    - Target date   (DATE, pre-existing)   ← same dates as Sprint End
    - Status        (single-select, pre-existing)
  {N} labels:
    - Epic labels (one per epic, e.g., epic:1-foundation ... epic:12-testing)
    - Phase labels (e.g., phase:poc, phase:hardening)
    - Layer labels (optional, project-specific architecture layers)
  {K} milestones (phase-based, NOT per-sprint):
    - PoC              (due: {sprint_6_end})    Sprints 1–6
    - Production Hardening (due: {sprint_12_end}) Sprints 7–12

Note: No "Phase" custom field — the milestone covers phase membership.

Proceed with onboarding? [Y/N]

在此处停止。等待用户批准。

步骤 5:执行设置

现在阅读 references/gh-commands.md——你需要用到下面每项操作的确切命令。

如果获得批准,请按以下顺序执行:

  1. 创建或连接 GitHub Project(第 2 节)——如果使用现有项目,只需获取其节点 ID
  2. 创建自定义字段(第 3 节)——Story ID、Epic、Sprint、Dev、Sprint Start、Sprint End、Story Points
  3. 查询所有字段 ID(第 4 节)——包括预先存在的 Start date、Target date、Status 字段
  4. 为 Sprint 和 Epic 字段设置彩虹颜色及 Sprint 目标描述(第 13 节)
    • Sprint 选项:循环使用 RED→ORANGE→YELLOW→GREEN→BLUE→PURPLE→PINK
    • Sprint 描述 = sprint-plan.md 中的 Sprint 目标
    • Epic 选项:RED→ORANGE→YELLOW→GREEN→BLUE→PURPLE→PINK→RED→ORANGE→YELLOW→GREEN→BLUE
  5. 创建标签(第 5 节)——共 17 个标签
  6. 创建基于阶段的里程碑(第 6 节)——PoC 和 Production Hardening

**重要:**调用 updateProjectV2Field 设置颜色/描述后,单选选项 ID 会发生变化(该变更会替换选项列表)。调用此变更后,务必重新查询选项 ID,并在配置中使用新的 ID。

步骤 6:编写配置

现在阅读 references/config-schema.md——你需要用到确切的 YAML 格式。

在项目根目录创建 .github-sync.yaml,按照该架构填写所有 ID。 注意:field_ids 或 option_ids 中不包含 phase 字段——Phase 已替换为里程碑。

步骤 7:报告完成情况
Onboarding complete!
  Project: https://github.com/orgs/{owner}/projects/{number}
  Config: .github-sync.yaml

Next: Run "push stories to github" to create issues.

推送工作流(文件 → GitHub)

将 BMAD 故事文件推送到 GitHub 作为 issue,添加到项目中,设置所有字段和日期字段,并建立关联。

步骤 1:加载配置

读取 .github-sync.yaml。确认所有字段 ID 均已填写。如果有任何 ID 为空,请从 GitHub 重新查询字段 ID(这些 ID 可能已丢失)。

步骤 2:扫描故事
python3 .agents/skills/github-sync/scripts/parse-artifacts.py --mode scan \
  --stories-dir .artifacts/implementation-artifacts

对于每个故事,确定使用创建还是编辑模式:

  • H1 为普通标题 # Story X.X: Title(无链接)→ CREATE
  • H1 包含 # [Story X.X: Title](url) → UPDATE(已同步)
步骤 3:处理部分同步(可选)

如果用户指定了筛选条件(例如“推送故事 1.1 1.2”、“推送 epic 1”、“推送 sprint 2”),请在继续之前筛选故事列表。如果没有筛选条件,则推送所有故事。

步骤 4:读取故事文件并构建 issue 内容

⚠️ 规则 4 在此处适用:使用 Read 工具读取每个文件。手动构建正文。不要使用脚本。

对于每个故事:

  1. 使用 Read 工具读取文件
  2. 阅读 references/content-mapping.md——查看第 1–4 节和第 9 节,了解确切格式
  3. 按照模板构建 issue 正文:
    • 用户故事引用块
    • 将 AC 编写为单行 Then 子句摘要(复选框)
    • 完整任务列表(仅包含 Task 2+——根据内容而非位置排除仅供 Agent 使用的任务)
    • 使用 #N GitHub issue 编号表示依赖关系
    • 可折叠的开发说明:表格、配置片段、架构模式——不要包含代码骨架、ASCII 树、“What NOT to Do”列表或参考资料
  4. 从 sprint-plan.md 中查找 Sprint、Dev 和 Epic(不要从故事文件正文中查找)
步骤 5:生成同步报告
=== GITHUB SYNC — PUSH REPORT ===
Generated: {timestamp}

--- CREATES ({count} new issues) ---

  [CREATE] {story_id} {short_title}
           File: {story_file_path}
           Epic: {epic_label} | Sprint: {sprint} | Dev: {dev} | Phase: {phase}
           Labels: epic:{N}-{name}, phase:{phase}
           Milestone: {PoC | Production Hardening}

--- UPDATES ({count} existing issues) ---

  [UPDATE] {story_id} {short_title} (#{issue_number})
           Changes: body updated

--- SKIPPED ({count} items) ---

  [SKIP] {story_id} {short_title} — already synced, no local changes

--- SUMMARY ---
Creates: {N} | Updates: {N} | Skips: {N}

Proceed? [Y/N]

在此停止。等待用户批准。

步骤 6:执行推送

如果获得批准,对于每个 CREATE:

  1. 将问题正文写入临时文件(/tmp/issue-{story_id}.md)
  2. gh issue create --title "..." --body-file /tmp/... --label "epic:X-name" --label "phase:poc" --milestone "{PoC|Production Hardening}"
  3. 从输出中提取问题 URL
  4. gh project item-add {project_number} --owner {owner} --url {issue_url} --format json
  5. 从 JSON 输出中提取项目 ID
  6. 使用 gh project item-edit 设置所有项目字段:
    • Story ID(文本)
    • Epic(单选选项)
    • Sprint(单选选项,例如 “Sprint 01”)
    • Dev(单选选项)
    • Sprint Start(来自 sprint-plan.md 的日期)
    • Sprint End(来自 sprint-plan.md 的日期)
    • Status(Backlog)
    • Start date(与 Sprint Start 日期相同——预先存在的字段)
    • Target date(与 Sprint End 日期相同——预先存在的字段)
  7. 将回链写入本地文件:将 H1 替换为 # [Story X.X: Title](issue_url)

对于每个 UPDATE:

  1. 将更新后的正文写入临时文件
  2. gh issue edit {number} --body-file /tmp/... --milestone "{phase_milestone}"
  3. 如果 sprint/epic 发生变化,则更新项目字段
步骤 7:设置关联关系

创建所有问题后,建立 GitHub 原生关联关系。

阅读 references/gh-commands.md 第 12 节,获取准确的 GraphQL mutation。

7a. 将 Epic 跟踪问题设为父项

为每个 Epic 创建一个跟踪问题(如果尚未创建)。正文模板见 references/content-mapping.md 第 10 节。然后为每个故事设置其 Epic 跟踪问题为父项:

mutation {
  addSubIssue(input: {
    issueId: "{epic_tracking_issue_node_id}"
    subIssueId: "{story_issue_node_id}"
    replaceParent: true
  }) {
    issue { number }
    subIssue { number }
  }
}
7b. 阻塞依赖项

从 sprint-plan.md 读取依赖关系表(每个 sprint 故事表中的 Dependencies 列)。对于每个依赖项 A → B(故事 A 依赖故事 B):

mutation {
  addBlockedBy(input: {
    issueId: "{story_A_node_id}"
    blockingIssueId: "{story_B_node_id}"
  }) {
    issue { number }
    blockingIssue { number }
  }
}

始终从 sprint-plan.md 获取依赖项,而不是从故事文件正文获取。 sprint 计划是权威的依赖关系记录。

通过以下方式获取问题节点 ID:

gh api graphql -f query='
  query {
    repository(owner:"{owner}", name:"{repo}") {
      issues(first:50, orderBy:{field:CREATED_AT, direction:ASC}) {
        nodes { number id title }
      }
    }
  }
'
步骤 8:报告完成情况
Push complete!
  Created: {N} issues
  Updated: {N} issues
  Skipped: {N} items
  Relationships set: {N} parent, {M} blocked-by

Config updated: last_synced = {timestamp}

拉取工作流(GitHub → 文件)

将状态、受指派人和任务完成情况从 GitHub 拉回本地 BMAD 文件。

步骤 1:加载配置并查询 GitHub

读取 .github-sync.yaml。然后阅读 references/gh-commands.md 第 9 节,获取完整的 GraphQL 项目条目查询。执行查询以获取所有项目条目。

步骤 2:将条目与本地文件匹配

对于每个具有 “Story ID” 字段值的 GitHub 条目:

  1. 查找匹配的本地故事文件(根据故事 ID → 文件名模式)
  2. 比较 GitHub 状态与本地文件状态:
    • 状态:GitHub 状态与本地 Status: 行
    • 受指派人:GitHub 受指派人与本地开发人员映射
    • 任务复选框:GitHub 问题正文中的复选框与本地文件中的复选框
步骤 3:生成同步报告
=== GITHUB SYNC — PULL REPORT ===
Generated: {timestamp}

--- FILE UPDATES ({count} items) ---

  [UPDATE] {story_filename}.md
           Status: ready-for-dev → done (from GitHub #{issue_number})
           Assignee: (none) → @{username}

--- NO CHANGES ({count} items) ---

  [OK] {story_filename}.md — in sync

--- GITHUB-ONLY ({count} items) ---

  [WARN] GitHub #{N} "{title}" — no matching local file

--- SUMMARY ---
File updates: {N} | No changes: {N} | Warnings: {N}

Proceed? [Y/N]

在此处暂停。等待用户批准。

步骤 4:执行拉取

如果获得批准,对于每个文件更新:

  1. 读取故事文件
  2. 使用映射后的 BMAD 状态更新 Status: 行
  3. 写回文件
  4. 更新配置中的 last_synced

状态检查(只读)

比较本地文件与 GitHub 状态,不做任何更改。无需批准。

# Scan local files
python3 .agents/skills/github-sync/scripts/parse-artifacts.py --mode scan \
  --stories-dir .artifacts/implementation-artifacts

# Query GitHub items (full field values)
# Use GraphQL query from references/gh-commands.md section 9

输出比较表:

=== GITHUB SYNC — STATUS ===

| Story | Local Status  | GitHub Status | Sprint | Synced? | Issue |
|-------|--------------|---------------|--------|---------|-------|
| 1.1   | ready-for-dev | Done          | 01     | NO      | #1    |
| 1.2   | ready-for-dev | Ready         | 01     | YES     | #2    |
| 2.1   | backlog       | (not synced)  | 02     | NO      | —     |

Summary: {N} in sync, {M} out of sync, {K} not yet pushed

部分同步筛选条件

筛选条件示例效果
按故事 IDpush stories 1.1 1.2 1.3仅同步这些故事
按 Epicpush epic 3Epic 3 中的所有故事
按 sprintpush sprint 2分配给 Sprint 2 的所有故事
按状态push unsynced仅同步尚未推送的故事
全部push 或 push all所有故事(默认)

错误处理

错误操作
gh 命令返回非零退出代码显示错误输出,建议修复方法,然后停止
配置中缺少 Field ID通过 gh-commands.md 的第 4 节重新查询字段 ID
达到速率限制(HTTP 429)显示警告,建议等待 60 秒,然后停止
Story 文件格式异常跳过,并在同步报告中发出警告
里程碑已存在跳过创建(幂等)
标签已存在跳过创建(幂等)
Story 已有关联的 Issue切换到更新模式
单选字段选项 ID 已过期每次调用 updateProjectV2Field 后重新查询——该 mutation 会替换所有选项并生成新的 ID
addBlockedBy 负载字段错误返回字段为 blockingIssue(而非 blockedByIssue)
updateProjectV2Field 拒绝 projectId此 mutation 只接受 fieldId,不接受 projectId
updateProjectV2Field 拒绝选项 id选项只能使用 name/color/description——不能包含 id 字段

参考文件索引

文件阅读时机
references/gh-commands.md需要准确的 gh CLI 命令或 GraphQL 查询时
references/content-mapping.md需要构建 Issue 正文、映射字段,或检查标签/里程碑方案时
references/config-schema.md需要创建或读取 .github-sync.yaml 时

评论

支持 Markdown