feat: migrate all codex team skills from spawn_agents_on_csv to spawn_agent + wait_agent architecture

- Delete 21 old team skill directories using CSV-wave pipeline pattern (~100+ files)
- Delete old team-lifecycle (v3) and team-planex-v2
- Create generic team-worker.toml and team-supervisor.toml (replacing tlv4-specific TOMLs)
- Convert 19 team skills from Claude Code format (Agent/SendMessage/TaskCreate)
  to Codex format (spawn_agent/wait_agent/tasks.json/request_user_input)
- Update team-lifecycle-v4 to use generic agent types (team_worker/team_supervisor)
- Convert all coordinator role files: dispatch.md, monitor.md, role.md
- Convert all worker role files: remove run_in_background, fix Bash syntax
- Convert all specs/pipelines.md references
- Final state: 20 team skills, 217 .md files, zero Claude Code API residuals

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
catlog22
2026-03-24 16:54:48 +08:00
parent 54283e5dbb
commit 1e560ab8e8
334 changed files with 28996 additions and 35516 deletions

View File

@@ -0,0 +1,250 @@
# Phase 1: Requirements Analysis
Gather team skill requirements from user input and build the `teamConfig` data structure that drives all subsequent phases.
## Objective
- Parse user input (text description, reference skill, or interactive)
- Determine roles, pipelines, specs, templates
- Auto-decide commands distribution (inline vs commands/ folder)
- Build comprehensive `teamConfig` object
- Confirm with user before proceeding
## Step 1.1: Detect Input Source
```javascript
function detectInputSource(userInput) {
// Source A: Reference to existing skill
if (userInput.includes('based on') || userInput.includes('参考') || userInput.includes('like')) {
return { type: 'reference', refSkill: extractSkillName(userInput) };
}
// Source B: Structured input with roles/pipelines
if (userInput.includes('ROLES:') || userInput.includes('PIPELINES:')) {
return { type: 'structured', data: parseStructuredInput(userInput) };
}
// Source C: Natural language description
return { type: 'natural', description: userInput };
}
```
**For reference source**: Read the referenced skill's SKILL.md and role files to extract structure.
**For natural language**: Use request_user_input to gather missing details interactively.
## Step 1.2: Gather Core Identity
```javascript
const skillNameResponse = request_user_input({
prompt: `团队技能名称?(kebab-case, e.g., team-code-review)\n\nSuggested: ${suggestedName}\nOr enter a custom name.`
});
const prefixResponse = request_user_input({
prompt: `会话前缀?(3-4字符用于任务ID, e.g., TCR)\n\nSuggested: ${suggestedPrefix}\nOr enter a custom prefix.`
});
```
If user provided clear name/prefix in input, skip this step.
## Step 1.3: Determine Roles
### Role Discovery from Domain
Analyze domain description to identify required roles:
```javascript
function discoverRoles(domain) {
const rolePatterns = {
'analyst': ['分析', 'analyze', 'research', 'explore', 'investigate', 'scan'],
'planner': ['规划', 'plan', 'design', 'architect', 'decompose'],
'writer': ['文档', 'write', 'document', 'draft', 'spec', 'report'],
'executor': ['实现', 'implement', 'execute', 'build', 'code', 'develop'],
'tester': ['测试', 'test', 'verify', 'validate', 'qa'],
'reviewer': ['审查', 'review', 'quality', 'check', 'audit', 'inspect'],
'security-expert': ['安全', 'security', 'vulnerability', 'penetration'],
'performance-optimizer': ['性能', 'performance', 'optimize', 'benchmark'],
'data-engineer': ['数据', 'data', 'pipeline', 'etl', 'migration'],
'devops-engineer': ['部署', 'devops', 'deploy', 'ci/cd', 'infrastructure'],
};
const matched = [];
for (const [role, keywords] of Object.entries(rolePatterns)) {
if (keywords.some(kw => domain.toLowerCase().includes(kw))) {
matched.push(role);
}
}
return matched;
}
```
### Role Configuration
For each discovered role, determine:
```javascript
function configureRole(roleName) {
return {
name: roleName,
prefix: determinePrefix(roleName),
inner_loop: determineInnerLoop(roleName),
hasCommands: false, // determined in Step 1.5
commands: [],
message_types: determineMessageTypes(roleName),
path: `roles/${roleName}/role.md`
};
}
// Standard prefix mapping
const prefixMap = {
'analyst': 'RESEARCH',
'writer': 'DRAFT',
'planner': 'PLAN',
'executor': 'IMPL',
'tester': 'TEST',
'reviewer': 'REVIEW',
// Dynamic roles use uppercase role name
};
// Inner loop: roles that process multiple tasks sequentially
const innerLoopRoles = ['executor', 'writer', 'planner'];
// Message types the role handles
const messageMap = {
'analyst': ['state_update'],
'writer': ['state_update', 'discuss_response'],
'planner': ['state_update'],
'executor': ['state_update', 'revision_request'],
'tester': ['state_update'],
'reviewer': ['state_update', 'discuss_request'],
};
```
## Step 1.4: Define Pipelines
### Pipeline Types from Role Combination
```javascript
function definePipelines(roles, domain) {
const has = name => roles.some(r => r.name === name);
// Full lifecycle: analyst → writer → planner → executor → tester → reviewer
if (has('analyst') && has('writer') && has('planner') && has('executor'))
return [{ name: 'full-lifecycle', tasks: buildFullLifecycleTasks(roles) }];
// Spec-only: analyst → writer → reviewer
if (has('analyst') && has('writer') && !has('executor'))
return [{ name: 'spec-only', tasks: buildSpecOnlyTasks(roles) }];
// Impl-only: planner → executor → tester → reviewer
if (has('planner') && has('executor') && !has('analyst'))
return [{ name: 'impl-only', tasks: buildImplOnlyTasks(roles) }];
// Custom: user-defined
return [{ name: 'custom', tasks: buildCustomTasks(roles, domain) }];
}
```
### Task Schema
```javascript
const taskSchema = {
id: 'PREFIX-NNN', // e.g., RESEARCH-001
role: 'analyst', // which role executes
name: 'Seed Analysis', // human-readable name
dependsOn: [], // task IDs that must complete first
isCheckpoint: false, // true for quality gates
isConditional: false, // true for routing decisions
description: '...'
};
```
## Step 1.5: Determine Commands Distribution
**Rule**: 1 action → inline in role.md. 2+ distinct actions → commands/ folder.
```javascript
function determineCommandsDistribution(roles) {
// Coordinator: always has commands/
// coordinator.commands = ['analyze', 'dispatch', 'monitor']
// Standard multi-action roles:
// executor → implement + fix → commands/
// reviewer (if both code & spec review) → review-code + review-spec → commands/
// All others → typically inline
for (const role of roles) {
const actions = countDistinctActions(role);
if (actions.length >= 2) {
role.hasCommands = true;
role.commands = actions.map(a => a.name);
}
}
}
```
## Step 1.6: Determine Specs and Templates
```javascript
// Specs: always include pipelines, add domain-specific
const specs = ['pipelines'];
if (hasQualityGates) specs.push('quality-gates');
if (hasKnowledgeTransfer) specs.push('knowledge-transfer');
// Templates: only if writer role exists
const templates = [];
if (has('writer')) {
// Detect from domain keywords
if (domain.includes('product')) templates.push('product-brief');
if (domain.includes('requirement')) templates.push('requirements');
if (domain.includes('architecture')) templates.push('architecture');
if (domain.includes('epic')) templates.push('epics');
}
```
## Step 1.7: Build teamConfig
```javascript
const teamConfig = {
skillName: string, // e.g., "team-code-review"
sessionPrefix: string, // e.g., "TCR"
domain: string, // domain description
title: string, // e.g., "Code Review Team"
roles: Array<RoleConfig>, // includes coordinator
pipelines: Array<Pipeline>,
specs: Array<string>, // filenames without .md
templates: Array<string>, // filenames without .md
conditionalRouting: boolean,
dynamicSpecialists: Array<string>,
};
```
## Step 1.8: Confirm with User
```
╔══════════════════════════════════════════╗
║ Team Skill Configuration Summary ║
╠══════════════════════════════════════════╣
Skill Name: ${skillName}
Session Prefix: ${sessionPrefix}
Domain: ${domain}
Roles (N):
├─ coordinator (commands: analyze, dispatch, monitor)
├─ role-a [PREFIX-*] (inline) 🔄
└─ role-b [PREFIX-*] (commands: cmd1, cmd2)
Pipelines:
└─ pipeline-name: TASK-001 → TASK-002 → TASK-003
Specs: pipelines, quality-gates
Templates: (none)
╚══════════════════════════════════════════╝
```
Use request_user_input to confirm or allow modifications.
## Output
- **Variable**: `teamConfig` — complete configuration for all subsequent phases
- **Next**: Phase 2 - Scaffold Generation

View File

@@ -0,0 +1,228 @@
# Phase 2: Scaffold Generation
Generate the SKILL.md universal router and create the directory structure for the team skill.
## Objective
- Create directory structure (roles/, specs/, templates/)
- Generate SKILL.md as universal router following v4 pattern
- SKILL.md must NOT contain beat model, pipeline details, or role Phase 2-4 logic
## Step 2.1: Create Directory Structure
```bash
skillDir=".claude/skills/${teamConfig.skillName}"
mkdir -p "${skillDir}"
# Create role directories
for role in teamConfig.roles:
mkdir -p "${skillDir}/roles/${role.name}"
if role.hasCommands:
mkdir -p "${skillDir}/roles/${role.name}/commands"
# Create specs directory
mkdir -p "${skillDir}/specs"
# Create templates directory (if needed)
if teamConfig.templates.length > 0:
mkdir -p "${skillDir}/templates"
```
## Step 2.2: Generate SKILL.md
The SKILL.md follows a strict template. Every generated SKILL.md contains these sections in order:
### Section 1: Frontmatter
```yaml
---
name: ${teamConfig.skillName}
description: ${teamConfig.domain}. Triggers on "${teamConfig.skillName}".
allowed-tools: spawn_agent(*), wait_agent(*), report_agent_job_result(*), request_user_input(*), Read(*), Write(*), Edit(*), Bash(*), Glob(*), Grep(*)
---
```
### Section 2: Title + Architecture Diagram
```markdown
# ${Title}
${One-line description}
## Architecture
\```
Skill(skill="${teamConfig.skillName}", args="task description")
|
SKILL.md (this file) = Router
|
+--------------+--------------+
| |
no --role flag --role <name>
| |
Coordinator Worker
roles/coordinator/role.md roles/<name>/role.md
|
+-- analyze → dispatch → spawn workers → STOP
|
+-------+-------+-------+
v v v v
[team-worker agents, each loads roles/<role>/role.md]
\```
```
### Section 3: Role Registry
```markdown
## Role Registry
| Role | Path | Prefix | Inner Loop |
|------|------|--------|------------|
| coordinator | roles/coordinator/role.md | — | — |
${teamConfig.roles.filter(r => r.name !== 'coordinator').map(r =>
`| ${r.name} | ${r.path} | ${r.prefix}-* | ${r.inner_loop} |`
).join('\n')}
```
### Section 4: Role Router
```markdown
## Role Router
Parse `$ARGUMENTS`:
- Has `--role <name>` → Read `roles/<name>/role.md`, execute Phase 2-4
- No `--role` → Read `roles/coordinator/role.md`, execute entry router
```
### Section 5: Shared Constants
```markdown
## Shared Constants
- **Session prefix**: `${teamConfig.sessionPrefix}`
- **Session path**: `.workflow/.team/${teamConfig.sessionPrefix}-<slug>-<date>/`
- **CLI tools**: `ccw cli --mode analysis` (read-only), `ccw cli --mode write` (modifications)
- **Message bus**: `mcp__ccw-tools__team_msg(session_id=<session-id>, ...)`
```
### Section 6: Worker Spawn Template
```markdown
## Worker Spawn Template
Coordinator spawns workers using this template:
\```
spawn_agent({
agent_type: "team_worker",
items: [{
description: "Spawn <role> worker",
team_name: <team-name>,
name: "<role>",
prompt: `## Role Assignment
role: <role>
role_spec: .codex/skills/${teamConfig.skillName}/roles/<role>/role.md
session: <session-folder>
session_id: <session-id>
team_name: <team-name>
requirement: <task-description>
inner_loop: <true|false>
Read role_spec file to load Phase 2-4 domain instructions.
Execute built-in Phase 1 (task discovery) -> role Phase 2-4 -> built-in Phase 5 (report).`
}]
})
\```
```
### Section 7: User Commands
```markdown
## User Commands
| Command | Action |
|---------|--------|
| `check` / `status` | View execution status graph |
| `resume` / `continue` | Advance to next step |
| `revise <TASK-ID> [feedback]` | Revise specific task |
| `feedback <text>` | Inject feedback for revision |
| `recheck` | Re-run quality check |
| `improve [dimension]` | Auto-improve weakest dimension |
```
### Section 8: Completion Action
```markdown
## Completion Action
When pipeline completes, coordinator presents:
\```
request_user_input({
prompt: "Pipeline complete. What would you like to do?\n\nOptions:\n1. Archive & Clean (Recommended) - Archive session, clean up team\n2. Keep Active - Keep session for follow-up work\n3. Export Results - Export deliverables to target directory"
})
\```
```
### Section 9: Specs Reference
```markdown
## Specs Reference
${teamConfig.specs.map(s =>
`- [specs/${s}.md](specs/${s}.md) — ${specDescription(s)}`
).join('\n')}
```
### Section 10: Session Directory
```markdown
## Session Directory
\```
.workflow/.team/${teamConfig.sessionPrefix}-<slug>-<date>/
├── team-session.json # Session state + role registry
├── spec/ # Spec phase outputs
├── plan/ # Implementation plan + TASK-*.json
├── artifacts/ # All deliverables
├── wisdom/ # Cross-task knowledge
├── explorations/ # Shared explore cache
├── discussions/ # Discuss round records
└── .msg/ # Team message bus
\```
```
### Section 11: Error Handling
```markdown
## Error Handling
| Scenario | Resolution |
|----------|------------|
| Unknown command | Error with available command list |
| Role not found | Error with role registry |
| CLI tool fails | Worker fallback to direct implementation |
| Fast-advance conflict | Coordinator reconciles on next callback |
| Completion action fails | Default to Keep Active |
```
## Step 2.3: Assemble and Write
Assemble all sections into a single SKILL.md file and write to `${skillDir}/SKILL.md`.
**Quality Rules**:
1. SKILL.md must NOT contain beat model (ONE_STEP_PER_INVOCATION, spawn-and-stop)
2. SKILL.md must NOT contain pipeline task details (task IDs, dependencies)
3. SKILL.md must NOT contain role Phase 2-4 logic
4. SKILL.md MUST contain role registry table with correct paths
5. SKILL.md MUST contain worker spawn template with correct `role_spec` paths
## Output
- **File**: `.claude/skills/${teamConfig.skillName}/SKILL.md`
- **Variable**: `skillDir` (path to skill root directory)
- **Next**: Phase 3 - Content Generation
## Next Phase
Return to orchestrator, then auto-continue to [Phase 3: Content Generation](03-content-generation.md).

View File

@@ -0,0 +1,330 @@
# Phase 3: Content Generation
Generate all role files, specs, and templates based on `teamConfig` and the generated SKILL.md.
## Objective
- Generate coordinator role.md + commands/ (analyze, dispatch, monitor)
- Generate each worker role.md (inline or with commands/)
- Generate specs/ files (pipelines.md + domain specs)
- Generate templates/ if needed
- Follow team-lifecycle-v4 golden sample patterns
## Golden Sample Reference
Read the golden sample at `~ or <project>/.claude/skills/team-lifecycle-v4/` for each file type before generating. This ensures pattern fidelity.
## Step 3.1: Generate Coordinator
The coordinator is the most complex role. It always has 3 commands.
### coordinator/role.md
```markdown
---
role: coordinator
---
# Coordinator — ${teamConfig.title}
## Identity
You are the coordinator for ${teamConfig.title}. You orchestrate the ${teamConfig.domain} pipeline by analyzing requirements, dispatching tasks, and monitoring worker progress.
## Boundaries
- **DO**: Analyze, dispatch, monitor, reconcile, report
- **DO NOT**: Implement domain work directly — delegate to workers
## Command Execution Protocol
Read command file → Execute ALL steps sequentially → Return to entry router.
Commands: `commands/analyze.md`, `commands/dispatch.md`, `commands/monitor.md`.
## Entry Router
On each invocation, detect current state and route:
| Condition | Handler |
|-----------|---------|
| First invocation (no session) | → Phase 1: Requirement Clarification |
| Session exists, no team | → Phase 2: Team Setup |
| Team exists, no tasks | → Phase 3: Dispatch (analyze.md → dispatch.md) |
| Tasks exist, none started | → Phase 4: Spawn First (monitor.md → handleSpawnNext) |
| Callback received | → monitor.md → handleCallback |
| User says "check"/"status" | → monitor.md → handleCheck |
| User says "resume"/"continue" | → monitor.md → handleResume |
| All tasks completed | → Phase 5: Report & Completion |
## Phase 0: Session Resume
If `.workflow/.team/${teamConfig.sessionPrefix}-*/team-session.json` exists:
- Load session state, verify team, reconcile task status
- Route to appropriate handler based on current state
## Phase 1: Requirement Clarification
- Parse user's task description at TEXT LEVEL
- Use request_user_input if requirements are ambiguous
- Execute `commands/analyze.md` for signal detection + complexity scoring
## Phase 2: Team Setup
- Session folder creation with session ID: `${teamConfig.sessionPrefix}-<slug>-<date>`
- Initialize team_msg message bus
- Create session directory structure
## Phase 3: Dispatch
- Execute `commands/dispatch.md`
- Creates task entries in tasks.json with blockedBy dependencies
## Phase 4: Spawn & Monitor
- Execute `commands/monitor.md` → handleSpawnNext
- Spawn ready workers as team_worker agents via spawn_agent()
- **STOP after spawning** — wait for callback
## Phase 5: Report & Completion
- Aggregate all task artifacts
- Present completion action to user
```
### coordinator/commands/analyze.md
Template based on golden sample — includes:
- Signal detection (keywords → capabilities)
- Dependency graph construction (tiers)
- Complexity scoring (1-3 Low, 4-6 Medium, 7+ High)
- Role minimization (cap at 5)
- Output: task-analysis.json
```markdown
# Command: Analyze
## Signal Detection
Scan requirement text for capability signals:
${teamConfig.roles.filter(r => r.name !== 'coordinator').map(r =>
`- **${r.name}**: [domain-specific keywords]`
).join('\n')}
## Dependency Graph
Build 4-tier dependency graph:
- Tier 0: Independent tasks (can run in parallel)
- Tier 1: Depends on Tier 0
- Tier 2: Depends on Tier 1
- Tier 3: Depends on Tier 2
## Complexity Scoring
| Score | Level | Strategy |
|-------|-------|----------|
| 1-3 | Low | Direct implementation, skip deep planning |
| 4-6 | Medium | Standard pipeline with planning |
| 7+ | High | Full spec → plan → implement cycle |
## Output
Write `task-analysis.json` to session directory:
\```json
{
"signals": [...],
"roles_needed": [...],
"dependency_tiers": [...],
"complexity": { "score": N, "level": "Low|Medium|High" },
"pipeline": "${teamConfig.pipelines[0].name}"
}
\```
```
### coordinator/commands/dispatch.md
Template — includes:
- Topological sort from dependency graph
- tasks.json entries with blockedBy for dependencies
- Task description template (PURPOSE/TASK/CONTEXT/EXPECTED/CONSTRAINTS)
### coordinator/commands/monitor.md
Template — includes:
- Beat model constants (ONE_STEP_PER_INVOCATION, SPAWN_MODE: spawn-and-stop)
- 6 handlers: handleCallback, handleCheck, handleResume, handleSpawnNext, handleComplete, handleAdapt
- Checkpoint detection for quality gates
- Fast-advance reconciliation
**Critical**: This is the ONLY file that contains beat model logic.
## Step 3.2: Generate Worker Roles
For each worker role in `teamConfig.roles`:
### Inline Role Template (no commands/)
```markdown
---
role: ${role.name}
prefix: ${role.prefix}
inner_loop: ${role.inner_loop}
message_types: [${role.message_types.join(', ')}]
---
# ${capitalize(role.name)} — ${teamConfig.title}
## Identity
You are the ${role.name} for ${teamConfig.title}.
Task prefix: `${role.prefix}-*`
## Phase 2: Context Loading
- Read task description from tasks.json (find by id)
- Load relevant session artifacts from session directory
- Load specs from `specs/` as needed
## Phase 3: Domain Execution
[Domain-specific execution logic for this role]
### Execution Steps
1. [Step 1 based on role's domain]
2. [Step 2]
3. [Step 3]
### Tools Available
- CLI tools: `ccw cli --mode analysis|write`
- Direct tools: Read, Write, Edit, Bash, Grep, Glob
- Message bus: `mcp__ccw-tools__team_msg`
- **Cannot use spawn_agent()** — workers must use CLI or direct tools
## Phase 4: Output & Report
- Write artifacts to session directory
- Log state_update via team_msg
- Publish wisdom if cross-task knowledge discovered
```
### Command-Based Role Template (has commands/)
```markdown
---
role: ${role.name}
prefix: ${role.prefix}
inner_loop: ${role.inner_loop}
message_types: [${role.message_types.join(', ')}]
---
# ${capitalize(role.name)} — ${teamConfig.title}
## Identity
You are the ${role.name} for ${teamConfig.title}.
Task prefix: `${role.prefix}-*`
## Phase 2: Context Loading
Load task description, detect mode/command.
## Phase 3: Command Router
| Condition | Command |
|-----------|---------|
${role.commands.map(cmd =>
`| [condition for ${cmd}] | → commands/${cmd}.md |`
).join('\n')}
Read command file → Execute ALL steps → Return to Phase 4.
## Phase 4: Output & Report
Write artifacts, log state_update.
```
Then generate each `commands/<cmd>.md` with domain-specific logic.
## Step 3.3: Generate Specs
### specs/pipelines.md
```markdown
# Pipeline Definitions
## Available Pipelines
${teamConfig.pipelines.map(p => `
### ${p.name}
| Task ID | Role | Name | Depends On | Checkpoint |
|---------|------|------|------------|------------|
${p.tasks.map(t =>
`| ${t.id} | ${t.role} | ${t.name} | ${t.dependsOn.join(', ') || '—'} | ${t.isCheckpoint ? '✓' : '—'} |`
).join('\n')}
`).join('\n')}
## Task Metadata Registry
Standard task description template:
\```
PURPOSE: [goal]
TASK: [steps]
CONTEXT: [session artifacts + specs]
EXPECTED: [deliverable format]
CONSTRAINTS: [scope limits]
\```
## Conditional Routing
${teamConfig.conditionalRouting ? `
PLAN-001 complexity assessment routes to:
- Low (1-3): Direct implementation
- Medium (4-6): Standard planning
- High (7+): Full spec → plan → implement
` : 'No conditional routing in this pipeline.'}
## Dynamic Specialist Injection
${teamConfig.dynamicSpecialists.length > 0 ?
teamConfig.dynamicSpecialists.map(s => `- ${s}: Injected when domain keywords detected`).join('\n') :
'No dynamic specialists configured.'
}
```
### Additional Specs
For each additional spec in `teamConfig.specs` (beyond pipelines), generate domain-appropriate content:
- **quality-gates.md**: Thresholds (Pass≥80%, Review 60-79%, Fail<60%), scoring dimensions, per-phase gates
- **knowledge-transfer.md**: 5 transfer channels, Phase 2 loading protocol, Phase 4 publishing protocol
## Step 3.4: Generate Templates
For each template in `teamConfig.templates`:
1. Check if golden sample has matching template at `~ or <project>/.claude/skills/team-lifecycle-v4/templates/`
2. If exists: copy and adapt for new domain
3. If not: generate domain-appropriate template structure
## Step 3.5: Generation Order
Execute in this order (respects dependencies):
1. **specs/** — needed by roles for reference
2. **coordinator/** — role.md + commands/ (3 files)
3. **workers/** — each role.md (+ optional commands/)
4. **templates/** — independent, generate last
For each file:
1. Read golden sample equivalent (if exists)
2. Adapt content for current teamConfig
3. Write file
4. Verify file exists
## Output
- **Files**: All role.md, commands/*.md, specs/*.md, templates/*.md
- **Next**: Phase 4 - Validation

View File

@@ -0,0 +1,320 @@
# Phase 4: Validation
Validate the generated team skill package for structural completeness, reference integrity, role consistency, and team-worker compatibility.
## Objective
- Verify all required files exist
- Validate SKILL.md role registry matches actual role files
- Check role.md frontmatter format for team-worker compatibility
- Verify pipeline task references match existing roles
- Report validation results
## Step 4.1: Structural Validation
```javascript
function validateStructure(teamConfig) {
const skillDir = `.claude/skills/${teamConfig.skillName}`;
const results = { errors: [], warnings: [], info: [] };
// Check SKILL.md exists
if (!fileExists(`${skillDir}/SKILL.md`)) {
results.errors.push('SKILL.md not found');
}
// Check coordinator structure
if (!fileExists(`${skillDir}/roles/coordinator/role.md`)) {
results.errors.push('Coordinator role.md not found');
}
for (const cmd of ['analyze', 'dispatch', 'monitor']) {
if (!fileExists(`${skillDir}/roles/coordinator/commands/${cmd}.md`)) {
results.errors.push(`Coordinator command ${cmd}.md not found`);
}
}
// Check worker roles
for (const role of teamConfig.roles.filter(r => r.name !== 'coordinator')) {
if (!fileExists(`${skillDir}/roles/${role.name}/role.md`)) {
results.errors.push(`Worker role.md not found: ${role.name}`);
}
if (role.hasCommands) {
for (const cmd of role.commands) {
if (!fileExists(`${skillDir}/roles/${role.name}/commands/${cmd}.md`)) {
results.errors.push(`Worker command not found: ${role.name}/commands/${cmd}.md`);
}
}
}
}
// Check specs
if (!fileExists(`${skillDir}/specs/pipelines.md`)) {
results.errors.push('specs/pipelines.md not found');
}
return results;
}
```
## Step 4.2: SKILL.md Content Validation
```javascript
function validateSkillMd(teamConfig) {
const skillDir = `.claude/skills/${teamConfig.skillName}`;
const results = { errors: [], warnings: [], info: [] };
const skillMd = Read(`${skillDir}/SKILL.md`);
// Required sections
const requiredSections = [
'Role Registry', 'Role Router', 'Shared Constants',
'Worker Spawn Template', 'User Commands', 'Session Directory'
];
for (const section of requiredSections) {
if (!skillMd.includes(section)) {
results.errors.push(`SKILL.md missing section: ${section}`);
}
}
// Verify role registry completeness
for (const role of teamConfig.roles) {
if (!skillMd.includes(role.path || `roles/${role.name}/role.md`)) {
results.errors.push(`Role registry missing path for: ${role.name}`);
}
}
// Verify session prefix
if (!skillMd.includes(teamConfig.sessionPrefix)) {
results.warnings.push(`Session prefix ${teamConfig.sessionPrefix} not found in SKILL.md`);
}
// Verify NO beat model content in SKILL.md
const beatModelPatterns = [
'ONE_STEP_PER_INVOCATION',
'spawn-and-stop',
'SPAWN_MODE',
'handleCallback',
'handleSpawnNext'
];
for (const pattern of beatModelPatterns) {
if (skillMd.includes(pattern)) {
results.errors.push(`SKILL.md contains beat model content: ${pattern} (should be in coordinator only)`);
}
}
return results;
}
```
## Step 4.3: Role Frontmatter Validation
Verify role.md files have correct YAML frontmatter for team-worker agent compatibility:
```javascript
function validateRoleFrontmatter(teamConfig) {
const skillDir = `.claude/skills/${teamConfig.skillName}`;
const results = { errors: [], warnings: [], info: [] };
for (const role of teamConfig.roles.filter(r => r.name !== 'coordinator')) {
const roleMd = Read(`${skillDir}/roles/${role.name}/role.md`);
// Check frontmatter exists
if (!roleMd.startsWith('---')) {
results.errors.push(`${role.name}/role.md missing YAML frontmatter`);
continue;
}
// Extract frontmatter
const fmMatch = roleMd.match(/^---\n([\s\S]*?)\n---/);
if (!fmMatch) {
results.errors.push(`${role.name}/role.md malformed frontmatter`);
continue;
}
const fm = fmMatch[1];
// Required fields
if (!fm.includes(`role: ${role.name}`)) {
results.errors.push(`${role.name}/role.md frontmatter missing 'role: ${role.name}'`);
}
if (!fm.includes(`prefix: ${role.prefix}`)) {
results.errors.push(`${role.name}/role.md frontmatter missing 'prefix: ${role.prefix}'`);
}
if (!fm.includes(`inner_loop: ${role.inner_loop}`)) {
results.warnings.push(`${role.name}/role.md frontmatter missing 'inner_loop: ${role.inner_loop}'`);
}
if (!fm.includes('message_types:')) {
results.warnings.push(`${role.name}/role.md frontmatter missing 'message_types'`);
}
}
return results;
}
```
## Step 4.4: Pipeline Consistency
```javascript
function validatePipelines(teamConfig) {
const skillDir = `.claude/skills/${teamConfig.skillName}`;
const results = { errors: [], warnings: [], info: [] };
// Check every role referenced in pipelines exists
const definedRoles = new Set(teamConfig.roles.map(r => r.name));
for (const pipeline of teamConfig.pipelines) {
for (const task of pipeline.tasks) {
if (!definedRoles.has(task.role)) {
results.errors.push(
`Pipeline '${pipeline.name}' task ${task.id} references undefined role: ${task.role}`
);
}
}
// Check for circular dependencies
const visited = new Set();
const stack = new Set();
for (const task of pipeline.tasks) {
if (hasCycle(task, pipeline.tasks, visited, stack)) {
results.errors.push(`Pipeline '${pipeline.name}' has circular dependency involving ${task.id}`);
}
}
}
// Verify specs/pipelines.md contains all pipelines
const pipelinesMd = Read(`${skillDir}/specs/pipelines.md`);
for (const pipeline of teamConfig.pipelines) {
if (!pipelinesMd.includes(pipeline.name)) {
results.warnings.push(`specs/pipelines.md missing pipeline: ${pipeline.name}`);
}
}
return results;
}
```
## Step 4.5: Commands Distribution Validation
```javascript
function validateCommandsDistribution(teamConfig) {
const skillDir = `.claude/skills/${teamConfig.skillName}`;
const results = { errors: [], warnings: [], info: [] };
for (const role of teamConfig.roles.filter(r => r.name !== 'coordinator')) {
if (role.hasCommands) {
// Verify commands/ directory exists and has files
const cmdDir = `${skillDir}/roles/${role.name}/commands`;
if (role.commands.length < 2) {
results.warnings.push(
`${role.name} has commands/ but only ${role.commands.length} command(s) — consider inline`
);
}
// Verify role.md references commands
const roleMd = Read(`${skillDir}/roles/${role.name}/role.md`);
for (const cmd of role.commands) {
if (!roleMd.includes(`commands/${cmd}.md`)) {
results.warnings.push(
`${role.name}/role.md doesn't reference commands/${cmd}.md`
);
}
}
} else {
// Verify no commands/ directory exists
const cmdDir = `${skillDir}/roles/${role.name}/commands`;
if (directoryExists(cmdDir)) {
results.warnings.push(
`${role.name} is inline but has commands/ directory`
);
}
}
}
return results;
}
```
## Step 4.6: Aggregate Results and Report
```javascript
function generateValidationReport(teamConfig) {
const structural = validateStructure(teamConfig);
const skillMd = validateSkillMd(teamConfig);
const frontmatter = validateRoleFrontmatter(teamConfig);
const pipelines = validatePipelines(teamConfig);
const commands = validateCommandsDistribution(teamConfig);
const allErrors = [
...structural.errors, ...skillMd.errors,
...frontmatter.errors, ...pipelines.errors, ...commands.errors
];
const allWarnings = [
...structural.warnings, ...skillMd.warnings,
...frontmatter.warnings, ...pipelines.warnings, ...commands.warnings
];
const gate = allErrors.length === 0 ? 'PASS' :
allErrors.length <= 2 ? 'REVIEW' : 'FAIL';
const skillDir = `.claude/skills/${teamConfig.skillName}`;
console.log(`
╔══════════════════════════════════════╗
║ Team Skill Validation Report ║
╠══════════════════════════════════════╣
║ Skill: ${teamConfig.skillName.padEnd(28)}
║ Gate: ${gate.padEnd(28)}
╚══════════════════════════════════════╝
Structure:
${skillDir}/
├── SKILL.md ✓
├── roles/
│ ├── coordinator/
│ │ ├── role.md ✓
│ │ └── commands/ (analyze, dispatch, monitor)
${teamConfig.roles.filter(r => r.name !== 'coordinator').map(r => {
const structure = r.hasCommands
? ` │ ├── ${r.name}/ (role.md + commands/)`
: ` │ ├── ${r.name}/role.md`;
return `${structure.padEnd(50)}`;
}).join('\n')}
├── specs/
│ └── pipelines.md ✓
└── templates/ ${teamConfig.templates.length > 0 ? '✓' : '(empty)'}
${allErrors.length > 0 ? `Errors (${allErrors.length}):\n${allErrors.map(e => `${e}`).join('\n')}` : 'Errors: None ✓'}
${allWarnings.length > 0 ? `Warnings (${allWarnings.length}):\n${allWarnings.map(w => `${w}`).join('\n')}` : 'Warnings: None ✓'}
Usage:
Skill(skill="${teamConfig.skillName}", args="<task description>")
`);
return { gate, errors: allErrors, warnings: allWarnings };
}
```
## Step 4.7: Error Recovery
```javascript
if (report.gate === 'FAIL') {
const recovery = request_user_input({
prompt: `Validation found ${report.errors.length} errors. How to proceed?\n\nOptions:\n1. Auto-fix - Attempt automatic fixes (missing files, frontmatter)\n2. Regenerate - Re-run Phase 3 with fixes\n3. Accept as-is - Manual fix later`
});
}
```
## Output
- **Report**: Validation results with quality gate (PASS/REVIEW/FAIL)
- **Completion**: Team skill package ready at `.claude/skills/${teamConfig.skillName}/`
## Completion
Team Skill Designer has completed. The generated team skill is ready for use.
```
Next Steps:
1. Review SKILL.md router for correctness
2. Review each role.md for domain accuracy
3. Test: Skill(skill="${teamConfig.skillName}", args="<test task>")
4. Iterate based on execution results
```