BMAD-METHOD/src/modules/bmm/workflows/1-requirements/crowdsource/open-epic-feedback/instructions.md

12 KiB
Raw Blame History

Open Epic Feedback - Collect Stakeholder Input on Story Breakdown

The workflow execution engine is governed by: {project-root}/_bmad/core/tasks/workflow.xml You MUST have already loaded and processed: {installed_path}/workflow.yaml

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 💬 OPEN EPIC FEEDBACK ROUND ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Call: mcp__github__get_me() current_user = response.login

GitHub MCP not accessible HALT Call: mcp__github__search_issues({ query: "repo:{{github_owner}}/{{github_repo}} label:type:epic-review label:review-status:draft is:open" })
  <check if="response.items.length == 0">
    <output>

No draft epics found.

Create an epic first with: "Create epic from PRD" HALT

  <action>
    draft_epics = response.items.map(issue => {
      const labels = issue.labels.map(l => l.name)
      return {
        key: labels.find(l => l.startsWith('epic:'))?.replace('epic:', ''),
        title: issue.title.replace(/^Epic Review:\s*/, ''),
        source_prd: labels.find(l => l.startsWith('source-prd:'))?.replace('source-prd:', ''),
        issue_number: issue.number
      }
    }).filter(e => e.key)
  </action>

  <output>

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 📦 DRAFT EPICS AVAILABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

{{#each draft_epics}} [{{@index + 1}}] epic:{{key}} - {{title}} Source: prd:{{source_prd}} | Issue: #{{issue_number}} {{/each}}

  </output>
</substep>

<ask>Select epic (1-{{draft_epics.length}}):</ask>
<action>epic_key = draft_epics[parseInt(response) - 1].key</action>
<action>review_issue_number = draft_epics[parseInt(response) - 1].issue_number</action>
📦 Selected: epic:{{epic_key}} epic_path = `${docs_dir}/epics/epic-${epic_key}.md` Read epic_path Epic document not found: {{epic_path}} HALT

epic_content = file_content title = extract_title(epic_content) version = extract_version(epic_content) stakeholders = extract_stakeholders(epic_content) source_prd = extract_source_prd(epic_content) stories = extract_epic_stories(epic_content)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 📦 EPIC SUMMARY ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Title: {{title}} Version: v{{version}} Source PRD: prd:{{source_prd}} Stories: {{stories.length}} implementation stories Stakeholders: {{stakeholders.length}}

Call: mcp__github__search_issues({ query: "repo:{{github_owner}}/{{github_repo}} label:type:epic-review label:epic:{{epic_key}} is:open" })
<check if="response.items.length == 0">
  <output>❌ No review issue found for epic:{{epic_key}}</output>
  <action>HALT</action>
</check>

<action>review_issue = response.items[0]</action>
<action>review_issue_number = review_issue.number</action>
Call: mcp__github__issue_read({ method: 'get', owner: github_owner, repo: github_repo, issue_number: review_issue_number }) review_issue = response 📋 Review Issue: #{{review_issue_number}} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ⚙️ FEEDBACK ROUND CONFIGURATION ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Epic feedback focuses on:

  • Scope: Is the epic size right? Should it be split/merged?

  • Story Breakdown: Are stories well-defined and independent?

  • Dependencies: Are technical dependencies captured?

  • Priority: Is the story order correct?

  • Technical Risk: Are there architecture concerns?

    Days until feedback deadline (default: {{feedback_days}}): feedback_days = parseInt(response) || feedback_days deadline = new Date() deadline.setDate(deadline.getDate() + feedback_days) deadline_str = deadline.toISOString().split('T')[0]

Deadline: {{deadline_str}} ({{feedback_days}} days from now)

Stakeholders to notify: {{#each stakeholders}} • @{{this}} {{/each}}

Add additional stakeholders? (comma-separated or 'none'): if (response.toLowerCase() !== 'none' && response.trim()) { additional = response.split(',').map(s => s.trim().replace('@', '')) stakeholders = [...new Set([...stakeholders, ...additional])] }

updated_content = epic_content .replace(/\*\*Status:\*\* .+/, '**Status:** Feedback') .replace(/\| Feedback Deadline \| .+ \|/, `| Feedback Deadline | ${deadline_str} |`)

Write updated_content to epic_path

Epic status updated to 'Feedback' // Get current labels current_labels = review_issue.labels.map(l => l.name)
// Update status label
new_labels = current_labels
  .filter(l => !l.startsWith('review-status:'))
  .concat(['review-status:open'])

Call: mcp__github__issue_write({ method: 'update', owner: "{{github_owner}}", repo: "{{github_repo}}", issue_number: review_issue_number, labels: new_labels, assignees: stakeholders })

Review issue updated with stakeholders feedback_comment = `## 💬 Feedback Round Open

${stakeholders.map(s => '@' + s).join(' ')}

Epic: epic:${epic_key} Version: v${version} Deadline: ${deadline_str} Source PRD: prd:${source_prd}


📦 Story Breakdown

{stories.map((s, i) => `{i + 1}. **{s.title}** ({s.complexity || 'TBD'})\n ${s.description || ''}`).join('\n\n')}


Feedback Types for Epics

Please provide feedback on:

  • 🔍 Scope: Is this epic the right size? Should it be split or merged with another?
  • 📝 Story Breakdown: Are stories well-defined, independent, and testable?
  • 🔗 Dependencies: Are technical dependencies correctly identified?
  • Priority: Is the story order optimal for delivery?
  • ⚠️ Technical Risk: Are there architectural or technical concerns?
  • Missing Stories: Should additional stories be added?

How to Submit Feedback

Reply with structured feedback or use the feedback workflow:

``` /feedback epic:${epic_key} Section: [Story Breakdown / Dependencies / Technical Risk / etc.] Type: [scope / dependency / priority / technical_risk / story_split / missing_story] Feedback: [Your detailed feedback] ```

Or simply comment with your thoughts.


Feedback requested by @{current_user} on {new Date().toISOString().split('T')[0]} Please respond by ${deadline_str}`

Call: mcp__github__add_issue_comment({ owner: "{{github_owner}}", repo: "{{github_repo}}", issue_number: review_issue_number, body: feedback_comment })

Feedback request posted ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ EPIC FEEDBACK ROUND OPENED ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Epic: epic:{{epic_key}} Title: {{title}} Review Issue: #{{review_issue_number}} Deadline: {{deadline_str}} Stakeholders: {{stakeholders.length}} notified


All stakeholders have been @mentioned and will receive GitHub notifications.

Monitor progress with:

  • "View feedback for epic:{{epic_key}}"
  • "Epic Dashboard" or [ED]

After collecting feedback:

  • "Synthesize feedback for epic:{{epic_key}}"

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

Helper Functions

function extract_title(content) {
  const match = content.match(/^#\s+(PRD|Epic):\s*(.+)$/m);
  return match ? match[2].trim() : 'Untitled';
}

function extract_version(content) {
  const match = content.match(/\*\*Version:\*\*\s*(\d+)/);
  return match ? match[1] : '1';
}

function extract_source_prd(content) {
  const match = content.match(/\*\*Source PRD:\*\*\s*`?prd:([^`\s]+)`?/);
  return match ? match[1] : null;
}

function extract_stakeholders(content) {
  const field = content.match(/\|\s*Stakeholders\s*\|\s*(.+?)\s*\|/);
  if (!field) return [];

  return field[1]
    .split(/[,\s]+/)
    .filter(s => s.startsWith('@'))
    .map(s => s.replace('@', ''));
}

function extract_epic_stories(content) {
  const stories = [];
  // Match story sections in various formats
  const storyRegex = /###\s+Story\s+\d+:\s*(.+)\n+([\s\S]*?)(?=###|---|\n##|$)/gi;
  let match;
  while ((match = storyRegex.exec(content)) !== null) {
    const title = match[1].trim();
    const body = match[2];

    // Extract complexity
    const complexityMatch = body.match(/\*\*Estimated Complexity:\*\*\s*(\w+)/i);

    // Extract description
    const descMatch = body.match(/\*\*Description:\*\*\s*(.+)/);

    stories.push({
      title: title,
      description: descMatch ? descMatch[1].trim() : '',
      complexity: complexityMatch ? complexityMatch[1] : null
    });
  }
  return stories;
}

Epic-Specific Feedback Types

feedback_types:
  scope_concern:
    label: "Scope"
    description: "Epic is too large/small, should be split/merged"
    emoji: "🔍"

  story_split:
    label: "Story Breakdown"
    description: "Story needs to be split, combined, or redefined"
    emoji: "📝"

  dependency:
    label: "Dependency"
    description: "Missing or incorrect dependency identification"
    emoji: "🔗"

  priority_question:
    label: "Priority"
    description: "Story order or priority should change"
    emoji: "⚡"

  technical_risk:
    label: "Technical Risk"
    description: "Architecture or technical feasibility concern"
    emoji: "⚠️"

  missing_story:
    label: "Missing Story"
    description: "An additional story should be added"
    emoji: ""

Natural Language Triggers

This workflow responds to:

  • "Open feedback for epic"
  • "Start epic feedback round"
  • "Get feedback on epic"
  • Menu trigger: OE