BMAD Workflow — Agile Story Management
BMAD (Breakthrough Method of Agile AI-driven Development) is the story-authoring and sprint-management workflow for all ktayl-solution and platform development projects. It bridges Claude-assisted story writing, version-controlled story files in minicloud-gitops, and GitHub Issues — with full automation at every step.
Why BMAD?
| Without BMAD | With BMAD |
|---|---|
| Stories written ad-hoc in GitHub Issues — no standard format | Stories versioned in git, reviewed like code |
| No traceability between architecture doc and implementation tasks | Each story references the CdCF section it implements |
| Story duplication when re-running issue creation | Idempotent sync — [S001-slug] prefix prevents duplicates |
| New project sprint setup takes 30+ min | Backstage template generates stubs + opens PR in 2 min |
| Definition of Done inconsistent per engineer | Tech-stack-specific DoD enforced by template |
The Complete Flow
┌─────────────────────────────────────────────────────────────────────┐
│ ENTRY POINTS │
│ │
│ A. Backstage template B. Claude in session C. Manual edit │
│ "New BMAD Sprint" (BMAD agent mode) S00N-slug.md │
└─────────────────┬──────────────────┬───────────────────┬───────────┘
│ │ │
└──────────────────┴───────────────────┘
│
▼
┌────────────────────────────────┐
│ minicloud-gitops │
│ bmad/stories/<proj>/<ms>/ │
│ S001-slug.md │
│ S002-slug.md ... │
└────────────┬───────────────────┘
│ PR merged to main
▼
┌────────────────────────────────┐
│ .github/workflows/ │
│ bmad-sync.yml fires │
│ → bmad-to-github.sh │
└────────────┬───────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ platform-backlog GitHub Issues │
│ [S001-slug] title ← milestone attached │
│ [S002-slug] title ← project board added │
│ ... │
└──────────────────────────────────────────────┘
Repository Layout
Stories live in minicloud-gitops alongside the GitOps manifests:
minicloud-gitops/
├── bmad/
│ ├── templates/
│ │ └── story-template.md # copy this when writing manually
│ └── stories/
│ └── <project-code>/ # e.g. cert-1, claims-service, portal
│ └── <milestone-slug>/ # e.g. m1-m2, m3-m5, sprint-1
│ ├── SPRINT-OVERVIEW.md # generated by Backstage template
│ ├── S001-setup.md
│ ├── S002-domain.md
│ └── ...
└── scripts/
└── bmad-to-github.sh # bridge: YAML frontmatter → GitHub Issues
Story ID convention
S<NNN>-<short-slug> within each sprint directory
S001–S009 core functional stories (domain, API, events, auth)
S010–S019 infrastructure (CI, k8s manifests, ArgoCD, monitoring)
S020+ cross-cutting (security hardening, performance, docs)
IDs reset per sprint directory — cert-1/m3-m5/S001 is different from cert-1/m1-m2/S001.
Path A — Backstage Template (Recommended for new sprints)
The fastest path. No CLI, no manual file creation.
-
Go to Backstage → Create → select New BMAD Sprint
-
Fill in the form:
Field Example Notes Project code cert-1Used as directory name — kebab-case Milestone slug m3-m5Directory name within project GitHub Milestone title CERT-1 M3-M5 — ktayl-claims-service (Java)Must match GitHub exactly Tech stack java-springDrives DoD checklist in stories Story count 6Number of stubs to scaffold -
Backstage generates story stubs and opens a PR on
minicloud-gitops -
Review the PR — open each
S00N-*.mdand fill in domain-specific Acceptance Criteria -
Merge the PR —
bmad-sync.ymlfires and creates all issues onplatform-backlogautomatically
:::tip Before merging the Backstage-generated PR The generated stories have placeholder ACs. Take 30 minutes to fill in the real acceptance criteria from the CdCF before merging — the GitHub Issues should be actionable, not boilerplate. :::
Path B — Claude Session (BMAD agent mode)
For domain-heavy sprints where Claude co-authors the stories from the CdCF.
In a Claude Code session, describe the sprint and reference the CdCF sections:
Write 10 BMAD stories for ktayl-claims-service Sprint M3-M5.
The service is a Java Spring Boot claims management API.
Reference: CdCF §6.2 (BF-SIN-01 to BF-SIN-06), §8 (NATS integration), §9 (data model).
Use the story template at bmad/templates/story-template.md.
Output to bmad/stories/cert-1/m3-m5/
Claude produces fully formed stories with CdCF-referenced ACs, technical notes, and DoD. Review, adjust, commit.
Official BMAD Tools
The BMAD Method provides a set of Claude Code skills that augment our custom workflow. Install once per repo:
npx bmad-method install --directory . --modules bmm --tools claude-code --yes
# Creates _bmad/ directory. Add to .gitignore: /_bmad/
Tool-to-workflow mapping
| When | Use | What it does |
|---|---|---|
| Before writing a story | /bmad-forge-idea | Adversarial pressure-testing — 3 verdicts: hardened / killed / clearer |
| Sprint kick-off | /bmad-sprint-planning | Readiness gate (PASS/CONCERNS/FAIL), produces sprint-status.yaml |
| Writing specs/ACs | /bmad-advanced-elicitation | Pre-mortem, first-principles, red-team analysis |
| Architecture decisions | /bmad-party-mode | Multi-agent design discussion; Anti-Consensus Club template |
| Deep unknowns | /bmad-deep-recon | Structured research: 6 types × 3 modes (discovery/targeted/validation) |
| Story implementation | /bmad-build | Spec-driven autonomous loop: clarify → implement → review → report |
| Autonomous multi-story | /bmad-build-auto | Unattended build loop; exits with blocked or done |
| Post-sprint | [bmad-review] | Evidence-based retrospective; 3 verdicts: accepted / accepted-with-open-items / rejected |
Named agents for story co-authoring
In a Claude session, invoke agents by name to use their specialist persona:
| Agent | Invoke | When |
|---|---|---|
| Mary (BA) | /bmad-agent-mary | Eliciting ACs from CdCF functional requirements |
| John (PM) | /bmad-agent-john | Writing the PRD, prioritisation, MoSCoW |
| Sally (UX) | /bmad-agent-sally | User journeys, edge-case flows |
| Winston (Architect) | /bmad-agent-winston | Technical notes, ADRs, system boundaries |
| Amelia (Dev) | /bmad-agent-amelia | Task breakdown, implementation approach |
Web planning (Gemini Gems / ChatGPT GPTs)
For analysis and planning conversations, BMAD bundles are available as web tools. The design principle: Plan in the web, build in the IDE.
| Bundle | Platform | When |
|---|---|---|
| Product Brief Coach | Gem / GPT | Initial scoping |
| PRD Coach | Gem / GPT | Writing the requirements doc |
| UX Coach | Gem / GPT | User flow design |
| Brainstorming Coach | Gem / GPT | Idea exploration before bmad-forge-idea |
Polished artifacts from web sessions go into bmad/stories/<project>/<ms>/ for git-versioning and the bridge script.
Path C — Manual Story Creation
For adding individual stories to an existing sprint mid-sprint.
# Copy the template
cp bmad/templates/story-template.md \
bmad/stories/cert-1/m1-m2/S011-performance-tests.md
# Edit the story
# Fill in id, title, estimate, labels, milestone, and all sections
Commit and push to main. The bmad-sync.yml action detects the changed file and creates the new issue. Existing issues in the same directory are skipped (idempotent).
Story Format Reference
Every story file has a YAML frontmatter block followed by structured Markdown sections.
Frontmatter
---
id: S001-short-slug # REQUIRED — used as [S001-short-slug] issue title prefix
title: "Full story title" # REQUIRED — GitHub Issue title (prefix added automatically)
status: Ready # Draft | Ready | In Progress | Done
type: Story # Story | Bug | Spike | Task
epic: project-slug # free-form epic grouping
milestone: "CERT-1 M1-M2 — ktayl-policy-service (Go)" # MUST match GitHub Milestone exactly
estimate: 3 # story points — Fibonacci: 1, 2, 3, 5, 8, 13
labels: [go, api, cert-1] # auto-created on platform-backlog if missing
priority: Must # Must | Should | Could | Won't (MoSCoW)
assignee: AndreLiar
---
Mandatory sections
| Section | Purpose |
|---|---|
## Story | User story sentence: "As a {role}, I want {action} so that {benefit}." |
## Background | Context — CdCF section reference, why this story exists |
## Acceptance Criteria | Numbered - [ ] AC-N: checkboxes — testable, unambiguous |
## Definition of Done | Always include: L0 lint ✅ · L1 tests ✅ · PR merged ✅ · ArgoCD Synced ✅ |
## Tasks | Implementation steps as - [ ] TASK-N: checkboxes |
## Dependencies | "Depends on: S002" · "Blocks: S007" |
Optional sections
| Section | When to add |
|---|---|
## Technical Notes | Non-obvious design decisions, gotchas, library choices |
## Spike Notes | For type: Spike — time-boxed investigation questions |
Running the Bridge Script Manually
The script is idempotent — safe to re-run. Issues with [S001-slug] already in their title are skipped.
cd ~/Developer/cloudplateform/minicloud-gitops
# 1. Always dry-run first
bash scripts/bmad-to-github.sh bmad/stories/cert-1/m1-m2 \
--milestone "CERT-1 M1-M2 — ktayl-policy-service (Go)" \
--dry-run
# 2. For real
bash scripts/bmad-to-github.sh bmad/stories/cert-1/m1-m2 \
--milestone "CERT-1 M1-M2 — ktayl-policy-service (Go)"
# Options
# --repo org/repo default: andrelair-platform/platform-backlog
# --project N default: 1 (minicloud platform roadmap)
# --dry-run print actions, create nothing
The script:
- Parses YAML frontmatter with Python (no yq dependency)
- Prefixes the title with
[S001-slug]for deduplication - Auto-creates missing labels on
platform-backlog(grey, update description later) - Attaches each issue to the milestone and project board
- Prints
Created: #250orSkipped (already exists): #250
GitHub Milestone Management
Each sprint has one GitHub Milestone on platform-backlog. The milestone title must match the milestone: field in every story's frontmatter character-for-character (including em-dashes and parentheses).
# Create a milestone before running the bridge script
gh milestone create \
--repo andrelair-platform/platform-backlog \
--title "CERT-1 M3-M5 — ktayl-claims-service (Java)" \
--description "Sprint M3-M5: claims service core + Spring Batch COREP" \
--due-date "2027-01-31"
# Verify it was created
gh api repos/andrelair-platform/platform-backlog/milestones \
--jq '.[] | [.number, .title] | @tsv'
Current milestones
| # | Title | Sprint |
|---|---|---|
| 10 | CERT-1 M0 — Architecture & Cadrage | ✅ Closed |
| 11 | CERT-1 M1-M2 — ktayl-policy-service (Go) | 🟡 Active |
| 12 | CERT-1 M3-M5 — ktayl-claims-service (Java) | ⬜ Planned |
| 13 | CERT-1 M6 — ktayl-ai-claims-assistant (Python) | ⬜ Planned |
| 14 | CERT-1 M7 — ktayl-portal (TypeScript) | ⬜ Planned |
| 15 | CERT-1 M8 — Integration & UAT | ⬜ Planned |
Label Conventions
| Label | Stack / Layer |
|---|---|
go java python typescript | Primary language |
backend frontend devops | Architecture layer |
api database domain-logic | Code area |
ci gitops kubernetes | Platform area |
security testing observability | Cross-cutting concern |
cert-1 claims-service portal | Project scope |
Labels are auto-created (grey) by the bridge script if they don't exist. To update descriptions/colours:
gh label edit "cert-1" \
--color "7c3aed" \
--description "CERT-1 / RNCP39583 deliverable" \
--repo andrelair-platform/platform-backlog
Project Codes Registry
| Code | Project | Tech stack | Milestones |
|---|---|---|---|
cert-1 | ktayl Claims & Policy Platform (RNCP39583) | Go → Java → Python → TypeScript | m0 → m1-m2 → m3-m5 → m6 → m7 → m8 |
To register a new project: add a row to this table and create the GitHub Milestones before the first sprint.
The GitHub Action (bmad-sync.yml)
The action at .github/workflows/bmad-sync.yml in minicloud-gitops:
- Trigger: push to
mainwith changes tobmad/stories/**/*.md - What it does: detects changed sprint directories, reads the
milestone:field from the first story's frontmatter, runsbmad-to-github.shfor each directory - Auth: uses
GITOPS_TOKENorg-level secret (already set, no configuration needed) - Idempotent: existing issues detected by
[S001-slug] in:titlesearch and skipped
:::note Adding stories to an existing sprint
Just create the new SNNN-slug.md file, commit to main. The action fires, skips the 10 existing issues, creates only the new one.
:::
Troubleshooting
"milestone not found" warning
The milestone: frontmatter value doesn't match any GitHub Milestone title exactly. Check for:
- Trailing spaces
- Wrong dash type (use
—em-dash, not–or-) - Wrong milestone title (compare with
gh api repos/.../milestones --jq '.[].title')
Duplicate issues created
The [S001-slug] prefix is missing from the issue title. This happens if issues were created by an old version of the script (before the prefix convention). Fix:
gh issue edit <number> \
--repo andrelair-platform/platform-backlog \
--title "[S001-short-slug] Original title here"
Label not found error
Older script versions required labels to exist before running. The current script creates missing labels automatically. Update the script: git pull origin main in minicloud-gitops.
Backstage template shows "not found"
The backstage-values.yaml in minicloud-gitops registers the template URL. After merging PR #696, ArgoCD syncs the ConfigMap, then kubectl rollout restart deployment/backstage -n backstage applies it. Template appears in Backstage within ~1 minute.