feat(bmvcs): add VCS adaptation examples

Add practical examples demonstrating VCS-agnostic adaptation:
- vcs-adaptation-examples.md: 6 real-world scenarios (GitHub Flow,
  GitFlow, No VCS, SVN, Trunk-Based, Multi-VCS)
- vcs-detection-implementation.py: Reference implementation of Git
  workflow auto-detection with confidence scoring
- examples/README.md: Guide to using examples and integration

Examples demonstrate "Detection as a HINT, not a DECISION" principle
with evidence-based suggestions and user confirmation.

Part 4/5 of BMVCS migration (#661)

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Serhii 2025-09-30 20:07:04 +03:00
parent bccfe9d651
commit 29d4dc030c
No known key found for this signature in database
GPG Key ID: 84A22AF415BE7704
3 changed files with 752 additions and 0 deletions

View File

@ -0,0 +1,79 @@
# BMVCS Examples
Practical examples demonstrating VCS-agnostic adaptation in BMAD.
## Files in This Directory
### [vcs-adaptation-examples.md](./vcs-adaptation-examples.md)
**Real-world scenarios** showing how BMAD adapts to different VCS workflows:
- **Startup with GitHub Flow**: Fast-paced web development
- **Enterprise with GitFlow**: Structured releases with versions
- **No Version Control**: One-time scripts and prototypes
- **Custom SVN Workflow**: Legacy system adaptation
- **Trunk-Based with Feature Flags**: Continuous deployment
- **Complex Multi-VCS Setup**: Mixed systems in one organization
Each example shows discovery dialogue, BMAD adaptations, and generated artifacts.
### [vcs-detection-implementation.py](./vcs-detection-implementation.py)
**Reference implementation** of Git workflow auto-detection:
- Analyzes repository history to detect workflow patterns
- Calculates confidence scores for GitFlow, GitHub Flow, and Trunk-Based
- Follows "Detection as a HINT, not a DECISION" principle
- Interactive confirmation with evidence presentation
- Handles edge cases (migration, unclear patterns, fresh repos)
**Note**: This is an example implementation in Python. The actual BMAD implementation may use JavaScript/TypeScript. This demonstrates the detection logic that can be adapted to any language.
## Usage
### Running the Detector Example
```bash
cd /path/to/your/git/repo
python /path/to/vcs-detection-implementation.py
```
The script will:
1. Analyze your Git history
2. Score workflow indicators
3. Present detection results with evidence
4. Ask for confirmation (never auto-decides)
5. Save configuration to `.bmad/vcs_config.json`
### Understanding the Examples
The adaptation examples show specific output for each workflow type. Use them as:
- **Reference**: See how BMAD should adapt terminology and structure
- **Templates**: Copy patterns for custom integrations
- **Documentation**: Explain VCS-agnostic behavior to users
## Key Principles Demonstrated
1. **Discovery First**: Always ask, never assume
2. **Evidence-Based**: Show detection reasoning transparently
3. **User Confirmation**: Detection is advisory, not prescriptive
4. **Graceful Fallback**: Handle unclear cases with questions
5. **Respect Existing**: Adapt to their workflow, don't change it
## Integration with BMAD Agents
These examples inform how all BMAD agents should adapt:
- **Architect**: Generate VCS-appropriate architecture docs
- **PM**: Create requirements matching workflow style
- **SM**: Size stories for the team's release cadence
- **Dev**: Suggest VCS-appropriate code delivery
- **QA**: Align test plans with workflow gates
## Further Reading
- [VCS Agnostic Principles](../docs/VCS_AGNOSTIC_PRINCIPLES.md)
- [Detection Confidence Scoring](../docs/VCS_DETECTION_CONFIDENCE.md)
- [Discovery Task Implementation](../tasks/discover-vcs.md)

View File

@ -0,0 +1,293 @@
# VCS Adaptation Examples
## Real-World Scenarios: How BMAD Adapts
### Example 1: Startup with GitHub Flow
**Context:** 5-person team, web SaaS, deploys daily
**Discovery:**
```
BMAD: "How does your team manage code versions?"
User: "Git with GitHub"
BMAD: "Which Git workflow best describes your approach?"
User: "GitHub Flow - simple feature branches"
```
**BMAD Adapts:**
- Architect generates lightweight, PR-sized architecture updates
- SM creates 1-3 day stories that map to single PRs
- Dev suggests branch names like `feature/add-user-auth`
- All docs optimized for quick review in PR comments
**Generated Architecture Snippet:**
```markdown
## Payment Service Update
_PR: #234 - feature/add-stripe-integration_
### Changes in This PR
- New Stripe webhook handler
- Updated payment models
- Added retry logic
### Testing
- [ ] Unit tests for webhook handler
- [ ] Integration test with Stripe test mode
- [ ] Manual testing checklist in PR
```
---
### Example 2: Enterprise with GitFlow
**Context:** 50-person team, banking software, quarterly releases
**Discovery:**
```
BMAD: "How does your team manage code versions?"
User: "Git with corporate server"
BMAD: "Which Git workflow?"
User: "GitFlow - we have develop, release, and hotfix branches"
```
**BMAD Adapts:**
- Architect creates version-oriented architecture docs
- PM generates release-scoped PRDs
- SM groups stories by release version
- Dev follows strict branch naming
**Generated Architecture Snippet:**
```markdown
## Release 2.4.0 Architecture
### Version Highlights
- New authentication system (breaking change)
- Performance improvements
- Database migration required
### Branch Status
- develop: v2.5.0 features in progress
- release/2.4.0: Final testing
- hotfix/2.3.1: Critical fix for production
### Migration Guide
From 2.3.x to 2.4.0:
1. Run migration script
2. Update config files
3. Restart services in order
```
---
### Example 3: No Version Control
**Context:** Data scientist, one-time analysis script
**Discovery:**
```
BMAD: "How does your team manage code versions?"
User: "No version control needed - this is a one-time script"
```
**BMAD Adapts:**
- All code in single, runnable package
- Extensive inline documentation
- No commit messages or branch references
- Date-stamped delivery
**Generated Package:**
```
customer_analysis_20240315/
├── README.md # Complete instructions
├── requirements.txt # All Python dependencies
├── analysis.py # Full script with comments
├── data/
│ └── sample.csv # Sample data format
└── output/
└── results_template.xlsx
```
**README Content:**
```markdown
# Customer Analysis Script
Generated: 2024-03-15
## Quick Start
1. Install dependencies: pip install -r requirements.txt
2. Place your data in data/input.csv
3. Run: python analysis.py
4. Results appear in output/
## No Version Control Required
This is a complete, self-contained package.
```
---
### Example 4: Custom SVN Workflow
**Context:** Game studio using Subversion
**Discovery:**
```
BMAD: "How does your team manage code versions?"
User: "Other version control system"
BMAD: "Which system?"
User: "Subversion (SVN)"
```
**BMAD Adapts:**
- Uses "revision" instead of "commit"
- References trunk/branches/tags structure
- Revision numbers, not hashes
- SVN-specific commands
**Generated Instructions:**
```markdown
## Integration Steps
1. Update your working copy:
svn update
2. Create feature branch:
svn copy ^/trunk ^/branches/feature-player-inventory
3. After implementation:
svn merge ^/branches/feature-player-inventory
4. Commit with revision message:
svn commit -m "Add player inventory system (refs ticket #456)"
```
---
### Example 5: Trunk-Based with Feature Flags
**Context:** Netflix-style continuous deployment
**Discovery:**
```
BMAD: "How does your team manage code versions?"
User: "Git with GitHub"
BMAD: "Which Git workflow?"
User: "Trunk-Based - we deploy continuously"
```
**BMAD Adapts:**
- Everything behind feature flags
- Tiny, hours-long tasks
- Direct commits or same-day PRs
- Progressive rollout plans
**Generated Story:**
````markdown
## Story: Add Recommendation Engine
Size: 4 hours
Flag: `recommendation-engine-v2`
### Implementation
```python
if feature_flag.is_enabled("recommendation-engine-v2", user_id):
return new_recommendation_engine(user_id)
else:
return legacy_recommendations(user_id)
```
````
### Rollout Plan
- Hour 1-2: Implement behind flag (0% users)
- Hour 3: Deploy and enable for employees
- Hour 4: Enable for 1% external users
- Day 2: 10% if metrics good
- Day 3: 50%
- Day 5: 100% and schedule flag removal
```
---
### Example 6: Complex Multi-VCS Setup
**Context:** Enterprise with mixed systems
**Discovery:**
```
BMAD: "How does your team manage code versions?"
User: "Custom/Complex setup"
BMAD: "Please describe:"
User: "Frontend in Git, backend in Perforce, configs in SVN"
````
**BMAD Adapts:**
- Asks for component-specific preferences
- Generates VCS-appropriate artifacts per component
- Uses neutral terminology in cross-component docs
**Generated Guidance:**
```markdown
## Multi-VCS Development Guide
### Frontend (Git/GitHub Flow)
- Feature branches from main
- PR review process
- Deploy on merge
### Backend (Perforce)
- Create changelist for features
- Submit after review
- Changelist numbers in deployment notes
### Configuration (SVN)
- Update from trunk before changes
- Commit with revision references
- Tag for production releases
### Cross-Component Changes
When updating across systems:
1. Frontend PR: #123
2. Backend Changelist: 456789
3. Config Revision: r1234
Reference all three in deployment ticket.
````
## Key Takeaways
1. **BMAD never assumes** - always discovers first
2. **Adapts terminology** - commit/changelist/revision as appropriate
3. **Respects workflows** - doesn't try to "improve" existing processes
4. **Practical focus** - generates what works with their tools
5. **Clear communication** - uses the team's language
This flexibility makes BMAD valuable to ANY team, regardless of their VCS choice.

View File

@ -0,0 +1,380 @@
#!/usr/bin/env python3
"""
Example implementation of VCS workflow auto-detection for BMAD agents.
This can be adapted for different languages and Git libraries.
"""
import subprocess
import json
from datetime import datetime, timedelta
from typing import Dict, List, Tuple, Optional
class GitWorkflowDetector:
"""
Auto-detect Git workflow from repository history.
Follows the principle: "Detection as a HINT, not a DECISION"
"""
def __init__(self, repo_path: str = '.'):
self.repo_path = repo_path
self.confidence_threshold = 0.7
def run_git_command(self, cmd: str) -> Optional[str]:
"""Execute git command and return output"""
try:
result = subprocess.run(
cmd.split(),
cwd=self.repo_path,
capture_output=True,
text=True,
check=True
)
return result.stdout.strip()
except subprocess.CalledProcessError:
return None
def detect_workflow(self) -> Dict:
"""
Main detection method that returns workflow suggestion with confidence.
"""
if not self.is_git_repo():
return {
'detected': False,
'reason': 'Not a Git repository'
}
# Calculate scores for each workflow
gitflow_score = self._score_gitflow()
github_flow_score = self._score_github_flow()
trunk_based_score = self._score_trunk_based()
# Check for migration
migration_info = self._detect_migration()
# Determine best match
scores = {
'gitflow': gitflow_score,
'github_flow': github_flow_score,
'trunk_based': trunk_based_score
}
best_workflow = max(scores.items(), key=lambda x: x[1]['score'])
workflow_name = best_workflow[0]
confidence = best_workflow[1]['score']
evidence = best_workflow[1]['evidence']
# Check if confidence meets threshold
if confidence < self.confidence_threshold:
return {
'detected': True,
'workflow': 'unclear',
'confidence': confidence,
'evidence': evidence,
'needs_clarification': True,
'migration_detected': migration_info['detected']
}
return {
'detected': True,
'workflow': workflow_name,
'confidence': confidence,
'evidence': evidence,
'migration_detected': migration_info['detected'],
'migration_info': migration_info if migration_info['detected'] else None
}
def is_git_repo(self) -> bool:
"""Check if current directory is a Git repository"""
return self.run_git_command('git rev-parse --git-dir') is not None
def _score_gitflow(self) -> Dict:
"""Score GitFlow indicators"""
score = 0.0
evidence = []
# Check for develop branch
branches = self.run_git_command('git branch -a')
if branches and ('develop' in branches or 'development' in branches):
score += 0.3
evidence.append("Found develop branch")
# Check for release branches
if branches and 'release/' in branches:
release_count = branches.count('release/')
score += 0.3
evidence.append(f"Found {release_count} release branches")
# Check for hotfix branches
if branches and 'hotfix/' in branches:
score += 0.2
evidence.append("Found hotfix branches")
# Check for version tags
tags = self.run_git_command('git tag -l v*')
if tags:
tag_count = len(tags.split('\n'))
score += 0.2
evidence.append(f"Found {tag_count} version tags")
return {'score': score, 'evidence': evidence}
def _score_github_flow(self) -> Dict:
"""Score GitHub Flow indicators"""
score = 0.0
evidence = []
# Check for PR merge patterns in recent commits
recent_commits = self.run_git_command(
'git log --oneline --since="90 days ago" --grep="Merge pull request"'
)
if recent_commits:
pr_count = len(recent_commits.split('\n'))
score += 0.3
evidence.append(f"Found {pr_count} PR merges in last 90 days")
# Check for squash merge patterns
squash_commits = self.run_git_command(
'git log --oneline --since="90 days ago" --grep="(#"'
)
if squash_commits:
score += 0.2
evidence.append("Found squash-merge patterns")
# Check average branch lifespan (simplified)
branches = self.run_git_command('git branch -a')
if branches and 'feature/' in branches:
score += 0.3
evidence.append("Using feature branch naming")
# No develop branch is positive for GitHub Flow
if branches and 'develop' not in branches:
score += 0.2
evidence.append("No develop branch (GitHub Flow indicator)")
return {'score': score, 'evidence': evidence}
def _score_trunk_based(self) -> Dict:
"""Score Trunk-Based Development indicators"""
score = 0.0
evidence = []
# Check ratio of direct commits to main
main_commits = self.run_git_command(
'git log --oneline --since="90 days ago" --first-parent main'
)
all_commits = self.run_git_command(
'git log --oneline --since="90 days ago"'
)
if main_commits and all_commits:
main_count = len(main_commits.split('\n'))
total_count = len(all_commits.split('\n'))
ratio = main_count / total_count
if ratio > 0.5:
score += 0.4
evidence.append(f"{int(ratio * 100)}% commits directly to main")
# Check for feature flags in commit messages
feature_flag_commits = self.run_git_command(
'git log --oneline --since="90 days ago" --grep="feature flag" -i'
)
if feature_flag_commits:
score += 0.3
evidence.append("Found feature flag usage in commits")
# Check for very short-lived branches (would need more complex analysis)
# Simplified: check if most branches are deleted quickly
deleted_branches = self.run_git_command('git reflog show --all | grep "branch:"')
if deleted_branches:
score += 0.3
evidence.append("Pattern suggests short-lived branches")
return {'score': score, 'evidence': evidence}
def _detect_migration(self) -> Dict:
"""Detect if workflow has changed recently"""
# Compare recent vs historical commit patterns
recent = self.run_git_command(
'git log --oneline --since="30 days ago" --pretty=format:"%d"'
)
historical = self.run_git_command(
'git log --oneline --since="90 days ago" --until="30 days ago" --pretty=format:"%d"'
)
if not recent or not historical:
return {'detected': False}
# Simple heuristic: check if branch naming patterns changed
recent_has_develop = 'develop' in recent
historical_has_develop = 'develop' in historical
if recent_has_develop != historical_has_develop:
return {
'detected': True,
'recent_pattern': 'GitFlow-like' if recent_has_develop else 'GitHub Flow-like',
'historical_pattern': 'GitFlow-like' if historical_has_develop else 'GitHub Flow-like'
}
return {'detected': False}
def interactive_confirmation(self, detection_result: Dict) -> str:
"""
Present detection results to user and get confirmation.
This demonstrates the "hint not decision" principle.
"""
if not detection_result['detected']:
print(f"{detection_result['reason']}")
return self.manual_selection()
if detection_result['workflow'] == 'unclear':
print("🤔 Could not confidently detect your workflow.")
print(f" Confidence: {detection_result['confidence']:.1%}")
return self.clarifying_questions()
# Present detection with evidence
print(f"🔍 Analyzed your Git history...")
print(f"\nDetected workflow: **{detection_result['workflow']}**")
print(f"Confidence: {detection_result['confidence']:.1%}\n")
print("Evidence:")
for item in detection_result['evidence']:
print(f"{item}")
if detection_result['migration_detected']:
print("\n📊 Note: Detected a possible workflow change recently")
print(f" Recent: {detection_result['migration_info']['recent_pattern']}")
print(f" Historical: {detection_result['migration_info']['historical_pattern']}")
# Get confirmation
print("\nIs this correct?")
print("1. Yes, that's right")
print("2. No, we actually use something else")
print("3. We recently changed our approach")
print("4. It's more complex than that")
choice = input("\nSelect (1-4): ")
if choice == '1':
return detection_result['workflow']
elif choice == '3':
return self.handle_migration()
else:
return self.manual_selection()
def clarifying_questions(self) -> str:
"""Ask progressive questions when detection is unclear"""
print("\nLet me ask a few questions to understand your workflow better:\n")
# Progressive questions to increase confidence
score_adjustments = {
'gitflow': 0,
'github_flow': 0,
'trunk_based': 0
}
# Question 1: Team size
print("1. How many developers actively commit code?")
print(" a) Just me")
print(" b) 2-5 developers")
print(" c) 6+ developers")
team_size = input("Select (a-c): ")
if team_size == 'a':
score_adjustments['trunk_based'] += 0.3
elif team_size == 'b':
score_adjustments['github_flow'] += 0.2
elif team_size == 'c':
score_adjustments['gitflow'] += 0.2
# Question 2: Release frequency
print("\n2. How often do you release to production?")
print(" a) Multiple times daily")
print(" b) Weekly")
print(" c) Monthly or less frequently")
release_freq = input("Select (a-c): ")
if release_freq == 'a':
score_adjustments['trunk_based'] += 0.3
elif release_freq == 'b':
score_adjustments['github_flow'] += 0.3
elif release_freq == 'c':
score_adjustments['gitflow'] += 0.3
# Determine recommendation
best_workflow = max(score_adjustments.items(), key=lambda x: x[1])
return best_workflow[0]
def manual_selection(self) -> str:
"""Fallback to manual workflow selection"""
print("\nWhich Git workflow best describes your team's approach?\n")
print("1. GitHub Flow - Simple feature branches with pull requests")
print(" → Best for: Web apps, continuous deployment\n")
print("2. GitFlow - Structured branches (develop, release, hotfix)")
print(" → Best for: Versioned software, scheduled releases\n")
print("3. Trunk-Based - Direct commits or very short branches")
print(" → Best for: Mature CI/CD, experienced teams\n")
print("4. Custom Git workflow")
choice = input("Select (1-4): ")
workflow_map = {
'1': 'github_flow',
'2': 'gitflow',
'3': 'trunk_based',
'4': 'custom'
}
return workflow_map.get(choice, 'github_flow')
def handle_migration(self) -> str:
"""Handle workflow migration scenario"""
print("\nWhich workflow should BMAD optimize for?")
print("1. The new approach (we've completed migration)")
print("2. The old approach (recent activity was exceptional)")
print("3. Both (we're still transitioning)")
choice = input("Select (1-3): ")
if choice == '3':
print("\nWhich workflow is your target state?")
return self.manual_selection()
def main():
"""Example usage of the detector"""
detector = GitWorkflowDetector()
# Run detection
result = detector.detect_workflow()
# Get user confirmation (following "hint not decision" principle)
confirmed_workflow = detector.interactive_confirmation(result)
# Save configuration
config = {
'vcs_config': {
'type': 'git',
'workflow': confirmed_workflow,
'detection_method': 'auto-detected' if result['detected'] else 'user-selected',
'confidence_score': result.get('confidence', 0),
'detection_evidence': result.get('evidence', []),
'cache': {
'detected_at': datetime.now().isoformat(),
'valid_until': (datetime.now() + timedelta(days=7)).isoformat()
}
}
}
print(f"\n✅ Configuration saved!")
print(f" Workflow: {confirmed_workflow}")
print(f" All BMAD agents will adapt to your {confirmed_workflow} workflow.")
# Save to file (in real implementation)
with open('.bmad/vcs_config.json', 'w') as f:
json.dump(config, f, indent=2)
if __name__ == '__main__':
main()