Plan new Product Increment - PM-led process (market research, spec, plan, auto-generate tasks). Auto-closes previous increment if PM gates pass.
Plan a new product increment from market research to ready-to-build. Use this when starting new work to auto-close previous increments and enforce WIP limits.
/plugin marketplace add anton-abyzov/specweave/plugin install sw@specweavePM-Led Workflow: From market research to ready-to-build increment.
You are helping the user create a new SpecWeave increment with automatic closure of previous increment if ready.
β THE IRON RULE: Cannot start increment N+1 until increment N is DONE
THIS IS NOT NEGOTIABLE - Enforce strict increment discipline!
# Run discipline check (exit codes: 0=pass, 1=violations, 2=error)
if ! specweave check-discipline; then
echo ""
echo "β Cannot create new increment! Discipline violations found."
echo ""
echo "π‘ What would you like to do?"
echo ""
echo "1οΈβ£ Close incomplete increments:"
echo " /sw:done <id>"
echo ""
echo "2οΈβ£ Check status:"
echo " specweave check-discipline --verbose"
echo ""
echo "3οΈβ£ Force create (DANGEROUS - violates discipline!):"
echo " Add --force flag to bypass this check"
echo ""
echo "β οΈ The discipline exists for a reason:"
echo " - Prevents scope creep"
echo " - Ensures completions are tracked"
echo " - Maintains living docs accuracy"
echo " - Keeps work focused"
echo ""
exit 1
fi
# β
Discipline check passed - proceed with planning
echo "β
Discipline check passed"
Why This is Strict (changed from v0.5.0):
/sw:close--force flag for emergencies (logged)Rationale:
π― ONLY RUNS IF Step 0A passes (no incomplete increments)
This step handles auto-closing the previous increment if it's ready.
Check for in-progress increments:
# Find increments with status: in-progress
grep -r "status: in-progress" .specweave/increments/*/spec.md
If previous increment found, validate PM gates:
Decision matrix:
All gates β
β Auto-close previous, create new (seamless)
Any gate β β This should never happen (caught by Step 0A)
β If it does, treat as incomplete and block
NOTE: Step 0B is now mostly redundant - Step 0A already blocks incomplete work. This step remains for auto-closing "in-progress" increments that ARE complete.
Auto-close output (if gates pass):
π Previous Increment Check
Found: 0001-user-authentication (in-progress)
PM Gate Validation:
ββ Gate 1 (Tasks): 8/8 P1 completed β
ββ Gate 2 (Tests): 5/5 passing (85% coverage) β
ββ Gate 3 (Docs): CLAUDE.md β
, README.md β
β
Auto-closing increment 0001...
Proceeding with new increment 0002...
Prompt output (if gates fail):
β οΈ Previous Increment Incomplete
Found: 0001-user-authentication (in-progress)
PM Gate Validation:
ββ Gate 1 (Tasks): 6/8 P1 completed β (2 P1 tasks remaining)
ββ Gate 2 (Tests): 3/5 passing (60% coverage) β
ββ Gate 3 (Docs): CLAUDE.md β
, README.md β³
Options:
A. Complete 0001 first (recommended)
β Run `/do 0001` to finish remaining tasks
B. Force close 0001 and defer tasks to 0002
β Transfer T006, T007 to new increment
C. Cancel and stay on 0001
β Continue working on authentication
What would you like to do? (A/B/C)
Why suggest, not force?
/done needed when gates passNEW PHILOSOPHY: Default to 1 active increment (maximum focus), allow 2 only for emergencies.
After passing pre-flight checks (Step 0A, 0B), enforce WIP limits based on simplified config.
Implementation:
import { MetadataManager } from '../core/metadata-manager';
import { ConfigManager } from '../core/config-manager';
import { IncrementType } from '../core/types';
// 1. Load config (defaults: maxActiveIncrements=1, hardCap=3, allowEmergencyInterrupt=true)
const config = ConfigManager.load();
const limits = config.limits || {
maxActiveIncrements: 1,
hardCap: 3,
allowEmergencyInterrupt: true,
typeBehaviors: {
canInterrupt: ['hotfix', 'bug']
}
};
// 2. Count active increments (NOT paused/completed/abandoned)
const active = MetadataManager.getAllActive();
const activeCount = active.length;
// 3. Ask user for increment type (or detect from title)
const incrementType = await promptForType(); // hotfix, feature, bug, change-request, refactor, experiment
// 4. HARD CAP WARNING (negotiable - user decides!)
if (activeCount >= limits.hardCap) {
console.log(chalk.yellow.bold('\nβ οΈ WIP LIMIT EXCEEDED\n'));
console.log(chalk.yellow(`You have ${activeCount} active increments (configured limit: ${limits.hardCap})\n`));
console.log(chalk.dim('Active increments:'));
active.forEach(inc => {
console.log(chalk.dim(` β’ ${inc.id} [${inc.type}]`));
});
console.log(chalk.blue('\nπ‘ Options:\n'));
console.log(chalk.white('1οΈβ£ Complete an increment: /sw:done <id>'));
console.log(chalk.white('2οΈβ£ Pause an increment: /sw:pause <id>'));
console.log(chalk.white('3οΈβ£ Increase limit: Edit .specweave/config.json limits.hardCap'));
console.log(chalk.white('4οΈβ£ Continue anyway (confirm below)\n'));
console.log(chalk.dim('Research: 3+ concurrent tasks = 40% slower + more bugs\n'));
// ASK user instead of blocking
const proceed = await promptConfirm('Continue with new increment anyway?');
if (!proceed) {
console.log(chalk.dim('Cancelled. Complete or pause existing work first.'));
process.exit(0);
}
console.log(chalk.green('β Proceeding with new increment...\n'));
}
// 5. SOFT ENFORCEMENT (activeCount >= maxActiveIncrements)
if (activeCount >= limits.maxActiveIncrements) {
const canInterrupt = limits.typeBehaviors?.canInterrupt || ['hotfix', 'bug'];
const isEmergency = canInterrupt.includes(incrementType);
if (isEmergency && limits.allowEmergencyInterrupt) {
// β
ALLOW - Emergency interrupt
console.log(chalk.yellow.bold('\nβ οΈ EMERGENCY INTERRUPT\n'));
console.log(chalk.yellow(`Starting ${incrementType} increment (emergency exception allowed)\n`));
console.log(chalk.dim('You have 1 active increment. This will be your 2nd (emergency ceiling).\n'));
console.log(chalk.blue('π Active increments:'));
active.forEach(inc => {
console.log(chalk.dim(` β’ ${inc.id} [${inc.type}]`));
});
console.log(chalk.yellow('\nπ‘ Recommendation: After emergency, complete or pause it before resuming normal work.\n'));
// Continue to Step 1
} else {
// β SOFT BLOCK - Warn and offer options
console.log(chalk.yellow.bold('\nβ οΈ WIP LIMIT REACHED\n'));
console.log(chalk.yellow(`You have ${activeCount} active increment(s) (recommended limit: ${limits.maxActiveIncrements})\n`));
console.log(chalk.yellow('Active increments:'));
active.forEach(inc => {
console.log(chalk.dim(` β’ ${inc.id} [${inc.type}]`));
});
console.log(chalk.dim('\nπ§ Focus Principle: ONE active increment = maximum productivity'));
console.log(chalk.dim('Starting a 2nd increment reduces focus and velocity.\n'));
console.log(chalk.blue('π‘ What would you like to do?\n'));
console.log(chalk.white('1οΈβ£ Complete current work (recommended)'));
console.log(chalk.dim(' Finish active increment before starting new\n'));
console.log(chalk.white('2οΈβ£ Pause current work'));
console.log(chalk.dim(' Pause active increment to focus on new work\n'));
console.log(chalk.white('3οΈβ£ Start 2nd increment anyway'));
console.log(chalk.dim(' Accept productivity cost (20% slower)\n'));
const choice = await prompt({
type: 'select',
message: 'Choose an option:',
choices: [
{ name: 'Complete current work', value: 'complete' },
{ name: 'Pause current work', value: 'pause' },
{ name: 'Start 2nd increment anyway', value: 'continue' }
]
});
if (choice === 'complete') {
console.log(chalk.green('\nβ
Smart choice! Finish current work first.\n'));
console.log(chalk.dim('Use /sw:do to continue work\n'));
process.exit(0);
} else if (choice === 'pause') {
console.log(chalk.blue('\nβΈοΈ Pausing current increment...\n'));
const pauseReason = await prompt({
type: 'input',
message: 'Reason for pausing:',
default: 'Paused to start new work'
});
for (const inc of active) {
await MetadataManager.pause(inc.id, pauseReason);
console.log(chalk.green(`β
Paused ${inc.id}`));
}
console.log(chalk.green('\nβ
Proceeding with new increment...\n'));
} else {
// choice === 'continue'
console.log(chalk.yellow('\nβ οΈ Starting 2nd increment (20% productivity cost)\n'));
console.log(chalk.dim('Research: Context switching reduces velocity significantly.\n'));
}
}
}
// 6. If activeCount < maxActiveIncrements, no warnings - proceed directly
if (activeCount === 0) {
console.log(chalk.green('β
No active increments. Starting fresh!\n'));
}
// Proceed to Step 1 (find next increment number)
Example Output - Hard Cap (2 active):
β HARD CAP REACHED
You have 2 active increments (absolute maximum: 2)
Active increments:
β’ 0005-authentication [feature]
β’ 0006-security-hotfix [hotfix]
π‘ You MUST complete or pause existing work first:
1οΈβ£ Complete an increment:
/sw:done <id>
2οΈβ£ Pause an increment:
/sw:pause <id> --reason="..."
3οΈβ£ Check status:
/sw:status
π Multiple hotfixes? Combine them into ONE increment!
Example: 0009-security-fixes (SQL + XSS + CSRF)
β This limit is enforced for your productivity.
Research: 3+ concurrent tasks = 40% slower + more bugs
Example Output - Soft Warning (1 active, starting 2nd):
β οΈ WIP LIMIT REACHED
You have 1 active increment(s) (recommended limit: 1)
Active increments:
β’ 0005-authentication [feature]
π§ Focus Principle: ONE active increment = maximum productivity
Starting a 2nd increment reduces focus and velocity.
π‘ What would you like to do?
1οΈβ£ Complete current work (recommended)
Finish active increment before starting new
2οΈβ£ Pause current work
Pause active increment to focus on new work
3οΈβ£ Start 2nd increment anyway
Accept productivity cost (20% slower)
Choose an option: 1
β
Smart choice! Finish current work first.
Use /sw:do to continue work
Example Output - Emergency Interrupt (hotfix):
β οΈ EMERGENCY INTERRUPT
Starting hotfix increment (emergency exception allowed)
You have 1 active increment. This will be your 2nd (emergency ceiling).
π Active increments:
β’ 0005-authentication [feature]
π‘ Recommendation: After emergency, complete or pause it before resuming normal work.
Proceeding with hotfix 0006...
Type-Based Limits (from TYPE_LIMITS in increment-metadata.ts):
Bypassing Warnings (not recommended):
β THIS STEP MUST BE COMPLETED BEFORE ANY SPEC GENERATION!
π§ ULTRATHINK REQUIRED - ANALYZE ALL AVAILABLE CONTEXT FIRST!
0. GATHER CONTEXT BEFORE API CALL:
# 1. Check existing project folders in living docs
ls .specweave/docs/internal/specs/
# 2. Check how recent increments assigned projects
grep -r "^\*\*Project\*\*:" .specweave/increments/*/spec.md | tail -10
# 3. Read config.json for project.name or multiProject.projects
cat .specweave/config.json | jq '.project.name, .multiProject'
π¨ NOW RUN THE CONTEXT API (via Bash tool):
specweave context projects
CAPTURE THE OUTPUT AND STORE IT:
// Example 1-level output:
{
"level": 1,
"projects": [{"id": "frontend-app"}, {"id": "backend-api"}, {"id": "shared"}]
}
// Example 2-level output:
{
"level": 2,
"projects": [{"id": "acme-corp"}],
"boardsByProject": {
"acme-corp": [{"id": "digital-ops"}, {"id": "mobile-team"}]
}
}
π§ ULTRATHINK - SMART PROJECT RESOLUTION (v0.35.0+ CRITICAL!):
RESOLUTION PRIORITY (MUST FOLLOW THIS ORDER!):
1. β
EXACT MATCH: config.project.name or multiProject.projects key β USE IT
2. β
LIVING DOCS: Existing folder in specs/ β USE THAT PROJECT ID
3. β
RECENT PATTERNS: Same feature type in past increments β USE SAME PROJECT
4. β οΈ UNCERTAIN: Multiple valid options OR no clear match β ASK USER!
5. π FALLBACK: If all else fails β USE "default" (NEVER "specweave"!)
β οΈ CRITICAL: IF UNCERTAIN - YOU MUST ASK THE USER!
I found multiple potential projects for this feature:
- frontend-app (keywords: UI, form, React)
- backend-api (keywords: API, endpoint)
Which project should I assign to this feature?
β NEVER DO THIS:
β CORRECT FALLBACK (when no projects configured):
**Project**: default
STORE THESE VALUES FOR USE IN STEP 5:
STRUCTURE_LEVEL = 1 or 2
AVAILABLE_PROJECTS = ["frontend-app", "backend-api", "shared"]
AVAILABLE_BOARDS = {...} // for 2-level only
WHY THIS IS MANDATORY:
{{PROJECT_ID}} placeholdersspec-project-validator.sh hookYOU MUST ACTUALLY RUN THE COMMAND - reading documentation about it is NOT enough!
.specweave/increments/ directory (active increments).specweave/increments/_archive/ directory (archived/abandoned increments)β οΈ MANDATORY CHECK before generating spec.md!
Structure Level Detection (use src/utils/structure-level-detector.ts):
import { detectStructureLevel } from './utils/structure-level-detector.js';
const structureConfig = detectStructureLevel(projectRoot);
// structureConfig.level: 1 or 2
// structureConfig.projects: available projects
// structureConfig.boardsByProject: boards per project (if 2-level)
Detection Sources (priority order):
sync.profiles.*.config.areaPathMapping)areaPaths arraysync.profiles.*.config.boardMapping)umbrella.teams)umbrella.childRepos)multiProject.enabled)Project/Board Selection - ULTRA-SMART LOGIC:
β οΈ CORE PRINCIPLE: Each User Story belongs to exactly ONE project (1-level) or ONE project+board (2-level). An increment can contain USs spanning MULTIPLE projects/boards.
RULE 1: NO QUESTION IF ONLY 1 OPTION
IF 1-level AND only 1 project β AUTO-SELECT silently, NO question
IF 2-level AND only 1 project AND only 1 board β AUTO-SELECT silently, NO question
RULE 2: KEYWORD-BASED AUTO-DETECTION
Analyze feature description for keywords before asking:
Project-Level Keywords (1-level and 2-level):
Frontend (FE): UI, form, button, page, component, React, Vue, Angular,
Next.js, CSS, style, responsive, chart, dashboard, view,
modal, widget, Tailwind, Material-UI, Recharts
Backend (BE): API, endpoint, REST, GraphQL, database, query, migration,
service, controller, authentication, JWT, session, middleware,
CRUD, Redis, PostgreSQL, MongoDB, microservice
Mobile: mobile, iOS, Android, React Native, Flutter, Expo, app, native,
push notification, offline, AsyncStorage, screen, touch, gesture
Infrastructure: deploy, CI/CD, Docker, Kubernetes, terraform, monitoring,
logging, pipeline, AWS, Azure, GCP, nginx, Helm, ArgoCD
Shared: types, interfaces, utilities, validators, shared, common, library,
SDK, models, constants, helpers
Board-Level Keywords (2-level structures only):
When project has multiple boards, also match board-specific keywords:
analytics/reporting: analytics, metrics, KPI, dashboard, report, chart, graph
user-management: user, auth, login, registration, profile, permissions, roles
integrations: integration, webhook, API, third-party, sync, import, export
payments: payment, billing, subscription, invoice, stripe, checkout
notifications: notification, alert, email, SMS, push, messaging
devops/platform: deploy, infrastructure, monitoring, CI/CD, pipeline
RULE 3: CONFIDENCE CALCULATION FORMULA
confidence = (matched_keywords / total_feature_keywords) Γ 100
Example: "Add React login form with JWT authentication"
Keywords found: React (FE), login (FE), form (FE), JWT (BE), authentication (BE)
FE matches: 3, BE matches: 2
FE confidence: 3/5 = 60%
BE confidence: 2/5 = 40%
β Primary: FE (60%), Secondary: BE (40%)
β SUGGEST: "Frontend (60%), but also touches Backend (40%)"
If multiple projects have similar confidence (within 15%):
β Treat as MULTI-PROJECT feature
β Auto-split USs by detected keywords
RULE 4: CONFIDENCE-BASED DECISION
>80% single project β AUTO-SELECT with notification (no question)
50-80% single project β SUGGEST with quick confirm option
Multiple projects within 15% β AUTO-SPLIT across projects
<50% OR ambiguous β ASK user with ALL options listed
RULE 5: MANDATORY Project: FIELD (v0.35.0+)
β EVERY US MUST have explicit **Project**: field - NO FALLBACKS!
Single-project mode: **Project**: = config.project.name
Multi-project mode: **Project**: = one of multiProject.projects keys
NEVER generate User Story without **Project**: field!
START
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β 1. Detect structure level (1 or 2) β
β 2. Count available projects/boards β
βββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββ
β ONLY 1 OPTION? β
β (1-level: 1 project) β
β (2-level: 1 project + 1 board) β
βββββββββββββββββββββββββββββββββββββββ
β
βββ YES βββΊ AUTO-SELECT SILENTLY
β "β
Project: {name} (auto-selected)"
β NO QUESTION ASKED
β
βΌ NO
βββββββββββββββββββββββββββββββββββββββ
β ANALYZE KEYWORDS in feature desc β
β Calculate confidence per project β
βββββββββββββββββββββββββββββββββββββββ
β
βββ HIGH (>80% single) βββΊ AUTO-SELECT + NOTIFY
β "β
Detected: {project} (keywords: React, form)"
β
βββ MULTI-PROJECT (within 15%) βββΊ AUTO-SPLIT USs
β "π Multi-project detected:
β β’ US-001 (Login UI) β web-app (60%)
β β’ US-002 (Auth API) β api-service (55%)
β Proceed? (Y/n)"
β
βββ MEDIUM (50-80%) βββΊ SUGGEST + CONFIRM
β "π Suggested: {project}. Confirm? (Y/n)"
β
βΌ LOW (<50%)
βββββββββββββββββββββββββββββββββββββββ
β ASK with ALL options (multiSelect) β
β Never truncate, never hide options β
βββββββββββββββββββββββββββββββββββββββ
CRITICAL: Assignment is at USER STORY level, not increment level!
Each US has its own project (and board for 2-level):
### US-001: Login Form UI
**Project**: web-app
**Board**: frontend <!-- 2-level only -->
### US-002: Auth API Endpoints
**Project**: api-service
**Board**: backend <!-- 2-level only -->
### US-003: Mobile Login
**Project**: mobile-app
**Board**: mobile-team <!-- 2-level only -->
User can manually edit project/board per US in spec.md anytime!
Scenario 1: Single Project (NO QUESTION)
Config: 1 project (my-app)
Feature: "Add dark mode toggle"
β AUTO-SELECT: my-app
β Output: "β
Project: my-app (single project - auto-selected)"
β NO question asked
Scenario 2: Multiple Projects, Clear Keywords (AUTO-DETECT)
Config: 3 projects (web-app, api-service, mobile-app)
Feature: "Add React dashboard with charts"
β Keywords: "React" (FE), "dashboard" (FE), "charts" (FE)
β Confidence: 95% β web-app
β Output: "β
Detected: web-app (keywords: React, dashboard, charts)"
β NO question (high confidence)
Scenario 3: Multi-Area Feature (SMART SPLIT)
Config: 3 projects (web-app, api-service, shared-lib)
Feature: "User authentication with JWT"
β This spans FE (login form) + BE (auth API) + shared (types)
β Output:
"π This feature spans multiple projects. Auto-assigning:
β’ US-001: Login UI β web-app
β’ US-002: Auth API β api-service
β’ US-003: Auth types β shared-lib
β
Proceed? You can modify per-US in spec.md"
Scenario 4: 2-Level, Single Project, Multiple Boards
Config: 1 project (enterprise-corp), 5 boards
Feature: "Add reporting dashboard"
β Project: AUTO-SELECT (only 1)
β Board keywords: "reporting" + "dashboard"
β Output:
"β
Project: enterprise-corp (auto-selected)
π Suggested board: analytics (keyword: reporting)
Confirm or select: [1] analytics [2] frontend [3] backend..."
Scenario 5: Ambiguous (ASK WITH ALL OPTIONS)
Config: 4 projects
Feature: "Improve system performance"
β No clear keyword match
β ASK with ALL options listed (multiSelect: true)
β Never hide behind "see all"
β FORBIDDEN: Asking when only 1 project/board exists
β FORBIDDEN: Hiding options behind "Let me see all"
β FORBIDDEN: Truncating project/board lists
β FORBIDDEN: Assigning ALL USs to same project when content differs
β
REQUIRED: Auto-select when only 1 option
β
REQUIRED: Use keyword matching before asking
β
REQUIRED: Each US has explicit project/board assignment
β
REQUIRED: When asking, show ALL options with descriptions
β
REQUIRED: Allow user to modify per-US in spec.md
spec.md YAML Format (v0.35.0+ - no project/board in frontmatter!):
---
increment: 0045-user-auth
title: "User Authentication"
# NOTE: project: and board: REMOVED from frontmatter!
---
Per-US Format (MANDATORY):
### US-001: Login Form
**Project**: web-app # β MANDATORY (single-project: use config.project.name)
**As a** user, I want...
### US-002: Auth API
**Project**: enterprise-corp # β MANDATORY (multi-project: pick from config)
**Board**: backend # β MANDATORY for 2-level structures
**As a** developer, I want...
Pass detected/selected values to increment-planner skill!
package.json β TypeScript/JavaScriptrequirements.txt or pyproject.toml β Pythongo.mod β GoCargo.toml β Rustpom.xml or build.gradle β Java*.csproj β C#/.NETπ NEW IN v0.4.0: Auto-detect plugins based on increment description
Before planning, analyze the feature description for plugin keywords and suggest relevant plugins:
# Example feature descriptions and their plugin suggestions:
"Deploy to Kubernetes" β kubernetes plugin
"Add Stripe payments" β payment-processing plugin
"Create React dashboard" β frontend-stack plugin
"Build FastAPI backend" β backend-stack plugin
"Sync with GitHub issues" β github plugin
"Integrate with Jira" β jira plugin
Detection Logic:
Output Format:
π‘ Plugin Detection
Analyzing feature: "Add authentication with NextJS and Stripe"
Suggested plugins:
β
frontend-stack (NextJS detected)
β
payment-processing (Stripe detected)
Would you like to enable these plugins? (Y/n)
If user confirms:
If user declines:
specweave plugin enable <name>π¨ CRITICAL - YOU MUST USE THE SKILL TOOL:
DO NOT manually create files. DO NOT skip this step. DO NOT write spec.md or plan.md directly.
β οΈ COMMON MISTAKE - DO NOT CALL /sw:plan:
/sw:plan is for EXISTING increments (with spec.md already created)/sw:increment creates NEW increments from scratchincrement-planner skill (NOT /sw:plan)You MUST invoke the increment-planner skill to orchestrate the full PM-led workflow:
Use the Skill tool:
command: "increment-planner"
Example of correct invocation:
Skill({
skill: "increment-planner",
args: "--id=0157-feature --description=\"...\" --project=my-project"
});
The increment-planner skill will:
WHY THIS IS MANDATORY:
BEFORE PROCEEDING, USE THE SKILL TOOL:
You must literally call the Skill tool like this:
// β
CORRECT - Use increment-planner skill
Skill({
skill: "increment-planner",
args: "--id=XXXX-name --description=\"...\" --project=my-project"
});
// β WRONG - DO NOT call /sw:plan for new increments
Skill({ skill: "sw:plan" }); // This is for EXISTING increments only!
Wait for the skill to complete. Do NOT continue to Step 7 until the increment-planner skill returns.
Self-Awareness Check (SpecWeave Contributors): If you are working in the SpecWeave repository itself (detected via package.json name === 'specweave'), you should see warnings reminding you that changes affect the framework itself, not a user project.
Error Handling (v1.0.102+): If errors occur, use standardized error messages for consistent UX:
import { ERROR_MESSAGES, formatError } from './src/utils/error-formatter.js';
// If user tries to plan existing increment with /sw:increment
formatError(ERROR_MESSAGES.WRONG_COMMAND_FOR_EXISTING_INCREMENT(incrementId));
// If invalid increment number format
formatError(ERROR_MESSAGES.INVALID_INCREMENT_NUMBER(provided, expected));
// If duplicate increment
formatError(ERROR_MESSAGES.DUPLICATE_INCREMENT(incrementId));
Only use this if Skill tool is unavailable or fails:
Manually invoke agents using Task tool:
Invoke PM Agent:
Task(
subagent_type: "specweave:pm:pm",
prompt: "Create product strategy for: [user description]
Detect tech stack from: [detected tech info]
Create living docs in .specweave/docs/internal/strategy/
Create increment spec.md that references strategy docs",
description: "PM product strategy"
)
Invoke Architect Agent:
Task(
subagent_type: "specweave:architect:architect",
prompt: "Read PM's strategy docs from .specweave/docs/internal/strategy/
Create technical architecture for: [user description]
Tech stack: [detected tech stack]
Create living docs in .specweave/docs/internal/architecture/
Create ADRs for all technical decisions
Create increment plan.md that references architecture docs",
description: "Architect technical design"
)
Auto-generate tasks.md:
Skill(command: "task-builder")
Pass detected tech stack to ALL agents (CRITICAL!)
After the increment-planner skill completes, verify:
Living docs created:
.specweave/docs/internal/strategy/{module}/ exists.specweave/docs/internal/architecture/adr/ has ADRsIncrement files created:
.specweave/increments/####-name/spec.md (references strategy docs, AC-IDs).specweave/increments/####-name/plan.md (references architecture docs, test strategy).specweave/increments/####-name/tasks.md (implementation + embedded tests in BDD format, v0.7.0+).specweave/increments/####-name/context-manifest.yamlHooks executed:
```
β
Created increment 0003-user-authentication
Detected tech stack:
- Language: {detected-language} (e.g., Python, TypeScript, Go, Java)
- Framework: {detected-framework} (e.g., Django, FastAPI, NextJS, Spring Boot)
- Database: {specified-database} (e.g., PostgreSQL, MySQL, MongoDB)
- Platform: {specified-platform} (e.g., AWS, Hetzner, Vercel, self-hosted)
Location: .specweave/increments/0003-user-authentication/
π Files created:
- spec.md (6 user stories, 15 requirements)
- tasks.md (42 implementation tasks using {framework} patterns)
- pm-analysis.md (product strategy)
- architecture.md (system design for {framework})
- infrastructure.md ({platform} deployment)
- security.md ({framework}-specific security)
- test-strategy.md (E2E tests for {framework})
β±οΈ Estimated effort: 3-4 weeks
```
π₯ CRITICAL: After increment planning, sync to living docs
π [Playing celebration sound...]
π Now syncing strategic documentation to living docs...
Run /sw:sync-docs update to create initial documentation:
/sw:sync-docs update
This will:
.specweave/docs/public/overview/features.md.specweave/docs/internal/architecture/diagrams/.specweave/docs/internal/operations/.specweave/docs/internal/security/After /sw:sync-docs update completes:
β
Strategic documentation synchronized!
π CRITICAL: After increment files are created, sync to living docs AND external tools:
π Syncing increment to living docs...
π‘ Syncing to external tools (GitHub/JIRA/ADO)...
π¨ MANDATORY - USE SlashCommand TOOL:
You MUST invoke the sync-specs command using the SlashCommand tool:
SlashCommand(command: "/sw:sync-specs {increment-id}")
DO NOT just mention the command in output - you MUST actually execute it!
WHY THIS IS MANDATORY (Bug Fix v0.33.0):
Alternative - call LivingDocsSync directly in TypeScript implementations:
import { LivingDocsSync } from './src/core/living-docs/living-docs-sync.js';
const sync = new LivingDocsSync(projectRoot);
const result = await sync.syncIncrement(incrementId, { dryRun: false });
if (result.success) {
console.log(`β
Living docs synced: ${result.featureId}`);
console.log(` Created: ${result.filesCreated.length} files`);
} else {
console.log(`β οΈ Living docs sync had errors (non-blocking): ${result.errors.join(', ')}`);
}
What syncIncrement() does automatically (Step 7 in the sync flow):
syncToExternalTools() which detects GitHub/JIRA/ADO from configcanUpsertInternalItems) before creating issuesGitHubFeatureSync.syncFeatureToGitHub(featureId)JiraFeatureSync.syncFeatureToJira(featureId)ADOFeatureSync.syncFeatureToADO(featureId)Expected output:
π Syncing increment to living docs...
β
Living docs synced: FS-118E
Created: 4 files (FEATURE.md, us-001.md, us-002.md, us-003.md)
π‘ Syncing to external tools: github
π Permissions: upsert=true, update=true, status=true
β
Synced to GitHub: 0 updated, 3 created
Permission-aware sync (v0.32.2+):
Before calling external sync, syncToExternalTools() checks permissions from .specweave/config.json:
| Permission | Controls | When Required |
|---|---|---|
canUpsertInternalItems | CREATE new issues for SpecWeave-created items | Creating increment issues |
canUpdateExternalItems | UPDATE issues imported from external tools | Updating imported items |
canUpdateStatus | UPDATE issue status (open/closed) | Closing completed items |
If canUpsertInternalItems: false:
β οΈ Skipping external sync - canUpsertInternalItems is disabled in config
π‘ Enable in .specweave/config.json: sync.settings.canUpsertInternalItems: true
Error handling:
External tool sync failures are NON-BLOCKING (increment creation succeeds):
β οΈ External sync failed: Rate limit exceeded
π‘ Run /sw:sync-specs {increment-id} to retry
After Step 10 completes:
β
Increment created and synced!
Next steps:
1. Review the increment plan and strategic docs
2. Start implementation: /sw:do {increment-id}
3. Monitor external tool status: /sw:status {increment-id}
π¨ Step 11: MANDATORY - Sync to External Tools (GitHub/JIRA/ADO)
After living docs sync, you MUST explicitly trigger external tool sync if configured:
# Check if GitHub sync is configured
if grep -q '"github"' .specweave/config.json 2>/dev/null || \
grep -q 'provider.*github' .specweave/config.json 2>/dev/null || \
[ -n "$(grep GITHUB_TOKEN .env 2>/dev/null)" ]; then
echo "π‘ GitHub sync configured - triggering sync..."
fi
β οΈ CRITICAL: External sync requires explicit command!
Living docs sync does NOT automatically create GitHub issues. You MUST run:
/sw-github:sync {increment-id}
Why this is separate?
canUpsertInternalItems: true)Expected output after /sw-github:sync:
π Syncing increment 0001-feature to GitHub...
β
GitHub sync complete:
π Created: 3 issues (US-001, US-002, US-003)
π Milestone: [FS-001] Feature Name
π Issues linked in metadata.json
If permissions not configured:
β οΈ GitHub sync skipped - canUpsertInternalItems is disabled
π‘ Enable in .specweave/config.json:
"sync": {
"settings": {
"canUpsertInternalItems": true
}
}
Final completion output:
β
Increment 0001-feature-name created successfully!
π Files:
ββ .specweave/increments/0001-feature-name/
ββ spec.md (3 User Stories, 12 ACs)
ββ plan.md (Technical Architecture)
ββ tasks.md (18 Tasks)
ββ metadata.json
π Living Docs:
ββ .specweave/docs/internal/specs/project-name/FS-001/
ββ FEATURE.md
ββ us-*.md (3 files)
π‘ External Tools:
ββ GitHub: 3 issues created (#42, #43, #44)
π Ready for implementation: /sw:do 0001
IMPORTANT: Tech stack is AUTO-DETECTED from project files (package.json, requirements.txt, etc.), NOT hardcoded!
IMPORTANT (v0.31.0+): project: (and board: for 2-level) fields are MANDATORY. See Step 1.5.
---
increment: 003-user-authentication
title: "User Authentication System"
priority: P1
status: planned
created: 2025-10-26
dependencies: []
structure: user-stories
# PROJECT/BOARD (v0.31.0+ MANDATORY)
project: web-app # REQUIRED - target project for living docs sync
board: digital-operations # REQUIRED only for 2-level structures (ADO/JIRA boards)
# Tech stack is DETECTED, not hardcoded
tech_stack:
detected_from: "package.json" # or "requirements.txt", "go.mod", etc.
language: "{detected-language}" # e.g., "typescript", "python", "go", "java", "rust"
framework: "{detected-framework}" # e.g., "nextjs", "django", "fastapi", "spring-boot", "gin"
database: "{specified-database}" # e.g., "postgresql", "mysql", "mongodb", "sqlite"
orm: "{detected-orm}" # e.g., "prisma", "django-orm", "sqlalchemy", "hibernate"
# Platform is SPECIFIED by user or detected from config
platform: "{specified-platform}" # e.g., "hetzner", "aws", "vercel", "self-hosted"
estimated_cost: "{calculated-based-on-platform}"
---
Example for TypeScript/NextJS project:
tech_stack:
detected_from: "package.json"
language: "typescript"
framework: "nextjs"
database: "postgresql"
orm: "prisma"
platform: "vercel"
estimated_cost: "$20/month"
Example for Python/Django project:
tech_stack:
detected_from: "requirements.txt"
language: "python"
framework: "django"
database: "postgresql"
orm: "django-orm"
platform: "hetzner"
estimated_cost: "$12/month"
Example for Go/Gin project:
tech_stack:
detected_from: "go.mod"
language: "go"
framework: "gin"
database: "postgresql"
orm: "gorm"
platform: "aws"
estimated_cost: "$25/month"
---
increment: 003-event-booking-saas
status: planned
dependencies:
- 001-skills-framework
- 002-role-based-agents
phases:
- infrastructure
- backend
- frontend
- testing
- deployment
estimated_tasks: 42
estimated_weeks: 3-4
---
If user says "autonomous mode" or "full automation":
.specweave/ not found: "Error: Not a SpecWeave project. Run specweave init first."Important: This is the main entry point for creating new work in SpecWeave.