Skip to content

About

Unified BMAD extension module that mirrors sprint tracking to GitLab Issues or GitHub Issues

Resources

Stars

0 stars

Watchers

0 watching

Forks

 
 

Latest commit

 

History

183 Commits

Folders and files

Repository files navigation

BMAD Issue Tracking

BMAD module that mirrors sprint tracking to GitLab Issues or GitHub Issues. Supports both cloud and self-hosted instances via their respective CLIs (glab / gh).

Uses native BMad TOML customization for workflow integrations. Installs through both BMad routes: the classic installer (npx bmad-method install --custom-source) and the Skills CLI (npx skills add).

Prerequisites

  • BMAD Method module (BMM) 6.12.0+ installed in your project
  • glab CLI (GitLab) or gh CLI (GitHub) installed and authenticated
  • Repository with Issues enabled
  • uv (mandatory from BMM 6.12.0+)

Architecture

The module plugs into BMM via two TOML hooks per target workflow:

  • activation_steps_append — runs before the BMM workflow: sets up the worktree, resolves variables (prd_key, story_key, branch patterns), captures context.
  • on_complete — runs after the BMM workflow: commits, pushes, creates/updates issues, manages MRs, posts comments.

The TOML files in assets/custom/ are pure pointers — they reference workflow YAML files in assets/workflows/ (deployed to _bmad/_config/custom/workflows/) that carry the actual logic. No business logic lives in TOML.

For the full architecture — branch/MR direction table, platform differences, step-authoring rules, caller-negotiation channels, bmad-loop integration design — see CLAUDE.md.

CI integration

The module participates in your CI pipeline via two layers:

  • common/wait-for-green-ci.yaml — the on_complete hook blocks until the MR/PR pipeline is green, for up to 30 minutes. The initial check goes through common/check-mr-ci.yaml → common/get-mr-pipeline.yaml; the rounds that follow inline the same lookup, and common/get-failed-jobs.yaml is read only on the failure path. The wait is a LOOP of eighteen rounds, each a single command of at most four polls 25 s apart (~100 s, inside the tool's 120 s default): the interpreter runs commands through a tool that times out, so one 30-minute command would be killed before it could report anything and ci-status.json would never be written. Two answers end the wait green without a pipeline: no_ci — the branch defines no pipeline, or three consecutive rounds saw an empty run list although it does (the counter resets on any round that sees one) — and no_mr, the flow with no remote MR at all, where there is no gate to enforce. Every lookup is pinned to the commit the hook pushed (git rev-parse HEAD, filtered on as --commit on GitHub and as the pipeline's sha on GitLab): both platforms list the previous commit's run for the first seconds after a push, so an unpinned gate could report green over a tree CI never built. "No run for this commit yet" is an empty listing, which the rules above already treat as "still coming".
  • ci-status.sh — the bmad-loop [verify] command (deployed to .bmad-loop/ci-status.sh by the setup skill). Reads the latest ci-status.json written by the unified workflow; exits 0 (green) or 1 (red, with diagnostic). The intelligent work (polling, log parsing, distinguishing flaky from real) is done by the on_complete hook — ci-status.sh is a fast, deterministic file-read.
  • ci-status.json — transient gate output at the worktree root: one story's verdict, written by common/write-ci-status.yaml and read by ci-status.sh. The setup skill gitignores it (step 4) because bmad-loop commits the story worktree as a single commit, and untracked the file rode that commit into the integration branch, leaving every story's stale verdict there.

In the manual flow (/bmad-build), the hook blocks the workflow on CI. In the bmad-loop flow, a red CI triggers an automatic repair session (re-invoke bmad-build-auto with the diagnostic) up to max_dev_attempts before deferring the story.

Installation

BMad has two install routes. They never coexist in one project — pick the one your project already uses.

Route BMad versions What this module ships for it
Classic installer — npx bmad-method install released BMAD (6.12.x) skills/module.yaml, skills/module-help.csv, .claude-plugin/marketplace.json
Skills CLI — npx skills add + bmad setup BMAD main only (6.13.0-next, not yet released) skills/*/module-manifest.toml

Route A: classic installer (released BMAD)

  1. Install or update BMad in your project as usual (npx bmad-method install, BMM ≥ 6.12.0).
  2. Add this module as a custom source. Interactive: run the installer again and answer yes to "install custom or community modules", then paste the repo URL or local path. Non-interactive:
npx bmad-method install --directory . --modules bmm \
  --custom-source https://github.com/jrevillard/bmad-issue-tracking \
  --tools claude-code --yes

Pin a release with --custom-source https://github.com/jrevillard/bmad-issue-tracking@v3.0.0, or point at a local clone (--custom-source /path/to/bmad-issue-tracking; changes take effect on reinstall). Both <repo> (Discovery mode via marketplace.json) and <repo>/skills (Direct mode) work as the source.

The installer registers the module as bmad-issue-tracking with its version in _bmad/_config/manifest.yaml, copies both skills to .claude/skills/ (the module directory _bmad/bmad-issue-tracking/ holds only its config and help catalog), and adds their rows to _bmad/_config/bmad-help.csv.

Route B: Skills CLI (BMAD main)

npx skills add bmad-code-org/BMAD-METHOD      # BMad core, then run `bmad setup` in your coding tool
npx skills add jrevillard/bmad-issue-tracking  # this module

The Skills CLI reads each skills/<name>/module-manifest.toml; both declare module = "bmad-issue-tracking".

Pinning to a release: the skills CLI treats @<ref> after the package name as a skill name filter, not a git ref — npx skills add jrevillard/bmad-issue-tracking@v3.0.0 looks for a skill named v3.0.0. For release-tag installs, the GitHub URL form is the only reliable syntax (see Development install).

Then, on either route: run the setup skill

/bmad-issue-tracking-setup

This deploys TOML overrides to _bmad/custom/, shared tasks to _bmad/_config/custom/, and configures:

  • issue_tracking.platform (gitlab or github)
  • issue_tracking.enabled (true)
  • issue_tracking.branch_patterns (default: feat/{prd_key}/prd, feat/{prd_key}/{story_key})
  • issue_tracking.host / issue_tracking.project (issue tracker; same keys for GitLab and GitHub) and issue_tracking.git_platform (from the git remote; git_host / git_project only when tracker and remote differ)

prd_key is captured automatically when running /bmad-prd (via activation_steps_append). No manual configuration needed.

Development install

For contributors testing branches or local edits before a release is tagged. Neither route deploys the TOML overrides, workflow YAMLs or the bmad-loop CI gate into your project's _bmad/; you must still run /bmad-issue-tracking-setup afterwards.

Classic installer

npx bmad-method install --directory . --modules bmm --custom-source /absolute/path/to/bmad-issue-tracking --tools claude-code --yes

Local sources are read from disk on every reinstall, no commit needed. A Git URL accepts /tree/<branch> or @<tag> to pick a ref.

Skills CLI, from a GitHub branch or tag

npx skills add https://github.com/jrevillard/bmad-issue-tracking/tree/skills-as-modules   # a branch
npx skills add https://github.com/jrevillard/bmad-issue-tracking/tree/v3.0.0               # a release tag

The CLI clones that ref (not the default branch), so each <skill>/module-manifest.toml is read from it. This is the form the pinning note above refers to.

Skills CLI, from a local clone

npx skills add /absolute/path/to/bmad-issue-tracking

The CLI reports per skill whether it copied or symlinked into the agent directory (.claude/skills/<skill>/, or a canonical .agents/skills/<skill>/). After a copy install, re-run the command after each edit; a symlinked install reads the working tree directly.

Caveats for the Skills CLI dev installs

  • npx skills update won't roll either form forward to a tagged release — you'll need to remove the dev install (npx skills remove) and reinstall via the production command.
  • The bmad setup doctor's state: "blocked" for the bmad-issue-tracking module is expected until you publish a tag matching the manifest's version. The install itself is healthy — only the release comparability check fails.

Development setup

This repo ships only this module's two skills (bmad-issue-tracking-setup, bmad-issue-tracking-sync). BMM core is NOT colocated here.

To test the install flow end-to-end, use a throwaway consumer project — never reinstall BMM into this repo:

One fresh directory per route — the two routes must not share a project.

Classic route (released BMAD); both skills end up registered as module bmad-issue-tracking:

mkdir /tmp/consumer-classic && cd /tmp/consumer-classic && git init
npx bmad-method install --directory . --modules bmm --custom-source /path/to/bmad-issue-tracking --tools claude-code --yes

Skills CLI route (BMAD main); the picker lists exactly 2 skills:

mkdir /tmp/consumer-skills && cd /tmp/consumer-skills && git init
npx skills add bmad-code-org/BMAD-METHOD
npx skills add /path/to/bmad-issue-tracking

uv run --with pytest --with pyyaml pytest runs the suite; tests/test_packaging.py keeps the metadata of both routes in agreement.

What gets installed

Skills (via BMAD installer)

Registered as slash commands in your IDE.

Skill Command Purpose
Sync Issues /bmad-issue-tracking-sync Sync sprint-status.yaml to issues, mark draft PR ready
Setup /bmad-issue-tracking-setup One-time integration setup

TOML overrides (via setup)

Deployed to _bmad/custom/. Survive BMM updates automatically.

Override file Target workflow Hook Behavior
bmad-create-prd.toml create-prd activation_steps_append, on_complete Captures prd_key at activation, creates PRD issue + PRD branch + draft PR/MR on completion. Superseded by bmad-prd.toml
bmad-prd.toml bmad-prd activation_steps_append, on_complete Unified PRD override: detects create/update/validate intent, replaces bmad-create-prd.toml and bmad-edit-prd.toml
bmad-create-architecture.toml create-architecture activation_steps_append, on_complete Switches to PRD worktree at activation, commits and pushes on completion
bmad-ux.toml bmad-ux activation_steps_append, on_complete Switches to PRD worktree at activation, commits and pushes on completion. Replaces bmad-create-ux-design.toml (skill retired in BMM 6.8.0)
bmad-create-epics-and-stories.toml create-epics-and-stories activation_steps_append, on_complete Switches to PRD worktree at activation, commits and pushes on completion
bmad-create-story.toml create-story activation_steps_append, on_complete Sets up story worktree at activation, creates issue + MR on completion (shim — deprecated upstream, bmad-build is the official path)
bmad-dev-story.toml dev-story activation_steps_append, on_complete Switches to story worktree at activation, posts summary, updates status (shim — deprecated upstream, bmad-build is the official path)
bmad-code-review.toml code-review activation_steps_append, on_complete Switches to story worktree at activation, posts review, updates status
bmad-build.toml bmad-build on_complete Manual flow: routes to the interactive dispatcher, which reads the spec status and runs the matching phase of post-dev-complete (push, wait for CI, update issue, comment); offers the optional MR merge on review-finish
bmad-build-auto.toml bmad-build-auto on_complete bmad-loop flow (unattended): routes to the non-interactive dispatcher; same phases plus ci-status.json for the bmad-loop [verify] gate; never prompts and never stages orchestrator-owned files
bmad-sprint-planning.toml sprint-planning activation_steps_append, on_complete Switches to PRD worktree at activation, triggers full issue sync
bmad-sprint-status.toml sprint-status activation_steps_append, on_complete Switches to PRD worktree at activation, triggers full issue sync (consolidated into bmad-sprint-planning in BMM 6.12.0, retained as shim alias)
bmad-edit-prd.toml edit-prd activation_steps_append, on_complete Switches to PRD worktree at activation, updates PRD issue description. Superseded by bmad-prd.toml
bmad-correct-course.toml correct-course activation_steps_append, on_complete Switches to PRD worktree at activation, updates issue descriptions for modified stories/epics/PRD
bmad-retrospective.toml retrospective activation_steps_append, on_complete Switches to PRD worktree at activation, creates issue with retrospective content

Note: All overrides require BMM 6.12.0+ (uniform customize.toml support across all BMM workflows; targets the 6.12.0 skill set).

Shared custom tasks (via setup)

Copied to _bmad/_config/custom/ — referenced by TOML on_complete hooks.

  • bmad-workflow-lang.md — the workflow language specification the TOML hooks reference
  • workflows/issue-sync/ — prepare.yaml (platform, labels, board, PRD issue) and sync.yaml (sync issues, mark MR ready, summary)

Usage

Sync sprint status to issues

/bmad-issue-tracking-sync

Creates/updates issues for all sprint entries, manages labels, reconciles statuses, marks draft PR ready when all epics are done.

One PRD per repository

A project has one PRD and one initiative key, set once. BMM 6.12.0 writes a single {planning_artifacts}/prd.md, and the module derives everything from it: one PRD issue (PRD: <prd-key>), one PRD branch (branch_patterns.prd with the key substituted) and one PRD worktree. bmad-prd reads the intent off that file — a prd.md that already carries a prd_key is an update, whatever the user asked for — so asking to create a second PRD with a new key continues as an update to the existing one and says so. The key lives in the PRD frontmatter; to work on a different initiative, use a different repository.

Issue titles

Issues created by the module follow a fixed naming convention:

Type Title
PRD PRD: <prd-key>
Story Story 1.4: Login Form
Epic Epic 1: Authentication
Retrospective Retrospective: Epic 1

Epic titles are derived from the planning artifacts created by BMM workflows (epics.md). Story titles come from the spec, through common/story-title.yaml: the frontmatter title:, else the first # H1, else the story key's slug segments (1-4-login-form → Login Form). Whichever tier answers, a leading Story N.M: is stripped — the prefix is added once, by the caller.

Branch strategy

When branch_patterns is configured in the setup — one PRD branch per repository, story branches beneath it:

Event Action
PRD created PRD worktree created in activation + draft PR/MR (PRD → default branch)
Story created Story worktree created in activation (from PRD) + issue + MR (story → PRD)
Story developed Story worktree entered, changes committed
Story reviewed Issue status updated, worktree exited (only if MR merged)
All epics done Draft PR/MR marked as ready for review

BMAD Loop integration

The module is compatible with bmad-loop (deterministic orchestrator that drives bmad-build-auto per story in isolated worktrees). bmad-loop is the single writer of sprint-status.yaml; the module mirrors it to issues. Zero user interaction during the run.

Prerequisites: bmad-loop ≥ 0.9.0, BMM ≥ 6.12.0, sprint-status.yaml from bmad-sprint-planning.

Flow:

  1. bmad-loop run — each story is implemented/reviewed/verified in its own worktree and merged back locally. At the end of every bmad-build-auto session, the skill executes its on_complete hook (from bmad-build-auto.toml), which runs common/post-build-dispatch-auto.yaml → common/post-build-dispatch.yaml → common/post-dev-complete.yaml. This unified workflow handles the full lifecycle for the story:
    • dev-finish phase (spec status in-review / in-progress): pushes the code, ensures the issue + trace MR exist (common/ensure-issue.yaml / common/ensure-mr.yaml), waits for CI (common/wait-for-green-ci.yaml), writes ci-status.json (common/write-ci-status.yaml), and updates the issue status. The MR is ensured before the gate: with no MR the gate has nothing to read and writes green.
    • review-finish phase (spec status done): commits review modifications, pushes, posts the review findings comment, mirrors the story to its issue (status label, result comment, MR link), then ensures the trace MR, waits for CI and writes ci-status.json. It ensures the MR for the same reason dev-finish does, and it is the phase where that matters most: bmad-build-auto finalises dev and review in one session, so under bmad-loop review-finish is the only phase a story ever reaches — without the MR the gate read nothing and wrote green.
    • ci-status.sh ([verify] command): reads ci-status.json written by the unified workflow. A red CI fails the verify command (with rich diagnostic), and bmad-loop runs a feedback-driven repair session (re-invoking bmad-build-auto with the diagnostic as feedback) — the story is auto-fixed and re-verified, up to max_dev_attempts, before the merge-back. A missing ci-status.json also fails (fixable) — the on_complete hook did not write it. Only a budget-exhausted CI defers the story (bmad-loop resolve to recover). Nothing else fails it: passed, no_ci (no pipeline defined, or three consecutive empty poll rounds) and no_mr (no remote MR to gate on) all write green. No bmad-loop plugins are needed — the on_complete hook drives everything.
  2. /bmad-issue-tracking-sync — unattended safety net: mirrors the updated sprint-status.yaml to issues (labels, statuses, close done), no worktree required, no prompts.
  3. git push origin main — the local merge-back is never pushed by bmad-loop.

Status mapping (bmad-loop values → module labels):

bmad-loop sprint-status Issue
backlog status::backlog
ready-for-dev status::ready-for-dev
in-progress status::in-progress
review status::review
awaiting-operator status::awaiting-operator (issue stays open — external action pending, confirm with bmad-loop confirm)
done status::done + issue closed

Execution trace: the unified workflow's ensure-mr.yaml ensures a trace MR/PR exists per story (left open) — a CI vehicle and the story's execution trace. After the local merge-back is pushed to the target branch, GitLab auto-marks it merged, keeping the story's diff and pipeline as a durable record. On GitHub there is no auto-detection of an out-of-band merge, so the trace PR would stay open — the close-trace-mr bmad-loop plugin (setup step 5) closes it at post_merge, looking it up with gh api repos/<owner>/<repo>/pulls -X GET -f head=<owner>:<branch> -f state=open and closing only PRs whose head.ref is the branch that was merged. Without the plugin, close it with gh pr close <number> when the story is done.

Migration from ci-wait.sh (if upgrading)

If you're upgrading from a version that used ci-wait.sh:

  1. Re-run /bmad-issue-tracking-setup — it will deploy ci-status.sh and update policy.toml
  2. Delete the old ci-wait.sh: rm .bmad-loop/ci-wait.sh
  3. If you previously installed the story-track-dev / story-track-review bmad-loop plugins (now removed — superseded by the bmad-build-auto.toml on_complete hook): delete them with rm -rf .bmad-loop/plugins/story-track-dev .bmad-loop/plugins/story-track-review and remove them from [plugins] enabled in .bmad-loop/policy.toml.

The architecture is simpler: at the end of every bmad-build-auto session, the skill's on_complete hook (from bmad-build-auto.toml) runs common/post-build-dispatch-auto.yaml → common/post-build-dispatch.yaml → common/post-dev-complete.yaml (dev-finish / review-finish), which pushes code + ensures issue/MR + waits CI + writes ci-status.json + tracks issue. ci-status.sh (verify command) reads the latest ci-status.json. No polling or API calls in the shell script — the workflow does the polling via common/wait-for-green-ci.yaml.

Limits (by design): no MR discussion threads (the MR is a CI vehicle + trace, not a review conversation); mark-mr-ready is not used in this flow.

Platform differences

Aspect GitLab GitHub
CLI glab gh
Labels status::done (double colon) status:done (single colon)
Description file -F "description=@file" --body-file "file"
State changes Single glab api call with state_event Separate gh issue close / gh issue reopen
Label updates -f "labels=..." (replaces all) --add-label / --remove-label (targeted)
Boards Created automatically Skipped in v1
Enterprise -R on subcommands, --hostname on glab api only -R on subcommands, --hostname on gh api only

After BMM updates

  • Skills — classic route: re-run npx bmad-method install (custom sources are refreshed with the rest). Skills CLI route: npx skills update, then run the bmad skill → bmad doctor. On either route re-run /bmad-issue-tracking-setup to refresh the deployed TOML/YAML assets in your _bmad/custom/ and _bmad/_config/custom/workflows/ trees.
  • TOML overrides — no action needed (survive BMM updates unless we rename a workflow).
  • Shared tasks — no action needed

Disabling

Set issue_tracking.enabled: false in _bmad/custom/issue-tracking.yaml.

Troubleshooting

bmad doctor reports state: "blocked" for issue-tracking. Expected until a tag matching the manifest's version is published. The install itself is healthy — only the release comparability check fails. (Dev installs always show this.)

/bmad-issue-tracking-setup says "platform mismatch". Your git remote (origin) and issue tracker are on different platforms (e.g. code on GitLab, issues on GitHub). The setup skill detects the mismatch and asks for the issue tracker host and project explicitly. The git_platform is set from the remote; platform is set from your answer. Issue ops use platform; MR/PR ops use git_platform. See CLAUDE.md § Platform differences.

Stories appear in the wrong issue. Parallel PRDs collide on story keys (1-3-login-form in two PRDs). common/find-issue.yaml is scoped by prd_key — pass it explicitly from the workflow (prd_key is captured during PRD activation and re-derived from prd.md in unattended flows).

/bmad-issue-tracking-sync prompts for prd_key. You're running it without a PRD worktree. Use common/find-prd-key.yaml (auto-resolves from prd.md at the repo root, fails closed) or pass prd_key via the workflow variable scope. The bmad-loop flow runs unattended — see CLAUDE.md § bmad-loop flow.

ci-status.json missing on disk. The on_complete hook didn't run — typically because the build session was interrupted before reaching the hook. Re-run the build to regenerate. The ci-status.sh verify treats missing ci-status.json as fixable (rc=1), so bmad-loop retries via a repair session rather than escalating.

prd_key is empty in _bmad/custom/issue-tracking.yaml. Normal for new installs — it's captured automatically the first time /bmad-create-prd (or bmad-prd with create intent) runs via activation_steps_append. Not a bug.

Configuration

The issue_tracking block in _bmad/custom/issue-tracking.yaml controls the integration:

issue_tracking:
  enabled: true
  platform: gitlab  # or github
  host: gitlab.com  # always configured by setup
  project: group/project  # always configured by setup
  branch_patterns:
    prd: "feat/{prd_key}/prd"
    story: "feat/{prd_key}/{story_key}"
  • platform — required. gitlab or github. Determines which CLI to use (glab / gh).
  • host — required. The issue tracker host (e.g. gitlab.com, github.com, or a self-hosted instance).
  • project — required. The project path (e.g. my-org/my-repo).
  • branch_patterns.prd — required. Pattern for the PRD branch. Must contain {prd_key}.
  • branch_patterns.story — required. Pattern for story branches. Must contain {prd_key} and {story_key}.

Cross-platform scenario: If your code is on GitLab but you want to track issues on GitHub (or vice versa), the setup skill detects the mismatch and asks for the issue tracker host and project explicitly. The git_platform (from the remote) drives MR/PR ops; the platform (from your answer) drives issue ops.

License

Released under the MIT License.

About

Unified BMAD extension module that mirrors sprint tracking to GitLab Issues or GitHub Issues

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages