feat(diagrams): add BMM workflow diagram generation system

Add D2-based diagram generation for BMM workflow visualization:

- bmm-workflow.d2: Main BMM workflow diagram with 4 phases
- quick-flow.d2: Quick Flow overlay diagram
- workflow-manifest.yaml: Machine-readable workflow structure
- generate-bmm-workflow-diagram.md: Prompt for diagram generation
- generate-manifest.md: Prompt for manifest maintenance
- post-process-svg.py: SVG post-processing (labels, legend, stamp)
- composite-quickflow.py: Proportional scaling and overlay compositing
- Fonts for technical/monospace aesthetic

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Alex Verkhovsky 2025-11-30 07:45:43 -07:00
parent c79d081128
commit b88cbe2ab7
17 changed files with 4805 additions and 0 deletions

3
docs/diagrams/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
*.png
*.jpg
*.svg

257
docs/diagrams/README.md Normal file
View File

@ -0,0 +1,257 @@
# BMM Workflow Diagram
This directory contains the BMM (BMad Method) workflow diagram and tools for generating it.
## Files
| File | Description |
| ---------------------------------- | --------------------------------------------------- |
| `workflow-manifest.yaml` | Workflow structure manifest (source of truth) |
| `generate-manifest.md` | Agentic prompt to generate/update manifest |
| `bmm-workflow.d2` | D2 source diagram |
| `bmm-workflow.svg` | Vector output (74KB) |
| `bmm-workflow.png` | Standard PNG (1600×1502, 257KB) |
| `bmm-workflow-print.png` | High-res for Nano-Banana input (4000×3755, 732KB) |
| `bmm-workflow-vintage.jpg` | Print-ready vintage version (2144×1984, 1.1MB) |
| `bmm-workflow-vintage-web.jpg` | Web-optimized vintage (1400×1296, 281KB) |
| `generate-bmm-workflow-diagram.md` | Generation prompt for Claude |
| `gracefully-age.prompt.md` | Nano-Banana Pro prompt for vintage treatment |
| `post-process-svg.py` | SVG post-processing (labels, title, legend, footer) |
| `red-herring.png` | Fish stamp asset |
| `fonts/` | ShareTechMono font files |
## Workflow Manifest System
The workflow manifest (`workflow-manifest.yaml`) is the **source of truth** for BMM workflow structure. It contains:
- All workflows organized by phase
- Workflow connections and dependencies
- Decision points (e.g., "Has UI?")
- Feedback loops (e.g., code review → dev)
- Cross-phase connections
- Output file patterns
### Generating/Updating the Manifest
Use the `generate-manifest.md` agentic prompt to create or update the manifest:
1. Feed `generate-manifest.md` to an agentic LLM (Claude, Gemini, etc.)
2. The agent will:
- Scan `src/modules/bmm/workflows/` for all workflows
- Extract workflow names, descriptions, and outputs from `workflow.yaml` files
- Build the manifest with all connections and dependencies
- Compare with existing manifest (if present)
- **HARD STOP** if Quick Flow changes detected
- Prompt for approval if main workflow changes detected
- Write updated manifest to `workflow-manifest.yaml`
### When to Regenerate
Regenerate the manifest when:
- Adding new workflows
- Removing workflows
- Changing workflow outputs
- Changing workflow connections or dependencies
- Updating Quick Flow workflows (requires careful review)
### Change Detection
The manifest system includes intelligent change detection:
- **Quick Flow changes**: HARD STOP - these are critical paths
- **Main workflow changes**: User approval required
- **No changes**: Proceeds silently
## Generation Pipeline
### Step 1: Generate Base Diagram
Run the generation prompt with Claude:
```bash
# Claude will read generate-bmm-workflow-diagram.md and:
# 1. Analyze BMM workflow structure
# 2. Generate/update bmm-workflow.d2
# 3. Run d2 to create SVG
# 4. Post-process SVG
# 5. Convert to PNG
```
Or manually:
```bash
# Generate SVG from D2
d2 --font-regular=fonts/ShareTechMono-Regular.ttf \
--font-bold=fonts/ShareTechMono-Regular.ttf \
bmm-workflow.d2 bmm-workflow-technical.svg
# Post-process (shrink labels, outline title, add legend/footer/stamp)
python3 post-process-svg.py
# Convert to standard PNG
rsvg-convert bmm-workflow.svg -w 1600 -o bmm-workflow.png
# Convert to high-res PNG for Nano-Banana
rsvg-convert bmm-workflow.svg -w 4000 -o bmm-workflow-print.png
# Clean up
rm bmm-workflow-technical.svg
```
### Step 2: Vintage Treatment with Nano-Banana Pro
1. Go to [Nano-Banana Pro](https://nanobanana.org/) or use via Pixlr/Recraft
2. Upload `bmm-workflow-print.png` (the 4000px version)
3. Use the prompt from `gracefully-age.prompt.md`:
- Applies aged paper texture, fold creases, coffee stains
- Adds ink bleed and printing artifacts
- Preserves all text, boxes, and arrows exactly
- Does NOT apply sepia/fading (original colors are already vintage-toned)
4. Download the result (will be named something like `Gemini_Generated_Image_*.png`)
### Step 3: Remove the Watermark
Nano-Banana Pro adds a 4-pointed star watermark in the lower-right corner. Remove it:
```bash
# Set input file (adjust filename as needed)
INPUT=~/Downloads/Gemini_Generated_Image_XXXXX.png
# Find the watermark location (it's near the fish, bottom-right)
# The watermark is approximately at position (1950-2060, 1790-1900)
# Remove watermark by patching with nearby paper texture
magick "$INPUT" \
\( -clone 0 -crop 120x120+1950+1680 +repage \
\( -size 120x120 xc:black -fill white -draw "circle 60,60 60,5" -blur 0x12 \) \
-alpha off -compose CopyOpacity -composite \) \
-geometry +1950+1795 -compose over -composite \
bmm-workflow-vintage-clean.png
```
**How this works:**
- Crops a 120×120 patch of clean paper texture from above the watermark (at +1950+1680)
- Creates a circular feathered mask to blend edges
- Composites the patch over the watermark location (+1950+1795)
**Verify the fix:**
```bash
# Crop the corner to check
magick bmm-workflow-vintage-clean.png -crop 600x600+1544+1384 /tmp/check.png
open /tmp/check.png # or use any image viewer
```
The fish should be intact, watermark gone, no visible patch edges.
### Step 4: Fix the Legend
Nano-Banana garbles the small text in the legend. Fix by:
1. Covering the garbled text with vintage paper texture
2. Applying clean text with darken blend (preserves texture, shows text)
```bash
# Extract legend content from original (without outer borders)
magick bmm-workflow-print.png -crop 1600x450+1950+250 /tmp/legend-orig.png
magick /tmp/legend-orig.png -shave 25x25 /tmp/legend-content.png
# Scale to match Nano-Banana output
magick /tmp/legend-content.png -resize 831x211! /tmp/legend-content-scaled.png
# Sample clean paper texture (find an empty area - e.g., right of title)
magick bmm-workflow-vintage-clean.png -crop 100x100+900+120 /tmp/texture-patch.png
# Tile texture to cover legend area
magick /tmp/texture-patch.png -write mpr:tile +delete \
-size 850x220 tile:mpr:tile /tmp/texture-tiled.png
# Cover garbled legend with tiled texture
magick bmm-workflow-vintage-clean.png \
/tmp/texture-tiled.png -geometry +1055+143 -composite \
/tmp/vintage-erased.png
# Apply clean text with darken blend (white becomes transparent)
magick /tmp/vintage-erased.png \
/tmp/legend-content-scaled.png \
-geometry +1059+147 -compose darken -composite \
bmm-workflow-vintage-fixed.png
```
**Verify:**
```bash
magick bmm-workflow-vintage-fixed.png -crop 700x350+900+80 /tmp/legend-check.png
open /tmp/legend-check.png
```
The legend should have clean text on vintage paper texture, with box borders preserved.
### Step 5: Create Final Versions
```bash
# Print version (JPEG, 92% quality)
magick bmm-workflow-vintage-fixed.png \
-quality 92 \
bmm-workflow-vintage.jpg
# Web version (1400px wide, 85% quality)
magick bmm-workflow-vintage-fixed.png \
-resize 1400x \
-quality 85 \
bmm-workflow-vintage-web.jpg
# Clean up
rm bmm-workflow-vintage-clean.png bmm-workflow-vintage-fixed.png
```
**File sizes:**
- Print: ~1.1MB (2144×1984 at 92% JPEG)
- Web: ~280KB (1400×1296 at 85% JPEG)
## Troubleshooting
### Watermark in wrong position
The watermark location varies slightly between Nano-Banana runs. To find it:
```bash
# Create a corner crop to locate the watermark
magick input.png -crop 600x600+1544+1384 /tmp/corner.png
open /tmp/corner.png
```
Look for the 4-pointed star shape near the fish. Adjust the patch coordinates accordingly.
### Patch is visible
If the patched area looks different from surroundings:
- Sample texture from a different location (try areas with similar color/texture)
- Increase blur radius for softer blending
- Use a smaller patch size
### Colors too dark/faded after Nano-Banana
The prompt in `gracefully-age.prompt.md` explicitly tells Nano-Banana NOT to apply sepia/fading since our original colors are already vintage-toned. If results are too dark, emphasize this more in the prompt.
### Legend position is off
The legend position depends on the Nano-Banana output dimensions. If dimensions differ from 2144×1984:
1. Calculate new scale factors: `new_width/4000` and `new_height/3755`
2. Adjust crop position: `1950 * width_scale`, `250 * height_scale`
3. Adjust legend size: `1600 * width_scale`, `450 * height_scale`
## Dependencies
- [D2](https://d2lang.com/) - Diagram scripting language
- [rsvg-convert](https://wiki.gnome.org/Projects/LibRsvg) - SVG to PNG conversion
- [ImageMagick](https://imagemagick.org/) (magick command) - Image manipulation
- Python 3 - For post-processing scripts

View File

@ -0,0 +1,308 @@
direction: down
# Top-level vertical layout
grid-rows: 4
grid-columns: 1
grid-gap: 20
# Title row - left aligned via grid
title-row: "" {
style.fill: transparent
style.stroke: transparent
grid-rows: 1
grid-columns: 1
horizontal-gap: 0
title: "BMAD METHOD V6.0.0-ALPHA.12" {
style.fill: transparent
style.stroke: transparent
style.font-size: 48
style.bold: true
style.font-color: "#1a3a5c"
label.near: top-left
}
}
# Legend - positioned near title-row (handled by inject-legend.py post-processor)
vars: {
d2-config: {
layout-engine: elk
}
}
classes: {
phase1-box: {
style: {
fill: "#e8f4f8"
stroke: "#2d7d9a"
stroke-width: 3
border-radius: 12
font-size: 27
bold: true
font-color: "#1a5568"
}
}
phase2-box: {
style: {
fill: "#f0e8f8"
stroke: "#7d2d9a"
stroke-width: 3
border-radius: 12
font-size: 27
bold: true
font-color: "#4a1a68"
}
}
phase3-box: {
style: {
fill: "#f8f0e8"
stroke: "#9a7d2d"
stroke-width: 3
border-radius: 12
font-size: 27
bold: true
font-color: "#685a1a"
}
}
phase4-box: {
style: {
fill: "#e8f8f0"
stroke: "#2d9a7d"
stroke-width: 3
border-radius: 12
font-size: 27
bold: true
font-color: "#1a684a"
}
}
entry: {
style: {
fill: "#333"
stroke: "#111"
stroke-width: 2
border-radius: 8
font-size: 27
font-color: "#fff"
bold: true
}
}
n1: {
style: {
fill: "#fff"
stroke: "#2d7d9a"
stroke-width: 2
border-radius: 4
font-size: 27
}
}
n2: {
style: {
fill: "#fff"
stroke: "#7d2d9a"
stroke-width: 2
border-radius: 4
font-size: 27
}
}
n3: {
style: {
fill: "#fff"
stroke: "#9a7d2d"
stroke-width: 2
border-radius: 4
font-size: 27
}
}
n4: {
style: {
fill: "#fff"
stroke: "#2d9a7d"
stroke-width: 2
border-radius: 4
font-size: 27
}
}
decision: {
shape: diamond
style: {
fill: "#fff8e8"
stroke: "#7d2d9a"
stroke-width: 2
font-size: 27
}
}
opt: {
style: {
fill: "#f8f8f8"
stroke: "#888"
stroke-width: 2
stroke-dash: 5
border-radius: 4
font-size: 27
}
}
}
# Entry point row - positioned above border between Phase 1 and 2
init-row: "" {
style.fill: transparent
style.stroke: transparent
grid-rows: 1
grid-columns: 4
grid-gap: 25
spacer-left: "" { style.opacity: 0 }
init: "/workflow-init\n@bmm-workflow-status.yaml" { class: n1 }
spacer-right1: "" { style.opacity: 0 }
spacer-right2: "" { style.opacity: 0 }
}
# Lanes container (horizontal) - wider gaps for A4 landscape ratio
lanes: "" {
style.fill: transparent
style.stroke: transparent
grid-rows: 1
grid-columns: 4
grid-gap: 90
# PHASE 1: DISCOVERY - activities in any order, ending with Product Brief
phase1: "PHASE 1: DISCOVERY\n " {
class: phase1-box
style.stroke-dash: 5
width: 400
# Group of parallel/unordered activities - stacked vertically
activities: "Activities (any order)" {
style.fill: "transparent"
style.stroke: "#2d7d9a"
style.stroke-dash: 3
style.font-size: 26
style.font-color: "#666"
style.italic: true
style.border-radius: 8
grid-rows: 4
grid-columns: 1
grid-gap: 6
brain: "/brainstorm" { class: n1 }
research: "/research" { class: n1 }
domain: "/domain-research" { class: n1 }
doc: "/document-project" { class: n1 }
}
brief: "/product-brief\n@product-brief.md" { class: n1 }
activities -> brief
}
# PHASE 2: PLANNING - no internal grid
phase2: "PHASE 2: PLANNING\n " {
class: phase2-box
width: 350
tech: "/tech-spec\n@tech-spec.md" { class: opt }
prd: "/prd\n@PRD.md" { class: n2 }
hasui: "Has UI?" { class: decision }
ux: "/ux-design\n@ux-design.md" { class: n2 }
# Force Tech Spec above PRD
tech -> prd: { style.opacity: 0 }
prd -> hasui
hasui -> ux: Yes
}
# PHASE 3: SOLUTIONING - no internal grid
phase3: "PHASE 3: SOLUTIONING\n " {
class: phase3-box
width: 400
# Invisible spacer to push content down
spacer: "" {
style.opacity: 0
height: 60
}
arch: "/architecture\n@architecture.md" { class: n3 }
epics: "/create-epics-and-stories\n@epics.md" { class: n3 }
impl: "/implementation-readiness\n@impl-readiness-report.md" { class: n3 }
spacer -> arch: { style.opacity: 0 }
arch -> epics
epics -> impl
}
# PHASE 4: IMPLEMENTATION - no internal grid, let loops show
phase4: "PHASE 4: IMPLEMENTATION\n " {
class: phase4-box
width: 520
sprint: "/sprint-planning\n@sprint-status.yaml" { class: n4 }
create: "/create-story\n@{epic}-{story}-*.md" { class: n4 }
dev: "/dev-story" { class: n4 }
review: "/code-review" { class: n4 }
done: "/story-done" { class: n4 }
retro: "/retrospective" { class: n4 }
# Standalone utility - not connected to main flow, forced to bottom
course-container: "" {
style.fill: transparent
style.stroke: transparent
grid-rows: 2
grid-columns: 1
grid-gap: 4
course: "/correct-course\n@sprint-change-proposal.md" { class: n4 }
course-label: "(run when issues arise)" {
style.fill: transparent
style.stroke: transparent
style.font-size: 21
style.italic: true
style.font-color: "#666"
}
}
# Force course-container below dev (the lowest node in the flow)
dev -> course-container: { style.opacity: 0 }
# Main flow
sprint -> create
create -> dev
dev -> review
review -> done
done -> retro
# Feedback loops - these should now be visible
review -> dev: fixes { style.stroke-dash: 3; style.stroke: "#f57c00"; style.font-size: 21; style.italic: true }
done -> create: next story { style.stroke-dash: 3; style.stroke: "#f57c00"; style.font-size: 21; style.italic: true }
retro -> sprint: next epic { style.stroke-dash: 3; style.stroke: "#f57c00"; style.font-size: 21; style.italic: true }
}
}
# Entry to lanes
init-row.init -> lanes.phase1.activities: { style.stroke: "#2d7d9a"; style.stroke-width: 2 }
init-row.init -> lanes.phase2.tech: Quick-flow { style.stroke-dash: 5; style.stroke: "#999"; style.font-size: 21; style.italic: true }
# Cross-phase flows
lanes.phase1.brief -> lanes.phase2.prd
lanes.phase2.hasui -> lanes.phase3.arch: No
lanes.phase2.ux -> lanes.phase3.arch
lanes.phase2.tech -> lanes.phase3.epics: { style.stroke-dash: 5; style.stroke: "#999" }
lanes.phase3.impl -> lanes.phase4.sprint
# Footer row
footer-row: "" {
style.fill: transparent
style.stroke: transparent
footer: "DRAFTED: 2025-11-29 • REPOSITORY: github.com/bmad-code-org/BMAD-METHOD • LICENSE: MIT • UNCLASSIFIED • DISTRIBUTION: UNLIMITED • SUPERSEDES: ALL PREVIOUS EDITIONS" {
style.fill: transparent
style.stroke: transparent
style.font-size: 21
style.font-color: "#555"
style.italic: true
label.near: bottom-left
}
}

View File

@ -0,0 +1,139 @@
#!/usr/bin/env python3
"""
Composite Quick Flow diagram onto main BMM workflow as a paper overlay.
SCALING PRINCIPLE: Both diagrams use the same font sizes in D2 (27px for workflow boxes).
To maintain visual consistency, the Quick Flow must be scaled by the same factor as the
main diagram. This is calculated from the SVG viewBox dimensions and target PNG width.
Formula:
scale_factor = main_png_width / main_svg_native_width
quick_flow_width = quick_flow_svg_native_width * scale_factor
"""
import re
from PIL import Image, ImageDraw, ImageFilter
# Configuration
MAIN_SVG = "bmm-workflow.svg"
MAIN_IMAGE = "bmm-workflow.png"
OVERLAY_SVG = "quick-flow.svg"
OVERLAY_IMAGE = "quick-flow.png"
OUTPUT_IMAGE = "bmm-workflow-with-quickflow.png"
# Overlay positioning
OVERLAY_X = 150 # Left margin
OVERLAY_Y_FROM_BOTTOM = 140 # Distance from bottom
# Paper effect settings
SHADOW_OFFSET = 0
SHADOW_BLUR = 0
SHADOW_COLOR = (0, 0, 0, 0)
BORDER_COLOR = (255, 255, 255) # No visible border
BORDER_WIDTH = 0
PAPER_PADDING = 0
ROTATION_ANGLE = -5 # 5° clockwise
def get_svg_native_width(svg_path):
"""Extract native width from SVG viewBox attribute."""
with open(svg_path, 'r') as f:
content = f.read()
# Match the first viewBox (the main SVG element)
match = re.search(r'viewBox="[0-9.-]+\s+[0-9.-]+\s+([0-9.]+)\s+[0-9.]+"', content)
if match:
return float(match.group(1))
raise ValueError(f"Could not find viewBox in {svg_path}")
def add_paper_effect(overlay):
"""Add paper-like styling: padding, border, shadow."""
# Add padding (white border around content)
padded_w = overlay.width + PAPER_PADDING * 2
padded_h = overlay.height + PAPER_PADDING * 2
paper = Image.new('RGBA', (padded_w, padded_h), (255, 255, 255, 255))
paper.paste(overlay, (PAPER_PADDING, PAPER_PADDING))
# Draw border
draw = ImageDraw.Draw(paper)
draw.rectangle(
[0, 0, padded_w - 1, padded_h - 1],
outline=BORDER_COLOR,
width=BORDER_WIDTH
)
# Slight rotation for natural "placed" look
paper = paper.rotate(ROTATION_ANGLE, expand=True, fillcolor=(255, 255, 255, 0), resample=Image.BICUBIC)
# Create shadow
shadow_size = (paper.width + SHADOW_OFFSET * 2 + SHADOW_BLUR * 2,
paper.height + SHADOW_OFFSET * 2 + SHADOW_BLUR * 2)
shadow = Image.new('RGBA', shadow_size, (0, 0, 0, 0))
# Draw shadow rectangle
shadow_draw = ImageDraw.Draw(shadow)
shadow_draw.rectangle(
[SHADOW_BLUR + SHADOW_OFFSET,
SHADOW_BLUR + SHADOW_OFFSET,
SHADOW_BLUR + SHADOW_OFFSET + paper.width,
SHADOW_BLUR + SHADOW_OFFSET + paper.height],
fill=SHADOW_COLOR
)
shadow = shadow.filter(ImageFilter.GaussianBlur(SHADOW_BLUR))
# Composite paper onto shadow
shadow.paste(paper, (SHADOW_BLUR, SHADOW_BLUR), paper)
return shadow
def main():
# Load images
main_img = Image.open(MAIN_IMAGE).convert('RGBA')
overlay_img = Image.open(OVERLAY_IMAGE).convert('RGBA')
print(f"Main image: {main_img.size}")
print(f"Overlay image: {overlay_img.size}")
# Calculate proportional scale factor from SVG dimensions
main_svg_width = get_svg_native_width(MAIN_SVG)
overlay_svg_width = get_svg_native_width(OVERLAY_SVG)
scale_factor = main_img.width / main_svg_width
target_overlay_width = int(overlay_svg_width * scale_factor)
print(f"Main SVG native width: {main_svg_width}px")
print(f"Overlay SVG native width: {overlay_svg_width}px")
print(f"Scale factor: {scale_factor:.4f}")
print(f"Target overlay width: {target_overlay_width}px")
# Resize overlay to maintain font scale parity
aspect = overlay_img.height / overlay_img.width
new_height = int(target_overlay_width * aspect)
overlay_img = overlay_img.resize((target_overlay_width, new_height), Image.LANCZOS)
print(f"Overlay resized to: {overlay_img.size}")
# Add paper effect
paper_overlay = add_paper_effect(overlay_img)
# Calculate position (bottom-left area)
pos_x = OVERLAY_X
pos_y = main_img.height - paper_overlay.height - OVERLAY_Y_FROM_BOTTOM
print(f"Placing overlay at: ({pos_x}, {pos_y})")
# Composite
main_img.paste(paper_overlay, (pos_x, pos_y), paper_overlay)
# Save (convert to RGB for PNG without alpha issues)
main_img = main_img.convert('RGB')
main_img.save(OUTPUT_IMAGE, 'PNG')
print(f"Saved: {OUTPUT_IMAGE}")
if __name__ == "__main__":
main()

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -0,0 +1,284 @@
# Generate BMM Workflow Diagram
This prompt generates a D2 diagram showing the BMad Method (BMM) workflow phases and their workflows.
## Instructions
Read workflow structure from the manifest and generate a D2 diagram with the following specifications:
### 1. Load Workflow Manifest
Read `docs/diagrams/workflow-manifest.yaml` to get:
- **Version info**: `bmad_version` for the diagram title
- **Entry point**: `entry.workflow-init` with its output file
- **Phases**: All 4 phases (discovery, planning, solutioning, implementation)
- Phase labels, directories, optional flags
- Workflows within each phase (id, name, outputs)
- Connections within phases
- Decision points (e.g., "Has UI?")
- Feedback loops (Phase 4)
- **Quick Flow**: Separate diagram with its own entry and workflows
- **Cross-phase connections**: How phases connect to each other
- **Legend**: All output documents with descriptions
**Do NOT scan the codebase** - all workflow information is in the manifest.
### 2. Diagram Structure
```
direction: down
# Top-level vertical layout
grid-rows: 3
grid-columns: 1
grid-gap: 20
# Row 1: Title
title: "BMAD METHOD V{VERSION}" # Uppercase for blueprint aesthetic
To get version:
1. Read `bmad_version` from workflow-manifest.yaml
2. Use verbatim with "V" prefix uppercase: e.g., "6.0.0-alpha.12" → "V6.0.0-ALPHA.12"
# Row 2: Entry point (workflow-init)
# Position above border between Phase 1 and 2 using spacers:
init-row with grid-columns: 4
- 1 spacer left
- workflow-init box
- 2 spacers right
# Row 3: Lanes container
lanes with grid-columns: 4 for 4 phases side-by-side
```
### 3. Phase Layout
Use ELK layout engine for better container width support:
```d2
vars: {
d2-config: {
layout-engine: elk
}
}
```
Each phase is a colored container with explicit width for A4 landscape ratio:
- **Phase 1 (Discovery)**: Teal/cyan (#e8f4f8), dashed border (optional phase), width: 400
- Contains "Activities (any order)" sub-container
- All activities flow to product-brief
- **Phase 2 (Planning)**: Purple/lavender (#f0e8f8), width: 350
- tech-spec at top (quick-flow entry point)
- prd → Has UI? → ux-design flow
- **Phase 3 (Solutioning)**: Gold/amber (#f8f0e8), width: 400
- Vertical flow: architecture → epics-and-stories → impl-readiness
- **Phase 4 (Implementation)**: Green/mint (#e8f8f0), width: 520
- Vertical flow with feedback loops (orange dashed)
- Loops: fixes (review→dev), next story (dev→create), next epic (retro→sprint)
Set `grid-gap: 90` on lanes container to achieve ~1.41:1 A4 landscape ratio.
### 4. Naming Convention
All workflow boxes use:
- Forward slash prefix: `/workflow-name`
- Kebab-case: `/sprint-planning`, `/code-review`
- Decision diamonds don't get slashes: "Has UI?"
### 5. Output Document Labels
Workflows that produce artifacts show the output filename on a second line:
```d2
# Use newline to show output document
brief: "/product-brief\n@product-brief.md" { class: n1 }
prd: "/prd\n@PRD.md" { class: n2 }
```
**Get output documents from the manifest:**
- Read each workflow's `outputs` array
- For each output file, show it on a second line with the workflow name
- Example: If workflow `product-brief` has output `@product-brief.md`, render as `/product-brief\n@product-brief.md`
Post-process SVG to make `@*` lines smaller (14px) and gray (#777):
```python
# In shrink-output-labels.py
pattern = r'<tspan[^>]*>@[^<]*</tspan>'
# Add: font-size="14px" fill="#777777"
```
### 6. Cross-Phase Connections
**Get connections from the manifest:**
- Read `cross_phase_connections` array for main diagram connections
- Read `phases.*.connections` for within-phase connections
- Read `phases.*.decisions` for decision points
- Read `phases.*.feedback_loops` for Phase 4 loops
**Note**: Quick-flow is a separate diagram (not connected to main diagram)
### 7. Styling Classes
```d2
classes: {
phase1-box: { fill: "#e8f4f8", stroke: "#2d7d9a", stroke-width: 3, border-radius: 12 }
phase2-box: { fill: "#f0e8f8", stroke: "#7d2d9a", stroke-width: 3, border-radius: 12 }
phase3-box: { fill: "#f8f0e8", stroke: "#9a7d2d", stroke-width: 3, border-radius: 12 }
phase4-box: { fill: "#e8f8f0", stroke: "#2d9a7d", stroke-width: 3, border-radius: 12 }
n1: { fill: "#fff", stroke: "#2d7d9a", stroke-width: 2, border-radius: 4, font-size: 18 }
n2: { fill: "#fff", stroke: "#7d2d9a", stroke-width: 2, border-radius: 4, font-size: 18 }
n3: { fill: "#fff", stroke: "#9a7d2d", stroke-width: 2, border-radius: 4, font-size: 18 }
n4: { fill: "#fff", stroke: "#2d9a7d", stroke-width: 2, border-radius: 4, font-size: 18 }
decision: { shape: diamond, fill: "#fff8e8", stroke: "#7d2d9a" }
opt: { stroke: "#888", fill: "#f8f8f8", stroke-dash: 5 }
}
```
### 8. Title Styling
Title should be:
- Large font (48px)
- Bold
- Uppercase
- Dark blue color (#1a3a5c)
Post-process to apply outline/hollow letter effect:
```python
# In outline-title.py - make title have stroke but no fill
pattern = r'(<text[^>]*)(fill="#[^"]*")([^>]*style="[^"]*font-size:48px">BMAD METHOD[^<]*</text>)'
replacement = r'\1fill="none" stroke="#1a3a5c" stroke-width="2"\3'
```
### 9. Font
Use ShareTechMono for technical/monospace aesthetic:
```bash
d2 --font-regular=fonts/ShareTechMono-Regular.ttf \
--font-bold=fonts/ShareTechMono-Regular.ttf \
bmm-workflow.d2 bmm-workflow.svg
```
### 10. Output Generation
Generate files in this order:
1. `bmm-workflow.d2` - the diagram source
2. Generate base SVG:
```bash
d2 --font-regular=fonts/ShareTechMono-Regular.ttf \
--font-bold=fonts/ShareTechMono-Regular.ttf \
bmm-workflow.d2 bmm-workflow-technical.svg
```
3. Post-process for output label styling:
```bash
python3 scripts/shrink-output-labels.py bmm-workflow-technical.svg bmm-workflow.svg
```
4. Post-process for outline title:
```bash
python3 scripts/outline-title.py bmm-workflow.svg bmm-workflow.svg
```
5. Left-align the title:
```bash
python3 scripts/left-align-title.py bmm-workflow.svg bmm-workflow.svg
```
6. Inject legend into top-right:
```bash
python3 scripts/inject-legend.py bmm-workflow.svg bmm-workflow.svg
```
7. Convert to PNG (max width 1600px to keep file size reasonable):
```bash
rsvg-convert bmm-workflow.svg -w 1600 -o bmm-workflow.png
```
8. Verify PNG size before reading (must check dimensions first):
```bash
identify bmm-workflow.png # Should be ~1600x1150 or smaller
```
If dimensions exceed 1600px width, regenerate with `-w 1600` flag.
9. Clean up intermediate file:
```bash
rm bmm-workflow-technical.svg
```
### 11. Post-Processing Scripts
Located in `scripts/` directory:
**shrink-output-labels.py** - Makes `@*.md` labels smaller and gray
**outline-title.py** - Applies hollow/outline effect to title text
### 12. Self-Check
Before finalizing, verify the following:
**Manifest Loading:**
- [ ] workflow-manifest.yaml loaded successfully
- [ ] Version extracted from manifest for title
- [ ] All 4 phases read from manifest
- [ ] Quick-flow section read from manifest
- [ ] All connections and decisions extracted
**Layout & Structure**
- [ ] Four phases displayed horizontally (left to right: Discovery → Planning → Solutioning → Implementation)
- [ ] Phase 1 has dashed border (optional phase)
- [ ] Phases 2-4 have solid borders
- [ ] All workflow boxes are consistent sizes (not shrunk or expanded)
- [ ] Aspect ratio is approximately 1.41:1 (A4 landscape)
**Workflow Boxes**
- [ ] All workflow names start with `/` prefix
- [ ] Decision diamond ("Has UI?") has no `/` prefix
- [ ] Workflows with outputs show `@filename.md` on second line
- [ ] Output labels are smaller and grayed (after post-processing)
**Connections**
- [ ] `/workflow-init` connects to Phase 1 activities (solid line)
- [ ] `/workflow-init` connects to `/tech-spec` (dashed line, "Quick-flow" label)
- [ ] `/product-brief``/prd` connection exists
- [ ] "Has UI?" diamond has "Yes" → `/ux-design` and "No" → `/architecture`
- [ ] `/tech-spec``/epics-and-stories` (dashed line, quick-flow path)
- [ ] `/impl-readiness``/sprint-planning` connection exists
**Phase 4 Feedback Loops**
- [ ] `/code-review``/dev-story` loop exists (orange dashed, "fixes" label)
- [ ] `/dev-story``/create-story` loop exists (orange dashed, "next story" label)
- [ ] `/retrospective``/sprint-planning` loop exists (orange dashed, "next epic" label)
**Title**
- [ ] Title is uppercase: "BMAD METHOD V{VERSION}"
- [ ] Title has outline/hollow letter effect (after post-processing)
- [ ] Version matches current release tag
**Output Documents**
- [ ] `/product-brief` shows `@product-brief.md`
- [ ] `/tech-spec` shows `@tech-spec.md`
- [ ] `/prd` shows `@PRD.md`
- [ ] `/ux-design` shows `@ux-design.md`
- [ ] `/architecture` shows `@architecture.md`
- [ ] `/epics-and-stories` shows `@epics/*.md`
- [ ] `/create-story` shows `@story-*.md`
**Final Output**
- [ ] SVG renders correctly in browser
- [ ] PNG converts without font issues (use `rsvg-convert`)
- [ ] No text overflow or clipping in boxes
- [ ] Colors match phase scheme (teal, purple, gold, green)
- [ ] Legend box in top-right with all output document descriptions
- [ ] Red herring fish stamp visible in bottom-right corner, rotated
- [ ] Footer with metadata (date, repository, license, distribution statement)

View File

@ -0,0 +1,283 @@
# Generate BMM Workflow Manifest
This prompt generates a YAML manifest of all BMM workflows, their connections, and dependencies. The manifest serves as the source of truth for diagram generation and workflow documentation.
## Instructions
You are an agentic assistant tasked with researching the BMM workflow structure and generating a comprehensive manifest. Follow these steps:
### 1. Research Phase
Scan the BMM workflow structure to discover all workflows:
**Locations to scan:**
- `src/modules/bmm/workflows/1-analysis/` - Phase 1 (Discovery) workflows
- `src/modules/bmm/workflows/2-plan-workflows/` - Phase 2 (Planning) workflows
- `src/modules/bmm/workflows/3-solutioning/` - Phase 3 (Solutioning) workflows
- `src/modules/bmm/workflows/4-implementation/` - Phase 4 (Implementation) workflows
- `src/modules/bmm/workflows/bmad-quick-flow/` - Quick Flow workflows
- `src/modules/bmm/workflows/workflow-status/init/` - Entry point workflow
**For each workflow directory, extract from `workflow.yaml`:**
- `name` - The workflow name (e.g., "product-brief")
- `default_output_file` or output patterns - What files the workflow produces
- **DO NOT extract descriptions** - they cause false change detection and aren't used in diagrams
**Additional information to gather:**
- Read `package.json` to get the current BMAD version
- Get the current git commit hash (short form): `git rev-parse --short HEAD`
- Current timestamp in ISO format
- **Reference `docs/diagrams/bmm-workflow.d2`** for workflow connections (not descriptions)
### 2. Understand Workflow Connections
Study the existing `docs/diagrams/bmm-workflow.d2` file to understand:
**Within-phase connections:**
- Phase 1: All activities (brainstorm, research, domain-research, document-project) converge to product-brief
- Phase 3: architecture → create-epics-and-stories → implementation-readiness (sequential)
- Phase 4: sprint-planning → create-story → dev-story → code-review → story-done → retrospective (sequential)
**Decision points:**
- Phase 2: After `/prd`, there's a "Has UI?" decision
- Yes → `/ux-design`
- No → `/architecture` (cross-phase to Phase 3)
**Feedback loops (Phase 4):**
- code-review → dev-story (label: "fixes")
- story-done → create-story (label: "next story")
- retrospective → sprint-planning (label: "next epic")
**Cross-phase connections:**
- Entry: workflow-init → Phase 1 activities (main flow)
- Entry: workflow-init → quick-flow/create-tech-spec (quick-flow path)
- Phase 1: product-brief → Phase 2 prd
- Phase 2: ux-design → Phase 3 architecture
- Phase 2: tech-spec → Phase 3 create-epics-and-stories (quick-flow path, dashed)
- Phase 3: implementation-readiness → Phase 4 sprint-planning
**Standalone workflows:**
- Phase 4: `/correct-course` - Not part of main flow, run when issues arise
### 3. Build Manifest
Create a YAML manifest with this structure:
```yaml
version: '1.0'
generated: '<ISO timestamp>'
source_commit: '<git short hash>'
bmad_version: '<version from package.json>'
# Entry point
entry:
id: workflow-init
name: /workflow-init
outputs:
- file: '@bmm-workflow-status.yaml'
phases:
discovery:
label: 'PHASE 1: DISCOVERY'
directory: '1-analysis'
optional: true
parallel: true # Activities can run in any order
workflows:
- id: <workflow-id>
name: /<workflow-name>
outputs:
- file: '@filename.md'
description: '...' # Only output files have descriptions (for legend)
connections:
- from: [brainstorm-project, research, domain-research, document-project]
to: product-brief
type: converge
planning:
label: 'PHASE 2: PLANNING'
directory: '2-plan-workflows'
optional: false
parallel: false
workflows: [...]
decisions:
- id: has-ui
label: 'Has UI?'
after: prd
branches:
- condition: 'Yes'
to: ux-design
- condition: 'No'
to: architecture
connections:
- from: ux-design
to: architecture
solutioning:
label: 'PHASE 3: SOLUTIONING'
directory: '3-solutioning'
optional: false
parallel: false
workflows: [...]
connections:
- from: architecture
to: create-epics-and-stories
type: sequential
- from: create-epics-and-stories
to: implementation-readiness
type: sequential
implementation:
label: 'PHASE 4: IMPLEMENTATION'
directory: '4-implementation'
optional: false
parallel: false
workflows: [...]
connections:
- from: sprint-planning
to: create-story
type: sequential
# ... etc
feedback_loops:
- from: code-review
to: dev-story
label: 'fixes'
description: 'Return to dev for fixes'
# ... etc
quick_flow:
auto_regenerate: false
directory: 'bmad-quick-flow'
description: 'Fast-track path for experienced teams'
workflows: [...]
connections:
- from: create-tech-spec
to: quick-dev
type: sequential
cross_phase_connections:
- from: entry.workflow-init
to: phases.discovery.activities
label: 'Main flow'
type: entry
- from: entry.workflow-init
to: quick_flow.create-tech-spec
label: 'Quick-flow'
type: quick_flow
# ... etc
legend:
title: 'OUTPUTS'
items:
- file: '@filename.md'
description: '...'
# ... all output files from all workflows
```
### 4. Compare with Previous Manifest (if exists)
If `docs/diagrams/workflow-manifest.yaml` already exists:
1. Load the existing manifest
2. Compare with the newly generated manifest
3. Detect changes:
- Added workflows
- Removed workflows
- Changed workflow outputs
- Changed output file descriptions (in legend)
- Changed connections or dependencies
- Changed decision points or feedback loops
4. Categorize changes:
- **Quick Flow changes**: Any changes in the `quick_flow` section
- **Main workflow changes**: Any changes in `phases` or `cross_phase_connections`
### 5. Decision Point
**If Quick Flow changes detected:**
- **HARD STOP** - Do not proceed
- Report what changed in detail
- Ask user: "Quick Flow has changed. What would you like to do?"
- Option 1: Update manifest with changes
- Option 2: Keep existing manifest
- Option 3: Review changes and decide
**If main workflow changes detected:**
- Report what changed
- Ask user: "Main workflows have changed. Approve updating the manifest?"
- If approved: Proceed to write
- If rejected: Keep existing manifest
**If no changes detected:**
- Proceed silently to write manifest
### 6. Write Manifest
Write the manifest to `docs/diagrams/workflow-manifest.yaml`
Report summary:
- Number of workflows discovered
- Number of phases
- Number of output documents
- Any changes detected (if comparing)
## Self-Check
Before finalizing, verify:
**Completeness:**
- [ ] All workflow directories scanned
- [ ] All workflow.yaml files read
- [ ] All output files extracted
- [ ] Version and commit info included
- [ ] Timestamp is current
**Connections:**
- [ ] Within-phase connections defined
- [ ] Cross-phase connections defined
- [ ] Decision points defined
- [ ] Feedback loops defined
- [ ] Quick-flow paths defined
**Accuracy:**
- [ ] Workflow names match directory names
- [ ] Workflows do NOT have description fields (prevents false change detection)
- [ ] Output file descriptions are clear and concise (appear in legend)
- [ ] Output files match workflow.yaml patterns
- [ ] Connections match bmm-workflow.d2
**Change Detection (if applicable):**
- [ ] Previous manifest loaded correctly
- [ ] All changes detected
- [ ] Changes categorized correctly
- [ ] User prompted appropriately
## Notes
- This is an **agentic prompt**, not a formal BMAD workflow
- The manifest is the **source of truth** for diagram generation
- Quick Flow changes require **hard stop** - they're critical
- Main workflow changes require **user approval** - they're important
- The manifest should be **version controlled** in git

View File

@ -0,0 +1,26 @@
# Gracefully Age - Nano-Banana Pro Prompt
Age this technical diagram to look like a 1960s archival document.
CRITICAL - TEXT MUST BE PERFECT:
- Every letter, number, and symbol must remain crisp and undistorted
- No warping, smearing, or altering of ANY text
- No changes to lines, arrows, or box shapes
- Preserve all elements exactly as shown
ONLY apply:
- Aged paper texture (cream/yellowed) - Keep in mind that this image already looks like old paper, with its yellowish background and faded pastel tones.
- Subtle coffee stain in top-left corner
- Subtle fold creases
- Lightly worn edges and corners
- Light vignette
DO NOT apply any effect that distorts text. If in doubt, leave it alone.
NO watermarks or AI signatures.
## POST-PROCESSING
Nano-Banana will add a 4-pointed star watermark in the bottom-right. Remove it using the instructions in README.md.

View File

@ -0,0 +1,46 @@
#!/usr/bin/env python3
"""
Post-process Quick Flow SVG to style output labels like main diagram.
"""
import re
INPUT_FILE = "quick-flow.svg"
OUTPUT_FILE = "quick-flow.svg"
def shrink_output_labels(content):
"""Make @*.md output labels smaller and grayed."""
def shrink_tspan(match):
tspan = match.group(0)
return tspan.replace('<tspan', '<tspan font-size="24px" fill="#666666"')
pattern = r'<tspan[^>]*>(@[^<]*|Shortcut for[^<]*|Can run standalone)</tspan>'
content = re.sub(pattern, shrink_tspan, content)
return content
def outline_title(content):
"""Make the title text have an outline/stencil effect."""
# Match title text with font-size 4Xpx and fill color
pattern = r'(<text[^>]*)(fill="#1a3a5c")([^>]*style="[^"]*font-size:4\dpx[^"]*")'
replacement = r'\1fill="none" stroke="#1a3a5c" stroke-width="1.5"\3'
return re.sub(pattern, replacement, content)
def main():
with open(INPUT_FILE, 'r') as f:
content = f.read()
content = shrink_output_labels(content)
content = outline_title(content)
with open(OUTPUT_FILE, 'w') as f:
f.write(content)
print(f"Post-processed: {INPUT_FILE}")
if __name__ == "__main__":
main()

233
docs/diagrams/post-process-svg.py Executable file
View File

@ -0,0 +1,233 @@
#!/usr/bin/env python3
"""
Post-process BMM workflow diagram SVG.
Transforms raw D2 output into the final styled diagram.
Run from docs/diagrams directory.
"""
import re
import base64
# =============================================================================
# CONFIGURATION
# =============================================================================
INPUT_FILE = "bmm-workflow-technical.svg"
OUTPUT_FILE = "bmm-workflow.svg"
STAMP_FILE = "red-herring.png"
# =============================================================================
# PROCESSING STEPS
# =============================================================================
def process_svg():
"""Run all SVG post-processing steps in order."""
with open(INPUT_FILE, 'r') as f:
content = f.read()
content = shrink_output_labels(content)
content = outline_title(content)
content = left_align_title(content)
content = inject_legend(content)
content = inject_stamp(content)
with open(OUTPUT_FILE, 'w') as f:
f.write(content)
print(f"Post-processed: {INPUT_FILE} -> {OUTPUT_FILE}")
# =============================================================================
# STEP 1: Shrink output labels (@*.md)
# =============================================================================
def shrink_output_labels(content):
"""Make @*.md output labels smaller and grayed."""
def shrink_tspan(match):
tspan = match.group(0)
return tspan.replace('<tspan', '<tspan font-size="24px" fill="#666666"')
# Match tspan elements containing @...
pattern = r'<tspan[^>]*>@[^<]*</tspan>'
content = re.sub(pattern, shrink_tspan, content)
return content
# =============================================================================
# STEP 2: Outline title text
# =============================================================================
def outline_title(content):
"""Make the title text have an outline/hollow effect."""
# Pattern: <text ... fill="#1a3a5c" ... style="...font-size:4Xpx">
pattern = r'(<text[^>]*)(fill="#1a3a5c")([^>]*style="[^"]*font-size:4\dpx[^"]*")'
replacement = r'\1fill="none" stroke="#1a3a5c" stroke-width="1.5"\3'
return re.sub(pattern, replacement, content)
# =============================================================================
# STEP 3: Left-align title
# =============================================================================
def left_align_title(content):
"""Left-align the title text."""
def align_title(match):
text_elem = match.group(0)
text_elem = text_elem.replace('text-anchor:middle', 'text-anchor:start')
text_elem = re.sub(r'x="[^"]*"', 'x="50"', text_elem)
return text_elem
pattern = r'<text[^>]*font-size:4[0-9]px[^>]*>BMAD METHOD[^<]*</text>'
return re.sub(pattern, align_title, content)
# =============================================================================
# STEP 4: Inject legend
# =============================================================================
LEGEND_WIDTH = 1200
LEGEND_SVG = '''
<g id="legend" transform="translate({x}, {y})">
<!-- Legend box -->
<rect x="0" y="0" width="1200" height="336" rx="4" ry="4" fill="#fafafa" stroke="#666" stroke-width="1"/>
<!-- Title -->
<text x="20" y="32" font-family="ShareTechMono, monospace" font-size="24" font-weight="bold" fill="#333">OUTPUTS</text>
<!-- Separator line -->
<line x1="20" y1="46" x2="1180" y2="46" stroke="#999" stroke-width="1"/>
<!-- Left column -->
<text x="20" y="80" font-family="ShareTechMono, monospace" font-size="20">
<tspan fill="#333" font-weight="bold">@bmm-workflow-status.yaml</tspan>
<tspan fill="#666"> · Workflow tracking</tspan>
</text>
<text x="20" y="116" font-family="ShareTechMono, monospace" font-size="20">
<tspan fill="#333" font-weight="bold">@product-brief.md</tspan>
<tspan fill="#666"> · Product vision and scope</tspan>
</text>
<text x="20" y="152" font-family="ShareTechMono, monospace" font-size="20">
<tspan fill="#333" font-weight="bold">@tech-spec.md</tspan>
<tspan fill="#666"> · Quick-flow technical spec</tspan>
</text>
<text x="20" y="188" font-family="ShareTechMono, monospace" font-size="20">
<tspan fill="#333" font-weight="bold">@PRD.md</tspan>
<tspan fill="#666"> · Product requirements</tspan>
</text>
<text x="20" y="224" font-family="ShareTechMono, monospace" font-size="20">
<tspan fill="#333" font-weight="bold">@ux-design.md</tspan>
<tspan fill="#666"> · UX/UI design spec</tspan>
</text>
<text x="20" y="260" font-family="ShareTechMono, monospace" font-size="20">
<tspan fill="#333" font-weight="bold">@architecture.md</tspan>
<tspan fill="#666"> · System architecture</tspan>
</text>
<text x="20" y="296" font-family="ShareTechMono, monospace" font-size="20">
<tspan fill="#333" font-weight="bold">@impl-readiness-report.md</tspan>
<tspan fill="#666"> · Readiness validation</tspan>
</text>
<!-- Right column -->
<text x="620" y="80" font-family="ShareTechMono, monospace" font-size="20">
<tspan fill="#333" font-weight="bold">@epics.md</tspan>
<tspan fill="#666"> · Epic and story breakdown</tspan>
</text>
<text x="620" y="116" font-family="ShareTechMono, monospace" font-size="20">
<tspan fill="#333" font-weight="bold">@sprint-status.yaml</tspan>
<tspan fill="#666"> · Sprint progress tracking</tspan>
</text>
<text x="620" y="152" font-family="ShareTechMono, monospace" font-size="20">
<tspan fill="#333" font-weight="bold">@{{epic}}-{{story}}-*.md</tspan>
<tspan fill="#666"> · Implementation stories</tspan>
</text>
<text x="620" y="188" font-family="ShareTechMono, monospace" font-size="20">
<tspan fill="#333" font-weight="bold">@sprint-change-proposal.md</tspan>
<tspan fill="#666"> · Course correction</tspan>
</text>
</g>
'''
def inject_legend(content):
"""Inject legend box in top-right corner."""
legend_y = 180
# Find Phase 4 right edge
phase4_match = re.search(
r'phase4-box[^>]*>.*?<rect[^>]*x="([0-9.]+)"[^>]*width="([0-9.]+)"',
content, re.DOTALL
)
if phase4_match:
phase4_x = float(phase4_match.group(1))
phase4_w = float(phase4_match.group(2))
legend_x = phase4_x + phase4_w - LEGEND_WIDTH + 97
else:
legend_x = 2314 - LEGEND_WIDTH + 97
legend = LEGEND_SVG.format(x=legend_x, y=legend_y)
last_svg_pos = content.rfind('</svg>')
if last_svg_pos != -1:
content = content[:last_svg_pos] + legend + '\n' + content[last_svg_pos:]
return content
# =============================================================================
# STEP 5: Inject red herring stamp
# =============================================================================
STAMP_WIDTH = 200
STAMP_HEIGHT = 134
STAMP_MARGIN_X = 220
STAMP_MARGIN_Y = 85
STAMP_ROTATION = 10
def inject_stamp(content):
"""Inject red herring stamp in lower-right corner."""
# Read and encode stamp image
with open(STAMP_FILE, 'rb') as f:
stamp_data = base64.b64encode(f.read()).decode('utf-8')
# Get SVG dimensions
viewbox_match = re.search(r'viewBox="(\d+)\s+(\d+)\s+(\d+)\s+(\d+)"', content)
if viewbox_match:
svg_width = int(viewbox_match.group(3))
svg_height = int(viewbox_match.group(4))
else:
svg_width, svg_height = 2000, 1500
stamp_x = svg_width - STAMP_WIDTH - STAMP_MARGIN_X
stamp_y = svg_height - STAMP_HEIGHT - STAMP_MARGIN_Y
center_x = STAMP_WIDTH / 2
center_y = STAMP_HEIGHT / 2
stamp_svg = f'''
<g id="stamp" transform="translate({stamp_x}, {stamp_y}) rotate({STAMP_ROTATION}, {center_x}, {center_y})">
<image width="{STAMP_WIDTH}" height="{STAMP_HEIGHT}"
href="data:image/png;base64,{stamp_data}"/>
</g>
'''
last_svg_pos = content.rfind('</svg>')
if last_svg_pos != -1:
content = content[:last_svg_pos] + stamp_svg + '\n' + content[last_svg_pos:]
return content
# =============================================================================
# MAIN
# =============================================================================
if __name__ == "__main__":
process_svg()

View File

@ -0,0 +1,98 @@
direction: down
vars: {
d2-config: {
layout-engine: elk
}
}
classes: {
terminal: {
style: {
fill: "#1a3a5c"
stroke: "#0d1f30"
stroke-width: 2
border-radius: 40
font-size: 24
font-color: "#fff"
italic: true
}
}
workflow: {
style: {
fill: "#fff"
stroke: "#7d2d9a"
stroke-width: 2
border-radius: 6
font-size: 27
}
}
workflow-impl: {
style: {
fill: "#fff"
stroke: "#2d9a7d"
stroke-width: 2
border-radius: 6
font-size: 27
}
}
}
# Outer container: 3 rows x 1 column
outer: "" {
style.fill: transparent
style.stroke: transparent
grid-rows: 3
grid-columns: 1
vertical-gap: 20
# Row 1: Title
title: "QUICK FLOW" {
style.fill: transparent
style.stroke: transparent
style.font-size: 48
style.bold: true
style.font-color: "#1a3a5c"
}
# Row 2: Flow grid (3x3)
flow: "" {
style.fill: transparent
style.stroke: transparent
grid-rows: 3
grid-columns: 3
vertical-gap: 0
horizontal-gap: 60
# Row 1: spacer, spacer, exit
s1: "" { style.opacity: 0 }
s2: "" { style.opacity: 0 }
exit: "to /epics-and-stories" { class: terminal }
# Row 2: entry, tech-spec, spacer
entry: "from /workflow-init" { class: terminal }
tech: "/create-tech-spec\n@tech-spec.md\nShortcut for planning/arch" { class: workflow }
s3: "" { style.opacity: 0 }
# Row 3: spacer, spacer, quick-dev
s4: "" { style.opacity: 0 }
s5: "" { style.opacity: 0 }
quickdev: "/quick-dev\nShortcut for implementation\nCan run standalone" { class: workflow-impl }
}
# Row 3: Explanation
caption: "Fast track for simple changes" {
style.fill: transparent
style.stroke: transparent
style.font-size: 20
style.italic: true
style.font-color: "#666"
}
}
# Flow connections
outer.flow.entry -> outer.flow.tech: { style.stroke-width: 2; style.stroke: "#555" }
outer.flow.tech -> outer.flow.exit: { style.stroke-width: 2; style.stroke: "#888"; style.stroke-dash: 3 }
outer.flow.tech -> outer.flow.quickdev: { style.stroke-width: 2; style.stroke: "#555" }

View File

@ -0,0 +1,254 @@
version: "1.0"
generated: "2025-11-30T14:11:39Z"
source_commit: "31bdb1df"
bmad_version: "6.0.0-alpha.12"
# Entry point
entry:
id: workflow-init
name: /workflow-init
outputs:
- file: "@bmm-workflow-status.yaml"
description: "BMM workflow tracking status"
phases:
discovery:
label: "PHASE 1: DISCOVERY"
directory: "1-analysis"
optional: true
parallel: true # Activities can run in any order
workflows:
- id: brainstorm-project
name: /brainstorm-project
outputs: []
- id: research
name: /research
outputs: []
- id: domain-research
name: /domain-research
outputs: []
- id: document-project
name: /document-project
outputs: []
- id: product-brief
name: /product-brief
outputs:
- file: "@product-brief.md"
description: "Product vision and requirements"
# Connections within this phase
connections:
- from: [brainstorm-project, research, domain-research, document-project]
to: product-brief
type: converge # All activities converge to product-brief
planning:
label: "PHASE 2: PLANNING"
directory: "2-plan-workflows"
optional: false
parallel: false
workflows:
- id: tech-spec
name: /tech-spec
outputs:
- file: "@tech-spec.md"
description: "Technical specification"
optional: true # Part of quick-flow, not main flow
- id: prd
name: /prd
outputs:
- file: "@PRD.md"
description: "Product requirements document"
- id: ux-design
name: /ux-design
outputs:
- file: "@ux-design.md"
description: "UX design and wireframes"
# Decision points
decisions:
- id: has-ui
label: "Has UI?"
after: prd
branches:
- condition: "Yes"
to: ux-design
- condition: "No"
to: architecture # Cross-phase connection
connections:
- from: ux-design
to: architecture # Cross-phase connection
solutioning:
label: "PHASE 3: SOLUTIONING"
directory: "3-solutioning"
optional: false
parallel: false
workflows:
- id: architecture
name: /architecture
outputs:
- file: "@architecture.md"
description: "System architecture and design"
- id: create-epics-and-stories
name: /create-epics-and-stories
outputs:
- file: "@epics.md"
description: "Epic and story breakdown"
- id: implementation-readiness
name: /implementation-readiness
outputs:
- file: "@impl-readiness-report.md"
description: "Implementation readiness report"
connections:
- from: architecture
to: create-epics-and-stories
type: sequential
- from: create-epics-and-stories
to: implementation-readiness
type: sequential
implementation:
label: "PHASE 4: IMPLEMENTATION"
directory: "4-implementation"
optional: false
parallel: false
workflows:
- id: sprint-planning
name: /sprint-planning
outputs:
- file: "@sprint-status.yaml"
description: "Sprint status and planning"
- id: create-story
name: /create-story
outputs:
- file: "@{epic}-{story}-*.md"
description: "Story implementation details"
- id: dev-story
name: /dev-story
outputs: []
- id: code-review
name: /code-review
outputs: []
- id: story-done
name: /story-done
outputs: []
- id: retrospective
name: /retrospective
outputs: []
- id: correct-course
name: /correct-course
outputs:
- file: "@sprint-change-proposal.md"
description: "Sprint change proposal"
standalone: true # Not part of main flow
# Main flow
connections:
- from: sprint-planning
to: create-story
type: sequential
- from: create-story
to: dev-story
type: sequential
- from: dev-story
to: code-review
type: sequential
- from: code-review
to: story-done
type: sequential
- from: story-done
to: retrospective
type: sequential
# Feedback loops (iterative flows)
feedback_loops:
- from: code-review
to: dev-story
label: "fixes"
description: "Return to dev for fixes"
- from: story-done
to: create-story
label: "next story"
description: "Continue with next story in epic"
- from: retrospective
to: sprint-planning
label: "next epic"
description: "Start next epic/sprint"
# Quick Flow (separate diagram, composited into main diagram)
quick_flow:
auto_regenerate: false
directory: "bmad-quick-flow"
description: "Fast-track path for experienced teams"
# Quick-flow includes its own workflow-init node
entry:
id: workflow-init
name: /workflow-init
outputs:
- file: "@bmm-workflow-status.yaml"
workflows:
- id: create-tech-spec
name: /create-tech-spec
outputs:
- file: "@tech-spec.md"
description: "Technical specification"
- id: quick-dev
name: /quick-dev
outputs: []
connections:
- from: workflow-init
to: create-tech-spec
type: sequential
- from: create-tech-spec
to: quick-dev
type: sequential
# Cross-phase connections (main diagram only)
cross_phase_connections:
- from: entry.workflow-init
to: phases.discovery.activities
label: "Main flow"
type: entry
- from: phases.discovery.product-brief
to: phases.planning.prd
type: sequential
- from: phases.planning.tech-spec
to: phases.solutioning.create-epics-and-stories
label: "Quick-flow path"
type: quick_flow
- from: phases.solutioning.implementation-readiness
to: phases.implementation.sprint-planning
type: sequential
# Legend for diagram generation
legend:
title: "OUTPUTS"
items:
- file: "@bmm-workflow-status.yaml"
description: "BMM workflow tracking status"
- file: "@product-brief.md"
description: "Product vision and requirements"
- file: "@tech-spec.md"
description: "Technical specification"
- file: "@PRD.md"
description: "Product requirements document"
- file: "@ux-design.md"
description: "UX design and wireframes"
- file: "@architecture.md"
description: "System architecture and design"
- file: "@epics.md"
description: "Epic and story breakdown"
- file: "@impl-readiness-report.md"
description: "Implementation readiness report"
- file: "@sprint-status.yaml"
description: "Sprint status and planning"
- file: "@{epic}-{story}-*.md"
description: "Story implementation details"
- file: "@sprint-change-proposal.md"
description: "Sprint change proposal"