/ado-sync
Two-way sync between SpecWeave increment and Azure DevOps work item (push & pull by default)
> /plugin marketplace add anton-abyzov/specweave > /plugin install sw@specweave
How it fires
How this command gets triggered: by you, by Claude, or both.
- Fires itselfClaude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/ado-sync
Context preview
What this command does when you run it.
Two-way sync between SpecWeave increment and Azure DevOps work item (push & pull by default)
Command definition
ado-sync.mddescription: Two-way sync between SpecWeave increment and Azure DevOps work item (push & pull by default)
Sync ADO Work Item Command
**Usage**: `sw-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
# Two-way sync (default - both directions)
sw-ado:sync 0005
# Push only (one-way to ADO)
sw-ado:sync 0005 --direction to-ado
# Pull only (one-way from ADO)
sw-ado:sync 0005 --direction from-ado
---
Command Behavior
When user runs this command, Claude should:
0. Load Credentials from .env (MANDATORY FIRST)
**CRITICAL**: Read PAT from `.env` file, NOT from shell environment variables.
# Read PAT from .env file
ADO_PAT=$(grep '^AZURE_DEVOPS_PAT=' .env 2>/dev/null | cut -d'=' -f2)
if [ -z "$ADO_PAT" ]; then
echo "ERROR: AZURE_DEVOPS_PAT not found in .env file"
echo "Add to .env: AZURE_DEVOPS_PAT=your-pat-here"
exit 1
fi
1. Check Permission Gate (MANDATORY FIRST STEP)
**Before ANY ADO write operations**, check permissions:
// Read .specweave/config.json
const config = JSON.parse(await fs.readFile('.specweave/config.json', 'utf-8'));
const canUpdateExternal = config?.sync?.settings?.canUpdateExternalItems ?? false;
const canUpdateStatus = config?.sync?.settings?.canUpdateStatus ?? false;
// Permission check based on direction
if (direction === 'to-ado' || direction === 'two-way') {
if (!canUpdateExternal) {
console.log(`
❌ Permission Denied: ADO Write Operations Disabled
Cannot push changes to ADO (sync.settings.canUpdateExternalItems = false).
Options:
1. Enable writes: Set canUpdateExternalItems to true in config.json
2. Pull-only mode: sw-ado:sync ${incrementId} --direction from-ado
`);
return;
}
}For `--direction from-ado` (pull-only), permission check is skipped as it's read-only.
2. Resolve ADO Profile
Use the increment's stored profile or fall back to global activeProfile:
// Load increment metadata
const metadataPath = `.specweave/increments/${incrementId}/metadata.json`;
const metadata = JSON.parse(await fs.readFile(metadataPath, 'utf-8'));
// Priority: increment profile > global activeProfile
let profileName = metadata?.external_sync?.ado?.profile;
if (!profileName) {
profileName = config?.sync?.activeProfile;
}
// Validate profile exists
const profileConfig = config?.sync?.profiles?.[profileName];
if (!profileConfig || profileConfig.provider !== 'ado') {
console.log(`❌ ADO profile "${profileName}" not found`);
console.log('Available ADO profiles:', Object.entries(config?.sync?.profiles || {})
.filter(([_, p]) => p.provider === 'ado')
.map(([name]) => name)
.join(', '));
return;
}
const { organization, project } = profileConfig.config;
console.log(`Using ADO profile: ${profileName}`);
console.log(` Organization: ${organization}`);
console.log(` Project: ${project}`);3. Invoke ADO Manager Skill
Use Skill tool: Skill({ skill: "sw-ado:ado-sync", args: "{direction} sync for increment {increment-id} with ADO.
IMPORTANT:
- Permission verified: canUpdateExternalItems={canUpdateExternal}
- Using profile: {profileName} (org: {organization}, project: {project})
Phase 1 - Pull FROM ADO:
1. Fetch work item #{workItemId} 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 (if direction allows):
1. Read .specweave/increments/{increment-id}/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 metadata.json
6. POST comment to ADO API using org: {organization}, project: {project}
7. Update work item state/fields
Display: Sync summary with profile used"4. Display Result
Sync Summary for increment {increment-id}
Profile: {profileName}
Organization: {organization}
Project: {project}
Direction: {direction}
FROM ADO:
State: Active -> Resolved
Priority: 2 -> 1
Comments: 3 new
TO ADO:
Progress: 60% (6/10 tasks)
Posted comment #98765
Work Item: https://dev.azure.com/{organization}/{project}/_workitems/edit/{workItemId}---
Permission Check Matrix
| Direction | canUpdateExternalItems | Result | |-----------|------------------------|--------| | from-ado | any | Allowed (read-only) | | to-ado | false | Denied | | to-ado | true | Allowed | | two-way | false | Denied | | two-way | true | Allowed |
---
Profile Resolution
The command resolves the ADO profile in this order:
1. **Increment profile** (metadata.json -> external_sync.ado.profile) 2. **Global profile** (config.json -> sync.activeProfile)
This allows:
- Different increments to sync to different ADO projects
- No manual `activeProfile` switching needed
- Automatic project targeting
---
Example Output
Two-way Sync (Default)
User: sw-ado:sync 0005-payment-integration
Claude:
Checking permissions...
canUpdateExternalItems: true
Resolving ADO profile...
Using: ado-my-project (from increment)
Organization: acme-corp
Project: My Project
Syncing...
FROM ADO:
State changed: Active -> Resolved
Iteration updated: Sprint 23 -> Sprint 24
Priority changed: 2 -> 1
3 new comments from team
TO ADO:
Progress: 60% complete (6/10 tasks)
Posted comment (ID: 98765)
Updated completion field: 60%
Sync Complete!
Profile: ado-my-project
Work Item: https://dev.azure.com/acme-corp/My%20Project/_workitems/edit/12345
Permission Denied
User: sw-ado:sync 0005 --direction to-ado
Claude:
Checking permissions...
canUpdateExternalItems: fals
Read more
description: Two-way sync between SpecWeave increment and Azure DevOps work item (push & pull by default)
Sync ADO Work Item Command
**Usage**: `sw-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
# Two-way sync (default - both directions) sw-ado:sync 0005 # Push only (one-way to ADO) sw-ado:sync 0005 --direction to-ado # Pull only (one-way from ADO) sw-ado:sync 0005 --direction from-ado
---
Command Behavior
When user runs this command, Claude should:
0. Load Credentials from .env (MANDATORY FIRST)
**CRITICAL**: Read PAT from `.env` file, NOT from shell environment variables.
# Read PAT from .env file ADO_PAT=$(grep '^AZURE_DEVOPS_PAT=' .env 2>/dev/null | cut -d'=' -f2) if [ -z "$ADO_PAT" ]; then echo "ERROR: AZURE_DEVOPS_PAT not found in .env file" echo "Add to .env: AZURE_DEVOPS_PAT=your-pat-here" exit 1 fi
1. Check Permission Gate (MANDATORY FIRST STEP)
**Before ANY ADO write operations**, check permissions:
// Read .specweave/config.json
const config = JSON.parse(await fs.readFile('.specweave/config.json', 'utf-8'));
const canUpdateExternal = config?.sync?.settings?.canUpdateExternalItems ?? false;
const canUpdateStatus = config?.sync?.settings?.canUpdateStatus ?? false;
// Permission check based on direction
if (direction === 'to-ado' || direction === 'two-way') {
if (!canUpdateExternal) {
console.log(`
❌ Permission Denied: ADO Write Operations Disabled
Cannot push changes to ADO (sync.settings.canUpdateExternalItems = false).
Options:
1. Enable writes: Set canUpdateExternalItems to true in config.json
2. Pull-only mode: sw-ado:sync ${incrementId} --direction from-ado
`);
return;
}
}For `--direction from-ado` (pull-only), permission check is skipped as it's read-only.
2. Resolve ADO Profile
Use the increment's stored profile or fall back to global activeProfile:
// Load increment metadata
const metadataPath = `.specweave/increments/${incrementId}/metadata.json`;
const metadata = JSON.parse(await fs.readFile(metadataPath, 'utf-8'));
// Priority: increment profile > global activeProfile
let profileName = metadata?.external_sync?.ado?.profile;
if (!profileName) {
profileName = config?.sync?.activeProfile;
}
// Validate profile exists
const profileConfig = config?.sync?.profiles?.[profileName];
if (!profileConfig || profileConfig.provider !== 'ado') {
console.log(`❌ ADO profile "${profileName}" not found`);
console.log('Available ADO profiles:', Object.entries(config?.sync?.profiles || {})
.filter(([_, p]) => p.provider === 'ado')
.map(([name]) => name)
.join(', '));
return;
}
const { organization, project } = profileConfig.config;
console.log(`Using ADO profile: ${profileName}`);
console.log(` Organization: ${organization}`);
console.log(` Project: ${project}`);3. Invoke ADO Manager Skill
Use Skill tool: Skill({ skill: "sw-ado:ado-sync", args: "{direction} sync for increment {increment-id} with ADO.
IMPORTANT:
- Permission verified: canUpdateExternalItems={canUpdateExternal}
- Using profile: {profileName} (org: {organization}, project: {project})
Phase 1 - Pull FROM ADO:
1. Fetch work item #{workItemId} 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 (if direction allows):
1. Read .specweave/increments/{increment-id}/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 metadata.json
6. POST comment to ADO API using org: {organization}, project: {project}
7. Update work item state/fields
Display: Sync summary with profile used"4. Display Result
Sync Summary for increment {increment-id}
Profile: {profileName}
Organization: {organization}
Project: {project}
Direction: {direction}
FROM ADO:
State: Active -> Resolved
Priority: 2 -> 1
Comments: 3 new
TO ADO:
Progress: 60% (6/10 tasks)
Posted comment #98765
Work Item: https://dev.azure.com/{organization}/{project}/_workitems/edit/{workItemId}---
Permission Check Matrix
| Direction | canUpdateExternalItems | Result | |-----------|------------------------|--------| | from-ado | any | Allowed (read-only) | | to-ado | false | Denied | | to-ado | true | Allowed | | two-way | false | Denied | | two-way | true | Allowed |
---
Profile Resolution
The command resolves the ADO profile in this order:
1. **Increment profile** (metadata.json -> external_sync.ado.profile) 2. **Global profile** (config.json -> sync.activeProfile)
This allows:
- Different increments to sync to different ADO projects
- No manual `activeProfile` switching needed
- Automatic project targeting
---
Example Output
Two-way Sync (Default)
User: sw-ado:sync 0005-payment-integration Claude: Checking permissions... canUpdateExternalItems: true Resolving ADO profile... Using: ado-my-project (from increment) Organization: acme-corp Project: My Project Syncing... FROM ADO: State changed: Active -> Resolved Iteration updated: Sprint 23 -> Sprint 24 Priority changed: 2 -> 1 3 new comments from team TO ADO: Progress: 60% complete (6/10 tasks) Posted comment (ID: 98765) Updated completion field: 60% Sync Complete! Profile: ado-my-project Work Item: https://dev.azure.com/acme-corp/My%20Project/_workitems/edit/12345
Permission Denied
User: sw-ado:sync 0005 --direction to-ado Claude: Checking permissions... canUpdateExternalItems: fals
Spec-first AI development: describe a feature → AI creates spec + plan + tasks, builds autonomously, syncs to GitHub/JIRA. Domain-expert skills for PM, Architect, Frontend, QA learn your patterns permanently. Claude Code, Codex, Cursor, Copilot & more.
Repo: anton-abyzov/specweave
Other commands on specweave.
- /abandon
Abandon an incomplete increment (requirements changed, obsolete)
Open command - /ado-cleanup-duplicates
Clean up duplicate Azure DevOps work items for a Feature. Finds work items with duplicate titles and closes all except the first created item.
Open command - /ado-clone
Clone Azure DevOps repositories to local workspace. Use after init if cloning was skipped, or to add repos later.
Open command - /ado-close
Close Azure DevOps work item when increment complete
Open command - /ado-create
Create Azure DevOps work item from SpecWeave increment
Open command - /ado-import-areas
Import Azure DevOps area paths from a project and map them to SpecWeave projects. Creates 2-level directory structure with area path-based organization.
Open command

