Files
Claude-Code-Workflow/.claude/skills/team-skill-designer/phases/03-skill-generation.md
catlog22 a512564b5a Add integration verification and validation phases, role templates, and static graph tests
- Implement Phase 4: Integration Verification to ensure skill package consistency.
- Implement Phase 5: Validation to verify quality and deliver the final skill package.
- Create role-template.md for generating per-role execution detail files.
- Create skill-router-template.md for generating SKILL.md with role-based routing.
- Add tests for static graph relationship writing during index build in test_static_graph_integration.py.
2026-02-13 12:35:31 +08:00

19 KiB

Phase 3: Skill Package Generation

Generate the unified team skill package: SKILL.md (role router) + roles/*.md (per-role execution).

Objective

  • Generate SKILL.md with role router and shared infrastructure
  • Generate roles/coordinator.md
  • Generate roles/{worker-role}.md for each worker role
  • Generate specs/team-config.json
  • All files written to preview directory first

Input

  • Dependency: team-config.json (Phase 1), pattern-analysis.json (Phase 2)
  • Templates: templates/skill-router-template.md, templates/role-template.md
  • Reference: existing team commands (read in Phase 0)

Execution Steps

Step 1: Load Inputs

const config = JSON.parse(Read(`${workDir}/team-config.json`))
const analysis = JSON.parse(Read(`${workDir}/pattern-analysis.json`))
const routerTemplate = Read(`${skillDir}/templates/skill-router-template.md`)
const roleTemplate = Read(`${skillDir}/templates/role-template.md`)

// Create preview directory
const previewDir = `${workDir}/preview`
Bash(`mkdir -p "${previewDir}/roles" "${previewDir}/specs"`)

Step 2: Generate SKILL.md (Role Router)

This is the unified entry point. All roles invoke this skill with --role=xxx.

const rolesTable = config.roles.map(r =>
  `| \`${r.name}\` | ${r.task_prefix || 'N/A'} | ${r.description} | [roles/${r.name}.md](roles/${r.name}.md) |`
).join('\n')

const roleDispatchEntries = config.roles.map(r =>
  `  "${r.name}": { file: "roles/${r.name}.md", prefix: "${r.task_prefix || 'N/A'}" }`
).join(',\n')

const messageBusTable = config.worker_roles.map(r =>
  `| ${r.name} | ${r.message_types.map(mt => '\`' + mt.type + '\`').join(', ')} |`
).join('\n')

const spawnBlocks = config.worker_roles.map(r => `
// ${r.display_name}
Task({
  subagent_type: "general-purpose",
  team_name: teamName,
  name: "${r.name}",
  prompt: \`你是 team "\${teamName}" 的 ${r.name_upper}
当你收到 ${r.task_prefix}-* 任务时,调用 Skill(skill="${config.skill_name}", args="--role=${r.name}") 执行。

当前需求: \${taskDescription}
约束: \${constraints}

## 消息总线(必须)
每次 SendMessage 前,先调用 mcp__ccw-tools__team_msg 记录:
mcp__ccw-tools__team_msg({ operation: "log", team: "\${teamName}", from: "${r.name}", to: "coordinator", type: "<type>", summary: "<摘要>" })

工作流程:
1. TaskList → 找到 ${r.task_prefix}-* 任务
2. Skill(skill="${config.skill_name}", args="--role=${r.name}") 执行
3. team_msg log + SendMessage 结果给 coordinator
4. TaskUpdate completed → 检查下一个任务\`
})`).join('\n')

const skillMd = `---
name: ${config.skill_name}
description: Unified team skill for ${config.team_name} team. All roles invoke this skill with --role arg. Triggers on "team ${config.team_name}".
allowed-tools: ${config.all_roles_tools_union}
---

# Team ${config.team_display_name}

Unified team skill. All team members invoke this skill with \`--role=xxx\` for role-specific execution.

## Architecture Overview

\`\`\`
┌───────────────────────────────────────────┐
│  Skill(skill="${config.skill_name}")       │
│  args="--role=xxx"                        │
└───────────────┬───────────────────────────┘
                │ Role Router
    ┌───────────┼${'───────────┬'.repeat(Math.min(config.roles.length - 1, 3))}
    ${config.roles.map(r => `↓           `).join('').trim()}
${config.roles.map(r => `┌──────────┐ `).join('').trim()}
${config.roles.map(r => `│${r.name.padEnd(10)}│ `).join('').trim()}
${config.roles.map(r => `│ roles/   │ `).join('').trim()}
${config.roles.map(r => `└──────────┘ `).join('').trim()}
\`\`\`

## Role Router

### Input Parsing

Parse \`$ARGUMENTS\` to extract \`--role\`:

\`\`\`javascript
const args = "$ARGUMENTS"
const roleMatch = args.match(/--role[=\\s]+(\\w+)/)

if (!roleMatch) {
  throw new Error("Missing --role argument. Available roles: ${config.role_list}")
}

const role = roleMatch[1]
const teamName = "${config.team_name}"
\`\`\`

### Role Dispatch

\`\`\`javascript
const VALID_ROLES = {
${roleDispatchEntries}
}

if (!VALID_ROLES[role]) {
  throw new Error(\\\`Unknown role: \\\${role}. Available: \\\${Object.keys(VALID_ROLES).join(', ')}\\\`)
}

// Read and execute role-specific logic
Read(VALID_ROLES[role].file)
// → Execute the 5-phase process defined in that file
\`\`\`

### Available Roles

| Role | Task Prefix | Responsibility | Role File |
|------|-------------|----------------|-----------|
${rolesTable}

## Shared Infrastructure

### Team Configuration

\`\`\`javascript
const TEAM_CONFIG = {
  name: "${config.team_name}",
  sessionDir: ".workflow/.team-plan/${config.team_name}/",
  msgDir: ".workflow/.team-msg/${config.team_name}/"
}
\`\`\`

### Message Bus (All Roles)

Every SendMessage **before**, must call \`mcp__ccw-tools__team_msg\`:

\`\`\`javascript
mcp__ccw-tools__team_msg({
  operation: "log",
  team: "${config.team_name}",
  from: role,
  to: "coordinator",
  type: "<type>",
  summary: "<summary>"
})
\`\`\`

**Message types by role**:

| Role | Types |
|------|-------|
${messageBusTable}

### CLI 回退

\`\`\`javascript
Bash(\\\`ccw team log --team "${config.team_name}" --from "\\\${role}" --to "coordinator" --type "<type>" --summary "<摘要>" --json\\\`)
\`\`\`

### Task Lifecycle (All Roles)

\`\`\`javascript
// Phase 1: Discovery
const tasks = TaskList()
const myTasks = tasks.filter(t =>
  t.subject.startsWith(\\\`\\\${VALID_ROLES[role].prefix}-\\\`) &&
  t.owner === role &&
  t.status === 'pending' &&
  t.blockedBy.length === 0
)
if (myTasks.length === 0) return
const task = TaskGet({ taskId: myTasks[0].id })
TaskUpdate({ taskId: task.id, status: 'in_progress' })

// Phase 2-4: Role-specific (see roles/{role}.md)

// Phase 5: Report + Loop
TaskUpdate({ taskId: task.id, status: 'completed' })
\`\`\`

## Pipeline

\`\`\`
${config.pipeline.diagram}
\`\`\`

## Coordinator Spawn Template

\`\`\`javascript
TeamCreate({ team_name: "${config.team_name}" })
${spawnBlocks}
\`\`\`

## Error Handling

| Scenario | Resolution |
|----------|------------|
| Unknown --role value | Error with available role list |
| Missing --role arg | Error with usage hint |
| Role file not found | Error with expected path |
`

Write(`${previewDir}/SKILL.md`, skillMd)

Step 3: Generate Coordinator Role File

const taskChainCode = config.pipeline.stages.map((stage, i) => {
  const blockedByIds = stage.blockedBy.map(dep => {
    const depIdx = config.pipeline.stages.findIndex(s => s.name === dep)
    return `\${task${depIdx}Id}`
  })

  return `TaskCreate({ subject: "${stage.name}-001: ${stage.role} work", description: \`\${taskDescription}\`, activeForm: "${stage.name}进行中" })
TaskUpdate({ taskId: task${i}Id, owner: "${stage.role}"${blockedByIds.length > 0 ? `, addBlockedBy: [${blockedByIds.join(', ')}]` : ''} })`
}).join('\n\n')

const coordinationHandlers = config.worker_roles.map(r => {
  const resultType = r.message_types.find(mt => !mt.type.includes('error') && !mt.type.includes('progress'))
  return `| ${r.name_upper}: ${resultType?.trigger || 'work complete'} | team_msg log → TaskUpdate ${r.task_prefix} completed → check next |`
}).join('\n')

const coordinatorMd = `# Role: coordinator

Team coordinator. Orchestrates pipeline: requirement clarification → team creation → task chain → dispatch → monitoring → reporting.

## Role Identity

- **Name**: \`coordinator\`
- **Task Prefix**: N/A (creates tasks, doesn't receive them)
- **Responsibility**: Orchestration
- **Communication**: SendMessage to all teammates

## Message Types

| Type | Direction | Trigger |
|------|-----------|---------|
| \`plan_approved\` | coordinator → planner | Plan approved |
| \`plan_revision\` | coordinator → planner | Revision requested |
| \`task_unblocked\` | coordinator → worker | Task dependency met |
| \`shutdown\` | coordinator → all | Team shutdown |
| \`error\` | coordinator → user | Coordination error |

## Execution

### Phase 1: Requirement Clarification

Parse \`$ARGUMENTS\` for task description. Use AskUserQuestion for:
- MVP scope (minimal / full / comprehensive)
- Key constraints (backward compatible / follow patterns / test coverage)

Simple tasks can skip clarification.

### Phase 2: Create Team + Spawn Teammates

\`\`\`javascript
TeamCreate({ team_name: "${config.team_name}" })

${spawnBlocks}
\`\`\`

### Phase 3: Create Task Chain

\`\`\`javascript
${taskChainCode}
\`\`\`

### Phase 4: Coordination Loop

Receive teammate messages, dispatch based on content.
**Before each decision**: \`team_msg list\` to check recent messages.
**After each decision**: \`team_msg log\` to record.

| Received Message | Action |
|-----------------|--------|
${coordinationHandlers}
| Worker: error | Assess severity → retry or escalate to user |
| All tasks completed | → Phase 5 |

### Phase 5: Report + Persist

Summarize changes, test results, review findings.

\`\`\`javascript
AskUserQuestion({
  questions: [{
    question: "当前需求已完成。下一步:",
    header: "Next",
    multiSelect: false,
    options: [
      { label: "新需求", description: "提交新需求给当前团队" },
      { label: "关闭团队", description: "关闭所有 teammate 并清理" }
    ]
  }]
})
// 新需求 → 回到 Phase 1
// 关闭 → shutdown → TeamDelete()
\`\`\`

## Error Handling

| Scenario | Resolution |
|----------|------------|
| Teammate unresponsive | Send follow-up, 2x → respawn |
| Plan rejected 3+ times | Coordinator self-plans |
| Test stuck >5 iterations | Escalate to user |
| Review finds critical | Create fix task for executor |
`

Write(`${previewDir}/roles/coordinator.md`, coordinatorMd)

Step 4: Generate Worker Role Files

For each worker role, generate a complete role file with 5-phase execution.

for (const role of config.worker_roles) {
  const ra = analysis.role_analysis.find(r => r.role_name === role.name)

  // Phase 2 content based on responsibility type
  const phase2Content = {
    "Read-only analysis": `\`\`\`javascript
// Load plan for criteria reference
const planPathMatch = task.description.match(/\\.workflow\\/\\.team-plan\\/[^\\s]+\\/plan\\.json/)
let plan = null
if (planPathMatch) {
  try { plan = JSON.parse(Read(planPathMatch[0])) } catch {}
}

// Get changed files
const changedFiles = Bash(\`git diff --name-only HEAD~1 2>/dev/null || git diff --name-only --cached\`)
  .split('\\n').filter(Boolean)

// Read file contents for analysis
const fileContents = {}
for (const file of changedFiles.slice(0, 20)) {
  try { fileContents[file] = Read(file) } catch {}
}
\`\`\``,

    "Code generation": `\`\`\`javascript
// Extract plan path from task description
const planPathMatch = task.description.match(/\\.workflow\\/\\.team-plan\\/[^\\s]+\\/plan\\.json/)
if (!planPathMatch) {
  mcp__ccw-tools__team_msg({ operation: "log", team: "${config.team_name}", from: "${role.name}", to: "coordinator", type: "error", summary: "plan.json路径无效" })
  SendMessage({ type: "message", recipient: "coordinator", content: \`Cannot find plan.json in \${task.subject}\`, summary: "Plan not found" })
  return
}

const plan = JSON.parse(Read(planPathMatch[0]))
const planTasks = plan.task_ids.map(id =>
  JSON.parse(Read(\`\${planPathMatch[0].replace('plan.json', '')}.task/\${id}.json\`))
)
\`\`\``,

    "Orchestration": `\`\`\`javascript
function assessComplexity(desc) {
  let score = 0
  if (/refactor|architect|restructure|module|system/.test(desc)) score += 2
  if (/multiple|across|cross/.test(desc)) score += 2
  if (/integrate|api|database/.test(desc)) score += 1
  if (/security|performance/.test(desc)) score += 1
  return score >= 4 ? 'High' : score >= 2 ? 'Medium' : 'Low'
}

const complexity = assessComplexity(task.description)
\`\`\``,

    "Validation": `\`\`\`javascript
// Detect changed files for validation scope
const changedFiles = Bash(\`git diff --name-only HEAD~1 2>/dev/null || git diff --name-only --cached\`)
  .split('\\n').filter(Boolean)
\`\`\``
  }

  // Phase 3 content based on responsibility type
  const phase3Content = {
    "Read-only analysis": `\`\`\`javascript
// Core analysis logic
// Reference: .claude/commands/team/${ra.similar_to.primary}.md Phase 3

// Analyze each file
for (const [file, content] of Object.entries(fileContents)) {
  // Domain-specific analysis
}
\`\`\``,

    "Code generation": `\`\`\`javascript
// Reference: .claude/commands/team/${ra.similar_to.primary}.md Phase 3

${role.adaptive_routing ? `// Complexity-adaptive execution
if (planTasks.length <= 2) {
  // Direct file editing
  for (const pt of planTasks) {
    for (const f of (pt.files || [])) {
      const content = Read(f.path)
      Edit({ file_path: f.path, old_string: "...", new_string: "..." })
    }
  }
} else {
  // Delegate to code-developer sub-agent
  Task({
    subagent_type: "code-developer",
    run_in_background: false,
    description: \`Implement \${planTasks.length} tasks\`,
    prompt: \`## Goal
\${plan.summary}

## Tasks
\${planTasks.map(t => \`### \${t.title}\\n\${t.description}\`).join('\\n\\n')}

Complete each task according to its convergence criteria.\`
  })
}` : `// Direct execution
for (const pt of planTasks) {
  for (const f of (pt.files || [])) {
    const content = Read(f.path)
    Edit({ file_path: f.path, old_string: "...", new_string: "..." })
  }
}`}
\`\`\``,

    "Orchestration": `\`\`\`javascript
// Reference: .claude/commands/team/${ra.similar_to.primary}.md Phase 3

${role.adaptive_routing ? `if (complexity === 'Low') {
  // Direct execution with mcp__ace-tool__search_context + Grep/Glob
} else {
  // Launch sub-agents for complex work
  Task({
    subagent_type: "universal-executor",
    run_in_background: false,
    description: "${role.name} orchestration",
    prompt: \`Execute ${role.name} work for: \${task.description}\`
  })
}` : `// Direct orchestration`}
\`\`\``,

    "Validation": `\`\`\`javascript
// Reference: .claude/commands/team/${ra.similar_to.primary}.md Phase 3

let iteration = 0
const MAX_ITERATIONS = 5
while (iteration < MAX_ITERATIONS) {
  // Run validation
  const result = Bash(\`npm test 2>&1 || true\`)
  const passed = !result.includes('FAIL')

  if (passed) break

  // Attempt fix
  iteration++
  if (iteration < MAX_ITERATIONS) {
    // Auto-fix or delegate
  }
}
\`\`\``
  }

  // Phase 4 content
  const phase4Content = {
    "Read-only analysis": `\`\`\`javascript
// Classify findings by severity
const findings = { critical: [], high: [], medium: [], low: [] }
// ... populate findings from Phase 3 analysis
\`\`\``,

    "Code generation": `\`\`\`javascript
// Self-validation
const syntaxResult = Bash(\`tsc --noEmit 2>&1 || true\`)
const hasSyntaxErrors = syntaxResult.includes('error TS')
if (hasSyntaxErrors) {
  // Attempt auto-fix
}
\`\`\``,

    "Orchestration": `\`\`\`javascript
// Aggregate results from sub-agents
const aggregated = {
  // Merge findings, results, outputs
}
\`\`\``,

    "Validation": `\`\`\`javascript
// Analyze results
const resultSummary = {
  iterations: iteration,
  passed: iteration < MAX_ITERATIONS,
  // Coverage, pass rate, etc.
}
\`\`\``
  }

  const msgTypesTable = role.message_types.map(mt =>
    `| \`${mt.type}\` | ${role.name} → coordinator | ${mt.trigger} |`
  ).join('\n')

  const primaryMsgType = role.message_types.find(mt => !mt.type.includes('error') && !mt.type.includes('progress'))?.type || `${role.name}_complete`

  const roleMd = `# Role: ${role.name}

${role.description}

## Role Identity

- **Name**: \`${role.name}\`
- **Task Prefix**: \`${role.task_prefix}-*\`
- **Responsibility**: ${role.responsibility_type}
- **Communication**: SendMessage to coordinator only

## Message Types

| Type | Direction | Trigger |
|------|-----------|---------|
${msgTypesTable}

## Execution (5-Phase)

### Phase 1: Task Discovery

\`\`\`javascript
const tasks = TaskList()
const myTasks = tasks.filter(t =>
  t.subject.startsWith('${role.task_prefix}-') &&
  t.owner === '${role.name}' &&
  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: ${ra.phase_structure.phase2}

${phase2Content[role.responsibility_type]}

### Phase 3: ${ra.phase_structure.phase3}

${phase3Content[role.responsibility_type]}

### Phase 4: ${ra.phase_structure.phase4}

${phase4Content[role.responsibility_type]}

### Phase 5: Report to Coordinator

\`\`\`javascript
mcp__ccw-tools__team_msg({
  operation: "log",
  team: "${config.team_name}",
  from: "${role.name}",
  to: "coordinator",
  type: "${primaryMsgType}",
  summary: \`${role.task_prefix} complete: \${task.subject}\`
})

SendMessage({
  type: "message",
  recipient: "coordinator",
  content: \`## ${role.display_name} Results

**Task**: \${task.subject}
**Status**: \${resultStatus}

### Summary
\${resultSummary}

### Details
\${resultDetails}\`,
  summary: \`${role.task_prefix} complete\`
})

TaskUpdate({ taskId: task.id, status: 'completed' })

// Check for next task
const nextTasks = TaskList().filter(t =>
  t.subject.startsWith('${role.task_prefix}-') &&
  t.owner === '${role.name}' &&
  t.status === 'pending' &&
  t.blockedBy.length === 0
)

if (nextTasks.length > 0) {
  // Continue with next task → back to Phase 1
}
\`\`\`

## Error Handling

| Scenario | Resolution |
|----------|------------|
| No ${role.task_prefix}-* tasks available | Idle, wait for coordinator |
| Context/Plan file not found | Notify coordinator |
${role.adaptive_routing ? '| Sub-agent failure | Retry once, fallback to direct |\n' : ''}| Critical issue beyond scope | SendMessage fix_required |
| Unexpected error | Log via team_msg, report |
`

  Write(`${previewDir}/roles/${role.name}.md`, roleMd)
}

Step 5: Generate specs/team-config.json

Write(`${previewDir}/specs/team-config.json`, JSON.stringify({
  team_name: config.team_name,
  skill_name: config.skill_name,
  pipeline_type: config.pipeline_type,
  pipeline: config.pipeline,
  roles: config.roles.map(r => ({
    name: r.name,
    task_prefix: r.task_prefix,
    responsibility_type: r.responsibility_type,
    description: r.description
  })),
  collaboration_patterns: analysis.collaboration_patterns,
  generated_at: new Date().toISOString()
}, null, 2))

Output

  • Directory: {workDir}/preview/
  • Files:
    • preview/SKILL.md - Role router + shared infrastructure
    • preview/roles/coordinator.md - Coordinator execution
    • preview/roles/{role}.md - Per-worker role execution
    • preview/specs/team-config.json - Team configuration

Quality Checklist

  • SKILL.md contains role router with all roles
  • SKILL.md contains shared infrastructure (message bus, task lifecycle)
  • SKILL.md contains coordinator spawn template
  • Every role has a file in roles/
  • Every role file has 5-phase execution
  • Every role file has message types table
  • Every role file has error handling
  • team-config.json is valid JSON

Next Phase

-> Phase 4: Integration Verification