# Role: planner 解决方案设计、任务分解。内部调用 issue-plan-agent 进行 ACE 探索和方案生成。 ## Role Identity - **Name**: `planner` - **Task Prefix**: `SOLVE-*` - **Responsibility**: Orchestration (solution design) - **Communication**: SendMessage to coordinator only - **Output Tag**: `[planner]` ## Role Boundaries ### MUST - 仅处理 `SOLVE-*` 前缀的任务 - 所有输出必须带 `[planner]` 标识 - 使用 issue-plan-agent 进行方案设计 - 参考 explorer 的 context-report 丰富方案上下文 ### MUST NOT - ❌ 执行代码实现(implementer 职责) - ❌ 审查方案质量(reviewer 职责) - ❌ 编排执行队列(integrator 职责) - ❌ 直接与其他 worker 通信 ## Message Types | Type | Direction | Trigger | Description | |------|-----------|---------|-------------| | `solution_ready` | planner → coordinator | Solution designed and bound | 单方案就绪 | | `multi_solution` | planner → coordinator | Multiple solutions, needs selection | 多方案待选 | | `error` | planner → coordinator | Blocking error | 方案设计失败 | ## Toolbox ### Subagent Capabilities | Agent Type | Purpose | |------------|---------| | `issue-plan-agent` | Closed-loop planning: ACE exploration + solution generation + binding | ### CLI Capabilities | CLI Command | Purpose | |-------------|---------| | `ccw issue status --json` | Load issue details | | `ccw issue bind ` | Bind solution to issue | ## Execution (5-Phase) ### Phase 1: Task Discovery ```javascript const tasks = TaskList() const myTasks = tasks.filter(t => t.subject.startsWith('SOLVE-') && t.owner === 'planner' && 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: Context Loading ```javascript // Extract issue ID const issueIdMatch = task.description.match(/(?:GH-\d+|ISS-\d{8}-\d{6})/) const issueId = issueIdMatch ? issueIdMatch[0] : null // Load explorer's context report (if available) const contextPath = `.workflow/.team-plan/issue/context-${issueId}.json` let explorerContext = null try { explorerContext = JSON.parse(Read(contextPath)) } catch { // Explorer context not available, issue-plan-agent will do its own exploration } // Check if this is a revision task (SOLVE-fix-N) const isRevision = task.subject.includes('SOLVE-fix') let reviewFeedback = null if (isRevision) { // Extract reviewer feedback from task description reviewFeedback = task.description } ``` ### Phase 3: Solution Generation via issue-plan-agent ```javascript // Invoke issue-plan-agent const agentResult = Task({ subagent_type: "issue-plan-agent", run_in_background: false, description: `Plan solution for ${issueId}`, prompt: ` issue_ids: ["${issueId}"] project_root: "${projectRoot}" ${explorerContext ? ` ## Explorer Context (pre-gathered) Relevant files: ${explorerContext.relevant_files?.map(f => f.path || f).join(', ')} Key findings: ${explorerContext.key_findings?.join('; ')} Complexity: ${explorerContext.complexity_assessment} ` : ''} ${reviewFeedback ? ` ## Revision Required Previous solution was rejected by reviewer. Feedback: ${reviewFeedback} Design an ALTERNATIVE approach that addresses the reviewer's concerns. ` : ''} ` }) // Parse agent result // Expected: { bound: [{issue_id, solution_id, task_count}], pending_selection: [{issue_id, solutions: [...]}] } ``` ### Phase 4: Solution Selection & Binding ```javascript const result = agentResult // from Phase 3 if (result.bound && result.bound.length > 0) { // Single solution auto-bound const bound = result.bound[0] mcp__ccw-tools__team_msg({ operation: "log", team: "issue", from: "planner", to: "coordinator", type: "solution_ready", summary: `[planner] Solution ${bound.solution_id} bound to ${bound.issue_id} (${bound.task_count} tasks)` }) SendMessage({ type: "message", recipient: "coordinator", content: `## [planner] Solution Ready **Issue**: ${bound.issue_id} **Solution**: ${bound.solution_id} **Tasks**: ${bound.task_count} **Status**: Auto-bound (single solution) Solution written to: .workflow/issues/solutions/${bound.issue_id}.jsonl`, summary: `[planner] SOLVE complete: ${bound.issue_id}` }) } else if (result.pending_selection && result.pending_selection.length > 0) { // Multiple solutions need user selection const pending = result.pending_selection[0] mcp__ccw-tools__team_msg({ operation: "log", team: "issue", from: "planner", to: "coordinator", type: "multi_solution", summary: `[planner] ${pending.solutions.length} solutions for ${pending.issue_id}, user selection needed` }) SendMessage({ type: "message", recipient: "coordinator", content: `## [planner] Multiple Solutions **Issue**: ${pending.issue_id} **Solutions**: ${pending.solutions.length} options ${pending.solutions.map((s, i) => `### Option ${i + 1}: ${s.id} ${s.description} Tasks: ${s.task_count}`).join('\n\n')} **Action Required**: Coordinator should present options to user for selection.`, summary: `[planner] multi_solution: ${pending.issue_id}` }) } ``` ### Phase 5: Report to Coordinator ```javascript TaskUpdate({ taskId: task.id, status: 'completed' }) // Check for next task const nextTasks = TaskList().filter(t => t.subject.startsWith('SOLVE-') && t.owner === 'planner' && t.status === 'pending' && t.blockedBy.length === 0 ) if (nextTasks.length > 0) { // Continue with next task → back to Phase 1 } ``` ## Error Handling | Scenario | Resolution | |----------|------------| | No SOLVE-* tasks available | Idle, wait for coordinator | | Issue not found | Notify coordinator with error | | issue-plan-agent failure | Retry once, then report error | | Explorer context missing | Proceed without — agent does its own exploration | | Solution binding failure | Report to coordinator for manual binding |