Skip to content
Back to skills

Gh Labels Milestones

ASecurity

Bootstrap and sync GitHub labels and milestones idempotently. Use when setting up a new repository or syncing label definitions.

  • 24 stars
  • 0 votes
  • 0 copies
  • 4 views
  • Added September 10, 2026
devopspythonbashgitapidocumentation

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 10, 2026

npx -y skills add kinncj/MAPLE --skill gh-labels-milestones --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Gh Labels Milestones?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Gh Labels Milestones
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/kinncj-gh-labels-milestones-6e81cc8c/badge)](https://www.skillsdirectory.com/skills/kinncj-gh-labels-milestones-6e81cc8c)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: gh-labels-milestones
description: "Bootstrap and sync GitHub labels and milestones idempotently. Use when setting up a new repository or syncing label definitions."
---

# SKILL: gh-labels-milestones

## Purpose

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.

## Label Bootstrap

Use this at project start (`maple labels`) and in CI to guarantee label state.

```bash
# 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
}
```

## Label Groups

### Phase Labels (pipeline position)

```bash
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"
```

### Type Labels (work classification)

```bash
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"
```

### Priority Labels (MoSCoW)

```bash
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"
```

### Spec / Story Kit Labels

```bash
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"
```

### Design Labels

```bash
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"
```

### ADR Labels

```bash
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"
```

### UI / Accessibility Labels

```bash
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"
```

### Status Labels

```bash
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"
```

## Milestone Bootstrap

```bash
# 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"
```

## Milestone granularity gate (ask once, then persist)

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`.

```bash
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:
  ```bash
  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.

## Assign Labels to an Issue

```bash
# 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"
```

## Failure Modes

| 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 |

## Logging

```
[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
```

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.