一键导入
gh-labels-milestones
Bootstrap and sync GitHub labels and milestones idempotently. Use when setting up a new repository or syncing label definitions.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Bootstrap and sync GitHub labels and milestones idempotently. Use when setting up a new repository or syncing label definitions.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
MAPLE AI Development Squad — install the full skill set for multi-agent development workflows: pipeline-runner, tdd-workflow, playwright-cli, github-cli, mermaid-diagrams, and more. Designed for Claude Code, OpenCode, and GitHub Copilot.
Universal dispatcher: run a named taffy workflow (.claude/taffy/<name>.yaml), a skill (/skill-name), or a sub-agent (@agent-name). Falls back to skills.sh registry when a skill is not found locally. Tracks all runs in .claude/state/maple.json so the maple TUI shows live progress.
Universal dispatcher: run a named taffy workflow (.claude/taffy/<name>.yaml), a skill (/skill-name), or a sub-agent (@agent-name). Falls back to skills.sh registry when a skill is not found locally. Tracks all runs in .claude/state/maple.json so the maple TUI shows live progress.
Create, read, update, and link GitHub Issues as story artifacts throughout the story lifecycle. Use when managing issues for stories.
Manage GitHub Projects v2 board: add issues, update field values, and query board state. Use when managing project boards.
Manage GitHub Projects v2 board: add issues, update field values, and query board state. Use when managing project boards.
| name | gh-labels-milestones |
| description | Bootstrap and sync GitHub labels and milestones idempotently. Use when setting up a new repository or syncing label definitions. |
Bootstrap and sync GitHub labels and milestones idempotently. Labels and milestones are created if absent; existing ones are updated if color or description differs. Never delete — only add or update.
Use this at project start (maple labels) and in CI to guarantee label state.
# Idempotent label create-or-update
upsert_label() {
local name="$1" color="$2" description="$3"
if gh label list --json name --jq '.[].name' | grep -qx "$name"; then
gh label edit "$name" --color "$color" --description "$description"
else
gh label create "$name" --color "$color" --description "$description"
fi
}
upsert_label "phase:discover" "0075ca" "Phase 1: Discovery"
upsert_label "phase:architect" "0075ca" "Phase 2: Architecture"
upsert_label "phase:plan" "0075ca" "Phase 3: Planning"
upsert_label "phase:infra" "0075ca" "Phase 4: Infrastructure"
upsert_label "phase:implement" "0075ca" "Phase 5: Implementation"
upsert_label "phase:validate" "0075ca" "Phase 6: Validation"
upsert_label "phase:document" "0075ca" "Phase 7: Documentation"
upsert_label "phase:done" "0075ca" "Phase 8: Complete"
upsert_label "type:feature" "0052cc" "New capability"
upsert_label "type:bug" "d73a4a" "Defect"
upsert_label "type:spike" "e4e669" "Research / time-boxed exploration"
upsert_label "type:chore" "ededed" "Non-functional maintenance"
upsert_label "type:refactor" "ededed" "Code restructuring, no behavior change"
upsert_label "type:docs" "0075ca" "Documentation only"
upsert_label "priority:critical" "b60205" "Must ship — blocks launch"
upsert_label "priority:high" "e11d48" "Must have"
upsert_label "priority:medium" "f97316" "Should have"
upsert_label "priority:low" "84cc16" "Could have"
upsert_label "priority:wontfix" "ffffff" "Won't have this cycle"
upsert_label "spec:problem" "7057ff" "Problem statement written"
upsert_label "spec:approved" "7057ff" "Spec approved by PO"
upsert_label "spec:in-review" "7057ff" "Spec under review"
upsert_label "design:pending" "fbca04" "Awaiting design"
upsert_label "design:in-progress" "fbca04" "Design work active"
upsert_label "design:approved" "fbca04" "Design approved"
upsert_label "design:a11y-passed" "fbca04" "Accessibility review passed"
upsert_label "adr:required" "5319e7" "ADR must be written before implementation"
upsert_label "adr:in-progress" "5319e7" "ADR being authored"
upsert_label "adr:complete" "5319e7" "ADR accepted"
upsert_label "adr:rejected" "5319e7" "ADR rejected — see comments"
upsert_label "ui:required" "fef2c0" "Has UI surface — design review required"
upsert_label "ui:in-progress" "fef2c0" "UI implementation active"
upsert_label "ui:complete" "fef2c0" "UI complete and reviewed"
upsert_label "in-progress" "0052cc" "Work started"
upsert_label "blocked" "b60205" "Blocked — needs human"
upsert_label "validated" "0e8a16" "All tests pass"
upsert_label "tdd:red" "d73a4a" "Failing test written"
upsert_label "tdd:green" "0e8a16" "Tests passing"
# Idempotent milestone create
upsert_milestone() {
local title="$1" due="$2" description="$3"
EXISTING=$(gh api "repos/{owner}/{repo}/milestones" \
--jq ".[] | select(.title == \"$title\") | .number" 2>/dev/null)
if [ -n "$EXISTING" ]; then
gh api "repos/{owner}/{repo}/milestones/$EXISTING" \
-X PATCH \
-f title="$title" \
-f due_on="${due}T00:00:00Z" \
-f description="$description"
else
gh api "repos/{owner}/{repo}/milestones" \
-X POST \
-f title="$title" \
-f due_on="${due}T00:00:00Z" \
-f description="$description"
fi
}
# Example usage
upsert_milestone "v1.0" "2025-12-31" "Initial release"
Whether a change gets a milestone is driven by github.milestone_granularity in
project.config.yaml. An absent key in an older config counts as null.
GRANULARITY=$(python3 -c "
for line in open('project.config.yaml'):
s = line.strip()
if s.startswith('milestone_granularity:'):
v = s.split(':', 1)[1].split('#', 1)[0].strip().strip('\"').strip(\"'\")
print(v); break
")
null or empty — not yet decided. Ask the user once:
"Track milestones for this project? (yes = major & minor releases / no = skip)".
Persist the answer so we never re-ask. The key is absent in older configs,
so replace it if present, otherwise insert it under the github: block:
python3 - "$ANSWER" <<'PY' # ANSWER = "minor" (yes) or "none" (no)
import re, sys
val = sys.argv[1]
p = 'project.config.yaml'; s = open(p).read()
if re.search(r'^\s*milestone_granularity:', s, re.M):
s = re.sub(r'(^\s*milestone_granularity:\s*)\S+', r'\g<1>' + val, s, count=1, flags=re.M)
elif re.search(r'^github:\s*$', s, re.M):
s = re.sub(r'(^github:\s*\n)', r'\g<1> milestone_granularity: ' + val + '\n', s, count=1, flags=re.M)
else:
s = s.rstrip('\n') + '\ngithub:\n milestone_granularity: ' + val + '\n'
open(p, 'w').write(s)
PY
none — declined. Skip milestones entirely.minor (default when enabled) — major & minor only. Ensure vX.Y.0
exists (upsert_milestone); a patch attaches to its minor's vX.Y.0 and
never gets its own milestone.patch — also give patches their own vX.Y.Z milestone.The label taxonomy (type:bug / type:feature / type:docs / type:refactor /
type:chore) is the single source of truth defined above under Type Labels —
map the SemVer class to it (type:bug for a fix/patch, type:feature for a
feature/minor/major). Do not invent bug/enhancement labels.
# Add labels (idempotent — gh ignores if already present)
gh issue edit {issue_number} \
--add-label "type:feature,priority:high,phase:discover"
# Remove a specific label
gh issue edit {issue_number} --remove-label "phase:discover"
| Condition | Action |
|---|---|
| Label name collision (wrong color) | gh label edit — update in place |
| Milestone already exists | Patch via API — do not create duplicate |
gh not authenticated | Stop immediately. Do not retry. |
| Label with special characters | URL-encode the label name in API calls |
[gh-labels] UPSERT label="type:feature" color=0052cc
[gh-labels] SKIP label="priority:high" (unchanged)
[gh-milestones] CREATE "v1.0" due=2025-12-31
[gh-milestones] SKIP "v1.0" already exists