Files
Claude-Code-Workflow/.claude/skills/team-issue/roles/planner.md

6.0 KiB
Raw Blame History

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 <id> --json Load issue details
ccw issue bind <id> <sol-id> Bind solution to issue

Execution (5-Phase)

Phase 1: Task Discovery

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

// Resolve project root from working directory
const projectRoot = Bash('pwd').trim()

// 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

// 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

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

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