# Open Feedback Round - Start Async Stakeholder Review
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
Call: mcp__github__get_me()
current_user = response.login
HALT
Which document? Enter key (e.g., "user-auth" for PRD, "2" for Epic):
document_key = response
doc_path = {{docs_dir}}/prd/{{document_key}}.md
document_type = 'prd'
doc_prefix = 'PRD'
doc_label_prefix = 'prd'
doc_path = {{docs_dir}}/epics/epic-{{document_key}}.md
doc_prefix = 'Epic'
doc_label_prefix = 'epic'
Read doc_path
HALT
doc_content = file_content
// Parse document metadata
title = extract_between(doc_content, '# PRD: ', '\n') ||
extract_between(doc_content, '# Epic: ', '\n') ||
document_key
version = extract_field(doc_content, 'Version') || '1'
status = extract_field(doc_content, 'Status') || 'draft'
stakeholders = extract_stakeholders(doc_content)
owner = extract_field(doc_content, 'Product Owner')?.replace('@', '')
Continue anyway? (y/n):
HALT
Days until deadline (default: 5):
days = parseInt(response) || 5
deadline = new Date()
deadline.setDate(deadline.getDate() + days)
deadline_str = deadline.toISOString().split('T')[0]
// Build stakeholder checklist
checklist = stakeholders.map(s =>
`- [ ] @${s.replace('@', '')} - ⏳ Pending feedback`
).join('\n')
// Build issue body
issue_body = `# 📣 ${doc_prefix} Review: ${title} v${version}
**Document Key:** \`${doc_label_prefix}:${document_key}\`
**Version:** ${version}
**Owner:** @${owner || current_user}
**Status:** 🟡 Open for Feedback
---
## 📅 Deadline
**Feedback Due:** ${deadline_str}
---
## 📋 Document Summary
${extract_summary(doc_content)}
---
## 👥 Stakeholder Feedback Status
${checklist}
---
## 📝 How to Provide Feedback
1. Review the document: \`docs/${document_type}/${document_key}.md\`
2. For each piece of feedback, create a new comment or linked issue:
- **Clarification**: Something unclear → \`/feedback clarification\`
- **Concern**: Potential issue → \`/feedback concern\`
- **Suggestion**: Improvement idea → \`/feedback suggestion\`
- **Addition**: Missing requirement → \`/feedback addition\`
Or use the workflow: "Submit feedback on ${doc_label_prefix}:${document_key}"
---
## 🔄 Review Status
- [ ] All stakeholders have provided feedback
- [ ] Feedback synthesized into new version
- [ ] Ready for sign-off
---
_This review round was opened by @${current_user} on ${new Date().toISOString().split('T')[0]}_
`
Call: mcp__github__search_issues({
query: "repo:{{github_owner}}/{{github_repo}} label:type:{{doc_label_prefix}}-review label:{{doc_label_prefix}}:{{document_key}} is:open"
})
Choice:
review_issue = response.items[0]
Goto step 4 (skip issue creation)
Call: mcp__github__issue_write({
method: 'update',
owner: github_owner,
repo: github_repo,
issue_number: response.items[0].number,
state: 'closed',
state_reason: 'not_planned'
})
HALT
labels = [
`type:${doc_label_prefix}-review`,
`${doc_label_prefix}:${document_key}`,
`version:${version}`,
'review-status:open'
]
Call: mcp__github__issue_write({
method: 'create',
owner: "{{github_owner}}",
repo: "{{github_repo}}",
title: "{{doc_prefix}} Review: {{title}} v{{version}}",
body: issue_body,
labels: labels,
assignees: stakeholders.map(s => s.replace('@', ''))
})
review_issue = response
// Update the Status field in the document
updated_content = doc_content
.replace(/\*\*Status:\*\* .+/, '**Status:** Feedback')
.replace(/\| Feedback Deadline \| .+ \|/, `| Feedback Deadline | ${deadline_str} |`)
Write updated_content to doc_path
if (document_type === 'prd') {
cacheManager.writePrd(document_key, updated_content, {
status: 'feedback',
review_issue: review_issue.number,
feedback_deadline: deadline_str
})
} else {
cacheManager.writeEpic(document_key, updated_content, {
status: 'feedback',
review_issue: review_issue.number,
feedback_deadline: deadline_str
})
}
mentions = stakeholders.map(s => `@${s.replace('@', '')}`).join(' ')
notification = `## 📣 Feedback Requested
${mentions}
You have been asked to review this ${doc_prefix}.
**Deadline:** ${deadline_str}
**Document:** \`docs/${document_type}/${document_key}.md\`
Please review and provide your feedback by creating linked feedback issues or comments.
---
**Quick Actions:**
- View document in repo
- Use "Submit feedback" workflow
- Comment directly on this issue
Thank you for your input! 🙏`
Call: mcp__github__add_issue_comment({
owner: "{{github_owner}}",
repo: "{{github_repo}}",
issue_number: review_issue.number,
body: notification
})
## Helper Functions
```javascript
// Extract text between markers
function extract_between(content, start, end) {
const startIdx = content.indexOf(start);
if (startIdx === -1) return null;
const endIdx = content.indexOf(end, startIdx + start.length);
return content.slice(startIdx + start.length, endIdx).trim();
}
// Extract field from markdown table or bold format
function extract_field(content, field) {
// Try bold format: **Field:** value
const boldMatch = content.match(new RegExp(`\\*\\*${field}:\\*\\*\\s*(.+?)(?:\\n|$)`));
if (boldMatch) return boldMatch[1].trim();
// Try table format: | Field | value |
const tableMatch = content.match(new RegExp(`\\|\\s*${field}\\s*\\|\\s*(.+?)\\s*\\|`));
if (tableMatch) return tableMatch[1].trim();
return null;
}
// Extract stakeholders from document
function extract_stakeholders(content) {
const field = extract_field(content, 'Stakeholders');
if (!field) return [];
return field
.split(/[,\s]+/)
.filter(s => s.startsWith('@'))
.map(s => s.replace('@', ''));
}
// Extract summary section from document
function extract_summary(content) {
// Try to get Vision + Problem Statement
const vision = extract_between(content, '## Vision', '##') ||
extract_between(content, '## Vision', '\n---');
const problem = extract_between(content, '## Problem Statement', '##') ||
extract_between(content, '## Problem Statement', '\n---');
if (vision || problem) {
let summary = '';
if (vision) summary += `**Vision:** ${vision.slice(0, 200)}...\n\n`;
if (problem) summary += `**Problem:** ${problem.slice(0, 200)}...`;
return summary;
}
// Fallback: first 500 chars
return content.slice(0, 500) + '...';
}
```
## Natural Language Triggers
This workflow responds to:
- "Open feedback for [prd-key]"
- "Start feedback round for [document]"
- "Request feedback on PRD"
- Menu trigger: `OF`