From project-orchestration-skills
Graduates an in-repo backlog (roadmap phases, sprint deliverables, ADRs) onto a forge issue tracker at a thin-hybrid default when the backlog outgrows a single contributor.
How this skill is triggered — by the user, by Claude, or both
Slash command
/project-orchestration-skills:graduate-backlogThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Bridge a project's **in-repo backlog** onto a **forge issue tracker** at the moment the backlog
Bridge a project's in-repo backlog onto a forge issue tracker at the moment the backlog
outgrows a single contributor. The orchestration skills author a rich in-repo backlog —
docs/roadmap/roadmap.md (phases → target versions → task lists), docs/sprints/*.md
(plans/retrospectives), a Nygard ADR sequence, and a Keep-a-Changelog CHANGELOG.md. Once more
than one person needs to see and claim that work, they need a tracker — but that transform is
manual and uncodified.
This skill performs it conservatively. The default is thin-hybrid: planning stays in-repo,
and the tracker holds only incoming/reactive work plus — at most — the current milestone's tactical
items. That is light externalization, not a board build-out. A richer board is opt-in (the
roadmap-visible level), justified by a real need for roadmap visibility.
The trigger is team scale, not exposure. Graduation is driven by who needs to see the work — the same signal as the t0→t1 tier bump ("more than one contributor"). It is not gated on the Public distribution profile: a corporate team on an internal GitLab needs a board without ever open-sourcing, and a solo public repo may never need one. Exposure gates compliance controls, not work organization. (Workspace decision records: "Distribution-Profile Axis for Compliance Qualification", "Work-Organization Graduation: Thin-Hybrid Backlog Externalization", "Plugin Taxonomy by Lifecycle, Not Exposure" — cited by title because bare numbers would collide with the target project's own ADR sequence, which Phase 3 writes into.)
Establish vs operate. This skill establishes tracker structure from the backlog;
incoming-issue(project-maintenance-skills) operates it afterward. Where that plugin is installed it owns the richer contributor-facing setup — issue templates,good first issue, the full triage taxonomy. This skill creates only the minimal labels it needs, so it works standalone in contexts where the maintenance plugin is absent.
public-release go/no-go gate (project-maintenance-skills), deciding how work is organized publiclyNot for: Solo projects with no collaborators — the backlog stays in-repo; say so and stop. Building a heavy Projects-v2 board unless roadmap visibility is an explicit goal. Re-cutting already-shipped work as issues.
owner/repo, auto-detected from git remotes.plan — Phases 1–2: analyze the in-repo backlog and emit the hybrid-boundary decision; no writes (dry run)milestones — Phase 4: seed milestones from open roadmap phasesissues — Phase 5: create labels, then issues from current-sprint open deliverablesfull — Phases 1–6 in sequence: plan → confirm → record the boundary ADR (Phase 3) → milestones → issues → reconcile (Phase 6). Phases 3 and 6 are what produce the skill's headline output and anti-drift rule, so full is the only scope that satisfies this skill's own Validation.thin):
thin — milestones for open phases + issues for current-sprint deliverables only (default)roadmap-visible — Phase 5b: additionally mirror open roadmap phases as tracked issues, for team and stakeholder visibility of the longer arcDetect the forge from remotes:
git remote -v
github.com → ghgitlab.com / self-hosted GitLab → glabcodeberg.org / self-hosted Forgejo/Gitea → tea (the Gitea/Forgejo CLI), or the Gitea REST APIThe hybrid-boundary decision (Phases 2–3, 6) is forge-independent — only the seeding commands in
Phases 4–5 branch by forge. See the Forge Command Reference for the
per-forge equivalents.
A self-hosted GitLab or Forgejo/Gitea instance is a first-class target: point the CLI at it
(glab auth login --hostname gitlab.internal.example, tea login add --url …) — the workflow is
identical. An internal corporate forge is a normal case, not an exception.
Confirm the backlog has outgrown one contributor. Graduation is triggered by team scale, not exposure — do not check the distribution profile:
git shortlog -sn --since="6 months ago" HEAD | head
Proceed if any of these hold: more than one recent committer; the project accepts contributions from beyond the maintainer (an open contributor base is a team, whatever the exposure); or the maintainer states that collaborators need claimable work. If it is a genuinely solo project with no collaborators, stop — a tracker adds ceremony without a reader. Say so plainly rather than seeding an audience-free board.
Locate source artifacts (skip gracefully if absent):
docs/roadmap/roadmap.md — phases, target versions, task lists, Sprint Historydocs/sprints/ — current sprint plan (open deliverables) + README.md indexdocs/adr/ (+ index.yml if present) — decision log (back-link targets)CHANGELOG.md — the [Unreleased] section (authoritative shipped-work record)Check tracker preconditions: do the labels this skill maps onto exist?
gh label list # glab label list | tea labels ls
Type labels (enhancement / bug / documentation) are GitHub defaults and usually exist
already; on GitLab/Forgejo they may not. The priority: * labels rarely exist anywhere.
Create only what is missing (Phase 5) — this skill is self-sufficient and must not assume
another plugin has run.
If incoming-issue (project-maintenance-skills) is available and the project is Public,
prefer running it (scope: setup) first: it establishes the full contributor-facing taxonomy and
issue templates, of which these labels are a subset. Treat it as an enrichment, not a
prerequisite — a corporate consumer may not have that plugin installed at all.
plan)Parse and classify — read-only, no forge writes:
{title, target version, status}. Split into open (candidate
milestones) and completed (never re-cut).docs/sprints/sprint-NNNN-plan.md (candidate issues).[Unreleased] → the trustworthy record of what actually shipped.Trust the changelog over checkboxes. Roadmap
- [ ]checkbox state is frequently stale (shipped features left unticked). Corroborate any "done" againstCHANGELOG.mdbefore excluding it, and derive issues from sprint deliverables, not from roadmap checkboxes.
Output a plan: candidate milestones, candidate issues, and the proposed hybrid boundary. In plan
scope, stop here and present it for confirmation.
Adopt the thin-hybrid default and record it as a project-local ADR in the target project's
own docs/adr/ (use its setup-adrs adrtools numbering — title # N. Work-Organization Boundary).
This is the target project's decision, distinct from the workspace ADR that defines the stance:
| Concern | Canonical home | Rationale |
|---|---|---|
| Strategic roadmap (phases, target versions) | in-repo roadmap.md | version-controlled north star |
| Architecture decisions | in-repo docs/adr/ | the "why"; back-link target for issues |
| Sprint retrospectives | in-repo docs/sprints/ | narrative record |
| Incoming / community / reactive work | tracker | contributor-facing |
| Current-milestone tactical items | tracker (thin) | claimable by contributors |
| Per-issue / milestone status | tracker (single source of truth) | avoids table drift |
Record the single source of truth for tactical status explicitly, so hand-maintained tables
(roadmap Sprint History, docs/sprints/README.md) don't drift against the board.
milestones)Create one milestone per open roadmap phase. Idempotent — check for an existing milestone of the same title before creating:
# List existing milestone titles
gh api "repos/{owner}/{repo}/milestones?state=open" --jq '.[].title'
# Create only if absent
gh api "repos/{owner}/{repo}/milestones" \
-f title="Phase 3 — v0.2.0" \
-f state="open" \
-f description="Graduated from docs/roadmap/roadmap.md Phase 3. Canonical roadmap stays in-repo."
glab) or Forgejo (tea), use the equivalent from the Forge Command Reference; the open-phases-only and idempotency rules are unchanged.issues)Create issues from current-sprint open deliverables (Phase 2), each back-linked and idempotent (search by a stable title before creating).
Applying a label that does not exist fails the issue creation, so this step precedes Step 2.
Idempotent — each label create no-ops if the label is already there:
# Type labels: GitHub defaults, but absent on a fresh GitLab/Forgejo project
gh label create "enhancement" --color a2eeef --description "New feature or request" 2>/dev/null || true
gh label create "bug" --color d73a4a --description "Something isn't working" 2>/dev/null || true
gh label create "documentation" --color 0075ca --description "Improvements or additions to documentation" 2>/dev/null || true
# Priority labels: rarely present on any forge
gh label create "priority: high" --color d93f0b --description "Severe impact" 2>/dev/null || true
gh label create "priority: medium" --color e4e669 --description "Moderate impact" 2>/dev/null || true
gh label create "priority: low" --color c2e0c6 --description "Minor impact" 2>/dev/null || true
Colours are part of the contract, not decoration. They match
incoming-issue's taxonomy exactly. Becauselabel createis made idempotent with|| true, first writer wins — a wrong colour here would survive silently forever once this skill runs first, and the two plugins would disagree with no error ever surfacing. Do not "improve" them.
See the Forge Command Reference for the glab/tea equivalents.
# Idempotency guard
gh issue list --search "in:title \"Wire the audit CI job\"" --state all --json number --jq '.[].number'
# Create, attach to milestone, apply the mapped priority/type labels (see the table below)
gh issue create \
--title "Wire the audit CI job" \
--milestone "Phase 3 — v0.2.0" \
--label "enhancement" --label "priority: high" \
--body "$(cat <<'BODY'
Graduated from docs/sprints/sprint-0004-plan.md (Deliverable 2).
**Back-links**
- Roadmap: docs/roadmap/roadmap.md → Phase 3
- ADR: docs/adr/0005-…
- Sprint: docs/sprints/sprint-0004-plan.md
Canonical strategic context stays in-repo; this issue tracks the tactical item only.
BODY
)"
Vocabulary mapping — do not invent new label names; these are the shared taxonomy:
| Internal (sprint plan) | Tracker |
|---|---|
| Story Priority: High | priority: high |
| Story Priority: Medium | priority: medium |
| Story Priority: Low | priority: low |
| Roadmap phase | milestone (not a label) |
| Deliverable kind (feature/bug/docs) | enhancement / bug / documentation |
Exact names matter: bare type labels, and a space after
priority:. Do not add atype:prefix or drop the space. These names are shared withincoming-issue(project-maintenance-skills), so a project that later adopts the maintenance plugin converges instead of ending up with two vocabularies — but nothing here depends on that plugin.
On GitLab (glab) or Forgejo (tea), swap the gh issue create line for the equivalent in the Forge Command Reference; the back-linking, idempotency, and vocabulary mapping are identical.
roadmap-visible)Skip this at the thin default. Only run it when the maintainer has explicitly asked for the
longer arc to be visible on the tracker — a team coordinating across phases, or stakeholders who
will not read docs/roadmap/roadmap.md.
For each open roadmap phase, create one tracked issue that mirrors it, attached to that phase's milestone from Phase 4:
gh issue create \
--title "Phase 3 — Knowledge-Formats Combination" \
--milestone "Phase 3 — v0.2.0" \
--label "documentation" \
--body "Mirror of docs/roadmap/roadmap.md → Phase 3, for tracker visibility.
**The roadmap remains canonical.** This issue is a pointer, not the source of truth: do not
maintain phase scope here. Close it when the milestone closes."
thin is the default.wrapup-sprint should honour this boundary when it next updates status tables.The workflow above shows GitHub (gh). The decision logic is identical on every forge — only the
Phase 4/5 seeding commands change:
| Operation | GitHub — gh | GitLab — glab | Forgejo/Gitea — tea |
|---|---|---|---|
| List open milestones | gh api "repos/{owner}/{repo}/milestones?state=open" --jq '.[].title' | glab api "projects/:fullpath/milestones?state=active" --jq '.[].title' | tea milestones ls --state open |
| Create milestone | gh api "repos/{owner}/{repo}/milestones" -f title="…" -f state=open | glab api --method POST "projects/:fullpath/milestones" -f title="…" | tea milestones create --title "…" |
| Find issue by title | gh issue list --search "in:title \"…\"" --state all | glab issue list --search "…" | tea issues ls --state all |
| Create issue (+ milestone, labels) | gh issue create --title "…" --milestone "…" --label "…" | glab issue create --title "…" --milestone "…" --label "…" | tea issues create --title "…" --milestone "…" --labels "…" |
| List labels | gh label list | glab label list | tea labels ls |
| Create label | gh label create "priority: high" --color d93f0b | glab label create --name "priority: high" --color "#d93f0b" | tea labels create --name "priority: high" --color d93f0b |
glab/tea act on the current repo, including self-hosted instances — authenticate once
(glab auth login --hostname gitlab.internal.example, tea login add --url https://forge.internal)
and every command below is unchanged. For glab api, :fullpath is the placeholder glab expands to
the current project's URL-encoded path (:id, the numeric project ID, also works).
tea has no server-side title search, so for idempotency list issues and filter by title locally;
use the Gitea REST API via curl + token (/api/v1/repos/{owner}/{repo}/…) for anything tea
doesn't expose (there is no tea api passthrough). Flags vary across tea versions — the table
above is verified against glab 1.107.0 and a tea build reporting go-sdk v0.15.1 — note that
tea --version reports an empty CLI version, so the go-sdk string is the only identifier it
offers; confirm with tea <command> --help if yours differs.
Conceptual mapping (informational — this skill seeds milestones and issues only, never iterations or epics): the roadmap→tracker analogues differ by forge:
| In-repo concept | GitHub | GitLab | Forgejo/Gitea |
|---|---|---|---|
| Roadmap phase | Milestone | Milestone (or group-level Epic) | Milestone |
| Sprint | Projects Iteration | Iteration / Iteration Cadence | Milestone (no native iteration) |
docs/adr/, recording the hybrid split and
the single source of truth.CLAUDE.md note: graduation performed, canonical-source rule.gh / glab / tea), including self-hosted GitLab/Forgejo; only the seeding commands branch by forge, the decision logic does notpriority:) — first writer wins, so a divergence here is permanent and silentpriority: *; phase mapped onto milestone (not a label)bootstrap-project — authors the in-repo backlog this migrates from, and owns the tier axis whose "more than one contributor" trigger this sharesplan-sprint / wrapup-sprint — define the sprint deliverables (issue source) and the roadmap Sprint History ledger; wrapup-sprint honours the single-source-of-truth boundary recorded heresetup-adrs — the ADR mechanism used to record the hybrid-boundary decisionincoming-issue (project-maintenance-skills) — operates the tracker afterward (establish → operate) and owns the full contributor-facing taxonomy; an optional enrichment for Public projects, never a prerequisitepublic-release (project-maintenance-skills) — the Private→Public gate, which invokes this skill when a graduating project also needs a contributor-facing trackernpx claudepluginhub jrjsmrtn/jrjsmrtn-skills --plugin project-orchestration-skillsManages backlog items through grooming, planning, and closure using GitHub Issues, Projects, Milestones. Interactive browser, auto-mode, resolve/close with evidence, SAM integration.
Bidirectional sync between BMAD planning markdown files (epics, stories, sprints) and GitHub Projects v2. Handles onboarding, push, pull, and status checks with explicit user approval.
Syncs session work into GitHub issues and queries track status across repos. Two modes: write (end-of-session sync with issue updates, epics, labels, Project placement) and read (status lookup).