1495 lines
39 KiB
Python
Executable File
1495 lines
39 KiB
Python
Executable File
#!/usr/bin/env -S uv run --script
|
|
# /// script
|
|
# requires-python = ">=3.11"
|
|
# dependencies = [
|
|
# "python-dotenv",
|
|
# "anthropic",
|
|
# ]
|
|
# ///
|
|
|
|
"""
|
|
BMAD Document Generator Utility
|
|
|
|
Generates BMAD methodology documents using Claude Haiku 4.5:
|
|
- Product Brief
|
|
- PRD (Product Requirements Document)
|
|
- Architecture Document
|
|
- Epic files with user stories
|
|
- Story Index summary
|
|
|
|
Commands:
|
|
brief <idea> <project_path> Generate product brief
|
|
prd <brief_path> <project_path> Generate PRD from brief
|
|
architecture <prd_path> <project_path> Generate architecture from PRD
|
|
epic <prd_path> <arch_path> <epic_num> <project_path> Generate single epic
|
|
index <epics_dir> <project_path> Generate story index
|
|
|
|
Examples:
|
|
uv run bmad_generator.py brief "AI todo app with voice input" "$(pwd)"
|
|
uv run bmad_generator.py prd bmad-backlog/product-brief.md "$(pwd)"
|
|
uv run bmad_generator.py architecture bmad-backlog/prd/prd.md "$(pwd)"
|
|
uv run bmad_generator.py epic bmad-backlog/prd/prd.md bmad-backlog/architecture/architecture.md 1 "$(pwd)"
|
|
uv run bmad_generator.py index bmad-backlog/epics/ "$(pwd)"
|
|
"""
|
|
|
|
import json
|
|
import sys
|
|
import os
|
|
import re
|
|
from pathlib import Path
|
|
from datetime import datetime
|
|
from dotenv import load_dotenv
|
|
|
|
|
|
def get_claude_model(task_type: str = "default") -> str:
|
|
"""
|
|
Get Claude model based on task complexity.
|
|
|
|
Args:
|
|
task_type: "complex" for large model (Sonnet), "default" for small model (Haiku)
|
|
|
|
Returns:
|
|
Model name string
|
|
"""
|
|
load_dotenv()
|
|
|
|
if task_type == "complex":
|
|
# Use large model (Sonnet 4.5) for complex tasks
|
|
return os.getenv("ANTHROPIC_LARGE_MODEL", "claude-sonnet-4-5-20250929")
|
|
else:
|
|
# Use small model (Haiku 4.5) for faster tasks
|
|
return os.getenv("ANTHROPIC_SMALL_MODEL", "claude-haiku-4-5-20251001")
|
|
|
|
|
|
def generate_brief(idea: str, project_path: str) -> str:
|
|
"""
|
|
Generate Product Brief from high-level idea.
|
|
|
|
Args:
|
|
idea: User's project idea
|
|
project_path: Project directory path
|
|
|
|
Returns:
|
|
Generated brief content
|
|
"""
|
|
load_dotenv()
|
|
|
|
api_key = os.getenv("ANTHROPIC_API_KEY")
|
|
if not api_key:
|
|
print("Error: ANTHROPIC_API_KEY not found", file=sys.stderr)
|
|
print("Please add your Anthropic API key to ~/.env file:", file=sys.stderr)
|
|
print("ANTHROPIC_API_KEY=sk-ant-your-key-here", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
from anthropic import Anthropic
|
|
client = Anthropic(api_key=api_key)
|
|
|
|
current_date = datetime.now().strftime("%B %d, %Y")
|
|
|
|
prompt = f"""Generate a comprehensive Product Brief following BMAD methodology.
|
|
|
|
User's Project Idea:
|
|
{idea}
|
|
|
|
Create a Product Brief with these sections (use exact headers):
|
|
|
|
# Product Brief: {{Project Name}}
|
|
|
|
**Version:** 1.0
|
|
**Date:** {current_date}
|
|
**Status:** Draft
|
|
|
|
---
|
|
|
|
## Executive Summary
|
|
|
|
{{Write 2-3 paragraphs covering:
|
|
- Product concept (what it is)
|
|
- Problem being solved
|
|
- Target market
|
|
- Key value proposition}}
|
|
|
|
---
|
|
|
|
## Problem Statement
|
|
|
|
{{Write 2-3 paragraphs covering:
|
|
- Current state and pain points (be specific)
|
|
- Impact of the problem (quantify if possible)
|
|
- Why existing solutions fall short
|
|
- Urgency and importance of solving this now}}
|
|
|
|
---
|
|
|
|
## Proposed Solution
|
|
|
|
{{Write 2-3 paragraphs covering:
|
|
- Core concept and approach
|
|
- Key differentiators from existing solutions
|
|
- Why this solution will succeed
|
|
- High-level product vision}}
|
|
|
|
---
|
|
|
|
## Target Users
|
|
|
|
### Primary User Segment
|
|
|
|
{{Define primary users with:
|
|
- Demographic/firmographic profile
|
|
- Current behaviors and workflows
|
|
- Specific needs and pain points
|
|
- Goals they're trying to achieve}}
|
|
|
|
### Secondary User Segment
|
|
|
|
{{Define secondary users (if applicable) with same details}}
|
|
|
|
---
|
|
|
|
## Goals & Success Metrics
|
|
|
|
### Business Objectives
|
|
- {{Objective 1 with metric}}
|
|
- {{Objective 2 with metric}}
|
|
- {{Objective 3 with metric}}
|
|
|
|
### User Success Metrics
|
|
- {{Metric 1: definition and target}}
|
|
- {{Metric 2: definition and target}}
|
|
- {{Metric 3: definition and target}}
|
|
|
|
### Key Performance Indicators (KPIs)
|
|
- {{KPI 1: definition and target}}
|
|
- {{KPI 2: definition and target}}
|
|
- {{KPI 3: definition and target}}
|
|
|
|
---
|
|
|
|
## MVP Scope
|
|
|
|
### Core Features (Must Have)
|
|
- **{{Feature 1}}:** {{Description and rationale}}
|
|
- **{{Feature 2}}:** {{Description and rationale}}
|
|
- **{{Feature 3}}:** {{Description and rationale}}
|
|
- **{{Feature 4}}:** {{Description and rationale}}
|
|
|
|
### Out of Scope for MVP
|
|
- {{Feature not included in MVP}}
|
|
- {{Feature not included in MVP}}
|
|
- {{Feature not included in MVP}}
|
|
|
|
### MVP Success Criteria
|
|
{{What defines MVP success - 2-3 sentences}}
|
|
|
|
---
|
|
|
|
## Post-MVP Vision
|
|
|
|
### Phase 2 Features
|
|
{{List 3-5 next-priority features after MVP}}
|
|
|
|
### Long-term Vision
|
|
{{1-2 year vision for the product}}
|
|
|
|
### Expansion Opportunities
|
|
{{Potential future expansions or adjacent markets}}
|
|
|
|
---
|
|
|
|
## Technical Considerations
|
|
|
|
### Platform Requirements
|
|
- **Target Platforms:** {{Web/Mobile/Desktop/etc}}
|
|
- **Browser/OS Support:** {{Specific requirements}}
|
|
- **Performance Requirements:** {{Load time, responsiveness, etc}}
|
|
|
|
### Technology Preferences
|
|
- **Frontend:** {{Framework preference or "TBD"}}
|
|
- **Backend:** {{Framework preference or "TBD"}}
|
|
- **Database:** {{Database preference or "TBD"}}
|
|
- **Hosting/Infrastructure:** {{Hosting preference or "TBD"}}
|
|
|
|
### Architecture Considerations
|
|
- **Repository Structure:** {{Monorepo/Polyrepo preference}}
|
|
- **Service Architecture:** {{Monolith/Microservices preference}}
|
|
- **Integration Requirements:** {{External integrations needed}}
|
|
- **Security/Compliance:** {{Security requirements}}
|
|
|
|
---
|
|
|
|
## Constraints & Assumptions
|
|
|
|
### Constraints
|
|
- **Budget:** {{Budget information}}
|
|
- **Timeline:** {{Timeline expectations}}
|
|
- **Resources:** {{Team size, availability}}
|
|
- **Technical:** {{Technical limitations}}
|
|
|
|
### Key Assumptions
|
|
- {{Assumption 1}}
|
|
- {{Assumption 2}}
|
|
- {{Assumption 3}}
|
|
|
|
---
|
|
|
|
## Risks & Open Questions
|
|
|
|
### Key Risks
|
|
- **{{Risk 1}}:** {{Description and potential impact}}
|
|
- **{{Risk 2}}:** {{Description and potential impact}}
|
|
- **{{Risk 3}}:** {{Description and potential impact}}
|
|
|
|
### Open Questions
|
|
- {{Question 1}}
|
|
- {{Question 2}}
|
|
- {{Question 3}}
|
|
|
|
### Areas Needing Further Research
|
|
- {{Research area 1}}
|
|
- {{Research area 2}}
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
### Immediate Actions
|
|
1. {{Action item 1}}
|
|
2. {{Action item 2}}
|
|
3. {{Action item 3}}
|
|
|
|
### PM Handoff
|
|
This Product Brief provides the foundation for creating a comprehensive PRD. Next step: Generate PRD with `/bmad:prd` command.
|
|
|
|
---
|
|
|
|
Be comprehensive but concise. Infer reasonable defaults based on the idea. Format as clean markdown."""
|
|
|
|
try:
|
|
# Use Haiku for brief generation (documentation task, fast)
|
|
model = get_claude_model("default")
|
|
|
|
response = client.messages.create(
|
|
model=model,
|
|
max_tokens=3000,
|
|
temperature=0.4,
|
|
messages=[{"role": "user", "content": prompt}]
|
|
)
|
|
|
|
brief_content = response.content[0].text.strip()
|
|
|
|
# Save to file
|
|
brief_path = Path(project_path) / "bmad-backlog" / "product-brief.md"
|
|
brief_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
with open(brief_path, 'w', encoding='utf-8', newline='\n') as f:
|
|
f.write(brief_content)
|
|
|
|
return brief_content
|
|
|
|
except Exception as e:
|
|
print(f"Error generating brief: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def generate_prd(brief_path: str, project_path: str) -> str:
|
|
"""
|
|
Generate PRD from Product Brief.
|
|
|
|
Args:
|
|
brief_path: Path to product-brief.md
|
|
project_path: Project directory path
|
|
|
|
Returns:
|
|
Generated PRD content
|
|
"""
|
|
load_dotenv()
|
|
|
|
api_key = os.getenv("ANTHROPIC_API_KEY")
|
|
if not api_key:
|
|
print("Error: ANTHROPIC_API_KEY not found", file=sys.stderr)
|
|
print("Please add your Anthropic API key to ~/.env file:", file=sys.stderr)
|
|
print("ANTHROPIC_API_KEY=sk-ant-your-key-here", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
# Read brief
|
|
try:
|
|
with open(brief_path, 'r', encoding='utf-8') as f:
|
|
brief_content = f.read()
|
|
except Exception as e:
|
|
print(f"Error reading brief: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
from anthropic import Anthropic
|
|
client = Anthropic(api_key=api_key)
|
|
|
|
current_date = datetime.now().strftime("%B %d, %Y")
|
|
|
|
# Extract project name from brief
|
|
project_name = extract_project_name(brief_content)
|
|
|
|
prompt = f"""Generate a comprehensive Product Requirements Document (PRD) following BMAD methodology.
|
|
|
|
Product Brief:
|
|
{brief_content}
|
|
|
|
Create a detailed PRD with these sections (use exact headers, follow BMAD template):
|
|
|
|
# Product Requirements Document (PRD)
|
|
## {project_name}
|
|
|
|
**Document Version:** 1.0
|
|
**Last Updated:** {current_date}
|
|
**Product Owner:** TBD
|
|
**Status:** Draft
|
|
|
|
---
|
|
|
|
## Executive Summary
|
|
|
|
### Vision
|
|
{{2-3 paragraphs describing the product vision}}
|
|
|
|
### Mission
|
|
{{1-2 paragraphs describing the mission}}
|
|
|
|
---
|
|
|
|
## Product Overview
|
|
|
|
### Target Users
|
|
1. **Primary:** {{User segment with detailed profile}}
|
|
2. **Secondary:** {{Secondary segment if applicable}}
|
|
3. **Tertiary:** {{Tertiary segment if applicable}}
|
|
|
|
### Core Value Propositions
|
|
1. {{Value prop 1 with details}}
|
|
2. {{Value prop 2 with details}}
|
|
3. {{Value prop 3 with details}}
|
|
4. {{Value prop 4 with details}}
|
|
5. {{Value prop 5 with details}}
|
|
|
|
### Competitive Positioning
|
|
- **vs {{Competitor 1}}:** {{How we differ}}
|
|
- **vs {{Competitor 2}}:** {{How we differ}}
|
|
- **vs {{Competitor 3}}:** {{How we differ}}
|
|
|
|
---
|
|
|
|
## Success Metrics
|
|
|
|
### North Star Metric
|
|
**{{Primary metric}}** {{Description and target}}
|
|
|
|
### Key Performance Indicators
|
|
|
|
#### Product Metrics
|
|
- **Engagement:**
|
|
- {{Metric 1}}: {{Target}}
|
|
- {{Metric 2}}: {{Target}}
|
|
|
|
- **Feature Adoption:**
|
|
- {{Metric 1}}: {{Target}}
|
|
- {{Metric 2}}: {{Target}}
|
|
|
|
#### Business Metrics
|
|
- **Growth:**
|
|
- {{Metric 1}}: {{Target}}
|
|
- {{Metric 2}}: {{Target}}
|
|
|
|
- **Revenue:**
|
|
- {{Metric 1}}: {{Target}}
|
|
- {{Metric 2}}: {{Target}}
|
|
|
|
---
|
|
|
|
## Feature Requirements
|
|
|
|
### V1 MVP (12-16 Weeks)
|
|
|
|
{{For each major feature (4-8 features):}}
|
|
|
|
#### {{N}}. {{Feature Name}}
|
|
**Priority:** P0 (Must Have) or P1 (Should Have)
|
|
|
|
**Requirements:**
|
|
- {{Requirement 1}}
|
|
- {{Requirement 2}}
|
|
- {{Requirement 3}}
|
|
|
|
**Acceptance Criteria:**
|
|
- [ ] {{Criterion 1}}
|
|
- [ ] {{Criterion 2}}
|
|
- [ ] {{Criterion 3}}
|
|
|
|
{{Repeat for all MVP features}}
|
|
|
|
### V2 Pro Features (8-12 Weeks Post-MVP)
|
|
|
|
{{List 4-6 post-MVP features with brief descriptions}}
|
|
|
|
---
|
|
|
|
## User Stories
|
|
|
|
{{Organize by Epic - aim for 3-6 epics total}}
|
|
|
|
### Epic 1: {{Epic Name}}
|
|
- As a **{{user}}**, I want **{{action}}** so that **{{benefit}}**
|
|
- As a **{{user}}**, I want **{{action}}** so that **{{benefit}}**
|
|
{{3-5 stories per epic}}
|
|
|
|
### Epic 2: {{Epic Name}}
|
|
{{Stories...}}
|
|
|
|
### Epic 3: {{Epic Name}}
|
|
{{Stories...}}
|
|
|
|
{{Continue for all epics}}
|
|
|
|
CRITICAL: Epic 1 MUST be "Foundation" or "Infrastructure" - establishing project setup, auth, basic structure.
|
|
|
|
---
|
|
|
|
## Technical Requirements
|
|
|
|
### Performance
|
|
- {{Metric 1}}: {{Target with p95}}
|
|
- {{Metric 2}}: {{Target}}
|
|
- {{Metric 3}}: {{Target}}
|
|
|
|
### Scalability
|
|
- Support {{N}} concurrent users (MVP)
|
|
- Support {{M}} concurrent users (Production)
|
|
- Handle {{X}} requests/operations per {{timeframe}}
|
|
|
|
### Security & Compliance
|
|
- {{Security requirement 1}}
|
|
- {{Security requirement 2}}
|
|
- {{Compliance standard if applicable}}
|
|
|
|
### Availability
|
|
- {{Uptime SLA}} uptime (free tier)
|
|
- {{Uptime SLA}} uptime (Pro tier if applicable)
|
|
|
|
### Browser Support
|
|
- {{Browser 1}} (versions)
|
|
- {{Browser 2}} (versions)
|
|
- {{Mobile support}}
|
|
|
|
---
|
|
|
|
## Data Requirements
|
|
|
|
### Data Sources
|
|
{{If project needs external data}}
|
|
|
|
#### {{Data Type 1}}
|
|
- **Source:** {{Vendor/API name or TBD}}
|
|
- **Freshness:** {{Real-time, hourly, daily}}
|
|
- **Format:** {{JSON, CSV, etc}}
|
|
|
|
{{Repeat for all data needs}}
|
|
|
|
### Data Quality
|
|
- {{Quality requirement 1}}
|
|
- {{Quality requirement 2}}
|
|
|
|
---
|
|
|
|
## AI/ML Requirements
|
|
|
|
{{Only include if project uses AI}}
|
|
|
|
### Use Cases
|
|
|
|
#### {{Use Case 1}}
|
|
- **Model:** {{GPT-4, Claude, local model, etc}}
|
|
- **Input:** {{What goes in}}
|
|
- **Output:** {{What comes out}}
|
|
- **Latency:** {{Response time requirement}}
|
|
- **Quality:** {{Accuracy/precision target}}
|
|
|
|
{{Repeat for all AI use cases}}
|
|
|
|
### Guardrails
|
|
- {{Guardrail 1 - e.g., source attribution}}
|
|
- {{Guardrail 2 - e.g., confidence thresholds}}
|
|
- {{Guardrail 3 - e.g., hallucination prevention}}
|
|
|
|
### Evaluation
|
|
- {{How to measure AI quality}}
|
|
- {{Evaluation frequency}}
|
|
|
|
---
|
|
|
|
## Design Requirements
|
|
|
|
### Design System
|
|
- **Framework:** {{Tailwind, Material UI, etc}}
|
|
- **Theme:** {{Dark/Light/Both}}
|
|
- **Accessibility:** {{WCAG level or None}}
|
|
- **Responsiveness:** {{Mobile-first, Desktop-first}}
|
|
|
|
### Key Screens
|
|
1. {{Screen 1 name and brief description}}
|
|
2. {{Screen 2 name and brief description}}
|
|
3. {{Screen 3 name and brief description}}
|
|
{{List 5-10 critical screens}}
|
|
|
|
---
|
|
|
|
## Go-to-Market Strategy
|
|
|
|
### Launch Phases
|
|
|
|
#### Phase 1: {{Phase name (e.g., Closed Alpha)}}
|
|
- {{Details, timeline, scope}}
|
|
|
|
#### Phase 2: {{Phase name}}
|
|
- {{Details}}
|
|
|
|
### Pricing Strategy
|
|
- **Free Tier:** {{Features and limitations}}
|
|
- **Pro Tier:** ${{price}}/month - {{Features}}
|
|
- **Team Tier:** {{If applicable}}
|
|
|
|
### Customer Acquisition
|
|
- **Organic:** {{SEO, content, etc}}
|
|
- **Community:** {{Platforms}}
|
|
- **Partnerships:** {{Ideas}}
|
|
- **Paid:** {{Advertising channels}}
|
|
|
|
---
|
|
|
|
## Risks & Mitigation
|
|
|
|
### Technical Risks
|
|
|
|
| Risk | Impact | Likelihood | Mitigation |
|
|
|------|--------|-----------|------------|
|
|
| {{Risk 1}} | {{High/Med/Low}} | {{High/Med/Low}} | {{How to mitigate}} |
|
|
| {{Risk 2}} | {{High/Med/Low}} | {{High/Med/Low}} | {{How to mitigate}} |
|
|
| {{Risk 3}} | {{High/Med/Low}} | {{High/Med/Low}} | {{How to mitigate}} |
|
|
|
|
### Business Risks
|
|
|
|
| Risk | Impact | Likelihood | Mitigation |
|
|
|------|--------|-----------|------------|
|
|
| {{Risk 1}} | {{High/Med/Low}} | {{High/Med/Low}} | {{How to mitigate}} |
|
|
| {{Risk 2}} | {{High/Med/Low}} | {{High/Med/Low}} | {{How to mitigate}} |
|
|
|
|
---
|
|
|
|
## Open Questions
|
|
|
|
1. {{Question 1}}
|
|
2. {{Question 2}}
|
|
3. {{Question 3}}
|
|
{{List 5-10 unresolved questions}}
|
|
|
|
---
|
|
|
|
## Appendix
|
|
|
|
### Glossary
|
|
- **{{Term 1}}:** {{Definition}}
|
|
- **{{Term 2}}:** {{Definition}}
|
|
|
|
### References
|
|
- {{Link 1}}: {{Description}}
|
|
- {{Link 2}}: {{Description}}
|
|
|
|
---
|
|
|
|
**Document Status:** ✅ Ready for Technical Review
|
|
**Next Steps:** Architecture document, epic breakdown
|
|
|
|
---
|
|
|
|
IMPORTANT GUIDELINES:
|
|
1. Be comprehensive - aim for 500-1000 lines
|
|
2. Epic 1 MUST be "Foundation" or "Infrastructure"
|
|
3. Include specific acceptance criteria (not vague)
|
|
4. Use proper priority labels (P0, P1, P2)
|
|
5. Make user stories actionable ("As a X, I want Y, so that Z")
|
|
6. Include realistic metrics and targets
|
|
7. Be specific with technical requirements
|
|
8. Format as clean markdown with proper headers"""
|
|
|
|
try:
|
|
# Use Haiku for PRD generation (documentation task)
|
|
model = get_claude_model("default")
|
|
|
|
# Haiku 4.5 supports up to 16384 output tokens
|
|
response = client.messages.create(
|
|
model=model,
|
|
max_tokens=16000,
|
|
temperature=0.3,
|
|
messages=[{"role": "user", "content": prompt}]
|
|
)
|
|
|
|
prd_content = response.content[0].text.strip()
|
|
|
|
# Save to file
|
|
prd_path = Path(project_path) / "bmad-backlog" / "prd" / "prd.md"
|
|
prd_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
with open(prd_path, 'w', encoding='utf-8', newline='\n') as f:
|
|
f.write(prd_content)
|
|
|
|
return prd_content
|
|
|
|
except Exception as e:
|
|
print(f"Error generating PRD: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def extract_project_name(content: str) -> str:
|
|
"""Extract project name from document header."""
|
|
|
|
# Pattern 1: Look for "# Product Requirements Document (PRD)" followed by "## ProjectName"
|
|
prd_h1_match = re.search(r'(?m)^#\s+Product Requirements Document(?:\s+\(PRD\))?', content)
|
|
if prd_h1_match:
|
|
# Found PRD header, now find the next H2 line
|
|
after_prd = content[prd_h1_match.end():]
|
|
h2_match = re.search(r'(?m)^##\s+(.+?)(?:\s+-\s+|\s*$)', after_prd)
|
|
if h2_match:
|
|
return h2_match.group(1).strip()
|
|
|
|
# Pattern 2: Look for "# Product Brief: NAME" or "# Architecture Document"
|
|
title_match = re.search(r'(?m)^#\s+(?:Product Brief|Architecture Document|PRD|Project):\s*(.+)', content)
|
|
if title_match:
|
|
return title_match.group(1).strip()
|
|
|
|
# Pattern 3: Look for standalone H1 with project name
|
|
h1_match = re.search(r'(?m)^#\s+([^#\n]+?)(?:\s+-\s+|\s*$)', content)
|
|
if h1_match:
|
|
title = h1_match.group(1).strip()
|
|
# Skip generic headers
|
|
if title not in ['Product Requirements Document', 'Architecture Document', 'Product Brief', 'PRD']:
|
|
return title
|
|
|
|
# Pattern 4: Look for H2 with project name (fallback)
|
|
h2_match = re.search(r'(?m)^##\s+(.+?)(?:\s+-\s+|\s*$)', content)
|
|
if h2_match:
|
|
title = h2_match.group(1).strip()
|
|
# Skip generic headers
|
|
if title not in ['Executive Summary', 'Table of Contents', 'Overview']:
|
|
return title
|
|
|
|
return "Project"
|
|
|
|
|
|
def generate_architecture(prd_path: str, project_path: str) -> str:
|
|
"""
|
|
Generate Architecture document from PRD.
|
|
|
|
Args:
|
|
prd_path: Path to prd.md
|
|
project_path: Project directory path
|
|
|
|
Returns:
|
|
Generated architecture content
|
|
"""
|
|
load_dotenv()
|
|
|
|
api_key = os.getenv("ANTHROPIC_API_KEY")
|
|
if not api_key:
|
|
print("Error: ANTHROPIC_API_KEY not found", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
# Read PRD
|
|
try:
|
|
with open(prd_path, 'r', encoding='utf-8') as f:
|
|
prd_content = f.read()
|
|
except Exception as e:
|
|
print(f"Error reading PRD: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
from anthropic import Anthropic
|
|
client = Anthropic(api_key=api_key)
|
|
|
|
current_date = datetime.now().strftime("%B %d, %Y")
|
|
project_name = extract_project_name(prd_content)
|
|
|
|
prompt = f"""Generate a comprehensive Architecture Document following BMAD methodology.
|
|
|
|
Product Requirements Document:
|
|
{prd_content[:3000]} # First part for context
|
|
|
|
Based on the PRD above, create a detailed Architecture Document.
|
|
|
|
This will be generated in TWO parts due to length. This is PART 1.
|
|
|
|
# Architecture Document
|
|
## {project_name}
|
|
|
|
**Document Version:** 1.0
|
|
**Last Updated:** {current_date}
|
|
**Architecture Owner:** TBD
|
|
**Status:** Draft
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
1. [System Overview](#system-overview)
|
|
2. [Architecture Principles](#architecture-principles)
|
|
3. [High-Level Architecture](#high-level-architecture)
|
|
4. [Component Details](#component-details)
|
|
5. [Data Architecture](#data-architecture)
|
|
6. [Infrastructure](#infrastructure)
|
|
7. [Security Architecture](#security-architecture)
|
|
8. [Deployment Strategy](#deployment-strategy)
|
|
9. [Monitoring & Observability](#monitoring--observability)
|
|
10. [Appendix](#appendix)
|
|
|
|
---
|
|
|
|
## System Overview
|
|
|
|
### Context
|
|
{{2-3 paragraphs explaining what the system does, referencing PRD features}}
|
|
|
|
### Key Requirements
|
|
{{Extract from PRD:
|
|
- Latency targets
|
|
- Throughput requirements
|
|
- Availability needs
|
|
- Security requirements}}
|
|
|
|
---
|
|
|
|
## Architecture Principles
|
|
|
|
{{List 6-10 guiding principles, e.g.:
|
|
1. **Mobile-First Design:** Responsive, progressive enhancement
|
|
2. **API-First Development:** RESTful/GraphQL, versioned
|
|
3. **Event-Driven Where Appropriate:** Async workflows
|
|
4. **AI Transparency:** Source attribution, confidence thresholds
|
|
5. **Observability-First:** Metrics, logging, tracing
|
|
6. **Cost Optimization:** Efficient scaling, caching}}
|
|
|
|
---
|
|
|
|
## High-Level Architecture
|
|
|
|
{{Create ASCII diagram showing all layers:
|
|
- Client Layer (Frontend)
|
|
- API Gateway Layer
|
|
- Application Layer (Backend services)
|
|
- Business Logic Layer
|
|
- Data Layer (Databases, cache)
|
|
- Data Ingestion Layer (if applicable)
|
|
- Streaming/Event Layer (if applicable)
|
|
- AI/ML Layer (if applicable)
|
|
- External Integrations
|
|
|
|
Use box-drawing characters for clarity}}
|
|
|
|
Example format:
|
|
```
|
|
┌─────────────────────────────────────────┐
|
|
│ CLIENT LAYER │
|
|
├─────────────────────────────────────────┤
|
|
│ Next.js / React │
|
|
└─────────────────────────────────────────┘
|
|
↓
|
|
┌─────────────────────────────────────────┐
|
|
│ APPLICATION LAYER │
|
|
├─────────────────────────────────────────┤
|
|
│ FastAPI / Express │
|
|
└─────────────────────────────────────────┘
|
|
{{etc}}
|
|
```
|
|
|
|
---
|
|
|
|
## Component Details
|
|
|
|
### Frontend
|
|
|
|
#### Technology Stack
|
|
- **Framework:** {{Next.js/React/Vue/etc based on PRD}}
|
|
- **Language:** {{TypeScript/JavaScript}}
|
|
- **Styling:** {{Tailwind/CSS-in-JS/etc}}
|
|
- **State Management:** {{Zustand/Redux/Context}}
|
|
- **Data Fetching:** {{React Query/SWR/etc}}
|
|
|
|
#### Key Features
|
|
- {{Feature 1}}
|
|
- {{Feature 2}}
|
|
- {{Feature 3}}
|
|
|
|
#### File Structure
|
|
```
|
|
app/ or src/
|
|
├── (auth)/
|
|
│ ├── login/
|
|
│ └── register/
|
|
├── (dashboard)/
|
|
│ ├── page.tsx
|
|
│ └── {{routes based on PRD}}
|
|
├── components/
|
|
│ ├── ui/
|
|
│ └── {{feature components}}
|
|
└── lib/
|
|
├── api-client.ts
|
|
└── utils.ts
|
|
```
|
|
|
|
### Backend
|
|
|
|
#### Technology Stack
|
|
- **Framework:** {{FastAPI/Express/Django based on PRD}}
|
|
- **Language:** {{Python/Node.js/etc}}
|
|
- **ORM:** {{SQLAlchemy/Prisma/TypeORM}}
|
|
- **Validation:** {{Pydantic/Zod/etc}}
|
|
- **Async:** {{asyncio/promises}}
|
|
|
|
#### Service Architecture
|
|
```
|
|
services/
|
|
├── api/
|
|
│ ├── routers/
|
|
│ │ ├── {{route1}}.py
|
|
│ │ ├── {{route2}}.py
|
|
│ │ └── {{route3}}.py
|
|
│ ├── dependencies.py
|
|
│ └── main.py
|
|
├── models/
|
|
├── schemas/
|
|
└── services/
|
|
```
|
|
|
|
---
|
|
|
|
Generate this first part comprehensively. Include specific tech stack based on PRD requirements. Be detailed. Next, I'll request part 2 with Data Architecture, Security, etc."""
|
|
|
|
try:
|
|
# Use Sonnet for architecture (complex technical task with code examples)
|
|
model = get_claude_model("complex")
|
|
|
|
# Sonnet 4.5 supports up to 16384 output tokens
|
|
response = client.messages.create(
|
|
model=model,
|
|
max_tokens=16000,
|
|
temperature=0.3,
|
|
messages=[{"role": "user", "content": prompt}]
|
|
)
|
|
|
|
arch_part1 = response.content[0].text.strip()
|
|
|
|
# Generate Part 2
|
|
prompt_part2 = f"""Continue the Architecture Document. This is PART 2.
|
|
|
|
Here's what you generated in Part 1:
|
|
{arch_part1[:1000]}
|
|
|
|
Now generate the remaining sections:
|
|
|
|
---
|
|
|
|
## Data Architecture
|
|
|
|
### Database Schema ({{PostgreSQL/MySQL/MongoDB based on tech stack}})
|
|
|
|
{{Generate CREATE TABLE statements for all main entities from PRD}}
|
|
|
|
Example:
|
|
```sql
|
|
CREATE TABLE users (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
email VARCHAR(255) UNIQUE NOT NULL,
|
|
created_at TIMESTAMPTZ DEFAULT NOW()
|
|
);
|
|
|
|
{{Add more tables for all PRD entities}}
|
|
```
|
|
|
|
{{If time-series data needed:}}
|
|
### Time-Series Tables (TimescaleDB)
|
|
```sql
|
|
CREATE TABLE {{timeseries_table}} (
|
|
time TIMESTAMPTZ NOT NULL,
|
|
{{fields}},
|
|
PRIMARY KEY (time, {{partition_key}})
|
|
);
|
|
|
|
SELECT create_hypertable('{{table}}', 'time');
|
|
```
|
|
|
|
{{If AI features:}}
|
|
### Vector Store (pgvector)
|
|
```sql
|
|
CREATE EXTENSION vector;
|
|
CREATE TABLE embeddings (
|
|
id UUID PRIMARY KEY,
|
|
embedding vector(1536),
|
|
{{fields}}
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
## Infrastructure
|
|
|
|
### MVP Deployment ({{Railway/Vercel/etc}})
|
|
{{Configuration, services, why chosen}}
|
|
|
|
### Production Deployment ({{GKE/ECS/etc}})
|
|
{{When to migrate, architecture, cost}}
|
|
|
|
---
|
|
|
|
## Security Architecture
|
|
|
|
### Authentication & Authorization
|
|
{{Flow diagram, JWT details, code examples}}
|
|
|
|
### Rate Limiting
|
|
{{Tier-based limits, implementation with code}}
|
|
|
|
### Data Encryption
|
|
{{At rest, in transit}}
|
|
|
|
---
|
|
|
|
## Deployment Strategy
|
|
|
|
### CI/CD Pipeline
|
|
```yaml
|
|
{{GitHub Actions or similar YAML}}
|
|
```
|
|
|
|
### Database Migrations
|
|
{{Alembic/Flyway examples}}
|
|
|
|
---
|
|
|
|
## Monitoring & Observability
|
|
|
|
### Metrics (Prometheus)
|
|
```python
|
|
{{Code examples of metrics}}
|
|
```
|
|
|
|
### Logging
|
|
```python
|
|
{{Structured logging examples}}
|
|
```
|
|
|
|
---
|
|
|
|
## Appendix
|
|
|
|
### Technology Decisions
|
|
|
|
| Component | Choice | Alternatives | Rationale |
|
|
|-----------|--------|-------------|-----------|
|
|
| Frontend | {{choice}} | {{alt1, alt2}} | {{why}} |
|
|
| Backend | {{choice}} | {{alt1, alt2}} | {{why}} |
|
|
| Database | {{choice}} | {{alt1, alt2}} | {{why}} |
|
|
|
|
### Performance Benchmarks
|
|
|
|
| Metric | Target | Measurement |
|
|
|--------|--------|-------------|
|
|
| {{metric}} | {{target}} | {{how measured}} |
|
|
|
|
### Cost Estimates
|
|
|
|
**MVP:**
|
|
- {{Service 1}}: ${{X}}/month
|
|
- {{Service 2}}: ${{Y}}/month
|
|
- **Total: ~${{Z}}/month**
|
|
|
|
**Production:**
|
|
- {{Scaled costs}}
|
|
|
|
---
|
|
|
|
**Document Status:** ✅ Ready for Implementation
|
|
**Next Steps:** Epic breakdown, story writing
|
|
|
|
---
|
|
|
|
Be comprehensive. Include real code examples. Be specific with costs."""
|
|
|
|
# Use same model for part 2 (Sonnet supports 16384 output tokens)
|
|
response_part2 = client.messages.create(
|
|
model=model,
|
|
max_tokens=16000,
|
|
temperature=0.3,
|
|
messages=[{"role": "user", "content": prompt_part2}]
|
|
)
|
|
|
|
arch_part2 = response_part2.content[0].text.strip()
|
|
|
|
# Combine parts
|
|
arch_content = arch_part1 + "\n\n" + arch_part2
|
|
|
|
# Save to file
|
|
arch_path = Path(project_path) / "bmad-backlog" / "architecture" / "architecture.md"
|
|
arch_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
with open(arch_path, 'w', encoding='utf-8', newline='\n') as f:
|
|
f.write(arch_content)
|
|
|
|
return arch_content
|
|
|
|
except Exception as e:
|
|
print(f"Error generating architecture: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def generate_epic(prd_path: str, arch_path: str, epic_number: int, project_path: str) -> str:
|
|
"""
|
|
Generate single epic file with user stories.
|
|
|
|
Args:
|
|
prd_path: Path to prd.md
|
|
arch_path: Path to architecture.md
|
|
epic_number: Epic number to generate
|
|
project_path: Project directory path
|
|
|
|
Returns:
|
|
Generated epic content
|
|
"""
|
|
load_dotenv()
|
|
|
|
api_key = os.getenv("ANTHROPIC_API_KEY")
|
|
if not api_key:
|
|
print("Error: ANTHROPIC_API_KEY not found", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
# Read PRD and Architecture
|
|
try:
|
|
with open(prd_path, 'r', encoding='utf-8') as f:
|
|
prd_content = f.read()
|
|
with open(arch_path, 'r', encoding='utf-8') as f:
|
|
arch_content = f.read()
|
|
except Exception as e:
|
|
print(f"Error reading documents: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
from anthropic import Anthropic
|
|
client = Anthropic(api_key=api_key)
|
|
|
|
current_date = datetime.now().strftime("%B %d, %Y")
|
|
|
|
# Extract epic info from PRD
|
|
epic_pattern = f"### Epic {epic_number}:"
|
|
epic_section = extract_section(prd_content, epic_pattern)
|
|
|
|
if not epic_section:
|
|
print(f"Error: Epic {epic_number} not found in PRD", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
prompt = f"""Generate a detailed Epic file following BMAD methodology.
|
|
|
|
Epic from PRD:
|
|
{epic_section}
|
|
|
|
Relevant Architecture (for technical notes):
|
|
{arch_content[:2000]}
|
|
|
|
Create epic file with this structure:
|
|
|
|
# EPIC-{epic_number:03d}: {{Epic Title}}
|
|
|
|
**Epic Owner:** {{Team or role}}
|
|
**Priority:** P0 (Must Have) or P1 (Should Have) or P2 (Nice to Have)
|
|
**Target Sprint:** Sprint {{X-Y}}
|
|
**Status:** 📋 Not Started
|
|
**Estimated Effort:** {{X}} story points
|
|
|
|
---
|
|
|
|
## Epic Description
|
|
|
|
{{2-3 paragraphs explaining:
|
|
- What this epic delivers
|
|
- Why it's important
|
|
- How it fits in the overall product}}
|
|
|
|
---
|
|
|
|
## Business Value
|
|
|
|
- {{Value point 1}}
|
|
- {{Value point 2}}
|
|
- {{Value point 3}}
|
|
|
|
---
|
|
|
|
## Success Criteria
|
|
|
|
- [ ] {{Epic-level success criterion 1}}
|
|
- [ ] {{Epic-level success criterion 2}}
|
|
- [ ] {{Epic-level success criterion 3}}
|
|
|
|
---
|
|
|
|
## User Stories
|
|
|
|
{{Generate 8-15 user stories for this epic}}
|
|
|
|
### STORY-{epic_number:03d}-{{story_num:02d}}: {{Story Title}}
|
|
**As a** {{user type}}
|
|
**I want** {{action}}
|
|
**So that** {{benefit}}
|
|
|
|
**Acceptance Criteria:**
|
|
- [ ] {{Criterion 1}}
|
|
- [ ] {{Criterion 2}}
|
|
- [ ] {{Criterion 3}}
|
|
|
|
**Technical Notes:**
|
|
```{{language}}
|
|
{{Code examples, file structures, or implementation hints from architecture}}
|
|
```
|
|
|
|
{{Repeat for all stories in this epic}}
|
|
|
|
---
|
|
|
|
## Dependencies
|
|
|
|
**Blocks:**
|
|
- {{What this epic enables}}
|
|
|
|
**Blocked By:**
|
|
- {{What must be done first}}
|
|
|
|
---
|
|
|
|
## Risks & Mitigation
|
|
|
|
| Risk | Impact | Likelihood | Mitigation |
|
|
|------|--------|-----------|------------|
|
|
| {{Risk}} | {{High/Med/Low}} | {{High/Med/Low}} | {{Mitigation}} |
|
|
|
|
---
|
|
|
|
## Technical Debt
|
|
|
|
- [ ] {{Known shortcut or future improvement}}
|
|
- [ ] {{Another item}}
|
|
|
|
---
|
|
|
|
## Related Epics
|
|
|
|
- **EPIC-{{X}}:** {{Relationship}}
|
|
- **EPIC-{{Y}}:** {{Relationship}}
|
|
|
|
---
|
|
|
|
## Definition of Done
|
|
|
|
- [ ] All user stories accepted by Product Owner
|
|
- [ ] Code reviewed and merged
|
|
- [ ] Unit tests pass with >70% coverage
|
|
- [ ] Integration tests pass
|
|
- [ ] Deployed to staging
|
|
- [ ] Documentation updated
|
|
|
|
---
|
|
|
|
**Last Updated:** {current_date}
|
|
**Status History:**
|
|
- {current_date}: Epic created
|
|
|
|
---
|
|
|
|
IMPORTANT:
|
|
- Be comprehensive (300-500 lines)
|
|
- Stories should be sequentially logical
|
|
- Include technical notes with code examples
|
|
- Reference architecture document
|
|
- Story format: STORY-{epic_number:03d}-{{num:02d}}
|
|
- Make acceptance criteria specific and testable"""
|
|
|
|
try:
|
|
# Use Haiku for epic generation (documentation)
|
|
model = get_claude_model("default")
|
|
|
|
# Haiku 4.5 supports up to 16384 output tokens
|
|
response = client.messages.create(
|
|
model=model,
|
|
max_tokens=16000,
|
|
temperature=0.3,
|
|
messages=[{"role": "user", "content": prompt}]
|
|
)
|
|
|
|
epic_content = response.content[0].text.strip()
|
|
|
|
# Extract epic title for filename
|
|
title_match = re.search(r'EPIC-\d+:\s*(.+)', epic_content)
|
|
epic_title = title_match.group(1).strip() if title_match else "epic"
|
|
epic_slug = epic_title.lower().replace(' ', '-').replace('&', 'and')
|
|
|
|
# Save to file
|
|
epic_path = Path(project_path) / "bmad-backlog" / "epics" / f"EPIC-{epic_number:03d}-{epic_slug}.md"
|
|
epic_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
with open(epic_path, 'w', encoding='utf-8', newline='\n') as f:
|
|
f.write(epic_content)
|
|
|
|
return epic_content
|
|
|
|
except Exception as e:
|
|
print(f"Error generating epic: {e}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def extract_section(content: str, section_header: str) -> str:
|
|
"""Extract section from markdown document."""
|
|
lines = content.split('\n')
|
|
section_lines = []
|
|
in_section = False
|
|
|
|
for line in lines:
|
|
if section_header.lower() in line.lower():
|
|
in_section = True
|
|
elif in_section and line.startswith('#') and section_header not in line:
|
|
break
|
|
elif in_section:
|
|
section_lines.append(line)
|
|
|
|
return '\n'.join(section_lines).strip()
|
|
|
|
|
|
def generate_index(epics_dir: str, project_path: str) -> str:
|
|
"""
|
|
Generate STORY-INDEX.md from all epic files.
|
|
|
|
Args:
|
|
epics_dir: Path to epics directory
|
|
project_path: Project directory path
|
|
|
|
Returns:
|
|
Generated index content
|
|
"""
|
|
epics_path = Path(epics_dir)
|
|
|
|
if not epics_path.exists():
|
|
print(f"Error: Epics directory not found: {epics_dir}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
# Scan for epic files
|
|
epic_files = sorted(epics_path.glob("EPIC-*.md"))
|
|
|
|
if not epic_files:
|
|
print("Error: No epic files found", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
# Parse each epic
|
|
epics_data = []
|
|
total_stories = 0
|
|
total_points = 0
|
|
|
|
for epic_file in epic_files:
|
|
with open(epic_file, 'r', encoding='utf-8') as f:
|
|
content = f.read()
|
|
|
|
# Extract epic number and name
|
|
match = re.search(r'EPIC-(\d+):\s*(.+)', content)
|
|
if match:
|
|
epic_num = int(match.group(1))
|
|
epic_name = match.group(2).strip()
|
|
else:
|
|
continue
|
|
|
|
# Count stories
|
|
story_count = len(re.findall(r'### STORY-\d+-\d+:', content))
|
|
|
|
# Estimate story points (rough - could parse if documented)
|
|
estimated_points = story_count * 4 # Average 4 points per story
|
|
|
|
epics_data.append({
|
|
'number': epic_num,
|
|
'name': epic_name,
|
|
'stories': story_count,
|
|
'points': estimated_points,
|
|
'file': epic_file.name
|
|
})
|
|
|
|
total_stories += story_count
|
|
total_points += estimated_points
|
|
|
|
# Generate index
|
|
current_date = datetime.now().strftime("%B %d, %Y")
|
|
|
|
# Extract project name (prioritize PRD > Brief > Epic, avoid file leaks)
|
|
project_name = "Project" # Default
|
|
|
|
# Try PRD first
|
|
prd_file = Path(project_path) / "bmad-backlog" / "prd" / "prd.md"
|
|
if prd_file.exists():
|
|
try:
|
|
with open(prd_file, 'r', encoding='utf-8') as f:
|
|
project_name = extract_project_name(f.read())
|
|
except Exception:
|
|
pass
|
|
|
|
# If no name from PRD, try Brief
|
|
if project_name == "Project":
|
|
brief_file = Path(project_path) / "bmad-backlog" / "product-brief.md"
|
|
if brief_file.exists():
|
|
try:
|
|
with open(brief_file, 'r', encoding='utf-8') as f:
|
|
project_name = extract_project_name(f.read())
|
|
except Exception:
|
|
pass
|
|
|
|
# If still no name, fall back to first epic
|
|
if project_name == "Project" and epic_files:
|
|
try:
|
|
with open(epic_files[0], 'r', encoding='utf-8') as f:
|
|
project_name = extract_project_name(f.read())
|
|
except Exception:
|
|
pass
|
|
|
|
index_content = f"""# {project_name} - Story Index
|
|
|
|
**Total Epics:** {len(epics_data)}
|
|
**Total User Stories:** {total_stories}
|
|
**Total Story Points:** {total_points} (estimated)
|
|
**Version:** 1.0
|
|
**Last Updated:** {current_date}
|
|
|
|
---
|
|
|
|
## Epic Overview
|
|
|
|
| Epic ID | Epic Name | Stories | Story Points | Status |
|
|
|---------|-----------|---------|--------------|--------|
|
|
"""
|
|
|
|
for epic in epics_data:
|
|
index_content += f"| EPIC-{epic['number']:03d} | {epic['name']} | {epic['stories']} | {epic['points']} | Not Started |\n"
|
|
|
|
index_content += f"| **TOTAL** | | **{total_stories}** | **{total_points}** | |\n"
|
|
index_content += "\n---\n\n"
|
|
|
|
# Add per-epic story details (would need to parse story IDs from files)
|
|
index_content += """## Story Details
|
|
|
|
For detailed story breakdown, see individual epic files in `epics/` directory.
|
|
|
|
---
|
|
|
|
## Priority Distribution
|
|
|
|
{{To be calculated from individual story priorities}}
|
|
|
|
---
|
|
|
|
## Development Phases
|
|
|
|
{{To be defined based on epic dependencies and sequencing}}
|
|
|
|
---
|
|
|
|
**Next Steps:**
|
|
1. Review and approve epic breakdown
|
|
2. Prioritize stories for Sprint 1
|
|
3. Begin implementation with `/titanium:plan bmad-backlog/epics/EPIC-001-*.md`
|
|
|
|
"""
|
|
|
|
# Save to file
|
|
index_path = Path(project_path) / "bmad-backlog" / "STORY-INDEX.md"
|
|
|
|
with open(index_path, 'w', encoding='utf-8', newline='\n') as f:
|
|
f.write(index_content)
|
|
|
|
return index_content
|
|
|
|
|
|
def main():
|
|
"""CLI interface for BMAD document generation."""
|
|
|
|
if len(sys.argv) < 3:
|
|
print("Usage: bmad_generator.py <command> <args...>", file=sys.stderr)
|
|
print("\nCommands:", file=sys.stderr)
|
|
print(" brief <idea> <project_path>", file=sys.stderr)
|
|
print(" prd <brief_path> <project_path>", file=sys.stderr)
|
|
print(" architecture <prd_path> <project_path>", file=sys.stderr)
|
|
print(" epic <prd_path> <arch_path> <epic_num> <project_path>", file=sys.stderr)
|
|
print(" index <epics_dir> <project_path>", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
command = sys.argv[1]
|
|
|
|
try:
|
|
if command == "brief":
|
|
if len(sys.argv) < 4:
|
|
print("Error: brief command requires <idea> <project_path>", file=sys.stderr)
|
|
print("Usage: bmad_generator.py brief \"idea\" \"$(pwd)\"", file=sys.stderr)
|
|
sys.exit(1)
|
|
idea = sys.argv[2]
|
|
project_path = sys.argv[3]
|
|
generate_brief(idea, project_path)
|
|
print("✅ Product brief generated: bmad-backlog/product-brief.md")
|
|
|
|
elif command == "prd":
|
|
if len(sys.argv) < 4:
|
|
print("Error: prd command requires <brief_path> <project_path>", file=sys.stderr)
|
|
print("Usage: bmad_generator.py prd bmad-backlog/product-brief.md \"$(pwd)\"", file=sys.stderr)
|
|
sys.exit(1)
|
|
brief_path = sys.argv[2]
|
|
project_path = sys.argv[3]
|
|
generate_prd(brief_path, project_path)
|
|
print("✅ PRD generated: bmad-backlog/prd/prd.md")
|
|
|
|
elif command == "architecture":
|
|
if len(sys.argv) < 4:
|
|
print("Error: architecture command requires <prd_path> <project_path>", file=sys.stderr)
|
|
print("Usage: bmad_generator.py architecture bmad-backlog/prd/prd.md \"$(pwd)\"", file=sys.stderr)
|
|
sys.exit(1)
|
|
prd_path = sys.argv[2]
|
|
project_path = sys.argv[3]
|
|
generate_architecture(prd_path, project_path)
|
|
print("✅ Architecture generated: bmad-backlog/architecture/architecture.md")
|
|
|
|
elif command == "epic":
|
|
if len(sys.argv) < 6:
|
|
print("Error: epic command requires <prd_path> <arch_path> <epic_num> <project_path>", file=sys.stderr)
|
|
print("Usage: bmad_generator.py epic bmad-backlog/prd/prd.md bmad-backlog/architecture/architecture.md 1 \"$(pwd)\"", file=sys.stderr)
|
|
sys.exit(1)
|
|
prd_path = sys.argv[2]
|
|
arch_path = sys.argv[3]
|
|
try:
|
|
epic_num = int(sys.argv[4])
|
|
except ValueError:
|
|
print(f"Error: epic_num must be an integer, got: {sys.argv[4]}", file=sys.stderr)
|
|
sys.exit(1)
|
|
project_path = sys.argv[5]
|
|
generate_epic(prd_path, arch_path, epic_num, project_path)
|
|
print(f"✅ Epic {epic_num} generated")
|
|
|
|
elif command == "index":
|
|
if len(sys.argv) < 4:
|
|
print("Error: index command requires <epics_dir> <project_path>", file=sys.stderr)
|
|
print("Usage: bmad_generator.py index bmad-backlog/epics/ \"$(pwd)\"", file=sys.stderr)
|
|
sys.exit(1)
|
|
epics_dir = sys.argv[2]
|
|
project_path = sys.argv[3]
|
|
generate_index(epics_dir, project_path)
|
|
print("✅ Story index generated: bmad-backlog/STORY-INDEX.md")
|
|
|
|
else:
|
|
print(f"Error: Unknown command: {command}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
except Exception as e:
|
|
print(f"Error: {e!s}", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|