12 KiB
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
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 🔔 OPEN FEEDBACK ROUND ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━Call: mcp__github__get_me() current_user = response.login
❌ GitHub MCP not accessible - required for coordination 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 ❌ Document not found: {{doc_path}}Please ensure the {{document_type}} exists. Use:
-
"Create PRD" (CP) to create a new PRD
-
Check that the key is correct 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('@', '')
⚠️ This {{document_type}} is currently in status: {{status}}
Feedback rounds can only be opened for documents in 'draft' or 'feedback' status. Current status suggests this may already be in synthesis or sign-off. Continue anyway? (y/n): HALT
📄 Document: {{title}} 📌 Key: {{doc_label_prefix}}:{{document_key}} 📊 Version: {{version}} 👥 Stakeholders: {{stakeholders.length}} ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 📅 FEEDBACK DEADLINE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━How long should stakeholders have to provide feedback?
Days until deadline (default: 5): days = parseInt(response) || 5 deadline = new Date() deadline.setDate(deadline.getDate() + days) deadline_str = deadline.toISOString().split('T')[0]
Deadline: {{deadline_str}} ({{days}} days from now) // 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
- Review the document: `docs/
{document_type}/{document_key}.md` - 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]}
`
<check if="response.items.length > 0">
<output>
⚠️ An open review round already exists for this document: Issue #{{response.items[0].number}}: {{response.items[0].title}}
Would you like to: [1] Use existing review issue [2] Close old and create new [3] Cancel 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' ]<action>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('@', ''))
})</action>
<action>review_issue = response</action>
<output>
✅ Review issue created: #{{review_issue.number}} {{review_issue.html_url}}
// 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 }) } ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 📨 STAKEHOLDER NOTIFICATION ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 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! 🙏`
<action>Call: mcp__github__add_issue_comment({
owner: "{{github_owner}}",
repo: "{{github_repo}}",
issue_number: review_issue.number,
body: notification
})</action>
✅ Stakeholders notified via GitHub @mentions
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ FEEDBACK ROUND OPENED
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Document: {{title}} v{{version}} Review Issue: #{{review_issue.number}} Deadline: {{deadline_str}} Stakeholders Notified: {{stakeholders.length}}
The following stakeholders have been notified: {{stakeholders.map(s => ' • @' + s.replace('@', '')).join('\n')}}
Next Steps:
- Stakeholders submit feedback via GitHub
- Monitor progress with: "View feedback for {{doc_label_prefix}}:{{document_key}}"
- When ready, synthesize with: "Synthesize feedback for {{doc_label_prefix}}:{{document_key}}"
Quick Commands:
- [VF] View Feedback
- [SZ] Synthesize Feedback
- [PD] PRD Dashboard / [ED] Epic Dashboard
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Helper Functions
// 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