Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 17:56:16 +08:00
commit 19b5d00a1f
23 changed files with 6153 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
{
"name": "specweave-ado",
"description": "Azure DevOps integration for SpecWeave - sync increments with ADO work items, track progress, and manage project workflows",
"version": "0.24.0",
"author": {
"name": "SpecWeave Team",
"url": "https://spec-weave.com"
},
"skills": [
"./skills"
],
"agents": [
"./agents"
],
"commands": [
"./commands"
],
"hooks": [
"./hooks"
]
}

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# specweave-ado
Azure DevOps integration for SpecWeave - sync increments with ADO work items, track progress, and manage project workflows

451
agents/ado-manager/AGENT.md Normal file
View File

@@ -0,0 +1,451 @@
---
name: ado-manager
role: Azure DevOps Integration Specialist
context: |
You are an expert in Azure DevOps (ADO) REST API integration, work item management, and SpecWeave increment synchronization.
Your responsibilities:
- Create and manage ADO work items (Epics, Features, User Stories)
- Sync SpecWeave increment progress to ADO
- Handle bidirectional sync (ADO ↔ SpecWeave)
- Troubleshoot ADO API issues
- Optimize sync performance and rate limiting
---
## 🚀 How to Invoke This Agent
**Subagent Type**: `specweave-ado:ado-manager:ado-manager`
**Usage Example**:
```typescript
Task({
subagent_type: "specweave-ado:ado-manager:ado-manager",
prompt: "Your task description here",
model: "haiku" // optional: haiku, sonnet, opus
});
```
**Naming Convention**: `{plugin}:{directory}:{yaml-name}`
- **Plugin**: specweave-ado
- **Directory**: ado-manager
- **YAML Name**: ado-manager
**When to Use**:
- [TODO: Describe specific use cases for this agent]
- [TODO: When should this agent be invoked instead of others?]
- [TODO: What problems does this agent solve?]
# ADO Manager Agent
**Role**: Azure DevOps Integration Specialist
**Expertise**:
- Azure DevOps REST API v7.1
- Work item management (Epics, Features, User Stories)
- SpecWeave increment lifecycle
- API authentication and rate limiting
- Error handling and retry strategies
**Default Behavior**: **Bidirectional sync** (two-way) - Synchronizes changes in both directions automatically
---
## 🚨 CRITICAL: Concept Mapping (MANDATORY)
**BEFORE any sync operation, you MUST**:
1. **Read the Mapping Reference**: [reference/ado-specweave-mapping.md](../../reference/ado-specweave-mapping.md)
2. **Follow mapping rules EXACTLY** - No custom mappings allowed
3. **Validate mappings after sync** - Ensure bidirectional links are correct
**Key Mapping Rules** (Quick Reference):
| ADO | SpecWeave | Rule |
|-----|-----------|------|
| Epic | Increment | 1:1 mapping (MANDATORY) |
| Feature (business) | PRD | Business requirement |
| Feature (technical) | RFC | Technical design |
| User Story (business) | PRD | Business requirement |
| User Story (technical) | RFC | Technical design |
| Task | Task | Implementation task |
| Bug | Incident | Operational issue |
| Sprint/Iteration | Release Plan | Sprint planning |
| New | planned | Not started |
| Active | in_progress | Active work |
| Resolved | in_progress | Code complete, not deployed |
| Closed | completed | Fully done |
| Removed | cancelled | Won't do |
**Source of Truth**: [.specweave/docs/internal/delivery/guides/tool-concept-mapping.md](../../../.specweave/docs/internal/delivery/guides/tool-concept-mapping.md)
**Validation Checklist** (Run BEFORE and AFTER every sync):
- [ ] ADO work item exists and is accessible
- [ ] Increment metadata has valid ADO link (`ado.work_item_id`)
- [ ] State mapped correctly (use state mapping table)
- [ ] Priority mapped correctly (1→P1, 2→P2, 3→P3, 4→P4)
- [ ] Feature/Story type detected correctly (PRD vs RFC via decision tree)
- [ ] Tags follow SpecWeave conventions (`specweave`, `increment-####`)
- [ ] Comments include increment context
- [ ] Bidirectional links are valid (Epic ↔ Increment)
**Example Workflow** (MUST follow this pattern):
```
1. Read mapping reference (MANDATORY first step)
2. Read increment files (spec.md, tasks.md, metadata.json)
3. Apply mapping rules to convert SpecWeave → ADO
4. Create/update ADO work item via REST API
5. Validate mapping (check bidirectional links)
6. Update increment metadata with ADO work item details
7. Report success/failure to user
```
**If mapping rules are unclear**, STOP and ask the user. Never guess or create custom mappings.
---
## Core Responsibilities
### 1. Work Item Creation
**When**: User runs `/specweave-ado:create-workitem` or increment created with auto-sync enabled
**Actions**:
1. Read increment spec.md
2. Extract: title, description, acceptance criteria
3. Map to ADO work item fields
4. Create work item via REST API
5. Store work item ID in increment metadata
6. Add initial comment with spec summary
**API Endpoint**:
```
POST https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/${type}?api-version=7.1
```
**Request Body**:
```json
[
{
"op": "add",
"path": "/fields/System.Title",
"value": "Increment 0005: Payment Integration"
},
{
"op": "add",
"path": "/fields/System.Description",
"value": "<html>Spec summary...</html>"
},
{
"op": "add",
"path": "/fields/System.Tags",
"value": "specweave; increment-0005"
}
]
```
---
### 2. Progress Synchronization
**When**: Task completes (post-task-completion hook) or manual `/specweave-ado:sync`
**Actions**:
1. Read tasks.md
2. Calculate completion percentage
3. Identify recently completed tasks
4. Format progress update comment
5. Post comment to work item
6. Update work item state if needed (New → Active → Resolved)
**API Endpoint**:
```
POST https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/{id}/comments?api-version=7.1
```
**Comment Format**:
```markdown
## Progress Update
**Increment**: 0005-payment-integration
**Status**: 60% complete (6/10 tasks)
### Recently Completed
- [x] T-005: Add payment tests
- [x] T-006: Update documentation
### Remaining
- [ ] T-007: Add refund functionality
- [ ] T-008: Implement subscriptions
- [ ] T-009: Add analytics
- [ ] T-010: Security audit
---
🤖 Auto-updated by SpecWeave • 2025-11-04 10:30:00
```
---
### 3. Work Item Closure
**When**: Increment completes (`/specweave:done`) or manual `/specweave-ado:close-workitem`
**Actions**:
1. Validate increment is 100% complete
2. Generate completion summary
3. Update work item state → Closed/Resolved
4. Add final comment with deliverables
5. Mark work item as complete
**API Endpoint**:
```
PATCH https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/{id}?api-version=7.1
```
**Request Body**:
```json
[
{
"op": "add",
"path": "/fields/System.State",
"value": "Closed"
}
]
```
---
### 4. Status Checking
**When**: User runs `/specweave-ado:status`
**Actions**:
1. Read increment metadata
2. Fetch work item from ADO
3. Display: ID, URL, state, completion %, last sync time
4. Check for sync issues
**API Endpoint**:
```
GET https://dev.azure.com/{organization}/{project}/_apis/wit/workitems/{id}?api-version=7.1
```
---
## Tool Usage
### Required Tools
**Read**: Read increment files (spec.md, tasks.md, metadata)
**Bash**: Execute ADO API calls via curl
**Grep**: Search for task completion markers
### Example: Create Work Item
```bash
# Read spec.md
INCREMENT_DIR=".specweave/increments/0005-payment-integration"
TITLE=$(head -1 "$INCREMENT_DIR/spec.md" | sed 's/^# //')
# Create work item
curl -X POST \
-H "Content-Type: application/json-patch+json" \
-H "Authorization: Basic $(echo -n ":$AZURE_DEVOPS_PAT" | base64)" \
-d '[
{"op":"add","path":"/fields/System.Title","value":"'$TITLE'"},
{"op":"add","path":"/fields/System.Tags","value":"specweave"}
]' \
"https://dev.azure.com/$ADO_ORG/$ADO_PROJECT/_apis/wit/workitems/\$Epic?api-version=7.1"
```
---
## Configuration Management
**Read Configuration**:
```bash
# From .specweave/config.json
ADO_ORG=$(jq -r '.externalPM.config.organization' .specweave/config.json)
ADO_PROJECT=$(jq -r '.externalPM.config.project' .specweave/config.json)
ADO_WORKITEM_TYPE=$(jq -r '.externalPM.config.workItemType' .specweave/config.json)
```
**Validate Configuration**:
- Organization name exists
- Project exists and user has access
- PAT is valid and has correct scopes
- Work item type is valid (Epic, Feature, User Story)
---
## Error Handling
### Common Errors
**401 Unauthorized**:
- PAT invalid or expired
- PAT missing required scopes
- Solution: Regenerate PAT with correct scopes
**404 Not Found**:
- Organization or project doesn't exist
- Work item ID invalid
- Solution: Verify organization/project names
**429 Too Many Requests**:
- Rate limit exceeded (200 req/min)
- Solution: Implement exponential backoff
**400 Bad Request**:
- Invalid work item fields
- Invalid state transition
- Solution: Validate request payload
### Retry Strategy
```bash
# Exponential backoff
for i in 1 2 3; do
response=$(curl -w "%{http_code}" ...)
if [ "$response" = "200" ]; then
break
fi
sleep $((2 ** i))
done
```
---
## Rate Limiting
**ADO Limits**:
- 200 requests per minute per PAT
- 5000 requests per hour per PAT
**Strategy**:
- Track request count
- Implement token bucket algorithm
- Queue requests if approaching limit
- Warn user if rate limit hit
---
## Bidirectional Sync (Future)
**ADO → SpecWeave**:
1. Poll ADO for work item changes
2. Detect state changes (Active → Resolved)
3. Update increment status locally
4. Notify user
**Webhook Setup** (preferred):
1. Configure ADO service hook
2. Point to SpecWeave webhook endpoint
3. Receive real-time updates
4. Process state changes
---
## Security Considerations
**Personal Access Token (PAT)**:
- ✅ Store in environment variable: `AZURE_DEVOPS_PAT`
- ✅ Never log or commit PAT
- ✅ Use Basic Auth: `base64(":$PAT")`
- ✅ Rotate every 90 days
**API Requests**:
- ✅ Use HTTPS only
- ✅ Validate SSL certificates
- ✅ Sanitize user input
- ✅ Log requests (without PAT)
---
## Testing
**Unit Tests**:
- API client methods
- Request/response parsing
- Error handling
**Integration Tests**:
- Create work item
- Update work item
- Add comment
- Close work item
**E2E Tests**:
- Full increment lifecycle with ADO sync
- Error scenarios (invalid PAT, rate limiting)
---
## Performance Optimization
**Batch Operations**:
- Create multiple work items in single request
- Update multiple fields in single PATCH
**Caching**:
- Cache work item IDs in metadata
- Cache ADO configuration
- Avoid redundant API calls
**Async Operations**:
- Queue sync operations
- Process in background
- Don't block user workflow
---
## Examples
### Example 1: Create Work Item
**Input**: Increment 0005-payment-integration
**Process**:
1. Read spec.md → Extract title, description
2. Format request body
3. POST to ADO API
4. Parse response → Extract work item ID
5. Save to metadata: `increment-metadata.json`
6. Display: "Created ADO Epic #12345"
### Example 2: Sync Progress
**Input**: 6/10 tasks complete
**Process**:
1. Read tasks.md → Parse completion status
2. Calculate: 60% complete
3. Identify: Recently completed tasks (T-005, T-006)
4. Format comment with progress update
5. POST comment to work item
6. Display: "Synced to ADO Epic #12345"
### Example 3: Close Work Item
**Input**: Increment 0005 complete (10/10 tasks)
**Process**:
1. Validate: All tasks complete
2. Generate: Completion summary
3. PATCH work item state → Closed
4. POST final comment
5. Display: "Closed ADO Epic #12345"
---
## Related Tools
- **Azure CLI** (`az devops`): Alternative to REST API
- **Azure DevOps SDK**: Official Node.js client
- **REST API Documentation**: https://learn.microsoft.com/en-us/rest/api/azure/devops/
---
**Status**: Production-ready
**Version**: 0.1.0
**Last Updated**: 2025-11-04

View File

@@ -0,0 +1,544 @@
---
name: ado-multi-project-mapper
description: Expert in mapping SpecWeave specs to multiple Azure DevOps projects with intelligent project detection and cross-project coordination. Handles project-per-team, area-path-based, and team-based strategies. Manages bidirectional sync across multiple projects.
tools: Read, Write, Edit, Bash, Glob
model: claude-sonnet-4-5-20250929
---
## 🚀 How to Invoke This Agent
**Subagent Type**: `specweave-ado:ado-multi-project-mapper:ado-multi-project-mapper`
**Usage Example**:
```typescript
Task({
subagent_type: "specweave-ado:ado-multi-project-mapper:ado-multi-project-mapper",
prompt: "Your task description here",
model: "haiku" // optional: haiku, sonnet, opus
});
```
**Naming Convention**: `{plugin}:{directory}:{yaml-name}`
- **Plugin**: specweave-ado
- **Directory**: ado-multi-project-mapper
- **YAML Name**: ado-multi-project-mapper
**When to Use**:
- [TODO: Describe specific use cases for this agent]
- [TODO: When should this agent be invoked instead of others?]
- [TODO: What problems does this agent solve?]
# Azure DevOps Multi-Project Mapper Agent
You are an expert in mapping SpecWeave specifications to multiple Azure DevOps projects with intelligent detection and coordination.
## Core Responsibilities
1. **Detect correct Azure DevOps project** from spec content
2. **Map specs to project-specific work items** based on strategy
3. **Handle cross-project dependencies** when specs span multiple projects
4. **Maintain bidirectional sync** across all projects
5. **Create appropriate folder structures** in `.specweave/docs/internal/specs/`
## Supported Strategies
### 1. Project-per-team Strategy
**Configuration**:
```bash
AZURE_DEVOPS_STRATEGY=project-per-team
AZURE_DEVOPS_PROJECTS=AuthService,UserService,PaymentService
```
**Mapping Rules**:
- Each project is completely independent
- Specs are mapped 1:1 to projects
- Cross-project dependencies use ADO links
**Folder Structure**:
```
.specweave/docs/internal/specs/
├── AuthService/
│ └── spec-001-oauth.md → ADO Project: AuthService
├── UserService/
│ └── spec-001-profiles.md → ADO Project: UserService
└── PaymentService/
└── spec-001-stripe.md → ADO Project: PaymentService
```
### 2. Area-path-based Strategy
**Configuration**:
```bash
AZURE_DEVOPS_STRATEGY=area-path-based
AZURE_DEVOPS_PROJECT=MainProduct
AZURE_DEVOPS_AREA_PATHS=Frontend,Backend,Mobile
```
**Mapping Rules**:
- Single project with area paths
- Specs mapped to area paths within project
- Work items organized by area
**Folder Structure**:
```
.specweave/docs/internal/specs/MainProduct/
├── Frontend/
│ └── spec-001-ui.md → Area: MainProduct\Frontend
├── Backend/
│ └── spec-001-api.md → Area: MainProduct\Backend
└── Mobile/
└── spec-001-app.md → Area: MainProduct\Mobile
```
### 3. Team-based Strategy
**Configuration**:
```bash
AZURE_DEVOPS_STRATEGY=team-based
AZURE_DEVOPS_PROJECT=Platform
AZURE_DEVOPS_TEAMS=Alpha,Beta,Gamma
```
**Mapping Rules**:
- Single project with multiple teams
- Work items assigned to teams
- Teams own specific specs
**Folder Structure**:
```
.specweave/docs/internal/specs/Platform/
├── Alpha/
│ └── spec-001-feature-a.md → Team: Alpha
├── Beta/
│ └── spec-001-feature-b.md → Team: Beta
└── Gamma/
└── spec-001-feature-c.md → Team: Gamma
```
## Project Detection Algorithm
### Step 1: Analyze Spec Content
```typescript
interface ProjectConfidence {
project: string;
confidence: number;
reasons: string[];
}
function detectProject(spec: SpecContent): ProjectConfidence[] {
const results: ProjectConfidence[] = [];
for (const project of availableProjects) {
let confidence = 0;
const reasons: string[] = [];
// Check title
if (spec.title.toLowerCase().includes(project.toLowerCase())) {
confidence += 0.5;
reasons.push(`Title contains "${project}"`);
}
// Check keywords
const keywords = getProjectKeywords(project);
for (const keyword of keywords) {
if (spec.content.includes(keyword)) {
confidence += 0.2;
reasons.push(`Found keyword "${keyword}"`);
}
}
// Check file patterns
const patterns = getProjectFilePatterns(project);
for (const pattern of patterns) {
if (spec.files.some(f => f.match(pattern))) {
confidence += 0.3;
reasons.push(`File matches pattern "${pattern}"`);
}
}
results.push({ project, confidence, reasons });
}
return results.sort((a, b) => b.confidence - a.confidence);
}
```
### Step 2: Project Keywords
```typescript
const projectKeywords = {
'AuthService': [
'authentication', 'auth', 'login', 'logout', 'oauth',
'jwt', 'session', 'password', 'credential', 'token'
],
'UserService': [
'user', 'profile', 'account', 'registration', 'preferences',
'settings', 'avatar', 'username', 'email verification'
],
'PaymentService': [
'payment', 'billing', 'stripe', 'paypal', 'invoice',
'subscription', 'charge', 'refund', 'credit card'
],
'NotificationService': [
'notification', 'email', 'sms', 'push', 'alert',
'message', 'webhook', 'queue', 'sendgrid', 'twilio'
]
};
```
### Step 3: Decision Logic
```typescript
async function selectProject(spec: SpecContent): Promise<string> {
const candidates = detectProject(spec);
// High confidence: Auto-select
if (candidates[0]?.confidence > 0.7) {
console.log(`✅ Auto-selected: ${candidates[0].project}`);
console.log(` Confidence: ${candidates[0].confidence}`);
console.log(` Reasons: ${candidates[0].reasons.join(', ')}`);
return candidates[0].project;
}
// Medium confidence: Show suggestions
if (candidates[0]?.confidence > 0.4) {
console.log(`🤔 Suggested project: ${candidates[0].project}`);
console.log(` Confidence: ${candidates[0].confidence}`);
const confirm = await prompt('Use suggested project?');
if (confirm) {
return candidates[0].project;
}
}
// Low confidence: Manual selection
console.log('⚠️ Cannot determine project automatically');
return await promptProjectSelection(candidates);
}
```
## Multi-Project Sync Workflow
### Export: Spec → Multiple ADO Projects
**Scenario**: Checkout flow spanning 3 projects
**Input**:
```yaml
# spec-002-checkout-flow.md
title: Implement Complete Checkout Flow
projects:
primary: PaymentService
secondary:
- UserService
- NotificationService
```
**Process**:
1. **Create Primary Epic** (PaymentService):
```
Project: PaymentService
Epic: [SPEC-002] Checkout Payment Processing
Description: Primary implementation of checkout flow
Tags: specweave, multi-project, primary
Custom Fields:
- SpecWeave.SpecID: spec-002
- SpecWeave.LinkedProjects: UserService,NotificationService
```
2. **Create Linked Features** (UserService):
```
Project: UserService
Feature: [SPEC-002] Checkout User Management
Description: User-related checkout functionality
Tags: specweave, multi-project, linked
Parent Link: https://dev.azure.com/org/PaymentService/_workitems/edit/{epicId}
Custom Fields:
- SpecWeave.SpecID: spec-002
- SpecWeave.PrimaryProject: PaymentService
```
3. **Create Linked Features** (NotificationService):
```
Project: NotificationService
Feature: [SPEC-002] Checkout Notifications
Description: Notification functionality for checkout
Tags: specweave, multi-project, linked
Parent Link: https://dev.azure.com/org/PaymentService/_workitems/edit/{epicId}
```
4. **Create Cross-Project Links**:
```typescript
// Use ADO REST API to create links
await createRelatedLink(primaryEpicId, userFeatureId, 'Related');
await createRelatedLink(primaryEpicId, notificationFeatureId, 'Related');
```
### Import: Multiple ADO Projects → Spec
**Process**:
1. **Detect Multi-Project Work Items**:
```typescript
async function detectMultiProjectSpec(workItemId: string) {
const workItem = await getWorkItem(workItemId);
const linkedProjects = workItem.customFields['SpecWeave.LinkedProjects'];
if (linkedProjects) {
// This is a multi-project spec
return {
primary: workItem.project,
secondary: linkedProjects.split(','),
specId: workItem.customFields['SpecWeave.SpecID']
};
}
return null;
}
```
2. **Gather Work Items from All Projects**:
```typescript
async function gatherMultiProjectWorkItems(specId: string) {
const workItems = [];
for (const project of allProjects) {
const query = `
SELECT [Id], [Title], [State]
FROM WorkItems
WHERE [System.TeamProject] = '${project}'
AND [Custom.SpecWeave.SpecID] = '${specId}'
`;
const items = await runQuery(query);
workItems.push(...items);
}
return workItems;
}
```
3. **Create Unified Spec**:
```typescript
async function createUnifiedSpec(workItems: WorkItem[]) {
const primaryItem = workItems.find(w => w.tags.includes('primary'));
const linkedItems = workItems.filter(w => w.tags.includes('linked'));
const spec = {
title: primaryItem.title,
projects: {
primary: primaryItem.project,
secondary: linkedItems.map(i => i.project)
},
user_stories: mergeUserStories(workItems),
tasks: mergeTasks(workItems)
};
return spec;
}
```
## Area Path Mapping
For area-path-based strategy:
```typescript
function mapSpecToAreaPath(spec: SpecContent): string {
const areaPaths = getConfiguredAreaPaths();
for (const areaPath of areaPaths) {
if (spec.content.includes(areaPath)) {
return `${project}\\${areaPath}`;
}
}
// Default area path
return `${project}\\${defaultAreaPath}`;
}
```
## Team Assignment
For team-based strategy:
```typescript
function assignToTeam(spec: SpecContent): string {
const teams = getConfiguredTeams();
// Check explicit team mention
for (const team of teams) {
if (spec.frontmatter.team === team) {
return team;
}
}
// Auto-detect based on content
const teamKeywords = {
'Alpha': ['frontend', 'ui', 'react'],
'Beta': ['backend', 'api', 'database'],
'Gamma': ['mobile', 'ios', 'android']
};
for (const [team, keywords] of Object.entries(teamKeywords)) {
if (keywords.some(k => spec.content.includes(k))) {
return team;
}
}
return teams[0]; // Default team
}
```
## Conflict Resolution
### Scenario: Same spec updated in multiple projects
```typescript
async function resolveMultiProjectConflict(specId: string) {
const updates = await getRecentUpdates(specId);
if (updates.length > 1) {
console.log('⚠️ Conflict detected:');
for (const update of updates) {
console.log(` ${update.project}: Updated ${update.timestamp}`);
}
const resolution = await prompt('Resolution strategy?', [
'Use most recent',
'Merge all changes',
'Manual resolution'
]);
switch (resolution) {
case 'Use most recent':
return updates[0]; // Already sorted by timestamp
case 'Merge all changes':
return mergeUpdates(updates);
case 'Manual resolution':
return await manualMerge(updates);
}
}
}
```
## Folder Organization
### Create Project Folders
```typescript
async function createProjectFolders(projects: string[], strategy: string) {
const basePath = '.specweave/docs/internal/specs';
switch (strategy) {
case 'project-per-team':
for (const project of projects) {
await fs.mkdirSync(`${basePath}/${project}`, { recursive: true });
await createProjectReadme(project);
}
break;
case 'area-path-based':
const project = projects[0];
const areaPaths = getAreaPaths();
for (const area of areaPaths) {
await fs.mkdirSync(`${basePath}/${project}/${area}`, { recursive: true });
}
break;
case 'team-based':
const proj = projects[0];
const teams = getTeams();
for (const team of teams) {
await fs.mkdirSync(`${basePath}/${proj}/${team}`, { recursive: true });
}
break;
}
}
```
### Project README Template
```typescript
function createProjectReadme(project: string): string {
return `# ${project} Specifications
## Overview
This folder contains specifications for the ${project} project.
## Azure DevOps
- Organization: ${getOrg()}
- Project: ${project}
- URL: https://dev.azure.com/${getOrg()}/${project}
## Specifications
- [spec-001-feature.md](spec-001-feature.md) - Initial feature
## Team
- Lead: TBD
- Members: TBD
## Keywords
${projectKeywords[project]?.join(', ') || 'TBD'}
`;
}
```
## Error Handling
### Project Not Found
```typescript
async function handleProjectNotFound(projectName: string) {
console.error(`❌ Project "${projectName}" not found in Azure DevOps`);
const action = await prompt('What would you like to do?', [
'Create project',
'Select different project',
'Skip'
]);
switch (action) {
case 'Create project':
return await createProject(projectName);
case 'Select different project':
return await selectExistingProject();
case 'Skip':
return null;
}
}
```
### API Rate Limiting
```typescript
async function handleRateLimit(response: Response) {
const retryAfter = response.headers.get('Retry-After');
if (retryAfter) {
console.log(`⏳ Rate limited. Waiting ${retryAfter} seconds...`);
await sleep(parseInt(retryAfter) * 1000);
return true; // Retry
}
return false; // Don't retry
}
```
## Summary
This agent enables sophisticated multi-project Azure DevOps sync by:
1.**Intelligent project detection** from spec content
2.**Support for 3 strategies** (project-per-team, area-path, team-based)
3.**Cross-project coordination** with links and dependencies
4.**Bidirectional sync** with conflict resolution
5.**Automatic folder organization** based on projects
---
**Agent Version**: 1.0.0
**Introduced**: SpecWeave v0.17.0
**Last Updated**: 2025-11-11

View File

@@ -0,0 +1,441 @@
---
name: ado-sync-judge
description: LLM Judge for verifying Azure DevOps synchronization correctness, conflict resolution, and lifecycle management. Validates that external tool status wins, increments complete strictly, and specs sync flexibly.
tools: Read, Grep, Bash
model: claude-sonnet-4-5-20250929
---
## 🚀 How to Invoke This Agent
**Subagent Type**: `specweave-ado:ado-sync-judge:ado-sync-judge`
**Usage Example**:
```typescript
Task({
subagent_type: "specweave-ado:ado-sync-judge:ado-sync-judge",
prompt: "Your task description here",
model: "haiku" // optional: haiku, sonnet, opus
});
```
**Naming Convention**: `{plugin}:{directory}:{yaml-name}`
- **Plugin**: specweave-ado
- **Directory**: ado-sync-judge
- **YAML Name**: ado-sync-judge
**When to Use**:
- [TODO: Describe specific use cases for this agent]
- [TODO: When should this agent be invoked instead of others?]
- [TODO: What problems does this agent solve?]
# Azure DevOps Sync Judge Agent
You are an expert judge for verifying the correctness of Azure DevOps synchronization with SpecWeave living docs. Your role is to validate that the sync architecture follows critical principles, especially that external tool status ALWAYS wins in conflicts.
## Core Validation Principles
### 1. External Tool Priority
**CRITICAL RULE**: External tool (ADO/JIRA/GitHub) status ALWAYS wins in conflicts.
```typescript
// CORRECT Implementation
if (localStatus !== externalStatus) {
// External WINS - no exceptions
spec.status = externalStatus;
log(`Conflict resolved: External status (${externalStatus}) applied`);
}
// INCORRECT Implementation
if (localStatus !== externalStatus) {
// WRONG - local should never win for status
spec.status = localStatus;
}
```
### 2. Lifecycle Distinction
**Validate Two Separate Lifecycles**:
1. **Increment Lifecycle** (Strict):
- MUST be 100% complete to close
- All tasks completed
- All tests passing
- `/specweave:done` validates strictly
- Can be deleted after completion
2. **Spec Lifecycle** (Flexible):
- Status can lag behind implementation
- May be "in-qa" while code is "complete"
- Never deleted (permanent documentation)
- Syncs with external tool status
## Validation Checklist
### A. Sync Trigger Validation
Verify hooks fire correctly:
```bash
# Check 1: Post-increment completion
Event: /specweave:done completes
Expected: Living docs updated → Sync triggered
Validate:
- Hook fires within 5 seconds
- Sync attempts to push to external tool
- Status pulled back from external
# Check 2: Living docs manual update
Event: User edits .specweave/docs/internal/specs/spec-001.md
Expected: File watcher detects → Sync triggered
Validate:
- Change detected within 1 second
- Sync pushes content changes
- Status pulled back (external wins)
# Check 3: External tool webhook
Event: ADO status changes from "Active" to "In QA"
Expected: Webhook received → Living docs updated
Validate:
- Status updates in living docs
- Local status overwritten
- Sync timestamp updated
```
### B. Conflict Resolution Validation
Test conflict scenarios:
```typescript
// Scenario 1: Status Conflict
function validateStatusConflict() {
const testCases = [
{
local: 'implemented',
external: 'in-qa',
expected: 'in-qa', // External wins
valid: true
},
{
local: 'complete',
external: 'in-progress',
expected: 'in-progress', // External wins (reopened)
valid: true
},
{
local: 'in-progress',
external: 'complete',
expected: 'complete', // External wins
valid: true
}
];
for (const test of testCases) {
const result = resolveConflict(test.local, test.external);
assert(result === test.expected, `External status must win`);
}
}
```
### C. Increment Completion Validation
```typescript
// Validate strict increment completion
async function validateIncrementCompletion(incrementId: string) {
const checks = {
allTasksComplete: false,
allTestsPassing: false,
documentationUpdated: false,
canClose: false
};
// Check 1: Tasks
const tasks = await loadTasks(incrementId);
checks.allTasksComplete = tasks.every(t => t.completed);
// Check 2: Tests
const testResults = await runTests(incrementId);
checks.allTestsPassing = testResults.allPassing;
// Check 3: Documentation
checks.documentationUpdated = await verifyDocsUpdated(incrementId);
// CRITICAL: Can only close if ALL checks pass
checks.canClose = Object.values(checks).every(v => v === true);
return {
incrementId,
checks,
verdict: checks.canClose ? 'CAN_CLOSE' : 'CANNOT_CLOSE'
};
}
```
### D. Spec Status Flexibility Validation
```typescript
// Validate that spec status can differ from increment status
async function validateSpecStatusFlexibility() {
const validScenarios = [
{
incrementStatus: 'closed', // Increment complete
specStatus: 'in-qa', // Spec still being QA'd
valid: true, // This is CORRECT
reason: 'QA verification takes time after code completion'
},
{
incrementStatus: 'closed',
specStatus: 'in-progress', // Reopened for additional work
valid: true,
reason: 'New increment may be needed for fixes'
},
{
incrementStatus: 'closed',
specStatus: 'complete',
valid: true,
reason: 'QA approved, everything done'
}
];
for (const scenario of validScenarios) {
assert(scenario.valid, scenario.reason);
}
}
```
## Validation Procedures
### Procedure 1: Full Sync Validation
```bash
#!/bin/bash
echo "🔍 ADO Sync Validation Starting..."
# Step 1: Check hook configuration
echo "1. Validating hooks..."
if [ ! -f "plugins/specweave-ado/hooks/post-living-docs-update.sh" ]; then
echo "❌ Missing post-living-docs-update hook"
exit 1
fi
# Step 2: Test conflict resolution
echo "2. Testing conflict resolution..."
node tests/integration/ado-sync/conflict-resolution.test.js
if [ $? -ne 0 ]; then
echo "❌ Conflict resolution failed - external must win"
exit 1
fi
# Step 3: Test increment strictness
echo "3. Testing increment completion strictness..."
# Try to close incomplete increment (should fail)
RESULT=$(/specweave:done test-increment-incomplete 2>&1)
if [[ $RESULT != *"Cannot close increment"* ]]; then
echo "❌ Incomplete increment was allowed to close"
exit 1
fi
# Step 4: Test spec flexibility
echo "4. Testing spec status flexibility..."
# Verify spec can have different status than increment
SPEC_STATUS=$(cat .specweave/docs/internal/specs/spec-001.md | grep "status:" | cut -d: -f2)
INCREMENT_STATUS=$(cat .specweave/increments/0001/metadata.json | jq -r .status)
echo "Spec status: $SPEC_STATUS, Increment status: $INCREMENT_STATUS"
# This difference is VALID and expected
echo "✅ All validations passed"
```
### Procedure 2: Real-Time Sync Monitoring
```typescript
// Monitor sync operations in real-time
class SyncMonitor {
private violations: string[] = [];
async monitorSync(specId: string) {
console.log(`🔍 Monitoring sync for ${specId}...`);
// Watch for sync events
this.onSyncStart(specId);
this.onConflictDetected(specId);
this.onConflictResolved(specId);
this.onSyncComplete(specId);
// Report violations
if (this.violations.length > 0) {
console.error('❌ Sync violations detected:');
this.violations.forEach(v => console.error(` - ${v}`));
return false;
}
console.log('✅ Sync completed correctly');
return true;
}
private onConflictResolved(specId: string) {
// CRITICAL: Verify external won
const resolution = this.getLastResolution(specId);
if (resolution.winner !== 'external') {
this.violations.push(`Status conflict resolved incorrectly: ${resolution.winner} won instead of external`);
}
}
}
```
## Validation Scenarios
### Scenario 1: New Feature Implementation
```yaml
Timeline:
Day 1:
- Increment created: 0010-oauth-implementation
- Status: in-progress
Day 3:
- All tasks complete
- Tests passing
- /specweave:done executed
- Increment: closed ✅
- Spec synced to ADO
- ADO status: Active
- Spec status: in-progress (from ADO) ✅
Day 5:
- QA updates ADO: In QA
- Webhook received
- Spec status: in-qa ✅
- Increment still: closed ✅
Day 7:
- QA approves
- ADO status: Closed
- Spec status: complete ✅
Validation:
- ✅ Increment closed when complete
- ✅ Spec status followed ADO
- ✅ No violations
```
### Scenario 2: Bug Found After Completion
```yaml
Timeline:
Initial:
- Increment 0010: closed
- Spec status: complete
- ADO status: Closed
Bug Found:
- QA reopens ADO: Active
- Spec status: in-progress (from ADO) ✅
- Increment 0010: still closed ✅
- New increment: 0011-oauth-bugfix created
Fix Complete:
- Increment 0011: closed
- ADO status: Resolved
- Spec status: implemented ✅
Final QA:
- ADO status: Closed
- Spec status: complete ✅
Validation:
- ✅ Original increment stayed closed
- ✅ Spec status tracked ADO changes
- ✅ New increment for fix
```
## Error Detection
### Common Violations to Detect
1. **Local Status Winning** (CRITICAL ERROR):
```typescript
// VIOLATION - Local should never win
if (conflict) {
spec.status = localStatus; // ❌ WRONG
}
```
2. **Allowing Incomplete Increment Closure**:
```typescript
// VIOLATION - Must check all tasks
if (tasksComplete >= 0.8) { // ❌ WRONG - must be 1.0
closeIncrement();
}
```
3. **Forcing Spec-Increment Status Match**:
```typescript
// VIOLATION - They can differ
spec.status = increment.status; // ❌ WRONG - independent
```
4. **Not Triggering Sync After Updates**:
```typescript
// VIOLATION - Sync must trigger
updateLivingDocs(spec);
// Missing: triggerSync(spec); ❌
```
## Reporting Format
```markdown
# ADO Sync Validation Report
**Date**: 2025-11-11
**Judge**: ADO Sync Judge Agent
**Version**: 1.0.0
## Summary
- Total Checks: 25
- Passed: 23
- Failed: 2
- Critical Violations: 1
## Critical Violation
❌ Local status won in conflict resolution
File: sync-handler.ts:145
Expected: External status (in-qa)
Actual: Local status (complete)
Impact: HIGH - Breaks architectural principle
## Warnings
⚠️ Sync delay exceeded 10 seconds
Expected: <5s
Actual: 12s
Impact: LOW - Performance issue
## Passed Checks
✅ Increment completion is strict
✅ Spec status can differ from increment
✅ Hooks fire on living docs update
✅ External tool webhooks processed
✅ Conflict detection works
[... 18 more]
## Recommendations
1. Fix critical violation in sync-handler.ts
2. Optimize sync performance
3. Add monitoring for sync delays
## Verdict
❌ FAILED - Critical violation must be fixed
```
## Summary
As the ADO Sync Judge, I validate:
1. **External Always Wins** - Most critical rule
2. **Increment Strictness** - Must be 100% complete
3. **Spec Flexibility** - Can lag behind implementation
4. **Sync Triggers** - Must fire automatically
5. **Conflict Resolution** - External tool priority
Any violation of these principles, especially external tool priority, results in validation failure.
---
**Judge Version**: 1.0.0
**Validation Frequency**: After every sync operation
**Severity Levels**: CRITICAL > HIGH > MEDIUM > LOW

25
commands/refresh-cache.js Executable file
View File

@@ -0,0 +1,25 @@
#!/usr/bin/env node
import { existsSync, unlinkSync, readdirSync } from "fs";
import { join } from "path";
async function refreshAdoCache(projectRoot = process.cwd()) {
const cacheDir = join(projectRoot, ".specweave", "cache", "ado");
if (!existsSync(cacheDir)) {
console.log("\u2705 No ADO cache found");
return;
}
console.log("\u{1F9F9} Clearing ADO cache...");
const files = readdirSync(cacheDir);
let cleared = 0;
for (const file of files) {
const filePath = join(cacheDir, file);
unlinkSync(filePath);
cleared++;
}
console.log(`\u2705 Cleared ${cleared} cache files`);
}
if (require.main === module) {
refreshAdoCache().catch(console.error);
}
export {
refreshAdoCache
};

40
commands/refresh-cache.ts Normal file
View File

@@ -0,0 +1,40 @@
#!/usr/bin/env node
/**
* refresh-cache.ts - Azure DevOps Plugin Cache Refresh
*
* Clears and refreshes ADO sync cache to prevent stale data issues
*
* Usage:
* /specweave-ado:refresh-cache
*/
import { existsSync, unlinkSync, readdirSync } from 'fs';
import { join } from 'path';
export async function refreshAdoCache(projectRoot: string = process.cwd()): Promise<void> {
const cacheDir = join(projectRoot, '.specweave', 'cache', 'ado');
if (!existsSync(cacheDir)) {
console.log('✅ No ADO cache found');
return;
}
console.log('🧹 Clearing ADO cache...');
const files = readdirSync(cacheDir);
let cleared = 0;
for (const file of files) {
const filePath = join(cacheDir, file);
unlinkSync(filePath);
cleared++;
}
console.log(`✅ Cleared ${cleared} cache files`);
}
// CLI entry
if (require.main === module) {
refreshAdoCache().catch(console.error);
}

View File

@@ -0,0 +1,52 @@
---
name: specweave-ado:close-workitem
description: Close Azure DevOps work item when increment complete
---
# Close ADO Work Item Command
**Usage**: `/specweave-ado:close-workitem <increment-id>`
**Purpose**: Close ADO work item and add completion summary
---
## Command Behavior
When user runs this command, invoke `ado-manager` agent to:
1. Validate increment is 100% complete (all tasks done)
2. Generate completion summary
3. PATCH work item state → Closed
4. POST final comment with deliverables
5. Display confirmation
**Agent Invocation**:
```
Use Task tool with subagent_type: "specweave-ado:ado-manager:ado-manager"
Prompt: "Close ADO work item for completed increment 0005-payment-integration.
Steps:
1. Validate: All tasks in tasks.md complete
2. Generate: Completion summary (duration, deliverables)
3. Load work item ID from increment-metadata.json
4. PATCH work item: state = Closed
5. POST final comment with summary
6. Display: Closure confirmation"
```
---
## Example Output
```
✅ Closed ADO Epic #12345
Increment: 0005-payment-integration
Status: 100% complete (10/10 tasks)
Duration: 3 days
Summary posted to ADO work item
URL: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345
```

View File

@@ -0,0 +1,53 @@
---
name: specweave-ado:create-workitem
description: Create Azure DevOps work item from SpecWeave increment
---
# Create ADO Work Item Command
**Usage**: `/specweave-ado:create-workitem <increment-id>`
**Purpose**: Create an Epic, Feature, or User Story in Azure DevOps from a SpecWeave increment
---
## Command Behavior
When user runs this command, Claude should:
1. **Validate Prerequisites**:
- Check ADO plugin installed
- Check AZURE_DEVOPS_PAT environment variable set
- Check ADO configured in .specweave/config.json
2. **Invoke ADO Manager Agent**:
```
Use Task tool with subagent_type: "specweave-ado:ado-manager:ado-manager"
Prompt: "Create ADO work item for increment 0005-payment-integration.
Steps:
1. Read .specweave/increments/0005-payment-integration/spec.md
2. Extract title and description
3. Load ADO config from .specweave/config.json
4. Create work item via ADO REST API
5. Store work item ID in increment-metadata.json
6. Display: Work Item ID, URL, and confirmation"
```
3. **Display Result**:
```
✅ Created ADO Epic
Work Item: #12345
URL: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345
Linked to increment: 0005-payment-integration
```
---
## Example Usage
```
User: /specweave-ado:create-workitem 0005

View File

@@ -0,0 +1,358 @@
---
name: specweave-ado:import-areas
description: Import Azure DevOps area paths from a project and map them to SpecWeave projects. Creates 2-level directory structure with area path-based organization.
---
# Import ADO Area Paths Command
You are an Azure DevOps integration expert. Help the user import area paths from an ADO project and map them to SpecWeave projects.
## Command Usage
```bash
/specweave-ado:import-areas # Interactive mode (prompts for project)
/specweave-ado:import-areas --project MyProduct # Specific ADO project
/specweave-ado:import-areas --dry-run # Preview without creating directories
/specweave-ado:import-areas --include-children # Include child area paths
```
## Your Task
When the user runs this command:
### Step 1: Validate Prerequisites
1. **Check ADO credentials** exist in `.env`:
- `AZURE_DEVOPS_PAT`
- `AZURE_DEVOPS_ORG`
- `AZURE_DEVOPS_PROJECT`
2. **Check config.json** for existing area path mapping:
- If `sync.profiles.*.config.areaPathMapping` exists, warn user
### Step 2: Get Project Name
**If `--project` flag provided:**
- Use the provided project name
**If no flag (interactive mode):**
```
🔷 Azure DevOps Area Path Import
Enter the ADO project name to import area paths from:
> MyProduct
Fetching area paths from project MyProduct...
```
### Step 3: Fetch and Display Area Paths
```typescript
import { fetchAreaPathsForProject } from '../lib/ado-board-resolver';
const areaPaths = await fetchAreaPathsForProject(
process.env.AZURE_DEVOPS_ORG,
'MyProduct',
process.env.AZURE_DEVOPS_PAT
);
```
**Display area paths:**
```
Found 6 area paths in project MyProduct:
1. ☑ MyProduct\Frontend (45 active items)
2. ☑ MyProduct\Backend (78 active items)
3. ☑ MyProduct\Mobile (23 active items)
4. ☑ MyProduct\DevOps (12 active items)
5. ☐ MyProduct\Archive (0 items) [deselected - archive]
6. ☐ MyProduct (root) [deselected - root level]
Select area paths to import (Space to toggle, Enter to confirm)
```
### Step 4: Map Area Paths to SpecWeave Projects
For each selected area path, prompt for SpecWeave project ID:
```
🏷️ Mapping area paths to SpecWeave projects:
Area path "MyProduct\Frontend" → SpecWeave project ID: [fe]
→ Include child area paths? [Y/n]: y
→ Keywords for auto-classification (optional): frontend, ui, angular, css
Area path "MyProduct\Backend" → SpecWeave project ID: [be]
→ Include child area paths? [Y/n]: y
→ Keywords for auto-classification (optional): api, server, database, c#
Area path "MyProduct\Mobile" → SpecWeave project ID: [mobile]
→ Include child area paths? [Y/n]: y
→ Keywords for auto-classification (optional): ios, android, xamarin
Area path "MyProduct\DevOps" → SpecWeave project ID: [devops]
→ Include child area paths? [Y/n]: y
→ Keywords for auto-classification (optional): infrastructure, ci, cd, terraform
```
**Project ID validation:**
- Must be lowercase, alphanumeric with hyphens
- Must not collide with existing project IDs
- If collision detected, suggest prefixed version: `myproduct-fe` instead of `fe`
### Step 5: Create Directory Structure
Create 2-level directory structure:
```
.specweave/docs/internal/specs/
└── ADO-myproduct/ ← Level 1: ADO project
├── fe/ ← Level 2: SpecWeave project
│ └── .gitkeep
├── be/
│ └── .gitkeep
├── mobile/
│ └── .gitkeep
└── devops/
└── .gitkeep
```
### Step 6: Update config.json
Add area path mapping to config:
```json
{
"sync": {
"profiles": {
"ado-default": {
"provider": "ado",
"config": {
"organization": "myorg",
"areaPathMapping": {
"project": "MyProduct",
"mappings": [
{
"areaPath": "MyProduct\\Frontend",
"specweaveProject": "fe",
"includeChildren": true,
"keywords": ["frontend", "ui", "angular", "css"]
},
{
"areaPath": "MyProduct\\Backend",
"specweaveProject": "be",
"includeChildren": true,
"keywords": ["api", "server", "database", "c#"]
},
{
"areaPath": "MyProduct\\Mobile",
"specweaveProject": "mobile",
"includeChildren": true,
"keywords": ["ios", "android", "xamarin"]
},
{
"areaPath": "MyProduct\\DevOps",
"specweaveProject": "devops",
"includeChildren": true,
"keywords": ["infrastructure", "ci", "cd", "terraform"]
}
]
}
}
}
}
},
"multiProject": {
"enabled": true,
"activeProject": "fe",
"projects": {
"fe": {
"name": "Frontend",
"externalTools": {
"ado": {
"areaPath": "MyProduct\\Frontend",
"project": "MyProduct"
}
}
},
"be": {
"name": "Backend",
"externalTools": {
"ado": {
"areaPath": "MyProduct\\Backend",
"project": "MyProduct"
}
}
},
"mobile": {
"name": "Mobile",
"externalTools": {
"ado": {
"areaPath": "MyProduct\\Mobile",
"project": "MyProduct"
}
}
},
"devops": {
"name": "DevOps",
"externalTools": {
"ado": {
"areaPath": "MyProduct\\DevOps",
"project": "MyProduct"
}
}
}
}
}
}
```
### Step 7: Display Summary
```
✅ Azure DevOps Area Paths Import Complete!
🔷 ADO Project: MyProduct
📁 Created: .specweave/docs/internal/specs/ADO-myproduct/
Area paths imported:
✓ MyProduct\Frontend → fe (includes children)
Keywords: frontend, ui, angular, css
✓ MyProduct\Backend → be (includes children)
Keywords: api, server, database, c#
✓ MyProduct\Mobile → mobile (includes children)
Keywords: ios, android, xamarin
✓ MyProduct\DevOps → devops (includes children)
Keywords: infrastructure, ci, cd, terraform
💡 Next steps:
1. Use /specweave:switch-project fe to switch active project
2. Create increment: /specweave:increment "feature name"
3. User stories will auto-sync to the correct area path based on keywords
📖 Documentation: .specweave/docs/internal/architecture/adr/0143-jira-ado-multi-level-project-mapping.md
```
## Examples
### Example 1: Interactive Import
```
User: /specweave-ado:import-areas
You:
🔷 Azure DevOps Area Path Import
Enter the ADO project name: MyProduct
Fetching area paths...
Found 4 area paths:
☑ MyProduct\Frontend
☑ MyProduct\Backend
☑ MyProduct\Mobile
☐ MyProduct (root) [deselected]
Mapping to SpecWeave projects:
MyProduct\Frontend → fe
MyProduct\Backend → be
MyProduct\Mobile → mobile
✅ Import complete! 3 area paths mapped.
```
### Example 2: Dry Run
```
User: /specweave-ado:import-areas --project MyProduct --dry-run
You:
🔷 Azure DevOps Area Path Import (DRY RUN)
Would import from project: MyProduct
Would create:
.specweave/docs/internal/specs/ADO-myproduct/
.specweave/docs/internal/specs/ADO-myproduct/fe/
.specweave/docs/internal/specs/ADO-myproduct/be/
.specweave/docs/internal/specs/ADO-myproduct/mobile/
Would update config.json with area path mapping.
No changes made (dry run).
```
### Example 3: Already Configured
```
User: /specweave-ado:import-areas
You:
⚠️ Area path mapping already exists for project MyProduct
Current mappings:
MyProduct\Frontend → fe
MyProduct\Backend → be
Do you want to:
1. Add more area paths
2. Replace existing mapping
3. Cancel
> 1
Fetching additional area paths...
☐ MyProduct\Frontend (already mapped)
☐ MyProduct\Backend (already mapped)
☑ MyProduct\Mobile (new)
☑ MyProduct\DevOps (new)
Added:
MyProduct\Mobile → mobile
MyProduct\DevOps → devops
✅ Updated! Now 4 area paths mapped.
```
## Error Handling
**Missing credentials:**
```
❌ Azure DevOps credentials not found
Please add to .env:
AZURE_DEVOPS_PAT=your_personal_access_token
AZURE_DEVOPS_ORG=your_organization
AZURE_DEVOPS_PROJECT=your_project
Or run: specweave init . (to configure Azure DevOps)
```
**Project not found:**
```
❌ ADO project "INVALID" not found in organization "myorg"
Available projects you have access to:
- MyProduct (My Product Development)
- Infrastructure (DevOps & Infrastructure)
- Legacy (Legacy Systems)
Tip: Use /specweave-ado:import-areas --project MyProduct
```
**No area paths found:**
```
⚠️ No child area paths found in project MyProduct
The project only has the root area path. This means:
1. Teams aren't using area paths for organization
2. You can create area paths in ADO Project Settings
Suggestions:
- Use single-project mode (no area path mapping)
- Create area paths in ADO: Project Settings → Work → Areas
- Run this command again after creating area paths
```
## Related Commands
- `/specweave-ado:import-projects` - Import multiple ADO projects
- `/specweave-ado:sync` - Sync increments with ADO
- `/specweave:switch-project` - Switch active SpecWeave project
- `/specweave:init-multiproject` - Initialize multi-project mode

View File

@@ -0,0 +1,331 @@
---
name: specweave-ado:import-projects
description: Import additional Azure DevOps projects post-init with area path mapping, filtering, and dry-run preview
---
# Import Azure DevOps Projects Command
You are an Azure DevOps project import expert. Help users add additional ADO projects to their SpecWeave workspace after initial setup.
## Purpose
This command allows users to import additional Azure DevOps projects **after** initial SpecWeave setup (`specweave init`), with area path mapping, filtering, and dry-run preview.
**Use Cases**:
- Adding new ADO projects to existing workspace
- Importing projects from different organizations
- Selective import with area path granularity
- Multi-project organization (Backend, Frontend, Mobile, Infrastructure)
## Command Syntax
```bash
# Basic import (interactive)
/specweave-ado:import-projects
# With area path granularity
/specweave-ado:import-projects --granularity two-level
# Dry-run (preview)
/specweave-ado:import-projects --dry-run
# Resume interrupted import
/specweave-ado:import-projects --resume
# Combined
/specweave-ado:import-projects --granularity top-level --dry-run
```
## Your Task
When the user runs this command:
### Step 1: Validate Prerequisites
```typescript
import { readEnvFile, parseEnvFile } from '../../../src/utils/env-file.js';
// 1. Check if ADO credentials exist
const envContent = readEnvFile(process.cwd());
const parsed = parseEnvFile(envContent);
if (!parsed.AZURE_DEVOPS_PAT || !parsed.AZURE_DEVOPS_ORG) {
console.log('❌ Missing Azure DevOps credentials. Run `specweave init` first.');
return;
}
// 2. Get existing configuration
const org = parsed.AZURE_DEVOPS_ORG;
const existingProject = parsed.AZURE_DEVOPS_PROJECT;
console.log(`\n📋 Organization: ${org}`);
console.log(` Current project: ${existingProject || 'None'}\n`);
```
### Step 2: Fetch Available Projects
```typescript
import { getProjectCount } from '../../../src/cli/helpers/project-count-fetcher.js';
import { AsyncProjectLoader } from '../../../src/cli/helpers/async-project-loader.js';
// Count check (< 1 second)
const countResult = await getProjectCount({
provider: 'ado',
credentials: {
organization: org,
pat: parsed.AZURE_DEVOPS_PAT
}
});
console.log(`✓ Found ${countResult.accessible} accessible project(s)`);
// Fetch all projects (with smart pagination)
const loader = new AsyncProjectLoader(
{
organization: org,
pat: parsed.AZURE_DEVOPS_PAT
},
'ado',
{
batchSize: 50,
updateFrequency: 5,
showEta: true
}
);
const result = await loader.fetchAllProjects(countResult.accessible);
const allProjects = result.projects;
```
### Step 3: Area Path Mapping (Multi-Project Organization)
```typescript
import { AreaPathMapper } from '../../../src/integrations/ado/area-path-mapper.js';
const { selectedProject } = await inquirer.prompt([{
type: 'select',
name: 'selectedProject',
message: 'Select ADO project to import area paths from:',
choices: allProjects.map(p => ({ name: p.name, value: p.name }))
}]);
const mapper = new AreaPathMapper({
credentials: { organization: org, pat: parsed.AZURE_DEVOPS_PAT },
project: selectedProject
});
// Fetch area path tree
const areaPathTree = await mapper.fetchAreaPaths();
// Get granularity suggestion
const suggestion = mapper.suggestGranularity(areaPathTree);
console.log(`\n💡 Suggestion: ${suggestion.suggested}`);
console.log(` ${suggestion.reasoning}\n`);
// Prompt for granularity (if not provided via CLI)
const granularity = args.granularity || await mapper.promptAreaPathGranularity(areaPathTree);
// Flatten area paths with selected granularity
const areaPaths = mapper.flattenAreaPaths(areaPathTree, granularity);
console.log(`\n📊 ${areaPaths.length} project(s) will be created from area paths:\n`);
areaPaths.forEach(ap => {
const projectId = mapper.mapToProjectId(ap.path);
console.log(`${ap.path}${projectId}`);
});
```
### Step 4: Dry-Run or Execute
```typescript
if (args.dryRun) {
console.log('\n🔎 DRY RUN: No changes will be made.\n');
console.log('The following projects would be configured:');
areaPaths.forEach(ap => {
const projectId = mapper.mapToProjectId(ap.path);
console.log(`${projectId} (${ap.path})`);
});
console.log(`\nTotal: ${areaPaths.length} projects would be configured\n`);
return;
}
// Confirm import
const { confirmed } = await inquirer.prompt([{
type: 'confirm',
name: 'confirmed',
message: `Configure ${areaPaths.length} project(s) from area paths?`,
default: true
}]);
if (!confirmed) {
console.log('⏭️ Import cancelled.');
return;
}
```
### Step 5: Update Configuration
```typescript
import { getConfigManager } from '../../../src/core/config/index.js';
const configManager = getConfigManager(process.cwd());
// Build area path configuration
const areaPathConfig: Record<string, string[]> = {};
for (const ap of areaPaths) {
const projectId = mapper.mapToProjectId(ap.path);
areaPathConfig[projectId] = [ap.path];
}
// Update configuration
await configManager.update({
issueTracker: {
provider: 'ado',
ado: {
organization: org,
project: selectedProject,
areaPathMapping: areaPathConfig,
granularity
}
}
});
// Update .env file
import { updateEnvFile } from '../../../src/utils/env-manager.js';
await updateEnvFile('AZURE_DEVOPS_PROJECT', selectedProject);
// Write area paths to .env (comma-separated)
const areaPathList = areaPaths.map(ap => ap.path).join(',');
await updateEnvFile('AZURE_DEVOPS_AREA_PATHS', areaPathList);
console.log('\n✅ Projects configured successfully!\n');
console.log(`Organization: ${org}`);
console.log(`Project: ${selectedProject}`);
console.log(`Granularity: ${granularity}`);
console.log(`\nArea paths configured:\n ${areaPathList.split(',').join('\n ')}\n`);
```
### Step 6: Resume Support
```typescript
if (args.resume) {
const { CacheManager } = await import('../../../src/core/cache/cache-manager.js');
const cacheManager = new CacheManager(process.cwd());
const importState = await cacheManager.get('ado-import-state');
if (!importState) {
console.log('⚠️ No import state found. Use without --resume to start fresh.');
return;
}
console.log(`\n📂 Resuming from: ${importState.lastAreaPath} (${importState.completed}/${importState.total})`);
// Skip already-processed area paths
const remainingPaths = areaPaths.filter(ap => !importState.processed.includes(ap.path));
// Continue import with remaining paths
// (use same logic as Step 5)
}
```
## Examples
### Example 1: Basic Import with Area Paths
**User**: `/specweave-ado:import-projects`
**Output**:
```
📋 Organization: mycompany
Current project: Platform
✓ Found 5 accessible project(s)
Select ADO project to import area paths from:
> Platform
💡 Suggestion: two-level
Balanced hierarchy (8 two-level areas). Recommended granularity.
Select area path granularity for project organization:
> Two-level (8 projects) - e.g., Backend-API, Backend-Database
📊 8 project(s) will be created from area paths:
✨ Platform/Backend/API → backend-api
✨ Platform/Backend/Database → backend-database
✨ Platform/Frontend/Web → frontend-web
✨ Platform/Frontend/Admin → frontend-admin
✨ Platform/Mobile/iOS → mobile-ios
✨ Platform/Mobile/Android → mobile-android
✨ Platform/Infrastructure/Cloud → infrastructure-cloud
✨ Platform/Infrastructure/Network → infrastructure-network
Configure 8 project(s) from area paths? (Y/n)
✅ Projects configured successfully!
Organization: mycompany
Project: Platform
Granularity: two-level
Area paths configured:
Platform/Backend/API
Platform/Backend/Database
Platform/Frontend/Web
Platform/Frontend/Admin
Platform/Mobile/iOS
Platform/Mobile/Android
Platform/Infrastructure/Cloud
Platform/Infrastructure/Network
```
### Example 2: Top-Level Only
**User**: `/specweave-ado:import-projects --granularity top-level`
**Output**:
```
Select area path granularity: top-level (forced via CLI)
📊 3 project(s) will be created from area paths:
✨ Platform/Backend → backend
✨ Platform/Frontend → frontend
✨ Platform/Mobile → mobile
```
### Example 3: Dry-Run
**User**: `/specweave-ado:import-projects --dry-run`
**Output**:
```
🔎 DRY RUN: No changes will be made.
The following projects would be configured:
✨ backend-api (Platform/Backend/API)
✨ backend-database (Platform/Backend/Database)
✨ frontend-web (Platform/Frontend/Web)
Total: 8 projects would be configured
```
## Important Notes
- **Multi-Project Organization**: Uses area paths to create logical project separation
- **Granularity Control**: Top-level, two-level, or full-tree based on hierarchy complexity
- **Atomic Updates**: Uses temp file + rename to prevent corruption
- **Progress Tracking**: Shows progress bar for large hierarchies (> 50 area paths)
- **Resume Support**: Interrupted imports can be resumed with `--resume`
## Related Commands
- `/specweave:init` - Initial SpecWeave setup
- `/specweave-ado:sync` - Sync increments with ADO work items
- `/specweave-ado:refresh-cache` - Clear cached ADO data
## Error Handling
- **Missing Credentials**: Prompt user to run `specweave init` first
- **API Errors**: Show clear error message with suggestion
- **No Area Paths**: Fallback to single-project mode
- **Permission Errors**: Check ADO PAT scopes
---
**Multi-Project Excellence**: This command enables sophisticated multi-project organization in Azure DevOps using area paths, perfect for large teams with complex hierarchies.

View File

@@ -0,0 +1,53 @@
---
name: specweave-ado:status
description: Check Azure DevOps sync status for increment
---
# ADO Status Command
**Usage**: `/specweave-ado:status <increment-id>`
**Purpose**: Display ADO sync status and work item details
---
## Command Behavior
When user runs this command, invoke `ado-manager` agent to:
1. Read increment-metadata.json
2. Fetch work item from ADO API
3. Display: ID, URL, state, completion %, last sync time
4. Check for sync issues
**Agent Invocation**:
```
Use Task tool with subagent_type: "specweave-ado:ado-manager:ado-manager"
Prompt: "Check ADO sync status for increment 0005-payment-integration.
Steps:
1. Read increment-metadata.json
2. Extract: work item ID, last sync time
3. GET work item from ADO API
4. Display status information
5. Check for any sync issues"
```
---
## Example Output
```
ADO Sync Status
===============
Increment: 0005-payment-integration
Work Item: #12345
URL: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345
State: Active
Completion: 60% (6/10 tasks)
Last Synced: 2025-11-04 10:30:00 (5 minutes ago)
Sync Enabled: ✅
Next Sync: Automatic on task completion
```

View File

@@ -0,0 +1,148 @@
---
name: specweave-ado:sync
description: Two-way sync between SpecWeave increment and Azure DevOps work item (push & pull by default)
---
# Sync ADO Work Item Command
**Usage**: `/specweave-ado:sync <increment-id> [options]`
**Purpose**: Two-way synchronization between SpecWeave increment and Azure DevOps work item
**Default**: Two-way sync (push & pull)
---
## Options
- `--direction <mode>`: Sync direction (default: `two-way`)
- `two-way`: SpecWeave ↔ ADO (default - recommended)
- `to-ado`: SpecWeave → ADO only (push progress)
- `from-ado`: ADO → SpecWeave only (pull updates)
## Examples
```bash
# Two-way sync (default - both directions)
/specweave-ado:sync 0005
# Push only (one-way to ADO)
/specweave-ado:sync 0005 --direction to-ado
# Pull only (one-way from ADO)
/specweave-ado:sync 0005 --direction from-ado
```
---
## Command Behavior
When user runs this command, invoke `ado-manager` agent to perform two-way sync:
### Phase 1: Pull FROM ADO (default behavior)
1. Fetch work item state from ADO API
2. Detect changes in ADO:
- State changes (New → Active → Resolved → Closed)
- Priority changes
- Iteration/sprint changes
- Comments from team members
- Field updates
3. Apply ADO changes to SpecWeave increment:
- Update increment status to match ADO state
- Update priority in metadata
- Import team comments to increment notes
- Update iteration tracking
### Phase 2: Push TO ADO (default behavior)
1. Read tasks.md from increment
2. Calculate completion percentage
3. Identify recently completed tasks
4. Format progress update comment
5. POST comment to ADO work item
6. Update work item state if needed (New → Active → Resolved)
7. Update custom fields (completion %, current task, etc.)
**Agent Invocation**:
```
Use Task tool with subagent_type: "specweave-ado:ado-manager:ado-manager"
Prompt: "Two-way sync for increment 0005-payment-integration with ADO.
Phase 1 - Pull FROM ADO:
1. Fetch work item #12345 from ADO API
2. Detect changes: state, priority, iteration, comments
3. Apply ADO changes to increment metadata
4. Import team comments to increment notes
Phase 2 - Push TO ADO:
1. Read .specweave/increments/0005/tasks.md
2. Calculate: X/Y tasks complete (Z%)
3. Identify: Recently completed tasks
4. Format comment with progress update
5. Load work item ID from increment-metadata.json
6. POST comment to ADO API
7. Update work item state/fields
Display: Two-way sync summary"
```
---
## Example Output
### Two-way Sync (Default)
```
🔄 Two-way sync for increment 0005...
✓ Azure DevOps work item: #12345
✓ Sync direction: Two-way (push & pull)
Detecting changes (both directions)...
FROM ADO:
✓ Work item state changed: Active → Resolved
✓ Iteration updated: Sprint 23 → Sprint 24
✓ Priority changed: 2 → 1
✓ 3 new comments from team
FROM SpecWeave:
✓ 2 new tasks completed (T-005, T-006)
✓ Progress: 40% → 60% (6/10 tasks)
✓ Current task: T-007
Syncing TO ADO...
✓ Posted progress comment (ID: 98765)
✓ Updated completion: 60%
✓ Updated current task field: T-007
Syncing FROM ADO...
✓ Updated increment status: active → completed
✓ Updated priority: P2 → P1
✓ Updated iteration tracking: Sprint 24
✓ Imported 3 team comments to increment notes
✅ Bidirectional Sync Complete!
SpecWeave ↔ ADO synchronized
• Pushed: Progress (60%), 2 task updates
• Pulled: State (Resolved), priority (P1), iteration, 3 comments
ADO Work Item: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345
Last synced: just now
Next sync: Automatic (hook-based) or manual when ready
```
### One-Way Sync (to-ado)
```
✅ Pushed to ADO Work Item #12345
Progress: 60% complete (6/10 tasks)
Recently Completed:
- T-005: Add payment tests
- T-006: Update documentation
URL: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345
```

201
hooks/README.md Normal file
View File

@@ -0,0 +1,201 @@
# SpecWeave Azure DevOps Plugin Hooks
**Plugin**: `specweave-ado`
**Location**: `plugins/specweave-ado/hooks/`
---
## Purpose
This hook automatically syncs SpecWeave increment progress to Azure DevOps Work Items after each task completion.
**Key Features**:
- ✅ Updates Azure DevOps work item status based on increment progress
- ✅ Syncs task completion state to ADO
- ✅ Bidirectional sync (local → Azure DevOps)
- ✅ Non-blocking (failures don't stop core workflow)
- ✅ Self-contained (no dependencies on core plugin)
---
## Available Hooks
### 1. `post-task-completion.sh`
**Triggers**: After ANY task is marked complete (via TodoWrite tool)
**Preconditions**:
- ✅ Active increment exists (`.specweave/increments/####/`)
-`metadata.json` has `.ado.item` field
- ✅ Node.js installed
- ✅ ADO sync script exists (`dist/commands/ado-sync.js`)
- ✅ Azure DevOps PAT in `.env`
**Actions**:
1. Reads increment metadata
2. Calls ADO sync script (Node.js)
3. Updates Azure DevOps work item status
4. Logs all actions to `.specweave/logs/hooks-debug.log`
**Example Flow**:
```
Task T-003 completed in tasks.md
Hook fires (PostToolUse + TodoWrite matcher)
ADO sync script updates work item #4567
Log: "[ADO] ✅ Azure DevOps sync complete"
```
**Dependencies**:
- Node.js 18+
- Azure DevOps PAT (`.env`)
- `jq` for JSON parsing
---
## Configuration
### Hook Registration (`hooks.json`)
```json
{
"hooks": {
"PostToolUse": [
{
"matcher": "TodoWrite",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/post-task-completion.sh"
}
]
}
]
}
}
```
### Metadata Format
Increments must have `metadata.json` with Azure DevOps work item link:
```json
{
"ado": {
"item": 4567,
"url": "https://dev.azure.com/org/project/_workitems/edit/4567",
"project": "MyProject"
}
}
```
### Environment Variables
Required in `.env`:
```bash
AZURE_DEVOPS_ORG=your-org
AZURE_DEVOPS_PROJECT=your-project
AZURE_DEVOPS_PAT=your_personal_access_token_here
```
---
## Installation
### Automatic (Recommended)
```bash
npx specweave init my-project
# Installs all plugins including specweave-ado
# Hooks auto-register via hooks.json
```
### Manual (Development)
```bash
# Install plugin
/plugin install specweave-ado
# Verify hook registration
cat ~/.claude/settings.json | grep specweave-ado
```
---
## Testing
### Test Hook Independently
```bash
# Test syntax
bash -n plugins/specweave-ado/hooks/post-task-completion.sh
# Test execution (requires active increment + ADO work item)
./plugins/specweave-ado/hooks/post-task-completion.sh
```
---
## Logging
All Azure DevOps sync actions are logged to:
```
.specweave/logs/hooks-debug.log
```
**Example Log Output**:
```
[2025-11-10] [ADO] 🔗 Azure DevOps sync hook fired
[2025-11-10] [ADO] 🔄 Syncing to Azure DevOps work item 4567
[2025-11-10] [ADO] ✅ Azure DevOps sync complete
```
**Log Prefixes**:
- `[ADO]` - All messages from this hook
- `🔗` - Hook fired
- `🔄` - Syncing started
- `✅` - Success
- `⚠️` - Warning (non-blocking failure)
- `` - Info (skipped due to precondition)
---
## Architecture
### Separation from Core Plugin
**Before (v0.12.x)**:
```
Core hook (500+ lines)
├── Azure DevOps sync ← Embedded in core!
```
**After (v0.13.0+)**:
```
Core hook (330 lines) ADO plugin hook (150 lines)
├── Core concerns ├── Check for ADO work item
├── Call Node.js sync script
└── Log actions
```
**Key Benefits**:
-**Optional plugin**: ADO sync only runs if `specweave-ado` installed
-**Independent testing**: Test ADO sync in isolation
-**No core dependencies**: Core plugin doesn't depend on Azure DevOps API
---
## Related Documentation
- **Core Plugin Hooks**: `plugins/specweave/hooks/README.md`
- **Architecture Analysis**: `.specweave/increments/0018-strict-increment-discipline-enforcement/reports/HOOKS-ARCHITECTURE-ANALYSIS.md`
- **ADO Sync Command**: `plugins/specweave-ado/commands/specweave-ado-sync.md`
---
**Version**: v0.13.0+
**Last Updated**: 2025-11-10

View File

@@ -0,0 +1,360 @@
#!/bin/bash
# ============================================================================
# Post Living Docs Update Hook - Azure DevOps Sync
# ============================================================================
#
# Triggered after living docs are updated to sync with Azure DevOps.
# CRITICAL: External tool status ALWAYS wins in conflicts!
#
# Triggers:
# 1. After /specweave:done (increment completion)
# 2. After /specweave:sync-docs update
# 3. After manual spec edits
# 4. After webhook from ADO
#
# ============================================================================
set +e # EMERGENCY FIX: Prevents Claude Code crashes
# EMERGENCY KILL SWITCH
if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
exit 0
fi
# Configuration
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
LIVING_DOCS_DIR="$PROJECT_ROOT/.specweave/docs/internal/specs"
LOG_FILE="$PROJECT_ROOT/.specweave/logs/ado-sync.log"
DEBUG=${DEBUG:-0}
# Ensure log directory exists
mkdir -p "$(dirname "$LOG_FILE")"
# ============================================================================
# Logging
# ============================================================================
log() {
local level=$1
shift
local message="$@"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
[ "$DEBUG" -eq 1 ] && echo "[$level] $message" >&2
}
log_info() {
log "INFO" "$@"
}
log_error() {
log "ERROR" "$@"
}
log_debug() {
[ "$DEBUG" -eq 1 ] && log "DEBUG" "$@"
}
# ============================================================================
# External Tool Detection
# ============================================================================
detect_external_tool() {
local spec_path=$1
# Check for external links in spec metadata
if grep -q "externalLinks:" "$spec_path"; then
if grep -q "ado:" "$spec_path"; then
echo "ado"
elif grep -q "jira:" "$spec_path"; then
echo "jira"
elif grep -q "github:" "$spec_path"; then
echo "github"
fi
fi
}
# ============================================================================
# Status Mapping
# ============================================================================
map_ado_status_to_local() {
local ado_status=$1
case "$ado_status" in
"New")
echo "draft"
;;
"Active")
echo "in-progress"
;;
"Resolved")
echo "implemented"
;;
"Closed")
echo "complete"
;;
"In Review"|"In QA")
echo "in-qa"
;;
*)
echo "unknown"
;;
esac
}
map_local_status_to_ado() {
local local_status=$1
case "$local_status" in
"draft")
echo "New"
;;
"in-progress")
echo "Active"
;;
"implemented")
echo "Resolved"
;;
"complete")
echo "Closed"
;;
"in-qa")
echo "In Review"
;;
*)
echo "Active"
;;
esac
}
# ============================================================================
# ADO API Functions
# ============================================================================
get_ado_work_item_status() {
local work_item_id=$1
local org="${AZURE_DEVOPS_ORG}"
local project="${AZURE_DEVOPS_PROJECT}"
local pat="${AZURE_DEVOPS_PAT}"
if [ -z "$org" ] || [ -z "$pat" ]; then
log_error "ADO credentials not configured"
return 1
fi
local api_url="https://dev.azure.com/${org}/${project}/_apis/wit/workitems/${work_item_id}?api-version=7.0"
log_debug "Fetching ADO work item $work_item_id status"
local response=$(curl -s -u ":${pat}" \
-H "Content-Type: application/json" \
"$api_url")
if [ $? -ne 0 ]; then
log_error "Failed to fetch ADO work item status"
return 1
fi
# Extract status from response
local status=$(echo "$response" | jq -r '.fields["System.State"]')
if [ "$status" = "null" ] || [ -z "$status" ]; then
log_error "Could not extract status from ADO response"
return 1
fi
echo "$status"
}
update_ado_work_item() {
local work_item_id=$1
local spec_content=$2
local org="${AZURE_DEVOPS_ORG}"
local project="${AZURE_DEVOPS_PROJECT}"
local pat="${AZURE_DEVOPS_PAT}"
if [ -z "$org" ] || [ -z "$pat" ]; then
log_error "ADO credentials not configured"
return 1
fi
# Extract current status from spec
local local_status=$(echo "$spec_content" | grep "^status:" | cut -d: -f2 | tr -d ' ')
local ado_status=$(map_local_status_to_ado "$local_status")
local api_url="https://dev.azure.com/${org}/${project}/_apis/wit/workitems/${work_item_id}?api-version=7.0"
# Create update payload
local payload=$(cat <<EOF
[
{
"op": "add",
"path": "/fields/System.State",
"value": "$ado_status"
},
{
"op": "add",
"path": "/fields/System.History",
"value": "Updated from SpecWeave living docs"
}
]
EOF
)
log_debug "Updating ADO work item $work_item_id with status: $ado_status"
curl -s -X PATCH \
-u ":${pat}" \
-H "Content-Type: application/json-patch+json" \
-d "$payload" \
"$api_url" > /dev/null
if [ $? -ne 0 ]; then
log_error "Failed to update ADO work item"
return 1
fi
log_info "Updated ADO work item $work_item_id"
}
# ============================================================================
# Conflict Resolution - CRITICAL: External Wins!
# ============================================================================
resolve_status_conflict() {
local spec_path=$1
local local_status=$2
local external_status=$3
local mapped_external=$(map_ado_status_to_local "$external_status")
if [ "$local_status" != "$mapped_external" ]; then
log_info "Status conflict detected:"
log_info " Local: $local_status"
log_info " External: $external_status (mapped: $mapped_external)"
log_info " Resolution: EXTERNAL WINS - applying $mapped_external"
# Update local spec with external status
sed -i.bak "s/^status: .*/status: $mapped_external/" "$spec_path"
# Add sync metadata
local timestamp=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
# Check if syncedAt exists, update or add
if grep -q "syncedAt:" "$spec_path"; then
sed -i.bak "s/syncedAt: .*/syncedAt: \"$timestamp\"/" "$spec_path"
else
# Add after externalLinks section
sed -i.bak "/externalLinks:/a\\
syncedAt: \"$timestamp\"" "$spec_path"
fi
# Clean up backup files
rm -f "${spec_path}.bak"
log_info "Local spec updated with external status: $mapped_external"
return 0
else
log_debug "No status conflict - local and external match: $local_status"
return 0
fi
}
# ============================================================================
# Main Sync Function
# ============================================================================
sync_spec_with_ado() {
local spec_path=$1
if [ ! -f "$spec_path" ]; then
log_error "Spec file not found: $spec_path"
return 1
fi
local spec_name=$(basename "$spec_path")
log_info "Syncing spec: $spec_name"
# Read spec content
local spec_content=$(cat "$spec_path")
# Extract ADO work item ID from metadata
local work_item_id=$(echo "$spec_content" | grep -A5 "externalLinks:" | grep -A3 "ado:" | grep "featureId:" | cut -d: -f2 | tr -d ' ')
if [ -z "$work_item_id" ]; then
log_debug "No ADO work item linked to spec, skipping sync"
return 0
fi
log_info "Found ADO work item ID: $work_item_id"
# Step 1: Push updates to ADO (content changes)
update_ado_work_item "$work_item_id" "$spec_content"
# Step 2: CRITICAL - Pull status from ADO (external wins!)
local external_status=$(get_ado_work_item_status "$work_item_id")
if [ -z "$external_status" ]; then
log_error "Could not fetch ADO status"
return 1
fi
log_info "ADO status: $external_status"
# Step 3: Extract local status
local local_status=$(echo "$spec_content" | grep "^status:" | cut -d: -f2 | tr -d ' ')
log_info "Local status: $local_status"
# Step 4: Resolve conflicts - EXTERNAL WINS
resolve_status_conflict "$spec_path" "$local_status" "$external_status"
log_info "Sync completed for $spec_name"
}
# ============================================================================
# Entry Point
# ============================================================================
main() {
log_info "=== Post Living Docs Update Hook Started ==="
# Get the spec path from arguments or environment
local spec_path="${1:-$SPECWEAVE_UPDATED_SPEC}"
if [ -z "$spec_path" ]; then
log_error "No spec path provided"
exit 1
fi
# Detect external tool
local tool=$(detect_external_tool "$spec_path")
if [ "$tool" != "ado" ]; then
log_debug "Not an ADO-linked spec, skipping"
exit 0
fi
log_info "Detected ADO integration for spec"
# Perform sync
sync_spec_with_ado "$spec_path"
local exit_code=$?
if [ $exit_code -eq 0 ]; then
log_info "=== Sync completed successfully ==="
else
log_error "=== Sync failed with exit code: $exit_code ==="
fi
exit $exit_code
}
# Run main function
main "$@"
# ALWAYS exit 0 - NEVER let hook errors crash Claude Code
exit 0

180
hooks/post-task-completion.sh Executable file
View File

@@ -0,0 +1,180 @@
#!/bin/bash
# SpecWeave Azure DevOps Sync Hook
# Runs after task completion to sync progress to Azure DevOps Work Items
#
# This hook is part of the specweave-ado plugin and handles:
# - Syncing task completion state to Azure DevOps work items
# - Updating ADO work item status based on increment progress
#
# Dependencies:
# - Node.js for running sync scripts
# - jq for JSON parsing
# - metadata.json must have .ado.item field
# - Azure DevOps PAT in .env
set +e # EMERGENCY FIX: Prevents Claude Code crashes
# EMERGENCY KILL SWITCH
if [[ "${SPECWEAVE_DISABLE_HOOKS:-0}" == "1" ]]; then
exit 0
fi
# ============================================================================
# PROJECT ROOT DETECTION
# ============================================================================
# Find project root by searching upward for .specweave/ directory
find_project_root() {
local dir="$1"
while [ "$dir" != "/" ]; do
if [ -d "$dir/.specweave" ]; then
echo "$dir"
return 0
fi
dir="$(dirname "$dir")"
done
# Fallback: try current directory
if [ -d "$(pwd)/.specweave" ]; then
pwd
else
echo "$(pwd)"
fi
}
PROJECT_ROOT="$(find_project_root "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)")"
cd "$PROJECT_ROOT" 2>/dev/null || true
# ============================================================================
# CONFIGURATION
# ============================================================================
LOGS_DIR=".specweave/logs"
DEBUG_LOG="$LOGS_DIR/hooks-debug.log"
mkdir -p "$LOGS_DIR" 2>/dev/null || true
# ============================================================================
# PRECONDITIONS CHECK
# ============================================================================
echo "[$(date)] [ADO] 🔗 Azure DevOps sync hook fired" >> "$DEBUG_LOG" 2>/dev/null || true
# Detect current increment
CURRENT_INCREMENT=$(ls -td .specweave/increments/*/ 2>/dev/null | xargs -n1 basename | grep -v "_backlog" | grep -v "_archive" | grep -v "_working" | head -1)
if [ -z "$CURRENT_INCREMENT" ]; then
echo "[$(date)] [ADO] No active increment, skipping ADO sync" >> "$DEBUG_LOG" 2>/dev/null || true
cat <<EOF
{
"continue": true
}
EOF
exit 0
fi
# Check for metadata.json
METADATA_FILE=".specweave/increments/$CURRENT_INCREMENT/metadata.json"
if [ ! -f "$METADATA_FILE" ]; then
echo "[$(date)] [ADO] No metadata.json for $CURRENT_INCREMENT, skipping ADO sync" >> "$DEBUG_LOG" 2>/dev/null || true
cat <<EOF
{
"continue": true
}
EOF
exit 0
fi
# Check for ADO work item link
if ! command -v jq &> /dev/null; then
echo "[$(date)] [ADO] ⚠️ jq not found, skipping ADO sync" >> "$DEBUG_LOG" 2>/dev/null || true
cat <<EOF
{
"continue": true
}
EOF
exit 0
fi
ADO_ITEM=$(jq -r '.ado.item // empty' "$METADATA_FILE" 2>/dev/null)
if [ -z "$ADO_ITEM" ]; then
echo "[$(date)] [ADO] No Azure DevOps work item linked to $CURRENT_INCREMENT, skipping sync" >> "$DEBUG_LOG" 2>/dev/null || true
cat <<EOF
{
"continue": true
}
EOF
exit 0
fi
# Check for Node.js
if ! command -v node &> /dev/null; then
echo "[$(date)] [ADO] ⚠️ Node.js not found, skipping ADO sync" >> "$DEBUG_LOG" 2>/dev/null || true
cat <<EOF
{
"continue": true
}
EOF
exit 0
fi
# Check for ADO sync script
if [ ! -f "dist/commands/ado-sync.js" ]; then
echo "[$(date)] [ADO] ⚠️ ado-sync.js not found, skipping ADO sync" >> "$DEBUG_LOG" 2>/dev/null || true
cat <<EOF
{
"continue": true
}
EOF
exit 0
fi
# ============================================================================
# AZURE DEVOPS SYNC LOGIC
# ============================================================================
echo "[$(date)] [ADO] 🔄 Syncing to Azure DevOps work item $ADO_ITEM" >> "$DEBUG_LOG" 2>/dev/null || true
# Run ADO sync command (non-blocking)
node dist/commands/ado-sync.js "$CURRENT_INCREMENT" 2>&1 | tee -a "$DEBUG_LOG" >/dev/null || {
echo "[$(date)] [ADO] ⚠️ Failed to sync to Azure DevOps (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
}
echo "[$(date)] [ADO] ✅ Azure DevOps sync complete" >> "$DEBUG_LOG" 2>/dev/null || true
# ============================================================================
# SPEC COMMIT SYNC (NEW!)
# ============================================================================
echo "[$(date)] [ADO] 🔗 Checking for spec commit sync..." >> "$DEBUG_LOG" 2>/dev/null || true
# Call TypeScript CLI to sync commits
if command -v node &> /dev/null && [ -f "$PROJECT_ROOT/dist/cli/commands/sync-spec-commits.js" ]; then
echo "[$(date)] [ADO] 🚀 Running spec commit sync..." >> "$DEBUG_LOG" 2>/dev/null || true
node "$PROJECT_ROOT/dist/cli/commands/sync-spec-commits.js" \
--increment "$PROJECT_ROOT/.specweave/increments/$CURRENT_INCREMENT" \
--provider ado \
2>&1 | tee -a "$DEBUG_LOG" >/dev/null || {
echo "[$(date)] [ADO] ⚠️ Spec commit sync failed (non-blocking)" >> "$DEBUG_LOG" 2>/dev/null || true
}
echo "[$(date)] [ADO] ✅ Spec commit sync complete" >> "$DEBUG_LOG" 2>/dev/null || true
else
echo "[$(date)] [ADO] Spec commit sync not available (node or script not found)" >> "$DEBUG_LOG" 2>/dev/null || true
fi
# ============================================================================
# OUTPUT TO CLAUDE
# ============================================================================
cat <<EOF
{
"continue": true
}
EOF
# ALWAYS exit 0 - NEVER let hook errors crash Claude Code
exit 0

121
plugin.lock.json Normal file
View File

@@ -0,0 +1,121 @@
{
"$schema": "internal://schemas/plugin.lock.v1.json",
"pluginId": "gh:anton-abyzov/specweave:plugins/specweave-ado",
"normalized": {
"repo": null,
"ref": "refs/tags/v20251128.0",
"commit": "4a3c84a4e8ad778b4da43b0e306b4b021d550ab5",
"treeHash": "1ce695eb7d73b7a58149df869fa3fc4e33f2dc0ef57d17e509f6670ed788d28b",
"generatedAt": "2025-11-28T10:13:50.575419Z",
"toolVersion": "publish_plugins.py@0.2.0"
},
"origin": {
"remote": "git@github.com:zhongweili/42plugin-data.git",
"branch": "master",
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
},
"manifest": {
"name": "specweave-ado",
"description": "Azure DevOps integration for SpecWeave - sync increments with ADO work items, track progress, and manage project workflows",
"version": "0.24.0"
},
"content": {
"files": [
{
"path": "README.md",
"sha256": "b249946662f8bc24d1950a625f2b3d47de1d0555b01c5d49cea3369890bc84b5"
},
{
"path": "agents/ado-multi-project-mapper/AGENT.md",
"sha256": "2b58d8b11bf53ef74b9053310c70432313f62e8473e719d502a550becfced1a2"
},
{
"path": "agents/ado-sync-judge/AGENT.md",
"sha256": "90e77144f6828121ffb4c46f97df4b5e146f7ac0103cf89f52eb230722ac127b"
},
{
"path": "agents/ado-manager/AGENT.md",
"sha256": "57dc4f48aa189c65dff4b2b430436affe648b23945ca31cd5c66c90baf79905d"
},
{
"path": "hooks/post-task-completion.sh",
"sha256": "93226022459b25018d3a8ea9cb731a15cca112f26f2803d78307e3f18e3e8287"
},
{
"path": "hooks/post-living-docs-update.sh",
"sha256": "56a32624cd851c72c6a336c38d6bd4e191a83337e655e52ccc84287673bed9d1"
},
{
"path": "hooks/README.md",
"sha256": "2e99005f33515648b559b4cb193033376824593c64d08a71d74fe6061d949b8e"
},
{
"path": ".claude-plugin/plugin.json",
"sha256": "d9663072d7e0b2641d12bab416a48b764c4e4440f3ce80d33eb7750e3f5119d1"
},
{
"path": "commands/specweave-ado-import-areas.md",
"sha256": "34e4baaf8c91a71d5b3d06589ea4e6cb30b4e5a4b0d3985f51e724d6f1d7ddcb"
},
{
"path": "commands/specweave-ado-create-workitem.md",
"sha256": "f2e54601ae743a79a4dbf53727fe2eb4c23728d99aa9f8c7461e7893fc3131f8"
},
{
"path": "commands/refresh-cache.ts",
"sha256": "0a2f00730d451bf758c3879a367401164cded2bcdf49ca388149cc992b4bff97"
},
{
"path": "commands/specweave-ado-sync.md",
"sha256": "72a4aa9a30c43fdb48a26c09d4c1c7fa38758c92acd3e4bdfcbee38ca269642f"
},
{
"path": "commands/specweave-ado-import-projects.md",
"sha256": "fbc0d52371d3a69b1369e307d5938f477150103b18ceeca7116109565610a606"
},
{
"path": "commands/specweave-ado-close-workitem.md",
"sha256": "af79460505f42ed7315b1fa799f85e4667939973a91fcf10d4cfd03395481b7e"
},
{
"path": "commands/refresh-cache.js",
"sha256": "b4e93399c119c347f8429c532ee763440afa0af458a948af128291107fc15bae"
},
{
"path": "commands/specweave-ado-status.md",
"sha256": "ea7c1f00014eb43e206bf244269f7fbc5bb742c4170a7aedf8f8525d4be7b434"
},
{
"path": "skills/specweave-ado-mapper/SKILL.md",
"sha256": "cd47caefdfaaa22fa1b2ea51a7641844c1070a124b4bbc16631f5d408bdc836a"
},
{
"path": "skills/ado-sync/README.md",
"sha256": "b67e7a6b3c4b0c511bffe68ba88b36cd4c25f097f5b4ebc9ef6bc8ed9a48e4cc"
},
{
"path": "skills/ado-sync/.gitignore",
"sha256": "94141423426c2b1cd10650984dc5f5e10c0f2ec3b54162bb90bcf07f36c6a725"
},
{
"path": "skills/ado-sync/SKILL.md",
"sha256": "e282681490062185996b0929d9fbd7b67906ff3eb03ead2fcab15d4b1cdcfe5f"
},
{
"path": "skills/ado-multi-project/SKILL.md",
"sha256": "d13cfd36c34c0bb45f3dd050300302e7160459d12b11172a646fcbbfd396fdf1"
},
{
"path": "skills/ado-resource-validator/SKILL.md",
"sha256": "7a2c7ee8230af2f0f2b18a605e78d58be19a1716fb904626d356920fe48023cb"
}
],
"dirSha256": "1ce695eb7d73b7a58149df869fa3fc4e33f2dc0ef57d17e509f6670ed788d28b"
},
"security": {
"scannedAt": null,
"scannerVersion": null,
"flags": []
}
}

View File

@@ -0,0 +1,541 @@
---
name: ado-multi-project
description: Expert at organizing specs and splitting tasks across multiple Azure DevOps projects. Handles project-per-team, area-path-based, and team-based architectures. Intelligently maps increments and specs to correct projects based on content analysis. Activates for multi-project Azure DevOps setups, task splitting, spec organization, team allocation, cross-project coordination.
allowed-tools: Read, Write, Edit, Glob
---
# Azure DevOps Multi-Project Skill
**Purpose**: Organize specs and increments across multiple Azure DevOps projects with intelligent mapping and folder organization.
## What This Skill Does
This skill handles complex multi-project Azure DevOps organizations by:
1. **Analyzing increment content** to determine which project it belongs to
2. **Creating project-specific folder structures** in `.specweave/docs/internal/specs/`
3. **Mapping user stories to correct projects** based on keywords and context
4. **Splitting tasks across projects** when increments span multiple teams
5. **Maintaining bidirectional sync** between local specs and Azure DevOps work items
## Supported Architectures
### 1. Project-per-team (Recommended for Microservices)
```
Organization: mycompany
├── AuthService (Project)
├── UserService (Project)
├── PaymentService (Project)
└── NotificationService (Project)
Local Structure:
.specweave/docs/internal/specs/
├── AuthService/
├── UserService/
├── PaymentService/
└── NotificationService/
```
### 2. Area-path-based (Monolithic Applications)
```
Organization: enterprise
└── ERP (Project)
├── Finance (Area Path)
├── HR (Area Path)
├── Inventory (Area Path)
└── Sales (Area Path)
Local Structure:
.specweave/docs/internal/specs/ERP/
├── Finance/
├── HR/
├── Inventory/
└── Sales/
```
### 3. Team-based (Small Organizations)
```
Organization: startup
└── Platform (Project)
├── Alpha Team
├── Beta Team
└── Gamma Team
Local Structure:
.specweave/docs/internal/specs/Platform/
├── AlphaTeam/
├── BetaTeam/
└── GammaTeam/
```
## Intelligent Project Detection
The skill analyzes increment content to determine the correct project:
### Detection Patterns
```typescript
const projectPatterns = {
'AuthService': {
keywords: ['authentication', 'login', 'oauth', 'jwt', 'session', 'password'],
filePatterns: ['auth/', 'login/', 'security/'],
confidence: 0.0
},
'UserService': {
keywords: ['user', 'profile', 'account', 'registration', 'preferences'],
filePatterns: ['users/', 'profiles/', 'accounts/'],
confidence: 0.0
},
'PaymentService': {
keywords: ['payment', 'stripe', 'billing', 'invoice', 'subscription'],
filePatterns: ['payment/', 'billing/', 'checkout/'],
confidence: 0.0
}
};
// Analyze spec content
const spec = readSpec(incrementId);
for (const [project, pattern] of Object.entries(projectPatterns)) {
pattern.confidence = calculateConfidence(spec, pattern);
}
// Select project with highest confidence
const selectedProject = Object.entries(projectPatterns)
.sort((a, b) => b[1].confidence - a[1].confidence)[0][0];
```
### Confidence Calculation
- **Keyword match**: +0.2 per keyword found
- **File pattern match**: +0.3 per pattern
- **Explicit mention**: +1.0 if project name in spec
- **Team mention**: +0.5 if team name matches
**Threshold**: Confidence > 0.7 = auto-assign, otherwise prompt user
## Usage Examples
### Example 1: Single-Project Increment
**Scenario**: Authentication feature for AuthService
**Spec Analysis**:
```
Title: "Add OAuth 2.0 authentication"
Keywords found: authentication, oauth, jwt
File patterns: src/auth/oauth-provider.ts
Confidence: AuthService = 0.9 ✅
```
**Action**:
```bash
# Auto-creates folder structure
.specweave/docs/internal/specs/AuthService/
└── spec-001-oauth-authentication.md
# Maps to Azure DevOps
Project: AuthService
Work Item: Epic "OAuth 2.0 Authentication"
```
### Example 2: Multi-Project Increment
**Scenario**: Checkout flow spanning multiple services
**Spec Analysis**:
```
Title: "Implement checkout flow with payment processing"
Keywords found: user, cart, payment, stripe, notification
Confidence:
- UserService = 0.6
- PaymentService = 0.8 ✅
- NotificationService = 0.5
```
**Action**:
```bash
# Creates multi-project structure
.specweave/docs/internal/specs/
├── PaymentService/
│ └── spec-002-checkout-payment.md (primary)
├── UserService/
│ └── spec-002-checkout-user.md (linked)
└── NotificationService/
└── spec-002-checkout-notifications.md (linked)
# Creates linked work items in Azure DevOps
PaymentService: Epic "Checkout Payment Processing" (primary)
UserService: Feature "User Cart Management" (links to primary)
NotificationService: Feature "Order Notifications" (links to primary)
```
### Example 3: Area Path Organization
**Scenario**: ERP system with module-based organization
**Configuration**:
```bash
AZURE_DEVOPS_STRATEGY=area-path-based
AZURE_DEVOPS_PROJECT=ERP
AZURE_DEVOPS_AREA_PATHS=Finance,HR,Inventory
```
**Spec Analysis**:
```
Title: "Add payroll calculation engine"
Keywords found: payroll, salary, tax, employee
Area match: HR (confidence = 0.85)
```
**Action**:
```bash
# Creates area-based structure
.specweave/docs/internal/specs/ERP/HR/
└── spec-003-payroll-engine.md
# Maps to Azure DevOps
Project: ERP
Area Path: ERP\HR
Work Item: Epic "Payroll Calculation Engine"
```
## Task Splitting Across Projects
When an increment spans multiple projects, tasks are intelligently split:
### Input: Unified tasks.md
```markdown
# Tasks for Checkout Flow
- T-001: Create shopping cart API (UserService)
- T-002: Implement Stripe integration (PaymentService)
- T-003: Add order confirmation email (NotificationService)
- T-004: Update user order history (UserService)
- T-005: Process payment webhook (PaymentService)
```
### Output: Project-specific work items
**UserService** (2 tasks):
- Task: Create shopping cart API
- Task: Update user order history
**PaymentService** (2 tasks):
- Task: Implement Stripe integration
- Task: Process payment webhook
**NotificationService** (1 task):
- Task: Add order confirmation email
## Folder Structure Creation
The skill automatically creates and maintains folder structure:
### On Increment Creation
```typescript
async function createProjectFolders(increment: Increment) {
const projects = detectProjects(increment);
for (const project of projects) {
const specPath = `.specweave/docs/internal/specs/${project}/`;
await ensureDir(specPath);
// Create project-specific spec
const spec = extractProjectSpec(increment, project);
await writeSpec(`${specPath}/spec-${increment.number}-${increment.name}.md`, spec);
// Create README if first spec in project
if (isFirstSpec(project)) {
await createProjectReadme(project);
}
}
}
```
### Project README Template
```markdown
# {Project} Specifications
## Overview
This folder contains specifications for the {Project} project.
## Architecture
{Brief description of project architecture}
## Team
- Team Lead: {name}
- Developers: {list}
## Specifications
- [spec-001-feature.md](spec-001-feature.md) - {description}
## External Links
- Azure DevOps: https://dev.azure.com/{org}/{project}
- Repository: {git-url}
```
## Sync Commands
### Sync Increment to Projects
```bash
/specweave-ado:sync-increment 0014
# Detects projects from spec
# Creates work items in each project
# Links work items together
```
### Sync Spec to Project
```bash
/specweave-ado:sync-spec AuthService/spec-001
# Syncs single spec to specific project
# Updates existing work item or creates new
```
### Sync All Specs
```bash
/specweave-ado:sync-all
# Syncs all specs across all projects
# Maintains relationships
# Updates bidirectionally
```
## Project Mapping Configuration
### Manual Mapping (config.json)
```json
{
"ado": {
"projectMappings": {
"auth-.*": "AuthService",
"user-.*": "UserService",
"payment-.*": "PaymentService",
"notification-.*": "NotificationService"
},
"defaultProject": "Platform",
"crossProjectLinking": true
}
}
```
### Auto-Detection Rules
```typescript
const autoDetectionRules = [
{
pattern: /auth|login|oauth|security/i,
project: "AuthService"
},
{
pattern: /user|profile|account/i,
project: "UserService"
},
{
pattern: /payment|billing|stripe/i,
project: "PaymentService"
}
];
```
## Cross-Project Coordination
### Dependency Management
When increments span projects, dependencies are tracked:
```yaml
# .specweave/increments/0014-checkout-flow/metadata.yml
projects:
primary: PaymentService
dependencies:
- UserService: [T-001, T-004]
- NotificationService: [T-003]
ado_mappings:
PaymentService:
epic: 12345
work_items: [12346, 12347]
UserService:
feature: 12348
work_items: [12349, 12350]
NotificationService:
feature: 12351
work_items: [12352]
```
### Cross-Project Queries
```typescript
// Find all work items for an increment across projects
async function getIncrementWorkItems(incrementId: string) {
const metadata = await readMetadata(incrementId);
const workItems = [];
for (const [project, mapping] of Object.entries(metadata.ado_mappings)) {
const items = await adoClient.getWorkItems(project, mapping.work_items);
workItems.push(...items);
}
return workItems;
}
```
## Best Practices
### 1. Consistent Naming
Use consistent naming across projects:
```
spec-001-oauth-authentication.md # Good
spec-001-auth.md # Too vague
SPEC_001_OAuth.md # Inconsistent format
```
### 2. Clear Project Boundaries
Define clear boundaries between projects:
```yaml
AuthService:
owns: [authentication, authorization, sessions]
not: [user profiles, user preferences]
UserService:
owns: [profiles, preferences, user data]
not: [authentication, passwords]
```
### 3. Link Related Specs
Link specs that span projects:
```markdown
# spec-002-checkout-payment.md
Related Specs:
- [User Cart](../UserService/spec-002-checkout-user.md)
- [Notifications](../NotificationService/spec-002-checkout-notifications.md)
```
### 4. Use Project Prefixes
Prefix increment names with primary project:
```bash
/specweave:increment "payment-stripe-integration"
/specweave:increment "auth-oauth-provider"
/specweave:increment "user-profile-redesign"
```
## Error Handling
### Project Not Found
```
❌ Project "AuthService" not found in Azure DevOps
Options:
1. Create project "AuthService"
2. Map to existing project
3. Skip this project
Your choice [1]:
```
### Ambiguous Project Detection
```
⚠️ Cannot determine project for increment 0014
Multiple projects detected:
- UserService (confidence: 0.6)
- PaymentService (confidence: 0.6)
Please select primary project:
1. UserService
2. PaymentService
3. Both (multi-project)
Your choice [3]:
```
### Sync Conflicts
```
⚠️ Sync conflict detected
Local: spec-001 updated 2 hours ago
Azure DevOps: Work item updated 1 hour ago
Options:
1. Use local version
2. Use Azure DevOps version
3. Merge changes
4. View diff
Your choice [3]:
```
## Integration with CI/CD
### Auto-sync on Commit
```yaml
# .github/workflows/specweave-sync.yml
on:
push:
paths:
- '.specweave/docs/internal/specs/**'
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: npx specweave ado-sync-all
env:
AZURE_DEVOPS_PAT: ${{ secrets.ADO_PAT }}
```
### Project-specific Pipelines
```yaml
# azure-pipelines.yml
trigger:
paths:
include:
- .specweave/docs/internal/specs/$(System.TeamProject)/**
variables:
- name: project
value: $(System.TeamProject)
steps:
- script: npx specweave ado-sync-project $(project)
```
## Summary
This skill enables sophisticated multi-project Azure DevOps organizations by:
1.**Intelligent project detection** from spec content
2.**Automatic folder organization** by project/area/team
3.**Task splitting** across multiple projects
4.**Cross-project linking** and dependency tracking
5.**Bidirectional sync** with Azure DevOps work items
**Result**: Seamless multi-project coordination with zero manual overhead!
---
**Skill Version**: 1.0.0
**Introduced**: SpecWeave v0.17.0
**Last Updated**: 2025-11-11

View File

@@ -0,0 +1,906 @@
---
name: ado-resource-validator
description: Validates Azure DevOps projects and resources exist, creates missing resources automatically. Smart enough to prompt user to select existing or create new projects. Supports multiple projects for project-per-team strategy, area paths for area-path-based strategy, and teams for team-based strategy. NEW - Per-project configuration support - AZURE_DEVOPS_AREA_PATHS_{ProjectName} and AZURE_DEVOPS_TEAMS_{ProjectName} for hierarchical organization. Activates for ado setup, ado validation, ado configuration, missing ado project, azure devops .env setup, per-project area paths, per-project teams.
allowed-tools: Read, Bash, Write, Edit
---
# Azure DevOps Resource Validator Skill
**Purpose**: Validate and auto-create Azure DevOps projects and resources, ensuring .env configuration is correct.
**Auto-Activation**: Triggers when Azure DevOps setup or validation is needed.
## What This Skill Does
This skill ensures your Azure DevOps configuration in `.env` is valid and all resources exist. It's **smart enough** to:
1. **Validate Azure DevOps projects** - Check if projects exist (multiple for project-per-team)
2. **Prompt for action** - Select existing project or create new one
3. **Validate area paths** - Check if area paths exist (for area-path-based strategy)
4. **Create missing area paths** - Auto-create area paths if missing
5. **Validate teams** - Check if teams exist (for team-based strategy)
6. **Update .env with correct values** - Ensure configuration is valid
## When This Skill Activates
**Automatically activates when**:
- You set up Azure DevOps integration for the first time
- You run `/specweave-ado:sync` and resources are missing
- Your `.env` has invalid Azure DevOps configuration
- You mention "ado setup" or "azure devops validation"
## Azure DevOps Configuration Structure
### Required .env Variables
```bash
AZURE_DEVOPS_PAT=your_token_here
AZURE_DEVOPS_ORG=yourorganization
AZURE_DEVOPS_STRATEGY=project-per-team # or area-path-based, team-based
```
### Strategy-Specific Variables
**Strategy 1: Project-per-team** (Multiple Projects)
```bash
AZURE_DEVOPS_STRATEGY=project-per-team
AZURE_DEVOPS_PROJECTS=WebApp,MobileApp,Platform
```
→ Validates that WebApp, MobileApp, and Platform projects exist
**Strategy 2: Area-path-based** (One Project, Multiple Area Paths)
```bash
AZURE_DEVOPS_STRATEGY=area-path-based
AZURE_DEVOPS_PROJECT=MainProduct
AZURE_DEVOPS_AREA_PATHS=Frontend,Backend,Mobile
```
→ Validates MainProduct project exists
→ Creates area paths if missing: MainProduct\Frontend, MainProduct\Backend, MainProduct\Mobile
**Strategy 3: Team-based** (One Project, Multiple Teams)
```bash
AZURE_DEVOPS_STRATEGY=team-based
AZURE_DEVOPS_PROJECT=MainProduct
AZURE_DEVOPS_TEAMS=Alpha Team,Beta Team,Gamma Team
```
→ Validates MainProduct project exists
→ Creates teams if missing: Alpha Team, Beta Team, Gamma Team
**NEW: Per-Project Configuration** (Advanced - Multiple Projects × Resources)
```bash
# Multiple projects with their own area paths and teams
AZURE_DEVOPS_STRATEGY=project-per-team
AZURE_DEVOPS_PROJECTS=Backend,Frontend,Mobile
# Per-project area paths (hierarchical naming)
AZURE_DEVOPS_AREA_PATHS_Backend=API,Database,Cache
AZURE_DEVOPS_AREA_PATHS_Frontend=Web,Admin,Public
AZURE_DEVOPS_AREA_PATHS_Mobile=iOS,Android,Shared
# Per-project teams (optional)
AZURE_DEVOPS_TEAMS_Backend=Alpha,Beta
AZURE_DEVOPS_TEAMS_Frontend=Gamma
```
→ Validates 3 projects exist: Backend, Frontend, Mobile
→ Creates area paths per project:
- Backend\API, Backend\Database, Backend\Cache
- Frontend\Web, Frontend\Admin, Frontend\Public
- Mobile\iOS, Mobile\Android, Mobile\Shared
→ Creates teams per project:
- Backend: Alpha, Beta
- Frontend: Gamma
**Naming Convention**: `{PROVIDER}_{RESOURCE_TYPE}_{PROJECT_NAME}`
## Validation Flow
### Step 1: Strategy Detection
**Read .env and detect strategy**:
```bash
AZURE_DEVOPS_STRATEGY=project-per-team
```
**Result**:
```
🔍 Detected strategy: Project-per-team
Projects to validate: WebApp, MobileApp, Platform
```
### Step 2: Project Validation (Project-per-team)
**Check if projects exist**:
```bash
# API calls to Azure DevOps
GET https://dev.azure.com/{org}/_apis/projects/WebApp
GET https://dev.azure.com/{org}/_apis/projects/MobileApp
GET https://dev.azure.com/{org}/_apis/projects/Platform
```
**If all projects exist**:
```
✅ All projects validated:
• WebApp (ID: abcd1234)
• MobileApp (ID: efgh5678)
• Platform (ID: ijkl9012)
```
**If some projects don't exist**:
```
⚠️ Projects not found:
✅ WebApp (exists)
❌ MobileApp (not found)
❌ Platform (not found)
What would you like to do?
1. Create missing projects
2. Select existing projects
3. Fix project names manually
4. Cancel
Your choice [1]:
```
**Option 1: Create Missing Projects**:
```
📦 Creating Azure DevOps projects...
Creating project: MobileApp...
✅ Project created: MobileApp (ID: mnop3456)
Creating project: Platform...
✅ Project created: Platform (ID: qrst7890)
✅ All projects now exist!
```
**Option 2: Select Existing Projects**:
```
Available projects in organization:
1. WebApp
2. ApiGateway
3. AuthService
4. NotificationService
5. DataPipeline
Select projects (comma-separated numbers) [2,3]:
✅ Updated .env: AZURE_DEVOPS_PROJECTS=WebApp,ApiGateway,AuthService
```
### Step 3: Area Path Validation (Area-path-based)
**Scenario**: One project with area paths
```bash
AZURE_DEVOPS_STRATEGY=area-path-based
AZURE_DEVOPS_PROJECT=MainProduct
AZURE_DEVOPS_AREA_PATHS=Frontend,Backend,Mobile,QA
```
**Validation**:
```
Checking project: MainProduct...
✅ Project "MainProduct" exists
Checking area paths...
✅ MainProduct\Frontend (exists)
✅ MainProduct\Backend (exists)
⚠️ MainProduct\Mobile (not found)
⚠️ MainProduct\QA (not found)
📦 Creating missing area paths...
✅ Created: MainProduct\Mobile
✅ Created: MainProduct\QA
✅ All area paths validated/created successfully
```
### Step 4: Team Validation (Team-based)
**Scenario**: One project with multiple teams
```bash
AZURE_DEVOPS_STRATEGY=team-based
AZURE_DEVOPS_PROJECT=MainProduct
AZURE_DEVOPS_TEAMS=Alpha Team,Beta Team,Gamma Team
```
**Validation**:
```
Checking project: MainProduct...
✅ Project "MainProduct" exists
Checking teams...
✅ Alpha Team (exists)
⚠️ Beta Team (not found)
⚠️ Gamma Team (not found)
📦 Creating missing teams...
✅ Created: Beta Team
✅ Created: Gamma Team
✅ All teams validated/created successfully
```
## Usage Examples
### Example 1: Fresh Azure DevOps Setup (Project-per-team)
**Scenario**: New setup with multiple projects for different teams
**Action**: Run `/specweave-ado:sync`
**What Happens**:
```bash
🔍 Validating Azure DevOps configuration...
Strategy: Project-per-team
Checking projects: WebApp, MobileApp, Platform...
⚠️ Projects not found:
• WebApp
• MobileApp
• Platform
What would you like to do?
1. Create new projects
2. Select existing projects
3. Cancel
Your choice [1]: 1
📦 Creating Azure DevOps projects...
Creating project: WebApp
Description: Web application frontend
Process template: Agile
✅ Created: WebApp (ID: proj-001)
Creating project: MobileApp
Description: Mobile application
Process template: Agile
✅ Created: MobileApp (ID: proj-002)
Creating project: Platform
Description: Backend platform services
Process template: Agile
✅ Created: Platform (ID: proj-003)
🎉 Azure DevOps configuration complete! All resources ready.
```
### Example 2: Migrate from Single to Multi-Project
**Scenario**: Currently using single project, want to split into multiple
**Current .env**:
```bash
AZURE_DEVOPS_PROJECT=MainProduct
```
**New .env**:
```bash
AZURE_DEVOPS_STRATEGY=project-per-team
AZURE_DEVOPS_PROJECTS=MainProduct-Frontend,MainProduct-Backend,MainProduct-Mobile
```
**What Happens**:
```bash
🔍 Detected strategy change: team-based → project-per-team
Validating new projects...
✅ MainProduct-Frontend (exists from previous split)
⚠️ MainProduct-Backend (not found)
⚠️ MainProduct-Mobile (not found)
Would you like to:
1. Create missing projects
2. Keep single project with area paths instead
3. Cancel
Your choice [1]: 1
📦 Creating projects...
✅ Created: MainProduct-Backend
✅ Created: MainProduct-Mobile
💡 Tip: You can now organize specs by project:
.specweave/docs/internal/specs/MainProduct-Frontend/
.specweave/docs/internal/specs/MainProduct-Backend/
.specweave/docs/internal/specs/MainProduct-Mobile/
```
### Example 3: Area Path Setup
**Scenario**: Large monolithic project with area-based organization
**Action**: Setup area paths for team organization
**What Happens**:
```bash
🔍 Validating Azure DevOps configuration...
Strategy: Area-path-based
Project: EnterpriseApp
Area Paths: Core, UserManagement, Billing, Reports, Analytics
Checking project: EnterpriseApp...
✅ Project exists
Checking area paths...
✅ EnterpriseApp\Core
✅ EnterpriseApp\UserManagement
⚠️ EnterpriseApp\Billing (not found)
⚠️ EnterpriseApp\Reports (not found)
⚠️ EnterpriseApp\Analytics (not found)
📦 Creating area paths...
Creating: EnterpriseApp\Billing
✅ Area path created with default team
Creating: EnterpriseApp\Reports
✅ Area path created with default team
Creating: EnterpriseApp\Analytics
✅ Area path created with default team
✅ All area paths ready!
Work items will be organized by area:
• Billing features → EnterpriseApp\Billing
• Report features → EnterpriseApp\Reports
• Analytics features → EnterpriseApp\Analytics
```
## Implementation Details
**Location**: `src/utils/external-resource-validator.ts`
**Core Classes**:
```typescript
// Main validator class
export class AzureDevOpsResourceValidator {
private pat: string;
private organization: string;
private envPath: string;
constructor(envPath: string = '.env') {
this.envPath = envPath;
const env = this.loadEnv();
this.pat = env.AZURE_DEVOPS_PAT || '';
this.organization = env.AZURE_DEVOPS_ORG || '';
}
// Main validation entry point
async validate(): Promise<AzureDevOpsValidationResult> {
const env = this.loadEnv();
const strategy = env.AZURE_DEVOPS_STRATEGY || 'project-per-team';
// Validate based on strategy
if (strategy === 'project-per-team') {
return this.validateMultipleProjects(projectNames);
} else if (strategy === 'area-path-based') {
return this.validateAreaPaths(projectName, areaPaths);
} else if (strategy === 'team-based') {
return this.validateTeams(projectName, teams);
}
}
}
// Public API function
export async function validateAzureDevOpsResources(
envPath: string = '.env'
): Promise<AzureDevOpsValidationResult> {
const validator = new AzureDevOpsResourceValidator(envPath);
return validator.validate();
}
```
**Key Implementation Features**:
1. **Async Project Creation** (ADO-specific):
```typescript
// ADO creates projects asynchronously - need to poll for completion
async createProject(name: string): Promise<AzureDevOpsProject> {
const result = await this.callAzureDevOpsApi('projects?api-version=7.0', 'POST', body);
// Wait for project to be fully created (ADO async behavior)
await this.waitForProjectCreation(result.id);
return { id: result.id, name, description };
}
// Poll until project is in 'wellFormed' state
private async waitForProjectCreation(projectId: string): Promise<void> {
const maxAttempts = 30; // 30 seconds max wait
for (let i = 0; i < maxAttempts; i++) {
const project = await this.getProject(projectId);
if (project.state === 'wellFormed') {
return; // Project is ready!
}
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1 second
}
throw new Error('Project creation timeout');
}
```
2. **Interactive Prompts** (when resources missing):
```typescript
const { action } = await inquirer.prompt([
{
type: 'select',
name: 'action',
message: `Project "${projectName}" not found. What would you like to do?`,
choices: [
{ name: 'Create new project', value: 'create' },
{ name: 'Select existing project', value: 'select' },
{ name: 'Skip this project', value: 'skip' },
{ name: 'Cancel', value: 'cancel' }
]
}
]);
```
3. **Automatic .env Updates**:
```typescript
// After creating projects, update .env
updateEnv(key: string, value: string): void {
const envContent = fs.readFileSync(this.envPath, 'utf-8');
const updated = envContent.replace(
new RegExp(`^${key}=.*$`, 'm'),
`${key}=${value}`
);
fs.writeFileSync(this.envPath, updated);
}
```
## CLI Command
**Automatic validation** (during setup):
```bash
# Runs automatically during specweave init
npx specweave init
# Also runs automatically before sync
/specweave-ado:sync 0014
```
**Manual validation**:
```bash
# Via skill activation
"Can you validate my Azure DevOps configuration?"
# Via TypeScript directly
npx tsx -e "import { validateAzureDevOpsResources } from './dist/utils/external-resource-validator.js'; await validateAzureDevOpsResources();"
# Via CLI (future command - planned)
specweave validate-ado
```
**Validation output**:
```typescript
interface AzureDevOpsValidationResult {
valid: boolean;
strategy: 'project-per-team' | 'area-path-based' | 'team-based';
projects: Array<{
name: string;
id: string;
exists: boolean;
}>;
created: string[]; // Names of newly created resources
envUpdated: boolean; // Whether .env was modified
}
// Example output:
{
valid: true,
strategy: 'project-per-team',
projects: [
{ name: 'WebApp', id: 'proj-001', exists: true },
{ name: 'MobileApp', id: 'proj-002', exists: true, created: true },
{ name: 'Platform', id: 'proj-003', exists: true, created: true }
],
created: ['MobileApp', 'Platform'],
envUpdated: false
}
```
## Smart Project Detection
### Auto-detect Based on Work Item Patterns
The skill can intelligently suggest project organization based on your existing work items:
```typescript
// Analyze existing work items
const workItems = await analyzeWorkItems(org, project);
// Detect patterns
const patterns = {
byArea: workItems.groupBy('areaPath'), // Area-based organization
byTeam: workItems.groupBy('assignedTeam'), // Team-based organization
byType: workItems.groupBy('workItemType') // Type-based organization
};
// Suggest strategy
if (patterns.byArea.length > 3) {
console.log('💡 Detected area-based organization');
console.log(' Suggested strategy: area-path-based');
} else if (patterns.byTeam.length > 2) {
console.log('💡 Detected team-based organization');
console.log(' Suggested strategy: team-based or project-per-team');
}
```
## Project Creation API
**Azure DevOps REST API** (v7.0):
### Create Project
```bash
POST https://dev.azure.com/{org}/_apis/projects?api-version=7.0
Content-Type: application/json
Authorization: Basic {base64(":PAT")}
{
"name": "MobileApp",
"description": "Mobile application project",
"capabilities": {
"versioncontrol": {
"sourceControlType": "Git"
},
"processTemplate": {
"templateTypeId": "adcc42ab-9882-485e-a3ed-7678f01f66bc" # Agile
}
}
}
Response:
{
"id": "proj-002",
"name": "MobileApp",
"state": "wellFormed"
}
```
### Create Area Path
```bash
POST https://dev.azure.com/{org}/{project}/_apis/wit/classificationnodes/areas?api-version=7.0
Content-Type: application/json
{
"name": "Frontend",
"attributes": {
"startDate": null,
"finishDate": null
}
}
Response:
{
"id": 123,
"name": "Frontend",
"path": "\\MainProduct\\Area\\Frontend"
}
```
### Create Team
```bash
POST https://dev.azure.com/{org}/_apis/projects/{projectId}/teams?api-version=7.0
Content-Type: application/json
{
"name": "Alpha Team",
"description": "Alpha development team"
}
Response:
{
"id": "team-001",
"name": "Alpha Team",
"projectName": "MainProduct"
}
```
## Configuration Examples
### Example 1: Microservices Architecture (Project-per-team)
**Before** (`.env`):
```bash
AZURE_DEVOPS_ORG=mycompany
AZURE_DEVOPS_PAT=xxx
```
**After validation**:
```bash
AZURE_DEVOPS_ORG=mycompany
AZURE_DEVOPS_PAT=xxx
AZURE_DEVOPS_STRATEGY=project-per-team
AZURE_DEVOPS_PROJECTS=AuthService,UserService,PaymentService,NotificationService
```
**Folder structure created**:
```
.specweave/docs/internal/specs/
├── AuthService/
│ └── spec-001-oauth-implementation.md
├── UserService/
│ └── spec-001-user-management.md
├── PaymentService/
│ └── spec-001-stripe-integration.md
└── NotificationService/
└── spec-001-email-notifications.md
```
### Example 2: Monolithic Application (Area-path-based)
**Before** (`.env`):
```bash
AZURE_DEVOPS_PROJECT=ERP
```
**After validation**:
```bash
AZURE_DEVOPS_ORG=enterprise
AZURE_DEVOPS_PAT=xxx
AZURE_DEVOPS_STRATEGY=area-path-based
AZURE_DEVOPS_PROJECT=ERP
AZURE_DEVOPS_AREA_PATHS=Finance,HR,Inventory,Sales,Reports
```
**Work item organization**:
```
ERP
├── Finance/ → Finance module features
├── HR/ → HR module features
├── Inventory/ → Inventory management
├── Sales/ → Sales module features
└── Reports/ → Reporting features
```
### Example 3: Platform Teams (Team-based)
**Before** (`.env`):
```bash
AZURE_DEVOPS_PROJECT=Platform
```
**After validation**:
```bash
AZURE_DEVOPS_ORG=techcorp
AZURE_DEVOPS_PAT=xxx
AZURE_DEVOPS_STRATEGY=team-based
AZURE_DEVOPS_PROJECT=Platform
AZURE_DEVOPS_TEAMS=Infrastructure,Security,Data,DevOps
```
**Team assignments**:
- Infrastructure Team → Cloud resources, networking
- Security Team → Auth, compliance, auditing
- Data Team → Databases, analytics, ML
- DevOps Team → CI/CD, monitoring, tooling
## Error Handling
### Error 1: Invalid Credentials
**Symptom**: API calls fail with 401 Unauthorized
**Solution**:
```
❌ Azure DevOps API authentication failed
Please check:
1. AZURE_DEVOPS_PAT is correct
2. Token has not expired
3. AZURE_DEVOPS_ORG is correct
Generate new token at:
https://dev.azure.com/{org}/_usersSettings/tokens
```
### Error 2: Insufficient Permissions
**Symptom**: Cannot create projects (403 Forbidden)
**Solution**:
```
❌ Insufficient permissions to create projects
You need:
- Project Collection Administrator role (for creating projects)
- Project Administrator role (for area paths and teams)
Contact your Azure DevOps administrator to request permissions.
```
### Error 3: Project Name Conflicts
**Symptom**: Project creation fails (name exists)
**Solution**:
```
❌ Project name "WebApp" already exists
Options:
1. Use a different project name
2. Select the existing project
3. Add a suffix (e.g., WebApp-v2)
Your choice [2]:
```
### Error 4: Organization Limits
**Symptom**: Cannot create more projects
**Solution**:
```
❌ Organization project limit reached (250 projects)
Consider:
1. Using area-path-based strategy (one project)
2. Archiving old projects
3. Upgrading organization plan
Contact Azure DevOps support for limit increases.
```
## Integration with SpecWeave Workflow
### Automatic Validation
When using `/specweave-ado:sync`, validation runs automatically:
```bash
/specweave-ado:sync 0014
# Internally calls:
1. validateAzureDevOpsResources()
2. Fix missing projects/area paths/teams
3. Create folder structure for specs
4. Proceed with sync
```
### Manual Validation
Run validation independently:
```bash
# Via skill
"Validate my Azure DevOps configuration"
# Via TypeScript
npx tsx src/utils/external-resource-validator.ts --provider=ado
# Via CLI (future)
specweave validate-ado
```
## Best Practices
✅ **Choose the right strategy**:
- **Project-per-team**: Best for autonomous teams, microservices
- **Area-path-based**: Best for monolithic apps, shared codebase
- **Team-based**: Best for small organizations, simple structure
✅ **Use descriptive names**:
```bash
# Good
AZURE_DEVOPS_PROJECTS=UserManagement,PaymentProcessing,NotificationEngine
# Bad
AZURE_DEVOPS_PROJECTS=Proj1,Proj2,Proj3
```
✅ **Document project mapping** (in README):
```markdown
## Azure DevOps Projects
- UserManagement: User authentication and profile management
- PaymentProcessing: Payment gateway integrations
- NotificationEngine: Email, SMS, and push notifications
```
✅ **Keep .env in version control** (gitignored tokens):
```bash
# Commit project structure
AZURE_DEVOPS_STRATEGY=project-per-team
AZURE_DEVOPS_PROJECTS=WebApp,MobileApp,Platform
# Don't commit sensitive data
AZURE_DEVOPS_PAT=<redacted>
```
## Folder Organization
Based on strategy, the skill creates appropriate folder structure:
### Project-per-team Structure
```
.specweave/docs/internal/specs/
├── WebApp/
│ ├── spec-001-user-interface.md
│ └── spec-002-responsive-design.md
├── MobileApp/
│ ├── spec-001-ios-features.md
│ └── spec-002-android-features.md
└── Platform/
├── spec-001-api-design.md
└── spec-002-database-schema.md
```
### Area-path-based Structure
```
.specweave/docs/internal/specs/MainProduct/
├── Frontend/
│ └── spec-001-ui-components.md
├── Backend/
│ └── spec-001-api-endpoints.md
└── Mobile/
└── spec-001-mobile-sync.md
```
### Team-based Structure
```
.specweave/docs/internal/specs/MainProduct/
├── AlphaTeam/
│ └── spec-001-feature-a.md
├── BetaTeam/
│ └── spec-001-feature-b.md
└── GammaTeam/
└── spec-001-feature-c.md
```
## Key Differences from JIRA
**Azure DevOps vs JIRA Resource Creation**:
| Aspect | Azure DevOps | JIRA |
|--------|-------------|------|
| **Project Creation** | Asynchronous (polling required) | Synchronous (immediate) |
| **Creation Time** | 5-30 seconds | <1 second |
| **Status Tracking** | Poll `state` field ('wellFormed') | No polling needed |
| **API Complexity** | Higher (async handling) | Lower (sync operations) |
| **Board Creation** | Auto-created with project | Requires separate API call |
| **Process Templates** | Required (Agile, Scrum, CMMI) | Not applicable |
**Why Async Matters**:
When you create an ADO project, the API returns immediately with `state: 'new'`, but the project isn't usable yet. The validator polls every 1 second (max 30 attempts) until `state: 'wellFormed'`:
```typescript
// Create project (returns immediately)
const project = await createProject('MobileApp'); // state: 'new'
// Poll until ready
await waitForProjectCreation(project.id); // Polls until state: 'wellFormed'
// Now safe to use!
console.log('✅ Project ready for work items');
```
**Impact on UX**:
- JIRA: "✅ Project created" (instant)
- ADO: "📦 Creating project... ⏳ Waiting for Azure DevOps to complete setup... ✅ Project ready!" (5-30s)
## Summary
This skill ensures your Azure DevOps configuration is **always valid** by:
1.**Validating projects** - Check if projects exist, prompt to select or create
2.**Supporting multiple strategies** - Project-per-team, area-path-based, team-based
3.**Auto-creating resources** - Projects, area paths, teams (with async handling)
4.**Organizing specs** - Create folder structure based on projects
5.**Clear error messages** - Actionable guidance for all failures
6.**Handles ADO async behavior** - Polls for project creation completion
**Result**: Zero manual Azure DevOps setup - system handles everything, including ADO's async project creation!
---
**Skill Version**: 1.1.0
**Introduced**: SpecWeave v0.17.0
**Last Updated**: 2025-11-11
**Key Changes v1.1.0**: Added implementation details, async project creation handling, JIRA comparison

3
skills/ado-sync/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
test-results/
*.log
.DS_Store

414
skills/ado-sync/README.md Normal file
View File

@@ -0,0 +1,414 @@
# ado-sync Skill
**Status**: To be developed
**Priority**: Medium
## Purpose
Bidirectional sync between SpecWeave increments and Azure DevOps (ADO)
**Note**: This skill handles ONLY Azure DevOps. For JIRA, see `jira-sync` skill.
## Features
### Export to ADO
- Create ADO work items from SpecWeave increments
- Map spec.md user stories → ADO User Stories
- Map tasks.md tasks → ADO Tasks
- Create Features if specified in spec.md
- Set Area Paths, Iterations, priorities
### Import from ADO
- Sync ADO updates back to SpecWeave
- Import existing ADO work items as increments
- Update status, assignees, comments
### Bidirectional Sync
- Keep status in sync (New, Active, Resolved, Closed)
- Sync descriptions and acceptance criteria
- Sync comments and attachments
- Handle conflicts intelligently
## ADO-Specific Concepts
### Mapping: SpecWeave → Azure DevOps
| SpecWeave | Azure DevOps |
|-----------|--------------|
| spec.md (with Feature) | Feature |
| spec.md User Story | User Story |
| tasks.md Task | Task |
| Acceptance Tests (spec.md) | Acceptance Criteria (User Story) |
| Acceptance Criteria (tasks.md) | Task checklist |
| Status: planned | New |
| Status: in-progress | Active |
| Status: completed | Closed |
### ADO Structure Example
**spec.md with ADO structure**:
```markdown
---
increment: 002-payment-processing
status: planned
structure: ado
ado_feature: 456
---
## Feature: Payment Processing
**ADO**: 456
**Area Path**: Platform/Payments
**Iteration**: Sprint 12
### User Story: Subscribe to Plan
**ADO**: 789
**Priority**: 1
**Area Path**: Platform/Payments
**Iteration**: Sprint 12
**Description**:
As a user, I want to subscribe to a monthly plan...
**Acceptance Criteria**:
- User can select plan
- Payment processed
- Subscription activated
```
**tasks.md creates Tasks**:
```markdown
## Tasks for ADO-789 (Subscribe to Plan)
### Task T001: Create StripeService
**ADO**: 790 (Task under User Story 789)
**Agent**: nodejs-backend
**Area Path**: Platform/Payments/Backend
**Iteration**: Sprint 12
**Description**: Create Stripe service class...
**Acceptance Criteria**:
- [ ] StripeService class exists
- [ ] Unit tests passing
```
## Authentication
**Personal Access Token (PAT)**:
**OAuth 2.0** (for apps):
```yaml
ado_sync:
url: "https://dev.azure.com/your-org"
project: "YourProject"
auth_type: "oauth"
client_id: "${ADO_CLIENT_ID}"
client_secret: "${ADO_CLIENT_SECRET}"
```
## Configuration
## Workflow
### Export Workflow (SpecWeave → ADO)
```
User: Creates increment in SpecWeave
.specweave/increments/0002-payment/
spec.md (with structure: ado)
tasks.md
↓ ado-sync detects new increment
Creates in ADO:
Feature: 456 "Payment Processing"
Area Path: Platform/Payments
Iteration: Sprint 12
User Story: 789 "Subscribe to Plan"
Area Path: Platform/Payments
Iteration: Sprint 12
Task: 790 "Create StripeService"
Area Path: Platform/Payments/Backend
Iteration: Sprint 12
Task: 791 "Create API endpoints"
Links created:
spec.md → ADO-789
tasks.md T001 → ADO-790
tasks.md T002 → ADO-791
```
### Import Workflow (ADO → SpecWeave)
```
User: Updates ADO work item status to "Active"
↓ ADO service hook triggers
ado-sync:
Detects change to ADO-789
Finds linked increment: 002-payment
Updates: .specweave/increments/0002-payment/spec.md
status: planned → in-progress
```
### Bidirectional Sync
```
User: Checks off task in tasks.md
- [x] T001: Create StripeService
↓ ado-sync detects change
Updates ADO:
Work Item 790 status → Closed
User: Changes ADO-789 to "Closed" in Azure DevOps
↓ ADO service hook triggers
ado-sync updates SpecWeave:
.specweave/increments/0002-payment/spec.md
status: in-progress → completed
```
## API Integration
### Azure DevOps REST API Endpoints Used
```typescript
// Create Feature
POST https://dev.azure.com/{org}/{project}/_apis/wit/workitems/$Feature?api-version=7.0
Content-Type: application/json-patch+json
[
{
"op": "add",
"path": "/fields/System.Title",
"value": "Payment Processing"
},
{
"op": "add",
"path": "/fields/System.AreaPath",
"value": "Platform/Payments"
},
{
"op": "add",
"path": "/fields/System.IterationPath",
"value": "Sprint 12"
}
]
// Create User Story (linked to Feature)
POST https://dev.azure.com/{org}/{project}/_apis/wit/workitems/$User%20Story?api-version=7.0
[
{
"op": "add",
"path": "/fields/System.Title",
"value": "Subscribe to Plan"
},
{
"op": "add",
"path": "/relations/-",
"value": {
"rel": "System.LinkTypes.Hierarchy-Reverse",
"url": "https://dev.azure.com/{org}/_apis/wit/workItems/456"
}
}
]
// Create Task (linked to User Story)
POST https://dev.azure.com/{org}/{project}/_apis/wit/workitems/$Task?api-version=7.0
[
{
"op": "add",
"path": "/fields/System.Title",
"value": "Create StripeService"
},
{
"op": "add",
"path": "/relations/-",
"value": {
"rel": "System.LinkTypes.Hierarchy-Reverse",
"url": "https://dev.azure.com/{org}/_apis/wit/workItems/789"
}
}
]
// Update status
PATCH https://dev.azure.com/{org}/{project}/_apis/wit/workitems/{id}?api-version=7.0
[
{
"op": "add",
"path": "/fields/System.State",
"value": "Active"
}
]
```
## Service Hooks (Webhooks)
### Setup ADO Service Hook
1. Go to Project Settings → Service hooks
2. Create new service hook:
- Service: Web Hooks
- Trigger: Work item updated
- URL: `https://your-app.com/api/webhooks/ado`
- Filters: Area path = Platform/Payments (optional)
### Service Hook Handler
```typescript
// Receives ADO service hook
POST /api/webhooks/ado
// ado-sync processes:
1. Verify request (optional: check secret)
2. Extract work item data
3. Find linked SpecWeave increment
4. Update spec.md or tasks.md
5. Commit changes (optional)
```
## ADO-Specific Features
### Area Paths
**Organize work by area**:
```markdown
# spec.md
---
ado_area_path: "Platform/Payments"
---
```
Maps to ADO Area Path for organization.
### Iterations/Sprints
**Assign to sprint**:
```markdown
# spec.md
---
ado_iteration: "Sprint 12"
---
```
Or auto-detect current sprint:
```yaml
# config.yaml
ado_sync:
auto_detect_iteration: true
```
### Work Item Types
**ADO supports custom work item types**:
- Epic → Feature → User Story → Task (default)
- Custom types supported via config
```yaml
ado_sync:
work_item_types:
epic: "Epic"
feature: "Feature"
story: "User Story"
task: "Task"
```
### Custom Fields
**Sync custom fields**:
```yaml
ado_sync:
custom_fields:
- name: "Custom.Priority"
map_from: "priority" # From spec.md frontmatter
- name: "Custom.Estimate"
map_from: "estimate"
```
## Conflict Resolution
**Scenario**: Both SpecWeave and ADO updated simultaneously
**Strategy**:
1. **Timestamp-based**: Latest change wins
2. **User prompt**: Ask user which to keep (via Ping.aiff)
3. **Merge**: Combine changes if possible
**Example**:
```
SpecWeave: status → in-progress (10:00 AM)
ADO: status → closed (10:05 AM)
ado-sync:
Latest is ADO (10:05 AM)
Update SpecWeave → completed
🔔 Ping.aiff: "ADO conflict resolved - ADO version used"
```
## Error Handling
**Common errors**:
- ADO API rate limits → Retry with exponential backoff
- Authentication failed → Notify user, check PAT
- Work item not found → Create if export, skip if import
- Network errors → Queue for retry
- Area Path invalid → Use default or notify user
## Testing
**Test scenarios**:
1. Create increment → Creates ADO work items
2. Update ADO → Updates SpecWeave
3. Update SpecWeave → Updates ADO
4. Area Path mapping
5. Iteration mapping
6. Conflict resolution
7. Service hook handling
8. Custom fields sync
## Integration with Other Skills
- **task-builder**: Reads ADO structure from spec.md
- **increment-planner**: Can specify structure: ado
## Comparison: JIRA vs ADO
| Feature | JIRA (jira-sync) | Azure DevOps (ado-sync) |
|---------|------------------|-------------------------|
| **Epic level** | Epic | Feature |
| **Story level** | Story | User Story |
| **Task level** | Sub-task | Task |
| **Organization** | Components, Labels | Area Paths |
| **Sprints** | Sprints (board-based) | Iterations (path-based) |
| **API** | JIRA REST API v3 | Azure DevOps REST API v7.0 |
| **Auth** | API Token | PAT or OAuth |
| **Webhooks** | JIRA Webhooks | Service Hooks |
| **Custom fields** | Custom fields | Work item fields |
## Future Enhancements
- Support for ADO Boards/Backlogs
- Sprint burndown sync
- Test case sync (ADO Test Plans)
- Build/release pipeline integration
- Wiki sync
- Git repo integration (link commits to work items)
---
**To implement**: See task in .specweave/increments/
**See also**: `jira-sync` skill for JIRA integration

406
skills/ado-sync/SKILL.md Normal file
View File

@@ -0,0 +1,406 @@
---
name: ado-sync
description: Bidirectional synchronization between SpecWeave increments and Azure DevOps work items (two-way sync by default). Activates ONLY when user asks questions about Azure DevOps integration or needs help configuring ADO sync. Does NOT activate for slash commands. For syncing, use /specweave-ado:sync command instead.
---
# Azure DevOps Sync Skill
**Purpose**: Seamlessly sync SpecWeave increments with Azure DevOps work items for unified project tracking.
**Default Behavior**: **Bidirectional (two-way) sync** - Changes in either system are automatically synchronized
**⚠️ IMPORTANT**: This skill provides HELP and GUIDANCE about Azure DevOps sync. For actual syncing, users should use the `/specweave-ado:sync` command directly. This skill should NOT auto-activate when the command is being invoked.
**Capabilities**:
- Bidirectional sync: SpecWeave ↔ ADO (default)
- Create ADO work items from increments
- Sync task progress → ADO comments
- Update increment status ← ADO state changes
- Pull ADO comments and field updates → SpecWeave
- Close work items when increments complete
- Support for Epics, Features, User Stories
---
## When This Skill Activates
**Do activate when**:
- User asks: "How do I set up Azure DevOps sync?"
- User asks: "What ADO credentials do I need?"
- User asks: "How does ADO integration work?"
- User needs help configuring Azure DevOps integration
**Do NOT activate when**:
- User invokes `/specweave-ado:sync` command (command handles it)
- Command is already running (avoid duplicate invocation)
- Task completion hook is syncing (automatic process)
- "Close ADO work item when done"
---
## Prerequisites
### 1. ADO Plugin Installed
```bash
# Check if installed
/plugin list --installed | grep specweave-ado
# Install if needed
/plugin install specweave-ado
```
### 2. Azure DevOps Personal Access Token (PAT)
**Create PAT**:
1. Go to https://dev.azure.com/{organization}/_usersSettings/tokens
2. Click "New Token"
3. Name: "SpecWeave Sync"
4. Scopes: Work Items (Read & Write), Comments (Read & Write)
5. Copy token → Set environment variable
**Set Token**:
```bash
export AZURE_DEVOPS_PAT="your-token-here"
```
### 3. ADO Configuration
Add to `.specweave/config.json`:
```json
{
"externalPM": {
"tool": "ado",
"enabled": true,
"config": {
"organization": "myorg",
"project": "MyProject",
"workItemType": "Epic",
"areaPath": "MyProject\\Team A",
"syncOnTaskComplete": true
}
}
}
```
---
## Commands Available
### `/specweave-ado:create-workitem <increment-id>`
**Purpose**: Create ADO work item from increment
**Example**:
```bash
/specweave-ado:create-workitem 0005
```
**Result**:
- Creates Epic/Feature/User Story in ADO
- Links work item to increment (metadata)
- Adds initial comment with spec summary
- Sets tags: `specweave`, `increment-0005`
---
### `/specweave-ado:sync <increment-id>`
**Purpose**: Sync increment progress with ADO work item
**Example**:
```bash
/specweave-ado:sync 0005
```
**Result**:
- Calculates task completion (%)
- Updates work item description
- Adds comment with progress update
- Updates state (New → Active → Resolved)
---
### `/specweave-ado:close-workitem <increment-id>`
**Purpose**: Close ADO work item when increment complete
**Example**:
```bash
/specweave-ado:close-workitem 0005
```
**Result**:
- Updates work item state → Closed
- Adds completion comment with summary
- Marks work item as resolved
---
### `/specweave-ado:status <increment-id>`
**Purpose**: Check ADO sync status for increment
**Example**:
```bash
/specweave-ado:status 0005
```
**Result**:
```
ADO Sync Status
===============
Increment: 0005-payment-integration
Work Item: #12345
URL: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345
State: Active
Completion: 60% (6/10 tasks)
Last Synced: 2025-11-04 10:30:00
Sync Enabled: ✅
```
---
## Automatic Sync
### When Task Completes
**Trigger**: Post-task-completion hook fires
**Flow**:
1. User marks task complete: `[x] T-005: Add payment tests`
2. Hook detects ADO sync enabled
3. Calculate new completion %
4. Update ADO work item comment:
```markdown
## Progress Update
**Increment**: 0005-payment-integration
**Status**: 60% complete (6/10 tasks)
### Recently Completed
- [x] T-005: Add payment tests
### Remaining
- [ ] T-007: Add refund functionality
- [ ] T-008: Implement subscriptions
- [ ] T-009: Add analytics
- [ ] T-010: Security audit
---
🤖 Auto-updated by SpecWeave
```
### When Increment Completes
**Trigger**: `/specweave:done` command
**Flow**:
1. User runs `/specweave:done 0005`
2. Validate all tasks complete
3. Close ADO work item automatically
4. Add completion comment with summary
---
## Work Item Types
### Epic (Recommended)
**Use When**: Large feature spanning multiple sprints
**Mapping**:
- SpecWeave increment → ADO Epic
- Tasks → Epic description (checklist)
- Progress → Epic comments
---
### Feature
**Use When**: Medium-sized feature within a sprint
**Mapping**:
- SpecWeave increment → ADO Feature
- Tasks → Feature description (checklist)
- Progress → Feature comments
---
### User Story
**Use When**: Small, single-sprint work
**Mapping**:
- SpecWeave increment → ADO User Story
- Tasks → User Story description (checklist)
- Progress → User Story comments
---
## Bidirectional Sync (Optional)
**Enable**: Set `bidirectional: true` in config
**Flow**: ADO → SpecWeave
1. User updates work item state in ADO (Active → Resolved)
2. SpecWeave detects change (polling or webhook)
3. Updates increment status locally
4. Notifies user: "Work item #12345 resolved → Increment 0005 marked complete"
**Note**: Bidirectional sync requires webhook or polling setup
---
## Configuration Options
**`.specweave/config.json`**:
```json
{
"externalPM": {
"tool": "ado",
"enabled": true,
"config": {
"organization": "myorg",
"project": "MyProject",
"personalAccessToken": "${AZURE_DEVOPS_PAT}",
"workItemType": "Epic",
"areaPath": "MyProject\\Team A",
"iterationPath": "MyProject\\Sprint 1",
"syncOnTaskComplete": true,
"syncOnIncrementComplete": true,
"createWorkItemsAutomatically": true,
"bidirectional": false,
"tags": ["specweave", "increment"],
"customFields": {
"incrementId": "Custom.IncrementId"
}
}
}
}
```
---
## Troubleshooting
### Error: "Personal Access Token invalid"
**Solution**:
1. Verify token is set: `echo $AZURE_DEVOPS_PAT`
2. Check token scopes: Work Items (Read & Write)
3. Ensure token not expired
4. Regenerate token if needed
---
### Error: "Work item not found"
**Solution**:
1. Check work item ID is correct
2. Verify you have access to the project
3. Ensure work item not deleted
---
### Error: "Organization or project not found"
**Solution**:
1. Verify organization name: https://dev.azure.com/{organization}
2. Check project name (case-sensitive)
3. Ensure you have access to the project
---
## API Rate Limits
**Azure DevOps**:
- Rate limit: 200 requests per minute per PAT
- Burst limit: 5000 requests per hour
- Recommendation: Enable rate limiting in config
**Config**:
```json
{
"externalPM": {
"config": {
"rateLimiting": {
"enabled": true,
"maxRequestsPerMinute": 150
}
}
}
}
```
---
## Security Best Practices
### DO:
- ✅ Store PAT in environment variable (`AZURE_DEVOPS_PAT`)
- ✅ Use `.env` file (gitignored)
- ✅ Set minimum required scopes
- ✅ Rotate PAT every 90 days
### DON'T:
- ❌ Commit PAT to git
- ❌ Share PAT via Slack/email
- ❌ Use PAT with excessive permissions
- ❌ Log PAT to console/files
---
## Related Commands
- `/specweave:inc` - Create increment (auto-creates ADO work item if enabled)
- `/specweave:do` - Execute tasks (auto-syncs progress to ADO)
- `/specweave:done` - Complete increment (auto-closes ADO work item)
- `/specweave:status` - Show increment status (includes ADO sync status)
---
## Examples
### Example 1: Create Increment with ADO Sync
```bash
# User
"Create increment for payment integration"
# SpecWeave (if ADO enabled)
1. PM agent generates spec.md
2. Auto-create ADO Epic #12345
3. Link Epic to increment metadata
4. Display: "Created increment 0005 → ADO Epic #12345"
```
### Example 2: Manual Sync
```bash
# User completed 3 tasks manually
# Now sync to ADO
/specweave-ado:sync 0005
# Result: ADO Epic #12345 updated with 30% progress
```
### Example 3: Check Sync Status
```bash
/specweave-ado:status 0005
# Output:
# Work Item: #12345
# URL: https://dev.azure.com/myorg/MyProject/_workitems/edit/12345
# State: Active
# Completion: 60%
# Last Synced: 5 minutes ago
```
---
**Status**: Ready to use
**Version**: 0.1.0
**Plugin**: specweave-ado

View File

@@ -0,0 +1,501 @@
---
name: specweave-ado-mapper
description: Expert in bidirectional conversion between SpecWeave increments and Azure DevOps (ADO) Epics/Features/User Stories/Tasks. Handles export (increment → ADO), import (ADO → increment), and bidirectional sync with conflict resolution. Activates for ADO sync, Azure DevOps sync, work item creation, import from ADO.
tools: Read, Write, Edit, Bash
model: claude-sonnet-4-5-20250929
---
# Specweave Ado Mapper Skill
You are an expert in mapping SpecWeave concepts to Azure DevOps (ADO) and vice versa with precision and traceability.
## Core Responsibilities
1. **Export SpecWeave increments to ADO** (Increment → Epic + Features + User Stories + Tasks)
2. **Import ADO Epics as SpecWeave increments** (Epic → Increment structure)
3. **Bidirectional sync** with conflict detection and resolution
4. **Maintain traceability** (store IDs, URLs, timestamps)
5. **Validate mapping accuracy** using test cases
6. **Handle edge cases** (missing fields, custom workflows, API errors)
---
## Azure DevOps Work Item Hierarchy
ADO uses a **4-level hierarchy** (one more level than JIRA):
```
Epic
└── Feature
└── User Story
└── Task
```
**Key Difference from JIRA**: ADO has **Feature** between Epic and User Story.
---
## Concept Mappings
### SpecWeave → ADO
| SpecWeave Concept | ADO Concept | Mapping Rules |
|-------------------|-------------|---------------|
| **Increment** | Epic | Title: `[Increment ###] [Title]` |
| **User Story** (from spec.md) | Feature (if large) OR User Story | Decision based on size |
| **Task** (from tasks.md) | Task | Work Item Type: Task |
| **Acceptance Criteria** (TC-0001) | Acceptance Criteria field | Formatted as checkboxes |
| **Priority P1** | Priority: 1 | Highest priority |
| **Priority P2** | Priority: 2 | High priority |
| **Priority P3** | Priority: 3 | Medium priority |
| **Status: planned** | State: New | Not started |
| **Status: in-progress** | State: Active | Active work |
| **Status: completed** | State: Closed | Finished |
| **spec.md** | Epic Description | Summary + link to spec (if repo) |
### ADO → SpecWeave
| ADO Concept | SpecWeave Concept | Import Rules |
|-------------|-------------------|--------------|
| **Epic** | Increment | Auto-number next available |
| **Feature** | User Story (large) | Extract title, description |
| **User Story** | User Story (small) | Extract acceptance criteria |
| **Task** | Task | Map to tasks.md checklist |
| **Acceptance Criteria** | TC-0001 format | Parse as test cases |
| **Priority 1** | Priority P1 | Critical |
| **Priority 2** | Priority P2 | Important |
| **Priority 3/4** | Priority P3 | Nice to have |
| **State: New** | Status: planned | Not started |
| **State: Active** | Status: in-progress | Active |
| **State: Closed** | Status: completed | Finished |
| **Area Path** | Context metadata | Store in frontmatter |
| **Iteration** | Context metadata | Store in frontmatter |
---
## Conversion Workflows
### 1. Export: Increment → ADO Epic
**Input**: `.specweave/increments/0001-feature-name/`
**Prerequisites**:
- Increment folder exists
- `spec.md` exists with valid frontmatter
- `tasks.md` exists
- ADO connection configured (PAT, organization, project)
**Process**:
1. **Read increment files**:
```bash
# Read spec.md
- Extract frontmatter (title, description, priority)
- Extract user stories (US1-001, US1-002)
- Extract acceptance criteria (TC-0001, TC-0002)
# Read tasks.md
- Extract task checklist
- Group tasks by user story
```
2. **Create ADO Epic**:
```
Title: [Increment 0001] Feature Name
Description:
{spec.md summary}
Specification: {link to spec.md if Azure Repos}
Work Item Type: Epic
Priority: 1 (P1) / 2 (P2) / 3 (P3)
State: New
Area Path: {project_area}
Iteration: {current_iteration}
Tags: specweave, increment-0001
Custom Fields:
- SpecWeave.IncrementID: 0001-feature-name
- SpecWeave.SpecURL: https://dev.azure.com/.../spec.md
```
3. **Create ADO Features OR User Stories**:
**Decision Logic**:
- If user story has >5 acceptance criteria → Create as Feature (large work)
- If user story has ≤5 acceptance criteria → Create as User Story (small work)
**Feature (large user story)**:
```
Title: {User Story title}
Description:
**As a** {role}
**I want to** {goal}
**So that** {benefit}
Acceptance Criteria:
- TC-0001: {criteria}
- TC-0002: {criteria}
...
Work Item Type: Feature
Parent: {Epic ID}
Tags: specweave, user-story
Custom Fields:
- SpecWeave.UserStoryID: US1-001
- SpecWeave.TestCaseIDs: TC-0001, TC-0002
```
**User Story (small user story)**:
```
(Same structure as Feature, but Work Item Type: User Story)
```
4. **Create ADO Tasks**:
```
Title: {Task description}
Work Item Type: Task
Parent: {Feature or User Story ID}
State: New
Tags: specweave, task
```
5. **Update increment frontmatter**:
```yaml
ado:
epic_id: "12345"
epic_url: "https://dev.azure.com/{org}/{project}/_workitems/edit/12345"
features:
- id: "12346"
user_story_id: "US1-001"
- id: "12347"
user_story_id: "US1-002"
area_path: "MyProject\\TeamA"
iteration: "Sprint 24"
last_sync: "2025-10-26T14:00:00Z"
sync_direction: "export"
```
**Output**:
```
✅ Exported to Azure DevOps!
Epic: 12345
URL: https://dev.azure.com/{org}/{project}/_workitems/edit/12345
Features: 3 created
User Stories: 2 created
Tasks: 12 created
Area Path: MyProject\TeamA
Iteration: Sprint 24
Last Sync: 2025-10-26T14:00:00Z
```
---
### 2. Import: ADO Epic → Increment
**Input**: ADO Epic ID (e.g., `12345`)
**Prerequisites**:
- Valid ADO Epic ID
- Epic exists and is accessible
- ADO connection configured
**Process**:
1. **Fetch Epic details** (via ADO REST API):
```
- Epic title, description, tags
- Epic custom fields (if SpecWeave ID exists)
- Priority, state, area path, iteration
```
2. **Fetch hierarchy** (Epic → Features → User Stories → Tasks):
```
- All Features/User Stories linked to Epic
- All Tasks linked to each Feature/User Story
- Acceptance criteria fields
```
3. **Auto-number next increment**:
```bash
# Scan .specweave/increments/ for highest number
ls .specweave/increments/ | grep -E '^[0-9]{4}' | sort -n | tail -1
# Increment by 1 → 0003
```
4. **Create increment folder**:
```
.specweave/increments/0003-imported-feature/
```
5. **Generate spec.md**:
```yaml
---
increment_id: "0003"
title: "{Epic title}"
status: "{mapped from ADO state}"
priority: "{mapped from ADO priority}"
created_at: "{Epic created date}"
ado:
epic_id: "12345"
epic_url: "https://dev.azure.com/{org}/{project}/_workitems/edit/12345"
features:
- id: "12346"
user_story_id: "US3-001"
area_path: "{area path}"
iteration: "{iteration}"
imported_at: "2025-10-26T14:00:00Z"
sync_direction: "import"
---
# {Epic title}
{Epic description}
## Context
- **Area Path**: {area_path}
- **Iteration**: {iteration}
- **ADO Epic**: [12345](https://dev.azure.com/.../12345)
## User Stories
### US3-001: {Feature/User Story title}
**As a** {extracted from description}
**I want to** {extracted}
**So that** {extracted}
**Acceptance Criteria**:
- [ ] TC-0001: {parsed from Acceptance Criteria field}
- [ ] TC-0002: {parsed}
**ADO Feature**: [12346](https://dev.azure.com/.../12346)
```
6. **Generate tasks.md**:
```markdown
# Tasks: {Increment title}
## User Story: US3-001
- [ ] {Task 1 title} (ADO: 12350)
- [ ] {Task 2 title} (ADO: 12351)
```
7. **Generate context-manifest.yaml** (default)
8. **Update ADO Epic** (add custom field):
```
Custom Field: SpecWeave.IncrementID = 0003-imported-feature
```
**Output**:
```
✅ Imported from Azure DevOps!
Increment: 0003-imported-feature
Location: .specweave/increments/0003-imported-feature/
User Stories: 5 imported
Tasks: 12 imported
ADO Epic: 12345
Area Path: MyProject\TeamA
Iteration: Sprint 24
```
---
### 3. Bidirectional Sync
**Process**: Similar to JIRA sync, with ADO-specific fields:
- Sync Area Path changes
- Sync Iteration changes
- Handle ADO-specific states (New, Active, Resolved, Closed)
- Sync Acceptance Criteria field
---
## ADO-Specific Concepts
### Area Path
**Definition**: Organizational hierarchy (e.g., `MyProject\TeamA\Backend`)
**Mapping**:
- Store in increment frontmatter: `ado.area_path`
- Not a direct SpecWeave concept
- Used for organizational context
### Iteration
**Definition**: Sprint/time period (e.g., `Sprint 24`)
**Mapping**:
- Store in increment frontmatter: `ado.iteration`
- Not a direct SpecWeave concept
- Used for planning context
### Work Item States
ADO uses **State** (not Status):
| ADO State | SpecWeave Status |
|-----------|------------------|
| New | planned |
| Active | in-progress |
| Resolved | in-progress (testing) |
| Closed | completed |
### Priority Values
ADO uses numeric priorities:
| ADO Priority | SpecWeave Priority |
|--------------|-------------------|
| 1 | P1 |
| 2 | P2 |
| 3 | P3 |
| 4 | P3 |
---
## Edge Cases and Error Handling
### Feature vs User Story Decision
**Problem**: SpecWeave user story → Should it be ADO Feature or User Story?
**Solution**:
```
Decision Logic:
- User story has >5 acceptance criteria → Feature (large work)
- User story has ≤5 acceptance criteria → User Story (small work)
- User can override with flag: --force-feature or --force-user-story
```
### Custom Area Paths
**Problem**: Project has custom Area Path structure
**Solution**:
```
Ask user:
"Select Area Path for this increment:
[1] MyProject\TeamA
[2] MyProject\TeamB
[3] Custom (enter path)"
```
### Custom Iterations
**Problem**: Sprint naming varies
**Solution**:
```
Ask user:
"Select Iteration for this increment:
[1] Sprint 24 (current)
[2] Sprint 25 (next)
[3] Backlog
[4] Custom (enter iteration)"
```
### ADO API Errors
**Problem**: Rate limit, authentication failure, network error
**Solution**:
```
❌ ADO API Error: Unauthorized (401)
Check your Personal Access Token (PAT):
1. Go to https://dev.azure.com/{org}/_usersSettings/tokens
2. Create new PAT with Work Items (Read, Write) scope
3. Update .env: ADO_PAT=your-token
```
---
## Templates
Use templates in `templates/` folder:
- `epic-from-increment.md` - Epic creation template
- `feature-from-user-story.md` - Feature creation template
- `user-story-from-small-story.md` - User Story creation template
- `increment-from-epic.md` - Increment import template
---
## References
Consult references in `references/` folder:
- `ado-concepts.md` - ADO structure (Epic, Feature, User Story, Task)
- `specweave-concepts.md` - SpecWeave structure
- `mapping-examples.md` - Real-world conversions with Area Paths and Iterations
---
## Test Cases
Validate all conversions using test cases in `test-cases/`:
1. **test-1-increment-to-epic.yaml** - Export with Feature/User Story decision
2. **test-2-epic-to-increment.yaml** - Import with Area Path and Iteration
3. **test-3-bidirectional-sync.yaml** - Sync with ADO-specific fields
**Run tests**:
```bash
npm run test:agents:specweave-ado-mapper
```
---
## Best Practices
1. **Respect ADO hierarchy** - Use Feature for large work, User Story for small
2. **Store Area Path and Iteration** - Important for organizational context
3. **Handle custom workflows** - Many ADO projects customize states
4. **Use PAT securely** - Store in .env, never commit
5. **Preserve traceability** - Store ADO IDs in frontmatter, SpecWeave IDs in ADO
---
## Usage Examples
### Export to ADO
```
User: "Export increment 0001 to Azure DevOps"
You:
1. Read increment files
2. Ask: "Area Path? [TeamA] [TeamB] [Custom]"
3. Ask: "Iteration? [Sprint 24] [Sprint 25] [Backlog]"
4. Create Epic
5. Decide Feature vs User Story (based on size)
6. Create Work Items
7. Update frontmatter
8. Present summary
```
### Import from ADO
```
User: "Import ADO epic 12345"
You:
1. Fetch Epic + hierarchy
2. Extract Area Path and Iteration
3. Auto-number increment
4. Generate spec.md with ADO metadata
5. Generate tasks.md
6. Update ADO Epic with SpecWeave ID
7. Present summary
```
---
**You are the authoritative mapper between SpecWeave and Azure DevOps. Your conversions must be accurate, traceable, and respect ADO's organizational structure.**