Files
gh-duongdev-ccpm/commands/spec:break-down.md
2025-11-29 18:24:24 +08:00

15 KiB

description, allowed-tools, argument-hint
description allowed-tools argument-hint
Break down Epic/Feature into Features/Tasks based on spec
LinearMCP
AskUserQuestion
<epic-or-feature-id>

Break Down: $1

🚨 CRITICAL: Safety Rules

READ FIRST: $CCPM_COMMANDS_DIR/SAFETY_RULES.md

NEVER submit, post, or update anything to Jira, Confluence, BitBucket, or Slack without explicit user confirmation, even in bypass permission mode.


Shared Helpers

READ: commands/_shared-linear-helpers.md

This command uses the following helper functions:

  • ensureLabelsExist() - Ensure labels exist before using them
  • getOrCreateLabel() - Create or retrieve individual labels

Argument

  • $1 - Epic ID (to break into Features) or Feature ID (to break into Tasks)

Workflow

Step 1: Fetch Issue and Determine Type

Use Linear MCP get_issue with ID $1:

  • Get issue details
  • Check if it's an Epic/Initiative or Feature (parent issue)
  • Find linked spec document
  • Get project/team information
const issueType = determineType(issue)

function determineType(issue) {
  // Check if issue is an Initiative (Epic)
  if (issue.type === 'initiative' || issue.project?.type === 'initiative') {
    return 'epic'
  }

  // Check if issue has sub-issues (Feature)
  if (issue.children && issue.children.length > 0) {
    return 'feature'
  }

  // Check labels
  if (issue.labels.includes('epic')) return 'epic'
  if (issue.labels.includes('feature')) return 'feature'

  // Default: treat as feature
  return 'feature'
}

Step 2: Fetch Spec Document

Extract spec document link from issue description:

// Look for pattern: [Epic Spec: Title](url) or [Feature Design: Title](url)
const docLinkPattern = /\[(?:Epic Spec|Feature Design): .+?\]\((.+?)\)/

const match = issue.description.match(docLinkPattern)
if (match) {
  const docUrl = match[1]
  // Extract doc ID from URL
  const docId = extractDocId(docUrl)
}

Use Linear MCP get_document to fetch spec content.

Step 3: Analyze Spec and Generate Breakdown

If Breaking Down EPIC → Features

Parse Epic Spec:

Look for "Features Breakdown" section in spec document.

## 📊 Features Breakdown

| Feature | Priority | Complexity | Est. Timeline |
|---------|----------|------------|---------------|
| JWT Auth | P0 | High | 2 weeks |
| OAuth Integration | P1 | Medium | 1 week |
| MFA Support | P2 | Low | 3 days |

AI Analysis:

const features = []

// Parse table
for (const row of featureTable) {
  const feature = {
    title: row.feature,
    priority: row.priority, // P0, P1, P2
    complexity: row.complexity, // High, Medium, Low
    estimate: row.estimate,
    description: generateDescription(row.feature, epicContext)
  }
  features.push(feature)
}

// Generate additional features if not in table
// Analyze epic requirements and suggest missing features
const suggestedFeatures = analyzeRequirements(epicSpec)
features.push(...suggestedFeatures)

Create Feature Issues:

For each feature:

// Ensure required labels exist before creating issues
const featureLabels = await ensureLabelsExist(epic.team.id,
  ['feature', 'spec:draft'],
  {
    descriptions: {
      'feature': 'Feature-level work item',
      'spec:draft': 'Specification in draft state'
    }
  }
);

{
  title: feature.title,
  team: epic.team,
  project: epic.project,
  parent: epic.id, // Link to epic
  labelIds: featureLabels, // Use validated label IDs
  priority: mapPriority(feature.priority), // P0=1, P1=2, P2=3, P3=4
  description: `
## 📄 Specification

**Feature Design Doc**: [Will be created] ← Use /ccpm:spec:write to populate

**Parent Epic**: [${epic.title}](${epic.url})
**Epic Spec**: [Link to epic spec doc]

---

## 🎯 Overview

${feature.description}

## 📋 Initial Requirements

[AI generates based on epic context and feature title]

## ⏱️ Estimate

**Complexity**: ${feature.complexity}
**Timeline**: ${feature.estimate}

---

**Next Steps:**
1. Run /ccpm:spec:write to create detailed feature design
2. Run /ccpm:spec:review to validate completeness
3. Run /ccpm:spec:break-down to create implementation tasks
  `
}

If Breaking Down FEATURE → Tasks

Parse Feature Design:

Look for "Implementation Plan" or "Task Breakdown" section:

## 🚀 Implementation Plan

### Task Breakdown
- [ ] **Task 1: Database schema**: Create user_auth table with migrations (Est: 2h)
- [ ] **Task 2: API endpoints**: POST /login, /logout, /refresh (Est: 4h)
- [ ] **Task 3: Frontend integration**: Login screen + auth context (Est: 6h)
- [ ] **Task 4: Testing**: Unit + integration tests (Est: 4h)

AI Analysis:

const tasks = []

// Parse task list
for (const item of taskList) {
  const task = {
    title: extractTitle(item), // "Database schema"
    description: extractDescription(item), // "Create user_auth table..."
    estimate: extractEstimate(item), // "2h"
    dependencies: extractDependencies(item) // If mentioned
  }
  tasks.push(task)
}

// Analyze dependencies
const dependencyGraph = buildDependencyGraph(tasks)

// Suggest additional tasks if missing
const suggestedTasks = analyzeMissingTasks(featureSpec, tasks)
// Example: Missing documentation task, missing E2E test task
tasks.push(...suggestedTasks)

Create Task Issues (as Sub-Issues):

For each task:

// Ensure required labels exist before creating tasks
const taskLabels = await ensureLabelsExist(feature.team.id,
  ['task', 'planning'],
  {
    descriptions: {
      'task': 'Implementation task',
      'planning': 'Task in planning phase'
    }
  }
);

{
  title: task.title,
  team: feature.team,
  project: feature.project,
  parent: feature.id, // Link to feature as sub-issue
  labelIds: taskLabels, // Use validated label IDs
  estimate: convertToPoints(task.estimate), // 2h → 1 point, 4h → 2 points
  description: `
## 📋 Task Description

${task.description}

---

## 📄 Related Spec

**Feature**: [${feature.title}](${feature.url})
**Feature Design**: [Link to design doc]

---

## 🎯 Acceptance Criteria

[AI generates based on task title and feature requirements]

- [ ] Criterion 1
- [ ] Criterion 2

---

## ⏱️ Estimate

**Time**: ${task.estimate}
**Complexity**: [Low/Medium/High based on estimate]

---

## 🔗 Dependencies

${task.dependencies ? `Depends on: ${task.dependencies.map(d => `[Task ${d}]`).join(', ')}` : 'No dependencies'}

---

**Next Steps:**
1. Run /ccpm:planning:plan to gather implementation research
2. Run /ccpm:implementation:start when ready to begin work
  `
}

Step 4: Show Preview

Before creating, show preview to user:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📊 Breakdown Preview: [$1]
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

🎯 Type: [Epic → Features / Feature → Tasks]
📄 Spec: [DOC-XXX]
🔢 Items to Create: [N]

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 Breakdown Items
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[If Epic → Features:]

1. **JWT Auth** (P0, High Complexity)
   - Timeline: 2 weeks
   - Description: Implement JWT-based authentication...

2. **OAuth Integration** (P1, Medium Complexity)
   - Timeline: 1 week
   - Description: Add OAuth 2.0 support for Google, GitHub...

3. **MFA Support** (P2, Low Complexity)
   - Timeline: 3 days
   - Description: Two-factor authentication with TOTP...

[If Feature → Tasks:]

1. **Database schema** (Est: 2h)
   - Description: Create user_auth table with migrations
   - Dependencies: None

2. **API endpoints** (Est: 4h)
   - Description: POST /login, /logout, /refresh
   - Dependencies: Task 1

3. **Frontend integration** (Est: 6h)
   - Description: Login screen + auth context
   - Dependencies: Task 2

4. **Testing** (Est: 4h)
   - Description: Unit + integration tests
   - Dependencies: Task 3

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📊 Summary
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Total Items: [N]
Total Estimate: [X hours / Y days]
Critical Path: [Task sequence]

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Step 5: Confirm Creation

Use AskUserQuestion:

{
  questions: [{
    question: "Create these [N] [features/tasks] in Linear?",
    header: "Confirm",
    multiSelect: false,
    options: [
      {
        label: "Yes, Create All",
        description: "Create all [N] items as shown above"
      },
      {
        label: "Let Me Edit First",
        description: "I want to modify the breakdown in the spec doc first"
      },
      {
        label: "Cancel",
        description: "Don't create anything"
      }
    ]
  }]
}

Step 6: Create Issues in Linear

If user confirms:

const createdIssues = []

try {
  // Ensure labels exist once before creating all issues
  // (Labels are reused across all items in the breakdown)
  const labels = isEpicBreakdown
    ? await ensureLabelsExist(parentIssue.team.id,
        ['feature', 'spec:draft'],
        {
          descriptions: {
            'feature': 'Feature-level work item',
            'spec:draft': 'Specification in draft state'
          }
        }
      )
    : await ensureLabelsExist(parentIssue.team.id,
        ['task', 'planning'],
        {
          descriptions: {
            'task': 'Implementation task',
            'planning': 'Task in planning phase'
          }
        }
      );

  for (const item of breakdownItems) {
    const issue = await createLinearIssue({
      ...item,
      labelIds: labels // Use pre-validated labels
    })
    createdIssues.push(issue)

    // Brief pause to avoid rate limits
    await sleep(500)
  }
} catch (error) {
  console.error(`Failed to create issues: ${error.message}`);

  if (error.message.includes('label')) {
    throw new Error(
      `Label operation failed. Please check that you have permission to create labels in this team.\n` +
      `Error: ${error.message}`
    );
  }

  throw error;
}

Update parent issue description to include links to created children:

For Epic:

## 🎨 Features

Created from spec breakdown:

- [Feature 1: JWT Auth](https://linear.app/workspace/issue/WORK-101)
- [Feature 2: OAuth Integration](https://linear.app/workspace/issue/WORK-102)
- [Feature 3: MFA Support](https://linear.app/workspace/issue/WORK-103)

For Feature:

## ✅ Implementation Tasks

Created from spec breakdown:

- [Task 1: Database schema](https://linear.app/workspace/issue/WORK-201)
- [Task 2: API endpoints](https://linear.app/workspace/issue/WORK-202)
- [Task 3: Frontend integration](https://linear.app/workspace/issue/WORK-203)
- [Task 4: Testing](https://linear.app/workspace/issue/WORK-204)

**💡 Tip**: Use /ccpm:utils:dependencies to visualize task order

Step 7: Display Results

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Breakdown Complete!
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

🎯 Parent: [$1 - Title]
🔢 Created: [N] [Features/Tasks]

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
📋 Created Items
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✅ WORK-101: JWT Auth (Feature, P0)
✅ WORK-102: OAuth Integration (Feature, P1)
✅ WORK-103: MFA Support (Feature, P2)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
💡 Suggested Next Actions
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Step 8: Interactive Next Actions

{
  questions: [{
    question: "Breakdown complete! What would you like to do next?",
    header: "Next Step",
    multiSelect: false,
    options: [
      // If broke down Epic → Features
      epicMode ? {
        label: "Write Feature Specs",
        description: "Start writing detailed design for first feature"
      } : {
        label: "Start Implementation",
        description: "Begin working on first task (/ccpm:implementation:start)"
      },
      {
        label: "View Dependencies",
        description: "Visualize task dependencies (/ccpm:utils:dependencies)"
      },
      {
        label: "Auto-Assign Agents",
        description: "AI-powered agent assignment (/ccpm:utils:auto-assign)"
      },
      {
        label: "View in Linear",
        description: "Open parent issue in Linear"
      }
    ]
  }]
}

Estimation Conversion

function convertToPoints(timeEstimate) {
  // Convert time estimates to Linear points
  const hours = parseHours(timeEstimate) // "2h" → 2, "1 day" → 8

  if (hours <= 2) return 1   // 1 point = 1-2 hours
  if (hours <= 4) return 2   // 2 points = 2-4 hours
  if (hours <= 8) return 3   // 3 points = 4-8 hours (1 day)
  if (hours <= 16) return 5  // 5 points = 1-2 days
  if (hours <= 40) return 8  // 8 points = 1 week
  return 13                  // 13 points = 2+ weeks
}

function mapPriority(priority) {
  // Linear priority: 1 = Urgent, 2 = High, 3 = Medium, 4 = Low, 0 = No priority
  const mapping = {
    'P0': 1,  // Urgent
    'P1': 2,  // High
    'P2': 3,  // Medium
    'P3': 4   // Low
  }
  return mapping[priority] || 0
}

Dependency Detection

function extractDependencies(taskDescription) {
  // Look for patterns:
  // - "depends on Task 1"
  // - "after Task 2"
  // - "requires Task 3"
  // - "(depends: 1, 2)"

  const patterns = [
    /depends on (?:Task )?(\d+)/gi,
    /after (?:Task )?(\d+)/gi,
    /requires (?:Task )?(\d+)/gi,
    /\(depends: ([\d, ]+)\)/gi
  ]

  const dependencies = []

  for (const pattern of patterns) {
    const matches = taskDescription.matchAll(pattern)
    for (const match of matches) {
      const taskNum = match[1]
      dependencies.push(parseInt(taskNum))
    }
  }

  return [...new Set(dependencies)] // Remove duplicates
}

Notes

  • Epic → Features creates Parent Issues
  • Feature → Tasks creates Sub-Issues
  • All created items link back to spec
  • Dependencies are parsed and preserved
  • Timeline estimates are converted to Linear points
  • Priority mapping follows P0=Urgent, P1=High, etc.
  • Label Handling: Uses shared Linear helpers from _shared-linear-helpers.md
    • Labels are validated/created once before batch issue creation
    • Features get labels: ['feature', 'spec:draft']
    • Tasks get labels: ['task', 'planning']
    • Graceful error handling if label creation fails
    • Automatic label reuse prevents duplicates