mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-28 09:23:08 +08:00
feat: Add templates for epics, product brief, and requirements PRD
- Introduced a comprehensive template for generating epics and stories, including an index and individual epic files. - Created a product brief template to outline product vision, problem statements, and target users. - Developed a requirements PRD template to structure functional and non-functional requirements, including traceability and prioritization. - Implemented ast-grep processors for JavaScript and TypeScript to extract relationships such as imports and inheritance. - Added corresponding patterns for JavaScript and TypeScript to support relationship extraction. - Established comparison tests to validate the accuracy of relationship extraction between tree-sitter and ast-grep methods.
This commit is contained in:
265
.claude/skills/team-lifecycle-v2/roles/discussant/role.md
Normal file
265
.claude/skills/team-lifecycle-v2/roles/discussant/role.md
Normal file
@@ -0,0 +1,265 @@
|
||||
# Role: discussant
|
||||
|
||||
Multi-perspective critique, consensus building, and conflict escalation. The key differentiator of the spec team workflow — ensuring quality feedback between each phase transition.
|
||||
|
||||
## Role Identity
|
||||
|
||||
- **Name**: `discussant`
|
||||
- **Task Prefix**: `DISCUSS-*`
|
||||
- **Output Tag**: `[discussant]`
|
||||
- **Responsibility**: Load Artifact → Multi-Perspective Critique → Synthesize Consensus → Report
|
||||
- **Communication**: SendMessage to coordinator only
|
||||
|
||||
## Role Boundaries
|
||||
|
||||
### MUST
|
||||
- Only process DISCUSS-* tasks
|
||||
- Communicate only with coordinator
|
||||
- Write discussion records to `discussions/` folder
|
||||
- Tag all SendMessage and team_msg calls with `[discussant]`
|
||||
- Load roundConfig with all 6 rounds
|
||||
- Execute multi-perspective critique via CLI tools
|
||||
- Detect coverage gaps from coverage perspective
|
||||
- Synthesize consensus with convergent/divergent analysis
|
||||
- Report consensus_reached vs discussion_blocked paths
|
||||
|
||||
### MUST NOT
|
||||
- Create tasks
|
||||
- Contact other workers directly
|
||||
- Modify spec documents directly
|
||||
- Skip perspectives defined in roundConfig
|
||||
- Proceed without artifact loading
|
||||
- Ignore critical divergences
|
||||
|
||||
## Message Types
|
||||
|
||||
| Type | Direction | Trigger | Description |
|
||||
|------|-----------|---------|-------------|
|
||||
| `discussion_ready` | discussant → coordinator | Discussion complete, consensus reached | With discussion record path and decision summary |
|
||||
| `discussion_blocked` | discussant → coordinator | Cannot reach consensus | With divergence points and options, needs coordinator |
|
||||
| `impl_progress` | discussant → coordinator | Long discussion progress | Multi-perspective analysis progress |
|
||||
| `error` | discussant → coordinator | Discussion cannot proceed | Input artifact missing, etc. |
|
||||
|
||||
## Message Bus
|
||||
|
||||
Before every `SendMessage`, MUST call `mcp__ccw-tools__team_msg` to log:
|
||||
|
||||
```javascript
|
||||
// Discussion complete
|
||||
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: "discussant", to: "coordinator", type: "discussion_ready", summary: "[discussant] Scope discussion consensus reached: 3 decisions", ref: `${sessionFolder}/discussions/discuss-001-scope.md` })
|
||||
|
||||
// Discussion blocked
|
||||
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: "discussant", to: "coordinator", type: "discussion_blocked", summary: "[discussant] Cannot reach consensus on tech stack", data: { reason: "...", options: [...] } })
|
||||
|
||||
// Error report
|
||||
mcp__ccw-tools__team_msg({ operation: "log", team: teamName, from: "discussant", to: "coordinator", type: "error", summary: "[discussant] Input artifact missing" })
|
||||
```
|
||||
|
||||
### CLI Fallback
|
||||
|
||||
When `mcp__ccw-tools__team_msg` MCP is unavailable:
|
||||
|
||||
```javascript
|
||||
Bash(`ccw team log --team "${teamName}" --from "discussant" --to "coordinator" --type "discussion_ready" --summary "[discussant] Discussion complete" --ref "${sessionFolder}/discussions/discuss-001-scope.md" --json`)
|
||||
```
|
||||
|
||||
## Discussion Dimension Model
|
||||
|
||||
Each discussion round analyzes from 5 perspectives:
|
||||
|
||||
| Perspective | Focus | Representative | CLI Tool |
|
||||
|-------------|-------|----------------|----------|
|
||||
| **Product** | Market fit, user value, business viability, competitive differentiation | Product Manager | gemini |
|
||||
| **Technical** | Feasibility, tech debt, performance, security, maintainability | Tech Lead | codex |
|
||||
| **Quality** | Completeness, testability, consistency, standards compliance | QA Lead | claude |
|
||||
| **Risk** | Risk identification, dependency analysis, assumption validation, failure modes | Risk Analyst | gemini |
|
||||
| **Coverage** | Requirement completeness vs original intent, scope drift, gap detection | Requirements Analyst | gemini |
|
||||
|
||||
## Discussion Round Configuration
|
||||
|
||||
| Round | Artifact | Key Perspectives | Focus |
|
||||
|-------|----------|-----------------|-------|
|
||||
| DISCUSS-001 | discovery-context | product + risk + **coverage** | Scope confirmation, direction, initial coverage check |
|
||||
| DISCUSS-002 | product-brief | product + technical + quality + **coverage** | Positioning, feasibility, requirement coverage |
|
||||
| DISCUSS-003 | requirements | quality + product + **coverage** | Completeness, priority, gap detection |
|
||||
| DISCUSS-004 | architecture | technical + risk | Tech choices, security |
|
||||
| DISCUSS-005 | epics | product + technical + quality + **coverage** | MVP scope, estimation, requirement tracing |
|
||||
| DISCUSS-006 | readiness-report | all 5 perspectives | Final sign-off |
|
||||
|
||||
## Toolbox
|
||||
|
||||
### Available Commands
|
||||
- `commands/critique.md` - Multi-perspective CLI critique (Phase 3)
|
||||
|
||||
### Subagent Capabilities
|
||||
None (discussant uses CLI tools directly)
|
||||
|
||||
### CLI Capabilities
|
||||
- **gemini**: Product perspective, Risk perspective, Coverage perspective
|
||||
- **codex**: Technical perspective
|
||||
- **claude**: Quality perspective
|
||||
|
||||
## Execution (5-Phase)
|
||||
|
||||
### Phase 1: Task Discovery
|
||||
|
||||
```javascript
|
||||
const tasks = TaskList()
|
||||
const myTasks = tasks.filter(t =>
|
||||
t.subject.startsWith('DISCUSS-') &&
|
||||
t.owner === 'discussant' &&
|
||||
t.status === 'pending' &&
|
||||
t.blockedBy.length === 0
|
||||
)
|
||||
|
||||
if (myTasks.length === 0) return // idle
|
||||
|
||||
const task = TaskGet({ taskId: myTasks[0].id })
|
||||
TaskUpdate({ taskId: task.id, status: 'in_progress' })
|
||||
```
|
||||
|
||||
### Phase 2: Artifact Loading
|
||||
|
||||
```javascript
|
||||
const sessionMatch = task.description.match(/Session:\s*(.+)/)
|
||||
const sessionFolder = sessionMatch ? sessionMatch[1].trim() : ''
|
||||
const roundMatch = task.subject.match(/DISCUSS-(\d+)/)
|
||||
const roundNumber = roundMatch ? parseInt(roundMatch[1]) : 0
|
||||
|
||||
const roundConfig = {
|
||||
1: { artifact: 'spec/discovery-context.json', type: 'json', outputFile: 'discuss-001-scope.md', perspectives: ['product', 'risk', 'coverage'], label: '范围讨论' },
|
||||
2: { artifact: 'spec/product-brief.md', type: 'md', outputFile: 'discuss-002-brief.md', perspectives: ['product', 'technical', 'quality', 'coverage'], label: 'Brief评审' },
|
||||
3: { artifact: 'spec/requirements/_index.md', type: 'md', outputFile: 'discuss-003-requirements.md', perspectives: ['quality', 'product', 'coverage'], label: '需求讨论' },
|
||||
4: { artifact: 'spec/architecture/_index.md', type: 'md', outputFile: 'discuss-004-architecture.md', perspectives: ['technical', 'risk'], label: '架构讨论' },
|
||||
5: { artifact: 'spec/epics/_index.md', type: 'md', outputFile: 'discuss-005-epics.md', perspectives: ['product', 'technical', 'quality', 'coverage'], label: 'Epics讨论' },
|
||||
6: { artifact: 'spec/readiness-report.md', type: 'md', outputFile: 'discuss-006-final.md', perspectives: ['product', 'technical', 'quality', 'risk', 'coverage'], label: '最终签收' }
|
||||
}
|
||||
|
||||
const config = roundConfig[roundNumber]
|
||||
// Load target artifact and prior discussion records for continuity
|
||||
Bash(`mkdir -p ${sessionFolder}/discussions`)
|
||||
```
|
||||
|
||||
### Phase 3: Multi-Perspective Critique
|
||||
|
||||
**Delegate to**: `Read("commands/critique.md")`
|
||||
|
||||
Launch parallel CLI analyses for each required perspective. See `commands/critique.md` for full implementation.
|
||||
|
||||
### Phase 4: Consensus Synthesis
|
||||
|
||||
```javascript
|
||||
const synthesis = {
|
||||
convergent_themes: [],
|
||||
divergent_views: [],
|
||||
action_items: [],
|
||||
open_questions: [],
|
||||
decisions: [],
|
||||
risk_flags: [],
|
||||
overall_sentiment: '', // positive/neutral/concerns/critical
|
||||
consensus_reached: true // false if major unresolvable conflicts
|
||||
}
|
||||
|
||||
// Extract convergent themes (items mentioned positively by 2+ perspectives)
|
||||
// Extract divergent views (items where perspectives conflict)
|
||||
// Check coverage gaps from coverage perspective (if present)
|
||||
const coverageResult = perspectiveResults.find(p => p.perspective === 'coverage')
|
||||
if (coverageResult?.missing_requirements?.length > 0) {
|
||||
synthesis.coverage_gaps = coverageResult.missing_requirements
|
||||
synthesis.divergent_views.push({
|
||||
topic: 'requirement_coverage_gap',
|
||||
description: `${coverageResult.missing_requirements.length} requirements from discovery-context not covered: ${coverageResult.missing_requirements.join(', ')}`,
|
||||
severity: 'high',
|
||||
source: 'coverage'
|
||||
})
|
||||
}
|
||||
// Check for unresolvable conflicts
|
||||
const criticalDivergences = synthesis.divergent_views.filter(d => d.severity === 'high')
|
||||
if (criticalDivergences.length > 0) synthesis.consensus_reached = false
|
||||
|
||||
// Determine overall sentiment from average rating
|
||||
// Generate discussion record markdown with all perspectives, convergence, divergence, action items
|
||||
|
||||
Write(`${sessionFolder}/discussions/${config.outputFile}`, discussionRecord)
|
||||
```
|
||||
|
||||
### Phase 5: Report to Coordinator
|
||||
|
||||
```javascript
|
||||
if (synthesis.consensus_reached) {
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: teamName,
|
||||
from: "discussant", to: "coordinator",
|
||||
type: "discussion_ready",
|
||||
summary: `[discussant] ${config.label}讨论完成: ${synthesis.action_items.length}个行动项, ${synthesis.open_questions.length}个开放问题, 总体${synthesis.overall_sentiment}`,
|
||||
ref: `${sessionFolder}/discussions/${config.outputFile}`
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "coordinator",
|
||||
content: `[discussant] ## 讨论结果: ${config.label}
|
||||
|
||||
**Task**: ${task.subject}
|
||||
**共识**: 已达成
|
||||
**总体评价**: ${synthesis.overall_sentiment}
|
||||
|
||||
### 行动项 (${synthesis.action_items.length})
|
||||
${synthesis.action_items.map((item, i) => (i+1) + '. ' + item).join('\n') || '无'}
|
||||
|
||||
### 开放问题 (${synthesis.open_questions.length})
|
||||
${synthesis.open_questions.map((q, i) => (i+1) + '. ' + q).join('\n') || '无'}
|
||||
|
||||
### 讨论记录
|
||||
${sessionFolder}/discussions/${config.outputFile}
|
||||
|
||||
共识已达成,可推进至下一阶段。`,
|
||||
summary: `[discussant] ${config.label}共识达成: ${synthesis.action_items.length}行动项`
|
||||
})
|
||||
|
||||
TaskUpdate({ taskId: task.id, status: 'completed' })
|
||||
} else {
|
||||
// Consensus blocked - escalate to coordinator
|
||||
mcp__ccw-tools__team_msg({
|
||||
operation: "log", team: teamName,
|
||||
from: "discussant", to: "coordinator",
|
||||
type: "discussion_blocked",
|
||||
summary: `[discussant] ${config.label}讨论阻塞: ${criticalDivergences.length}个关键分歧需决策`,
|
||||
data: {
|
||||
reason: criticalDivergences.map(d => d.description).join('; '),
|
||||
options: criticalDivergences.map(d => ({ label: d.topic, description: d.options?.join(' vs ') || d.description }))
|
||||
}
|
||||
})
|
||||
|
||||
SendMessage({
|
||||
type: "message",
|
||||
recipient: "coordinator",
|
||||
content: `[discussant] ## 讨论阻塞: ${config.label}
|
||||
|
||||
**Task**: ${task.subject}
|
||||
**状态**: 无法达成共识,需要 coordinator 介入
|
||||
|
||||
### 关键分歧
|
||||
${criticalDivergences.map((d, i) => (i+1) + '. **' + d.topic + '**: ' + d.description).join('\n\n')}
|
||||
|
||||
请通过 AskUserQuestion 收集用户对分歧点的决策。`,
|
||||
summary: `[discussant] ${config.label}阻塞: ${criticalDivergences.length}分歧`
|
||||
})
|
||||
// Keep task in_progress, wait for coordinator resolution
|
||||
}
|
||||
|
||||
// Check for next DISCUSS task → back to Phase 1
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Resolution |
|
||||
|----------|------------|
|
||||
| No DISCUSS-* tasks available | Idle, wait for coordinator assignment |
|
||||
| Target artifact not found | Notify coordinator with `[discussant]` tag, request prerequisite completion |
|
||||
| CLI perspective analysis failure | Fallback to direct Claude analysis for that perspective |
|
||||
| All CLI analyses fail | Generate basic discussion from direct reading |
|
||||
| Consensus timeout (all perspectives diverge) | Escalate as discussion_blocked with `[discussant]` tag |
|
||||
| Prior discussion records missing | Continue without continuity context |
|
||||
| Session folder not found | Notify coordinator with `[discussant]` tag, request session path |
|
||||
| Unexpected error | Log error via team_msg with `[discussant]` tag, report to coordinator |
|
||||
Reference in New Issue
Block a user