skilly. Buy ad slot
All skills
Community / AGENT SKILL

gh-labels-milestones

kinncj/MAPLE
0 installs 24 GitHub stars
0

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

BEFORE YOU INSTALL

Understand the trade-offs.

SECURITY REVIEW

Not yet assessed

Review the original instructions and requested permissions before installing.

No security review is available for this catalog entry yet.

SKILL QUALITY

Not yet assessed

How clearly the skill guides your agent, how complete its workflow is, and how you can check the outcome.

No quality assessment is available for this catalog entry yet.

The full skill.

Original instructions from the publisher’s SKILL.md

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