Skills › BMAD Method › bmad-agent-po › github-ticketing.toml
github-ticketing.toml
81 lines · skills/bmad-agent-po/config/github-ticketing.toml at bd70c64
1# Store starter: GitHub Issues. `scripts/read_store.py` reads this file as the base layer; the project's
2# _bmad/custom/ticketing-store-config.toml names the store, fills the empty fields below, and replaces
3# any other key here, key by key.
4# It updates with the skill and holds only what is specific to this store: the rules every store shares
5# are in references/board.md. Comments and `description` are never loaded; `description` is for choosing a store.
6#
7# One tool: the gh CLI, 2.94 or later (sub-issues and dependencies). Labels carry type and status,
8# sub-issues carry hierarchy, blocked-by relations carry blocking, milestones put initiatives on the roadmap.
9# Using the defaults below: the repo needs the type, status, and hitl labels; `setup` creates them.
11description = "GitHub Issues through the gh CLI: labels, sub-issues, blocked-by, milestones. For teams whose code and planning already live on GitHub."
13[tickets]
14store = "github"
15key = "" # ids are the repo's issue numbers; leave empty
16repo = "" # OWNER/REPO; empty = the repo of the current checkout (origin)
17access = """
18Use the gh CLI against `repo`, passing `-R <repo>` on every call when it is set. Needs gh 2.94+; check `--help` when a flag is doubted.
19"""
21fields = """
22risk is a label risk:<value>; severity is a label P0-P3. `setup` creates them with the other
23labels; publish and update set them like any label. estimate is a label est:<value> (`setup` creates none; add on first use). Empty field: no label.
24"""
26reference = """
27GitHub renders urls as links; nothing more to do.
28"""
30[verbs]
31setup = """
32Connect, unless `gh auth status` already shows a login: `gh auth login`.
33Labels must exist before they are used. List the repo's labels (`gh label list --limit 1000 --json name`)
34and run `gh label create <name>` for each of these it lacks, comparing names ignoring case: the
35[tickets.types] values except initiative (a milestone), the [tickets.status] values except done and
36dropped (closed states), `hitl`, risk:low, risk:medium, risk:high, and P0-P3. A create that fails with
37"already exists" found the label after all: leave it. Never `--force`: it recolours a label the repo
38already has.
39"""
41write = """
42One issue per new ticket. tracker_id is the issue number and remote its url.
43Create with content only: `gh issue create --title <t> --body-file <b> --label <type>,<[tickets.status].<state>>[,hitl,risk:<r>,P<n>]
44[--milestone <initiative>]`, and mirror tracker_id and remote from the url it prints before anything else. Then add the
45relations with `gh issue edit <n> --parent <n> --add-blocked-by <n,n>`, leaving out any that `gh issue view <n> --json
46parent,blockedBy` already shows, since adding one twice fails. Keep --parent and --blocked-by off the create: gh adds them
47after the issue exists, and when that step fails it exits non-zero without printing the url, so a rerun files the ticket
48twice. A create that fails with no url may still have made the issue: before creating again, list the newest issues
49(`gh issue list --state all --limit 100 --json number,title,body,createdAt`) twice, a few seconds apart since the list can
50trail a create, and take the one whose title and body are what was sent. None matches and the list does not reach back to
51the failed create: ask before creating again. Changes go through `gh issue edit <n>` (--body-file, --add-assignee,
52--add-blocked-by, label swaps; --add-sub-issue on the parent). No parent: omit --parent; no initiative: omit --milestone.
53Status is a label swap on an open issue. done: remove the status label and `gh issue close <n>`;
54dropped: the same with `--reason "not planned"`. An initiative is a
55milestone (`gh api repos/{owner}/{repo}/milestones -f title=<name>`) holding its tree's issues.
56"""
58query = """
59One issue: `gh issue view <n> --json
60number,title,labels,assignees,state,stateReason,milestone,parent,blockedBy,subIssuesSummary,body`.
61Type, hitl, risk, severity, and status are labels — except done and dropped, the closed states per
62[tickets.status]; after is blockedBy; the body's covers holds the source requirement ids. Children: `gh issue view <n>
63--json subIssues`. Words: `gh issue list --search "<words>" --state all`, narrowed by
64--label. An initiative's issues are the ones in its milestone; a standalone ticket has no milestone.
65"""
67# BMad type -> this store's type.
68[tickets.types]
69initiative = "milestone" # an initiative is a milestone, not an issue; its epics carry it
70epic = "epic"
71story = "story"
72spike = "spike"
73bug = "bug"
75# BMad state -> this store's status.
76[tickets.status]
77backlog = "backlog"
78in-progress = "in-progress"
79review = "review"
80done = "closed" # state, not a label
81dropped = "closed: not planned" # state, not a label