Loading...
Loading...
Compare original and translation side by side
Quick navigation
CLI commands, GraphQL queries →ghreferences/gh-commands.md- Issue body template, field mapping, labels, milestones →
references/content-mapping.md- Config file format →
references/config-schema.md- Artifact parser script →
scripts/parse-artifacts.py
快速导航
CLI命令、GraphQL查询 →ghreferences/gh-commands.md- Issue主体模板、字段映射、标签、里程碑 →
references/content-mapping.md- 配置文件格式 →
references/config-schema.md- 工件解析脚本 →
scripts/parse-artifacts.py
gh_item_urlreferences/content-mapping.mdgh_item_urlreferences/content-mapping.md| User Says | Workflow | Config Required? |
|---|---|---|
| "set up github project", "onboard", "initialize github" | Onboarding | No (creates config) |
| "push to github", "sync push", "create issues" | Push | Yes |
| "pull from github", "sync pull", "update from github" | Pull | Yes |
| "sync status", "what's out of sync" | Status Check | Yes |
.github-sync.yaml| 用户输入内容 | 工作流 | 是否需要配置? |
|---|---|---|
| "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.yamlStep 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'"Step 1: gh --version
→ 若未安装:"Install GitHub CLI: https://cli.github.com/"
Step 2: gh auth status
→ 若未认证:"Run: gh auth login"
Step 3: gh auth status (check for "project" in scopes
→ 若缺少权限:"Run: gh auth refresh -s project"
Step 4: (仅推送/拉取/状态检查时执行) 检查`.github-sync.yaml`是否存在
→ 若不存在:"Run onboarding first: say 'set up github project'"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.mdNote: The artifacts pathmay differ per project. Check the actual directory structure — some projects use.artifacts/. Confirm the correct paths with the user and use them throughout. Update_bmad-output/in the config accordingly.paths.*
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.*
gh repo view --json owner,name --jq '.owner.login + "/" + .name'gh project list --owner {owner} --format jsongh repo view --json owner,name --jq '.owner.login + "/" + .name'gh project list --owner {owner} --format jsonreferences/content-mapping.mdpython3 .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.mdreferences/content-mapping.mdpython3 .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=== 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]=== 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]references/gh-commands.mdCritical: After callingto set colors/descriptions, the single-select option IDs CHANGE (the mutation replaces the options list). Always re-query option IDs after calling this mutation and use the new IDs in the config.updateProjectV2Field
references/gh-commands.md关键提示: 调用设置颜色/描述后,单选选项ID会发生变化(该变更操作会替换选项列表)。调用此变更操作后请始终重新查询选项ID,并在配置中使用新ID。updateProjectV2Field
references/config-schema.md.github-sync.yamlphasefield_idsoption_idsreferences/config-schema.md.github-sync.yamlfield_idsoption_idsphaseOnboarding complete!
Project: https://github.com/orgs/{owner}/projects/{number}
Config: .github-sync.yaml
Next: Run "push stories to github" to create issues.Onboarding complete!
Project: https://github.com/orgs/{owner}/projects/{number}
Config: .github-sync.yaml
Next: Run "push stories to github" to create issues..github-sync.yaml.github-sync.yamlpython3 .agents/skills/github-sync/scripts/parse-artifacts.py --mode scan \
--stories-dir .artifacts/implementation-artifacts# Story X.X: Title# [Story X.X: Title](url)python3 .agents/skills/github-sync/scripts/parse-artifacts.py --mode scan \
--stories-dir .artifacts/implementation-artifacts# Story X.X: Title# [Story X.X: Title](url)references/content-mapping.md#Nreferences/content-mapping.md#N=== 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]=== 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]/tmp/issue-{story_id}.mdgh issue create --title "..." --body-file /tmp/... --label "epic:X-name" --label "phase:poc" --milestone "{PoC|Production Hardening}"gh project item-add {project_number} --owner {owner} --url {issue_url} --format jsongh project item-edit# [Story X.X: Title](issue_url)gh issue edit {number} --body-file /tmp/... --milestone "{phase_milestone}"/tmp/issue-{story_id}.mdgh issue create --title "..." --body-file /tmp/... --label "epic:X-name" --label "phase:poc" --milestone "{PoC|Production Hardening}"gh project item-add {project_number} --owner {owner} --url {issue_url} --format jsongh project item-edit# [Story X.X: Title](issue_url)gh issue edit {number} --body-file /tmp/... --milestone "{phase_milestone}"references/gh-commands.mdreferences/content-mapping.mdmutation {
addSubIssue(input: {
issueId: "{epic_tracking_issue_node_id}"
subIssueId: "{story_issue_node_id}"
replaceParent: true
}) {
issue { number }
subIssue { number }
}
}references/content-mapping.mdmutation {
addSubIssue(input: {
issueId: "{epic_tracking_issue_node_id}"
subIssueId: "{story_issue_node_id}"
replaceParent: true
}) {
issue { number }
subIssue { number }
}
}sprint-plan.mdDependenciesA → Bmutation {
addBlockedBy(input: {
issueId: "{story_A_node_id}"
blockingIssueId: "{story_B_node_id}"
}) {
issue { number }
blockingIssue { number }
}
}Always source dependencies from sprint-plan.md, not from story file bodies. The sprint plan is the authoritative dependency record.
gh api graphql -f query='
query {
repository(owner:"{owner}", name:"{repo}") {
issues(first:50, orderBy:{field:CREATED_AT, direction:ASC}) {
nodes { number id title }
}
}
}
'sprint-plan.mdDependenciesA → Bmutation {
addBlockedBy(input: {
issueId: "{story_A_node_id}"
blockingIssueId: "{story_B_node_id}"
}) {
issue { number }
blockingIssue { number }
}
}始终从sprint-plan.md获取依赖关系,不要从story文件主体获取。 sprint计划是权威的依赖记录。
gh api graphql -f query='
query {
repository(owner:"{owner}", name:"{repo}") {
issues(first:50, orderBy:{field:CREATED_AT, direction:ASC}) {
nodes { number id title }
}
}
}
'Push complete!
Created: {N} issues
Updated: {N} issues
Skipped: {N} items
Relationships set: {N} parent, {M} blocked-by
Config updated: last_synced = {timestamp}Push complete!
Created: {N} issues
Updated: {N} issues
Skipped: {N} items
Relationships set: {N} parent, {M} blocked-by
Config updated: last_synced = {timestamp}.github-sync.yamlreferences/gh-commands.md.github-sync.yamlreferences/gh-commands.mdStatus:Status:=== 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]=== 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]Status:last_syncedStatus:last_syncedundefinedundefined
Output a comparison table:
| 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 | — |
---
输出对比表:
| 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 | — |
---| Filter | Example | Effect |
|---|---|---|
| By story IDs | | Only these stories |
| By epic | | All stories in Epic 3 |
| By sprint | | All stories assigned to Sprint 2 |
| By status | | Only stories not yet pushed |
| All | | All stories (default) |
| 筛选维度 | 示例 | 效果 |
|---|---|---|
| 按story ID | | 仅同步这些stories |
| 按epic | | 同步Epic 3下的所有stories |
| 按sprint | | 同步分配到Sprint 2的所有stories |
| 按状态 | | 仅同步尚未推送的stories |
| 全部 | | 同步所有stories(默认) |
| Error | Action |
|---|---|
| Show the error output, suggest fix, halt |
| Field ID missing from config | Re-query field IDs via section 4 of gh-commands.md |
| Rate limit hit (HTTP 429) | Show warning, suggest waiting 60 seconds, halt |
| Story file has unexpected format | Skip with warning in the sync report |
| Milestone already exists | Skip creation (idempotent) |
| Label already exists | Skip creation (idempotent) |
| Issue already exists for story | Switch to update mode |
| Single-select option IDs stale | Re-query after any |
| Return field is |
| This mutation takes only |
| Options use |
| 错误 | 处理方式 |
|---|---|
| 展示错误输出,给出修复建议,终止流程 |
| 配置中缺少字段ID | 通过gh-commands.md第4节重新查询字段ID |
| 触发速率限制(HTTP 429) | 展示警告,建议等待60秒,终止流程 |
| Story文件格式不符合预期 | 在同步报告中给出警告并跳过 |
| 里程碑已存在 | 跳过创建(幂等) |
| 标签已存在 | 跳过创建(幂等) |
| Story对应的issue已存在 | 切换到更新模式 |
| 单选选项ID过期 | 任何 |
| 返回字段是 |
| 该变更操作仅接受 |
| 选项仅使用 |
| File | Read When |
|---|---|
| You need exact |
| You need to build issue body, map fields, or check label/milestone scheme |
| You need to create or read |
| 文件 | 读取时机 |
|---|---|
| 需要准确的 |
| 需要构建issue主体、映射字段或检查标签/里程碑方案时 |
| 需要创建或读取 |