Add orchestrator design, phase file generation, and validation processes

- Implement Phase 2: Orchestrator Design with detailed steps for generating SKILL.md
- Introduce Phase 3: Phase Files Design to create phase files with content fidelity
- Establish Phase 4: Validation & Integration to ensure structural completeness and reference integrity
- Include comprehensive validation checks for content quality and data flow consistency
- Enhance documentation with clear objectives and critical rules for each phase
This commit is contained in:
catlog22
2026-02-05 19:29:45 +08:00
parent eac1bb81c8
commit 47c192f584
20 changed files with 4211 additions and 3110 deletions

View File

@@ -0,0 +1,356 @@
# Phase 1: Requirements Analysis
Analyze workflow requirements from various sources (commands, descriptions, requirements docs) to build a structured workflow configuration.
## Objective
- Identify all phases/steps in the workflow
- Map data flow between phases
- Identify agents, tools, and conditional logic
- Detect source type and extract content accordingly
- Produce `workflowConfig` object for subsequent phases
## Step 1.1: Identify Input Source
```javascript
// Determine what the user provided
const inputType = detectInputType(userInput);
// Returns: 'command_set' | 'text_description' | 'requirements_doc' | 'existing_skill'
```
### Source Type Detection
| Indicator | Type | Action |
|-----------|------|--------|
| Path to `.claude/commands/**/*.md` | `command_set` | Read orchestrator + discover sub-commands |
| Free text describing workflow | `text_description` | Interactive requirements gathering |
| Path to `.md` or `.json` requirements | `requirements_doc` | Parse structured requirements |
| Path to `.claude/skills/**/*.md` | `existing_skill` | Analyze and restructure |
## Step 1.2: Source-Specific Analysis
### Mode A: Command Set Analysis
When source is an existing orchestrator command + sub-commands:
```javascript
// Step A.1: Read orchestrator command
const orchestratorPath = userInput; // e.g., ".claude/commands/workflow/plan.md"
const orchestratorContent = Read(orchestratorPath);
// Step A.2: Extract frontmatter
const frontmatter = extractYAMLFrontmatter(orchestratorContent);
// Fields: name, description, argument-hint, examples, allowed-tools, group
// Step A.3: Discover sub-commands by scanning Skill() calls
const skillCalls = orchestratorContent.match(/Skill\(skill="([^"]+)"/g);
// e.g., ["workflow:session:start", "workflow:tools:context-gather", ...]
// Step A.4: Map Skill() calls to file paths
// Pattern: "workflow:session:start" → ".claude/commands/workflow/session/start.md"
// "workflow:tools:context-gather" → ".claude/commands/workflow/tools/context-gather.md"
const subCommandPaths = skillCalls.map(call => {
const parts = call.replace('Skill(skill="', '').replace('"', '').split(':');
return `.claude/commands/${parts.join('/')}.md`;
});
// Step A.5: Read all sub-commands
const subCommands = [];
for (const path of subCommandPaths) {
const content = Read(path);
const fm = extractYAMLFrontmatter(content);
subCommands.push({
path: path,
content: content,
frontmatter: fm,
skillCallName: extractSkillCallName(path),
bodyContent: removeYAMLFrontmatter(content)
});
}
// Step A.6: Identify phase ordering from orchestrator execution flow
// Look for patterns like:
// "Phase 1: ..." → first Skill() call
// "Phase 2: ..." → second Skill() call
// Conditional logic (if/else) → conditional phases
const phaseOrder = extractPhaseOrder(orchestratorContent, skillCalls);
```
**Key Extraction Points from Orchestrator**:
| Section | What to Extract | Maps to |
|---------|-----------------|---------|
| Coordinator Role / Overview | Workflow description, execution model | SKILL.md description + Architecture |
| Core Rules | Orchestration constraints | SKILL.md Core Rules |
| Execution Process | Phase sequence + conditions | SKILL.md Execution Flow |
| Data Flow | Inter-phase variables | SKILL.md Data Flow |
| TodoWrite Pattern | Attachment/collapse examples | SKILL.md TodoWrite Pattern |
| Input Processing | Structured format rules | SKILL.md Input Processing |
| Error Handling | Recovery strategies | SKILL.md Error Handling |
| Coordinator Checklist | Pre/post actions | SKILL.md Coordinator Checklist |
| Related Commands | Prerequisites/follow-ups | SKILL.md Related Commands |
| Phase N sections | Phase-specific orchestrator instructions | SKILL.md inline (brief), Phase files (detail) |
**Key Extraction Points from Sub-Commands**:
| Section | What to Extract | Maps to |
|---------|-----------------|---------|
| Full body content | Complete execution detail | Phase file (preserved verbatim) |
| Agent prompts (Task calls) | Agent delegation logic | Phase file agent sections |
| Bash command blocks | Shell execution steps | Phase file step sections |
| Validation/Output sections | Phase outputs | Phase file Output section |
| Frontmatter | Tools, description | Phase file header context |
### Mode B: Text Description Analysis
When source is a natural language workflow description:
```javascript
// Interactive requirements gathering
const basicInfo = AskUserQuestion({
questions: [
{
question: "What is this workflow skill's name? (kebab-case)",
header: "Name",
multiSelect: false,
options: [
{ label: "Custom name", description: "Enter a custom skill name" },
{ label: "Auto-generate", description: "Generate from workflow description" }
]
},
{
question: "How many main phases does this workflow have?",
header: "Phases",
multiSelect: false,
options: [
{ label: "3 phases", description: "Simple linear workflow" },
{ label: "4 phases", description: "Standard workflow with validation" },
{ label: "5+ phases", description: "Complex workflow with conditions" }
]
}
]
});
// For each phase, gather details
const phases = [];
for (let i = 0; i < phaseCount; i++) {
const phaseInfo = AskUserQuestion({
questions: [
{
question: `Phase ${i+1}: What does this phase do?`,
header: `Phase ${i+1}`,
multiSelect: false,
options: [
{ label: "Session/Init", description: "Initialize session or state" },
{ label: "Context/Gather", description: "Collect information or analyze" },
{ label: "Process/Transform", description: "Process data or generate artifacts" },
{ label: "Validate/Review", description: "Quality check or user review" }
]
},
{
question: `Phase ${i+1}: Does it use agents?`,
header: "Agents",
multiSelect: false,
options: [
{ label: "No agents", description: "Direct execution only" },
{ label: "Single agent", description: "Delegates to one agent" },
{ label: "Multiple agents", description: "Parallel or sequential agents" }
]
}
]
});
phases.push(phaseInfo);
}
// Gather conditional logic
const conditions = AskUserQuestion({
questions: [{
question: "Are any phases conditional (skipped based on previous results)?",
header: "Conditions",
multiSelect: false,
options: [
{ label: "No conditions", description: "All phases always execute" },
{ label: "Has conditions", description: "Some phases execute conditionally" }
]
}]
});
```
### Mode C: Requirements Document
When source is a structured requirements document:
```javascript
// Read and parse requirements
const reqContent = Read(requirementsPath);
// Extract structured fields
// Expected format: Markdown with ## sections for each phase
// Or JSON with phases array
const requirements = parseRequirements(reqContent);
```
### Mode D: Existing Skill Restructure
When source is an existing skill to refactor:
```javascript
// Read existing SKILL.md
const existingSkill = Read(skillPath);
// Scan for phase files
const existingPhases = Glob(`${skillDir}/phases/*.md`);
// Analyze current structure for improvement
const analysis = analyzeExistingStructure(existingSkill, existingPhases);
```
## Step 1.3: Build Workflow Configuration
Regardless of source type, produce a unified `workflowConfig`:
```javascript
const workflowConfig = {
// Metadata
skillName: "workflow-plan", // kebab-case
title: "Workflow Plan", // Human-readable
description: "5-phase planning...", // One-line description
triggers: ["workflow:plan"], // Trigger phrases
allowedTools: ["Task", "AskUserQuestion", "TodoWrite", "Read", "Write", "Edit", "Bash", "Glob", "Grep", "Skill"],
// Source information
source: {
type: "command_set", // input source type
orchestratorPath: "...", // original orchestrator file
subCommandPaths: ["..."] // original sub-command files
},
// Phase definitions
phases: [
{
number: 1,
name: "Session Discovery",
slug: "session-discovery", // for filename: 01-session-discovery.md
description: "Create or discover workflow session",
sourcePath: ".claude/commands/workflow/session/start.md",
isConditional: false,
condition: null,
usesAgents: false,
agentTypes: [],
todoWriteSubTasks: [], // no sub-tasks (atomic phase)
outputVariables: ["sessionId"],
outputFiles: ["planning-notes.md"]
},
{
number: 2,
name: "Context Gathering",
slug: "context-gathering",
description: "Gather project context via agents",
sourcePath: ".claude/commands/workflow/tools/context-gather.md",
isConditional: false,
condition: null,
usesAgents: true,
agentTypes: ["cli-explore-agent", "context-search-agent"],
todoWriteSubTasks: [
"Analyze codebase structure",
"Identify integration points",
"Generate context package"
],
outputVariables: ["contextPath", "conflictRisk"],
outputFiles: ["context-package.json"]
},
{
number: 3,
name: "Conflict Resolution",
slug: "conflict-resolution",
description: "Detect and resolve conflicts",
sourcePath: ".claude/commands/workflow/tools/conflict-resolution.md",
isConditional: true,
condition: "conflictRisk >= 'medium'",
usesAgents: true,
agentTypes: ["cli-execution-agent"],
todoWriteSubTasks: [
"Detect conflicts with CLI analysis",
"Present conflicts to user",
"Apply resolution strategies"
],
outputVariables: [],
outputFiles: ["conflict-resolution.json"]
},
{
number: 4,
name: "Task Generation",
slug: "task-generation",
description: "Generate implementation plan and task JSONs",
sourcePath: ".claude/commands/workflow/tools/task-generate-agent.md",
isConditional: false,
condition: null,
usesAgents: true,
agentTypes: ["action-planning-agent"],
todoWriteSubTasks: [], // single agent task
outputVariables: [],
outputFiles: ["IMPL_PLAN.md", "IMPL-*.json", "TODO_LIST.md"]
}
],
// Data flow
dataFlow: [
{ from: "input", to: "phase1", variables: ["structuredDescription"] },
{ from: "phase1", to: "phase2", variables: ["sessionId"] },
{ from: "phase2", to: "phase3", variables: ["contextPath", "conflictRisk"] },
{ from: "phase2", to: "phase4", variables: ["contextPath"] },
{ from: "phase3", to: "phase4", variables: ["resolvedArtifacts"] }
],
// Features
features: {
hasAutoMode: true, // --yes flag support
hasConditionalPhases: true, // some phases may be skipped
hasTodoWriteSubTasks: true, // phases expand into sub-tasks
hasPlanningNotes: true, // accumulated state document
hasPostPhaseUpdates: true, // state updates between phases
hasMemoryCompaction: true, // compact after heavy phases
hasUserDecisionGate: true // user choice after final phase
}
};
```
## Step 1.4: User Confirmation
Present the analyzed structure to the user for confirmation:
```javascript
// Display summary
console.log(`
Workflow Analysis Complete:
Name: ${workflowConfig.skillName}
Phases: ${workflowConfig.phases.length}
${workflowConfig.phases.map(p =>
` ${p.number}. ${p.name}${p.isConditional ? ' (conditional)' : ''}${p.usesAgents ? ` [${p.agentTypes.join(', ')}]` : ''}`
).join('\n')}
Data Flow: ${workflowConfig.dataFlow.length} connections
Features: ${Object.entries(workflowConfig.features).filter(([,v]) => v).map(([k]) => k).join(', ')}
`);
const confirm = AskUserQuestion({
questions: [{
question: "Proceed with this workflow structure?",
header: "Confirm",
multiSelect: false,
options: [
{ label: "Yes, proceed", description: "Generate skill with this structure" },
{ label: "Modify phases", description: "Adjust phase count or ordering" },
{ label: "Add features", description: "Enable additional patterns (auto mode, conditions, etc.)" }
]
}]
});
```
## Output
- **Variable**: `workflowConfig` (structured configuration object)
- **TodoWrite**: Mark Phase 1 completed, Phase 2 in_progress
## Next Phase
Return to orchestrator, then auto-continue to [Phase 2: Orchestrator Design](02-orchestrator-design.md).

View File

@@ -0,0 +1,381 @@
# Phase 2: Orchestrator Design
Generate the SKILL.md orchestrator file from workflowConfig, applying all coordination patterns (progressive loading, TodoWrite, data flow, conditional execution).
## Objective
- Create `.claude/skills/{skillName}/SKILL.md` as pure coordinator
- Apply frontmatter conversion rules
- Generate architecture diagram from phase structure
- Build execution flow with `Ref:` markers and phase reference table
- Generate data flow diagram
- Build TodoWrite attachment/collapse patterns from phase definitions
- Include all orchestrator-level sections
## Step 2.1: Create Directory Structure
```bash
skillDir=".claude/skills/${workflowConfig.skillName}"
mkdir -p "${skillDir}/phases"
# Optional directories based on features
# mkdir -p "${skillDir}/specs" # if has domain specifications
# mkdir -p "${skillDir}/templates" # if has reusable templates
```
## Step 2.2: Generate Frontmatter
```javascript
function generateFrontmatter(config) {
return `---
name: ${config.skillName}
description: ${config.description}. Triggers on ${config.triggers.map(t => `"${t}"`).join(', ')}.
allowed-tools: ${config.allowedTools.join(', ')}
---`;
}
```
**Conversion from command frontmatter**:
```javascript
// If source is command_set, convert fields:
function convertCommandFrontmatter(commandFm, config) {
return {
name: commandFm.group
? `${commandFm.group}-${commandFm.name}` // "workflow" + "plan" → "workflow-plan"
: commandFm.name,
description: commandFm.description,
// argument-hint → removed (handled in Input Processing section)
// examples → removed (moved to inline docs)
// group → embedded in name prefix
allowedTools: expandToolWildcards(commandFm['allowed-tools'])
// "Skill(*), TodoWrite(*), Read(*)" → "Task, AskUserQuestion, TodoWrite, Read, Write, Edit, Bash, Glob, Grep, Skill"
};
}
// Expand tool wildcards
function expandToolWildcards(toolsStr) {
const expanded = toolsStr
.replace(/Skill\(\*\)/g, 'Skill')
.replace(/TodoWrite\(\*\)/g, 'TodoWrite')
.replace(/Read\(\*\)/g, 'Read')
.replace(/Bash\(\*\)/g, 'Bash')
.replace(/Glob\(\*\)/g, 'Glob')
.replace(/Grep\(\*\)/g, 'Grep')
.replace(/Task\(\*\)/g, 'Task');
// Add commonly needed tools if not present
const baseTools = ['Task', 'AskUserQuestion', 'TodoWrite', 'Read', 'Write', 'Edit', 'Bash', 'Glob', 'Grep'];
const current = expanded.split(',').map(t => t.trim());
const merged = [...new Set([...current, ...baseTools])];
return merged;
}
```
## Step 2.3: Generate Architecture Diagram
```javascript
function generateArchitectureDiagram(config) {
const phases = config.phases;
const maxWidth = 65;
let diagram = '```\n';
diagram += '┌' + '─'.repeat(maxWidth) + '┐\n';
diagram += `${config.title} Orchestrator (SKILL.md)${' '.repeat(maxWidth - config.title.length - 30)}\n`;
diagram += `│ → Pure coordinator: Execute phases, parse outputs, pass context${' '.repeat(maxWidth - 64)}\n`;
diagram += '└' + '─'.repeat(Math.floor(maxWidth/2)) + '┬' + '─'.repeat(maxWidth - Math.floor(maxWidth/2) - 1) + '┘\n';
// Phase boxes
diagram += ' │\n';
diagram += ' ' + phases.map(() => '┌─────────┐').join(' ') + '\n';
diagram += ' ' + phases.map((p, i) => {
const label = `Phase ${p.number}`.padEnd(9);
return `${label}`;
}).join(' ') + '\n';
diagram += ' ' + phases.map(p => {
const name = p.name.substring(0, 9).padEnd(9);
return `${name}`;
}).join(' ') + '\n';
diagram += ' ' + phases.map(() => '└─────────┘').join(' ') + '\n';
// Output labels
diagram += ' ' + phases.map(p => {
const vars = p.outputVariables.join(', ').substring(0, 11).padEnd(11);
return ` ${vars}`;
}).join('') + '\n';
diagram += '```';
return diagram;
}
```
## Step 2.4: Generate Execution Flow
The execution flow uses `Ref:` markers to point to phase documents, with a Phase Reference Documents table inline.
```javascript
function generateExecutionFlow(config) {
let flow = '## Execution Flow\n\n```\n';
flow += 'Input Parsing:\n';
flow += ' └─ Convert user input to structured format (GOAL/SCOPE/CONTEXT)\n\n';
for (const phase of config.phases) {
flow += `Phase ${phase.number}: ${phase.name}\n`;
if (phase.isConditional) {
flow += ` └─ Decision (${phase.condition}):\n`;
flow += ` ├─ condition met → Ref: phases/${String(phase.number).padStart(2, '0')}-${phase.slug}.md\n`;
if (phase.todoWriteSubTasks.length > 0) {
flow += ` │ ├─ Tasks attached: ${phase.todoWriteSubTasks.join(' → ')}\n`;
}
flow += ` │ └─ Output: ${phase.outputFiles.join(', ') || phase.outputVariables.join(', ')}\n`;
flow += ` └─ condition not met → Skip to Phase ${phase.number + 1}\n`;
} else {
flow += ` └─ Ref: phases/${String(phase.number).padStart(2, '0')}-${phase.slug}.md\n`;
if (phase.todoWriteSubTasks.length > 0) {
flow += ` ├─ Tasks attached: ${phase.todoWriteSubTasks.join(' → ')}\n`;
}
flow += ` └─ Output: ${[...phase.outputVariables, ...phase.outputFiles].join(', ')}\n`;
}
flow += '\n';
}
flow += 'Return:\n └─ Summary with recommended next steps\n';
flow += '```\n\n';
// Phase Reference Documents table
flow += '**Phase Reference Documents** (read on-demand when phase executes):\n\n';
flow += '| Phase | Document | Purpose |\n';
flow += '|-------|----------|---------|\n';
for (const phase of config.phases) {
const filename = `${String(phase.number).padStart(2, '0')}-${phase.slug}.md`;
flow += `| ${phase.number} | [phases/${filename}](phases/${filename}) | ${phase.description} |\n`;
}
return flow;
}
```
## Step 2.5: Generate Data Flow Section
```javascript
function generateDataFlow(config) {
let section = '## Data Flow\n\n```\n';
section += 'User Input (task description)\n';
section += ' ↓\n';
section += '[Convert to Structured Format]\n';
for (const phase of config.phases) {
const inputVars = config.dataFlow
.filter(d => d.to === `phase${phase.number}`)
.flatMap(d => d.variables);
const outputVars = [...phase.outputVariables, ...phase.outputFiles];
section += ' ↓\n';
section += `Phase ${phase.number}: ${phase.name}\n`;
if (inputVars.length > 0) {
section += ` ↓ Input: ${inputVars.join(' + ')}\n`;
}
if (outputVars.length > 0) {
section += ` ↓ Output: ${outputVars.join(' + ')}\n`;
}
if (phase.isConditional) {
section += ` ↓ Skip if ${phase.condition} is false → proceed to Phase ${phase.number + 1}\n`;
}
}
section += ' ↓\n';
section += 'Return summary to user\n';
section += '```\n';
return section;
}
```
## Step 2.6: Generate TodoWrite Pattern
```javascript
function generateTodoWritePattern(config) {
let section = '## TodoWrite Pattern\n\n';
section += '**Core Concept**: Dynamic task attachment and collapse for real-time visibility.\n\n';
section += '### Key Principles\n\n';
section += '1. **Task Attachment** (when phase executed):\n';
section += ' - Sub-tasks are **attached** to orchestrator\'s TodoWrite\n';
// Identify which phases have sub-tasks
const phasesWithSubTasks = config.phases.filter(p => p.todoWriteSubTasks.length > 0);
const phasesWithoutSubTasks = config.phases.filter(p => p.todoWriteSubTasks.length === 0);
if (phasesWithSubTasks.length > 0) {
section += ` - **${phasesWithSubTasks.map(p => `Phase ${p.number}`).join(', ')}**: Multiple sub-tasks attached\n`;
}
if (phasesWithoutSubTasks.length > 0) {
section += ` - **${phasesWithoutSubTasks.map(p => `Phase ${p.number}`).join(', ')}**: Single task (atomic)\n`;
}
section += '\n2. **Task Collapse** (after sub-tasks complete):\n';
if (phasesWithSubTasks.length > 0) {
section += ` - **Applies to ${phasesWithSubTasks.map(p => `Phase ${p.number}`).join(', ')}**: Remove sub-tasks, collapse to summary\n`;
}
section += ' - Maintains clean orchestrator-level view\n';
section += '\n3. **Continuous Execution**: After completion, automatically proceed to next phase\n\n';
// Generate TodoWrite examples for phases with sub-tasks
for (const phase of phasesWithSubTasks) {
section += `### Phase ${phase.number} (Tasks Attached):\n`;
section += '```json\n[\n';
// Previous phases completed
for (const prev of config.phases.filter(p => p.number < phase.number)) {
section += ` {"content": "Phase ${prev.number}: ${prev.name}", "status": "completed"},\n`;
}
// Current phase in_progress with sub-tasks
section += ` {"content": "Phase ${phase.number}: ${phase.name}", "status": "in_progress"},\n`;
phase.todoWriteSubTasks.forEach((task, i) => {
const status = i === 0 ? 'in_progress' : 'pending';
section += ` {"content": " → ${task}", "status": "${status}"},\n`;
});
// Remaining phases pending
for (const next of config.phases.filter(p => p.number > phase.number && !p.isConditional)) {
section += ` {"content": "Phase ${next.number}: ${next.name}", "status": "pending"},\n`;
}
section += ']\n```\n\n';
// Collapsed version
section += `### Phase ${phase.number} (Collapsed):\n`;
section += '```json\n[\n';
for (const p of config.phases.filter(pp => !pp.isConditional || pp.number <= phase.number)) {
const status = p.number <= phase.number ? 'completed' : 'pending';
section += ` {"content": "Phase ${p.number}: ${p.name}", "status": "${status}"},\n`;
}
section += ']\n```\n\n';
}
return section;
}
```
## Step 2.7: Generate Remaining Sections
Extract from source orchestrator or generate from config:
```javascript
function generateOrchestratorSections(config, sourceContent) {
const sections = [];
// Auto Mode (if feature enabled)
if (config.features.hasAutoMode) {
sections.push(extractOrGenerate(sourceContent, 'Auto Mode',
'## Auto Mode\n\nWhen `--yes` or `-y`: Auto-continue all phases, use recommended defaults.\n'));
}
// Core Rules
sections.push(extractOrGenerate(sourceContent, 'Core Rules',
generateDefaultCoreRules(config)));
// Input Processing
sections.push(extractOrGenerate(sourceContent, 'Input Processing',
generateDefaultInputProcessing(config)));
// Post-Phase Updates (if feature enabled)
if (config.features.hasPostPhaseUpdates) {
sections.push(extractOrGenerate(sourceContent, 'Post-Phase Updates',
generatePostPhaseUpdates(config)));
}
// Error Handling
sections.push(extractOrGenerate(sourceContent, 'Error Handling',
generateDefaultErrorHandling()));
// Coordinator Checklist
sections.push(extractOrGenerate(sourceContent, 'Coordinator Checklist',
generateCoordinatorChecklist(config)));
// Related Commands
sections.push(extractOrGenerate(sourceContent, 'Related Commands',
generateRelatedCommands(config)));
return sections.join('\n\n');
}
// Extract section from source if exists, otherwise generate default
function extractOrGenerate(sourceContent, sectionName, defaultContent) {
if (sourceContent) {
const extracted = extractSection(sourceContent, sectionName);
if (extracted) return extracted;
}
return defaultContent;
}
// Default Core Rules template
function generateDefaultCoreRules(config) {
return `## Core Rules
1. **Start Immediately**: First action is TodoWrite initialization, second action is Phase 1 execution
2. **No Preliminary Analysis**: Do not read files or gather context before Phase 1
3. **Parse Every Output**: Extract required data from each phase for next phase
4. **Auto-Continue**: Check TodoList status to execute next pending phase automatically
5. **Track Progress**: Update TodoWrite dynamically with task attachment/collapse pattern
6. **Progressive Phase Loading**: Read phase docs ONLY when that phase is about to execute
7. **DO NOT STOP**: Continuous multi-phase workflow until all phases complete`;
}
// Default Error Handling template
function generateDefaultErrorHandling() {
return `## Error Handling
- **Parsing Failure**: If output parsing fails, retry once, then report error
- **Validation Failure**: Report which file/data is missing
- **Command Failure**: Keep phase \`in_progress\`, report error, do not proceed`;
}
```
## Step 2.8: Assemble SKILL.md
```javascript
function assembleSkillMd(config, sourceContent) {
const parts = [
generateFrontmatter(config),
'',
`# ${config.title}`,
'',
config.description,
'',
generateArchitectureDiagram(config),
'',
generateDesignPrinciples(config),
'',
generateExecutionFlow(config),
'',
generateDataFlow(config),
'',
generateTodoWritePattern(config),
'',
generateOrchestratorSections(config, sourceContent)
];
const skillMdContent = parts.join('\n');
Write(`${skillDir}/SKILL.md`, skillMdContent);
}
```
**Critical Quality Rules**:
1. SKILL.md must NOT contain full execution detail (agent prompts, bash commands)
2. SKILL.md MUST contain `Ref:` markers pointing to phase files
3. SKILL.md MUST contain Phase Reference Documents table
4. Every phase mentioned in Execution Flow must have a corresponding phase file
5. Data flow variables must be consistent across sections
## Output
- **File**: `.claude/skills/{skillName}/SKILL.md`
- **TodoWrite**: Mark Phase 2 completed, Phase 3 in_progress
## Next Phase
Return to orchestrator, then auto-continue to [Phase 3: Phase Files Design](03-phase-design.md).

View File

@@ -0,0 +1,356 @@
# Phase 3: Phase Files Design
Generate phase files in `phases/` directory, preserving full execution detail from source content. Each phase file is a complete execution instruction.
## Objective
- Create `phases/0N-{slug}.md` for each phase in workflowConfig
- Preserve full source content (agent prompts, bash commands, code, validation)
- Add standard phase structure (header, objective, output, next phase)
- Handle different source types (command extraction vs new generation)
## Critical Rule
**Content Fidelity**: Phase files must be **content-faithful** to their source. Do NOT summarize, abbreviate, or simplify execution detail. The phase file IS the execution instruction.
| Content Type | Rule |
|-------------|------|
| Agent prompts (Task calls) | Preserve **verbatim** including all prompt text, variables, constraints |
| Bash command blocks | Preserve **verbatim** including all flags, paths, error handling |
| Code implementations | Preserve **verbatim** including all functions, validation logic |
| Validation checklists | Preserve **verbatim** including all check items |
| Error handling details | Preserve **verbatim** including recovery strategies |
| Tables and specifications | Preserve **verbatim** including all rows and columns |
| Comments and notes | Preserve **verbatim** including inline documentation |
**Anti-Pattern**: Creating a phase file that says "See original command for details" or "Execute the agent with appropriate parameters" - this defeats the purpose of the skill structure. The phase file must be self-contained.
## Step 3.1: Phase File Generation Strategy
```javascript
function selectGenerationStrategy(phase, config) {
if (config.source.type === 'command_set' && phase.sourcePath) {
return 'extract'; // Extract from existing command file
} else if (config.source.type === 'text_description') {
return 'generate'; // Generate from requirements
} else if (config.source.type === 'existing_skill') {
return 'restructure'; // Restructure existing content
}
return 'generate';
}
```
## Step 3.2: Mode A - Extract from Command
When source is an existing command file, transform its content into phase file format:
```javascript
function extractPhaseFromCommand(phase, config) {
const sourceContent = Read(phase.sourcePath);
const sourceFrontmatter = extractYAMLFrontmatter(sourceContent);
const sourceBody = removeYAMLFrontmatter(sourceContent);
// Phase file structure:
// 1. Phase header (new)
// 2. Source body content (preserved verbatim)
// 3. Output section (extracted or added)
// 4. Next Phase link (new)
let phaseContent = '';
// 1. Phase header
phaseContent += `# Phase ${phase.number}: ${phase.name}\n\n`;
phaseContent += `${phase.description}.\n\n`;
// 2. Source body content - PRESERVED VERBATIM
// Only modifications:
// a. Remove original H1 title (replaced by phase header)
// b. Remove command-specific frontmatter references
// c. Preserve everything else as-is
// Remove original H1 title line(s)
let bodyContent = sourceBody;
bodyContent = bodyContent.replace(/^# .+\n+/, '');
// Remove command-specific overview if it just restates what the phase header says
// But KEEP any overview content that adds execution detail
phaseContent += bodyContent;
// 3. Ensure Output section exists
if (!bodyContent.includes('## Output')) {
phaseContent += '\n## Output\n\n';
if (phase.outputVariables.length > 0) {
phaseContent += phase.outputVariables.map(v => `- **Variable**: \`${v}\``).join('\n') + '\n';
}
if (phase.outputFiles.length > 0) {
phaseContent += phase.outputFiles.map(f => `- **File**: \`${f}\``).join('\n') + '\n';
}
phaseContent += `- **TodoWrite**: Mark Phase ${phase.number} completed, Phase ${phase.number + 1} in_progress\n`;
}
// 4. Ensure Next Phase link exists
if (!bodyContent.includes('## Next Phase')) {
const nextPhase = config.phases.find(p => p.number === phase.number + 1);
if (nextPhase) {
const nextFilename = `${String(nextPhase.number).padStart(2, '0')}-${nextPhase.slug}.md`;
phaseContent += `\n## Next Phase\n\n`;
phaseContent += `Return to orchestrator, then auto-continue to [Phase ${nextPhase.number}: ${nextPhase.name}](${nextFilename}).\n`;
}
}
return phaseContent;
}
```
### Content Preservation Checklist
When extracting from commands, verify these content types are preserved:
```javascript
function verifyContentPreservation(sourceContent, phaseContent) {
const checks = {
// Count code blocks
sourceCodeBlocks: (sourceContent.match(/```/g) || []).length / 2,
phaseCodeBlocks: (phaseContent.match(/```/g) || []).length / 2,
// Count Task/Agent calls
sourceAgentCalls: (sourceContent.match(/Task\(/g) || []).length,
phaseAgentCalls: (phaseContent.match(/Task\(/g) || []).length,
// Count bash commands
sourceBashBlocks: (sourceContent.match(/```bash/g) || []).length,
phaseBashBlocks: (phaseContent.match(/```bash/g) || []).length,
// Count tables
sourceTables: (sourceContent.match(/\|.*\|.*\|/g) || []).length,
phaseTables: (phaseContent.match(/\|.*\|.*\|/g) || []).length,
// Count AskUserQuestion calls
sourceAUQ: (sourceContent.match(/AskUserQuestion/g) || []).length,
phaseAUQ: (phaseContent.match(/AskUserQuestion/g) || []).length,
// Line count comparison (phase should be >= source minus frontmatter)
sourceLines: sourceContent.split('\n').length,
phaseLines: phaseContent.split('\n').length
};
const issues = [];
if (checks.phaseCodeBlocks < checks.sourceCodeBlocks) {
issues.push(`Missing code blocks: source=${checks.sourceCodeBlocks}, phase=${checks.phaseCodeBlocks}`);
}
if (checks.phaseAgentCalls < checks.sourceAgentCalls) {
issues.push(`Missing agent calls: source=${checks.sourceAgentCalls}, phase=${checks.phaseAgentCalls}`);
}
if (checks.phaseBashBlocks < checks.sourceBashBlocks) {
issues.push(`Missing bash blocks: source=${checks.sourceBashBlocks}, phase=${checks.phaseBashBlocks}`);
}
if (checks.phaseTables < checks.sourceTables * 0.8) {
issues.push(`Missing tables: source=${checks.sourceTables}, phase=${checks.phaseTables}`);
}
if (checks.phaseAUQ < checks.sourceAUQ) {
issues.push(`Missing AskUserQuestion: source=${checks.sourceAUQ}, phase=${checks.phaseAUQ}`);
}
return { checks, issues, passed: issues.length === 0 };
}
```
### Handling Orchestrator-Level Content in Source Commands
Some commands mix orchestrator-level instructions (coordination, TodoWrite) with execution detail. Separation rules:
| Content in Source Command | Goes To | Rule |
|---------------------------|---------|------|
| Phase execution steps, agent prompts, bash commands | **Phase file** | Preserve verbatim |
| TodoWrite update examples specific to this phase | **Phase file** (optional) | Keep if useful for context |
| Inter-phase data passing code | **SKILL.md** Post-Phase Updates | Extract to orchestrator |
| Coordinator instructions ("after this phase, auto-continue") | **SKILL.md** Core Rules | Extract to orchestrator |
| Conditional logic ("if conflict_risk >= medium") | **SKILL.md** Execution Flow | Extract to orchestrator |
When in doubt, **keep content in the phase file**. It's better to have slight overlap than to lose execution detail.
## Step 3.3: Mode B - Generate from Requirements
When source is a text description, generate phase files interactively:
```javascript
function generatePhaseFromRequirements(phase, config) {
let phaseContent = '';
// Phase header
phaseContent += `# Phase ${phase.number}: ${phase.name}\n\n`;
phaseContent += `${phase.description}.\n\n`;
// Objective
phaseContent += `## Objective\n\n`;
phaseContent += `- ${phase.description}\n`;
if (phase.outputVariables.length > 0) {
phaseContent += `- Produce: ${phase.outputVariables.join(', ')}\n`;
}
if (phase.outputFiles.length > 0) {
phaseContent += `- Generate: ${phase.outputFiles.join(', ')}\n`;
}
phaseContent += '\n';
// Execution steps
phaseContent += `## Execution\n\n`;
if (phase.usesAgents) {
// Generate agent delegation skeleton
for (const agentType of phase.agentTypes) {
phaseContent += `### Step: ${agentType} Delegation\n\n`;
phaseContent += '```javascript\n';
phaseContent += `const result = Task({\n`;
phaseContent += ` subagent_type: "${mapAgentType(agentType)}",\n`;
phaseContent += ` prompt: \`\n`;
phaseContent += ` [ROLE] ${agentType}\n`;
phaseContent += ` [TASK] ${phase.description}\n`;
phaseContent += ` [INPUT] \${inputData}\n`;
phaseContent += ` [OUTPUT] \${outputPath}\n`;
phaseContent += ` \`,\n`;
phaseContent += ` run_in_background: false\n`;
phaseContent += `});\n`;
phaseContent += '```\n\n';
}
} else {
// Generate direct execution skeleton
phaseContent += `### Step ${phase.number}.1: Execute\n\n`;
phaseContent += `TODO: Add execution detail for ${phase.name}\n\n`;
}
// Output
phaseContent += `## Output\n\n`;
phase.outputVariables.forEach(v => {
phaseContent += `- **Variable**: \`${v}\`\n`;
});
phase.outputFiles.forEach(f => {
phaseContent += `- **File**: \`${f}\`\n`;
});
phaseContent += `- **TodoWrite**: Mark Phase ${phase.number} completed\n\n`;
// Next Phase
const nextPhase = config.phases.find(p => p.number === phase.number + 1);
if (nextPhase) {
const nextFilename = `${String(nextPhase.number).padStart(2, '0')}-${nextPhase.slug}.md`;
phaseContent += `## Next Phase\n\n`;
phaseContent += `Return to orchestrator, then auto-continue to [Phase ${nextPhase.number}: ${nextPhase.name}](${nextFilename}).\n`;
}
return phaseContent;
}
// Map custom agent type names to Task subagent_types
function mapAgentType(agentType) {
const mapping = {
'cli-explore-agent': 'cli-explore-agent',
'context-search-agent': 'context-search-agent',
'cli-execution-agent': 'cli-execution-agent',
'action-planning-agent': 'action-planning-agent',
'code-developer': 'code-developer',
'test-fix-agent': 'test-fix-agent',
'general-purpose': 'general-purpose',
'Explore': 'Explore'
};
return mapping[agentType] || 'general-purpose';
}
```
## Step 3.4: Write Phase Files
```javascript
function writePhaseFiles(config) {
const skillDir = `.claude/skills/${config.skillName}`;
for (const phase of config.phases) {
const filename = `${String(phase.number).padStart(2, '0')}-${phase.slug}.md`;
const filepath = `${skillDir}/phases/${filename}`;
const strategy = selectGenerationStrategy(phase, config);
let content;
switch (strategy) {
case 'extract':
content = extractPhaseFromCommand(phase, config);
// Verify content preservation
const sourceContent = Read(phase.sourcePath);
const verification = verifyContentPreservation(sourceContent, content);
if (!verification.passed) {
console.warn(`⚠️ Content preservation issues for Phase ${phase.number}:`);
verification.issues.forEach(issue => console.warn(` - ${issue}`));
// Re-extract with more aggressive preservation
content = extractPhaseFromCommand(phase, config, { aggressive: true });
}
break;
case 'generate':
content = generatePhaseFromRequirements(phase, config);
break;
case 'restructure':
content = restructureExistingPhase(phase, config);
break;
}
Write(filepath, content);
console.log(`✓ Generated: ${filepath} (${content.split('\n').length} lines)`);
}
}
```
## Step 3.5: Cross-Phase Consistency Check
After generating all phase files, verify cross-phase consistency:
```javascript
function checkCrossPhaseConsistency(config) {
const skillDir = `.claude/skills/${config.skillName}`;
const issues = [];
for (const phase of config.phases) {
const filename = `${String(phase.number).padStart(2, '0')}-${phase.slug}.md`;
const content = Read(`${skillDir}/phases/${filename}`);
// Check: Next Phase links point to correct file
const nextPhaseMatch = content.match(/\[Phase (\d+): (.+?)\]\((.+?)\)/);
if (nextPhaseMatch) {
const nextNum = parseInt(nextPhaseMatch[1]);
const nextPhase = config.phases.find(p => p.number === nextNum);
if (!nextPhase) {
issues.push(`Phase ${phase.number}: Next Phase link points to non-existent Phase ${nextNum}`);
}
}
// Check: Output variables match config
for (const varName of phase.outputVariables) {
if (!content.includes(varName)) {
issues.push(`Phase ${phase.number}: Output variable '${varName}' not mentioned in content`);
}
}
}
return issues;
}
```
## Size Comparison Reference
Expected phase file sizes relative to their source commands:
| Scenario | Phase File Size vs Source | Reason |
|----------|--------------------------|--------|
| Command extraction | ≥ 90% of source | Minor removals (H1 title, frontmatter) |
| New generation (with agents) | 50-200 lines | Agent prompt skeletons |
| New generation (direct) | 30-80 lines | Step skeletons |
| Restructure | ~100% of source | Content reorganization only |
**Red Flag**: If a phase file is significantly smaller than its source (< 70%), content was likely lost during extraction. Re-check with `verifyContentPreservation()`.
## Output
- **Files**: `.claude/skills/{skillName}/phases/0N-{slug}.md` for each phase
- **TodoWrite**: Mark Phase 3 completed, Phase 4 in_progress
## Next Phase
Return to orchestrator, then auto-continue to [Phase 4: Validation & Integration](04-validation.md).

View File

@@ -0,0 +1,397 @@
# Phase 4: Validation & Integration
Validate the generated skill package for structural completeness, reference integrity, and content quality. Produce a validation report and integration summary.
## Objective
- Verify all required files exist
- Validate SKILL.md references match actual phase files
- Check content preservation (for command extraction source)
- Verify cross-phase data flow consistency
- Report validation results to user
## Step 4.1: Structural Validation
```javascript
function validateStructure(config) {
const skillDir = `.claude/skills/${config.skillName}`;
const results = { errors: [], warnings: [], info: [] };
// Check SKILL.md exists
const skillMdExists = fileExists(`${skillDir}/SKILL.md`);
if (!skillMdExists) {
results.errors.push('SKILL.md not found');
}
// Check all phase files exist
for (const phase of config.phases) {
const filename = `${String(phase.number).padStart(2, '0')}-${phase.slug}.md`;
const filepath = `${skillDir}/phases/${filename}`;
if (!fileExists(filepath)) {
results.errors.push(`Phase file missing: ${filepath}`);
}
}
// Check SKILL.md frontmatter
if (skillMdExists) {
const skillMd = Read(`${skillDir}/SKILL.md`);
const fm = extractYAMLFrontmatter(skillMd);
if (!fm.name) results.errors.push('Frontmatter missing: name');
if (!fm.description) results.errors.push('Frontmatter missing: description');
if (!fm['allowed-tools']) results.errors.push('Frontmatter missing: allowed-tools');
// Check description has trigger phrase
if (fm.description && !fm.description.includes('Triggers on')) {
results.warnings.push('Description missing trigger phrase (Triggers on "...")');
}
}
return results;
}
```
## Step 4.2: Reference Integrity
```javascript
function validateReferences(config) {
const skillDir = `.claude/skills/${config.skillName}`;
const results = { errors: [], warnings: [], info: [] };
const skillMd = Read(`${skillDir}/SKILL.md`);
// Extract all Ref: markers from SKILL.md
const refMarkers = skillMd.match(/Ref: phases\/\S+\.md/g) || [];
const linkedFiles = skillMd.match(/\[phases\/\S+\.md\]\(phases\/\S+\.md\)/g) || [];
// Collect all referenced phase files
const referencedFiles = new Set();
for (const ref of refMarkers) {
referencedFiles.add(ref.replace('Ref: ', ''));
}
for (const link of linkedFiles) {
const match = link.match(/\(phases\/\S+\.md\)/);
if (match) referencedFiles.add(match[0].replace(/[()]/g, ''));
}
// Check each referenced file exists
for (const refFile of referencedFiles) {
if (!fileExists(`${skillDir}/${refFile}`)) {
results.errors.push(`Referenced file not found: ${refFile}`);
}
}
// Check each phase file is referenced in SKILL.md
for (const phase of config.phases) {
const filename = `phases/${String(phase.number).padStart(2, '0')}-${phase.slug}.md`;
if (!referencedFiles.has(filename)) {
results.warnings.push(`Phase file not referenced in SKILL.md: ${filename}`);
}
}
// Check Phase Reference Documents table exists
if (!skillMd.includes('Phase Reference Documents')) {
results.errors.push('SKILL.md missing Phase Reference Documents table');
}
// Check Phase Reference Documents table has entries for all phases
for (const phase of config.phases) {
const filename = `${String(phase.number).padStart(2, '0')}-${phase.slug}.md`;
if (!skillMd.includes(filename)) {
results.errors.push(`Phase Reference table missing entry for: ${filename}`);
}
}
return results;
}
```
## Step 4.3: Content Quality (Command Extraction Only)
```javascript
function validateContentQuality(config) {
const skillDir = `.claude/skills/${config.skillName}`;
const results = { errors: [], warnings: [], info: [] };
if (config.source.type !== 'command_set') {
results.info.push('Content quality check skipped (not command extraction)');
return results;
}
for (const phase of config.phases) {
if (!phase.sourcePath) continue;
const sourceContent = Read(phase.sourcePath);
const sourceBody = removeYAMLFrontmatter(sourceContent);
const filename = `${String(phase.number).padStart(2, '0')}-${phase.slug}.md`;
const phaseContent = Read(`${skillDir}/phases/${filename}`);
// Line count comparison
const sourceLines = sourceBody.split('\n').length;
const phaseLines = phaseContent.split('\n').length;
const ratio = phaseLines / sourceLines;
if (ratio < 0.7) {
results.errors.push(
`Phase ${phase.number} content loss: source=${sourceLines} lines, phase=${phaseLines} lines (${Math.round(ratio * 100)}%)`
);
} else if (ratio < 0.9) {
results.warnings.push(
`Phase ${phase.number} possible content reduction: source=${sourceLines}, phase=${phaseLines} (${Math.round(ratio * 100)}%)`
);
} else {
results.info.push(
`Phase ${phase.number} content preserved: source=${sourceLines}, phase=${phaseLines} (${Math.round(ratio * 100)}%)`
);
}
// Code block count comparison
const sourceBlocks = (sourceBody.match(/```/g) || []).length / 2;
const phaseBlocks = (phaseContent.match(/```/g) || []).length / 2;
if (phaseBlocks < sourceBlocks) {
results.warnings.push(
`Phase ${phase.number} missing code blocks: source=${sourceBlocks}, phase=${phaseBlocks}`
);
}
// Agent prompt preservation
const sourceAgents = (sourceBody.match(/Task\(|subagent_type/g) || []).length;
const phaseAgents = (phaseContent.match(/Task\(|subagent_type/g) || []).length;
if (phaseAgents < sourceAgents) {
results.errors.push(
`Phase ${phase.number} missing agent calls: source=${sourceAgents}, phase=${phaseAgents}`
);
}
}
return results;
}
```
## Step 4.4: Data Flow Consistency
```javascript
function validateDataFlow(config) {
const skillDir = `.claude/skills/${config.skillName}`;
const results = { errors: [], warnings: [], info: [] };
const skillMd = Read(`${skillDir}/SKILL.md`);
// Check all data flow variables are mentioned in SKILL.md
for (const flow of config.dataFlow) {
for (const variable of flow.variables) {
if (!skillMd.includes(variable)) {
results.warnings.push(
`Data flow variable '${variable}' (${flow.from}${flow.to}) not found in SKILL.md`
);
}
}
}
// Check conditional phases have their condition in SKILL.md
for (const phase of config.phases) {
if (phase.isConditional && phase.condition) {
// Extract the key variable from condition
const condVar = phase.condition.match(/\w+/)?.[0];
if (condVar && !skillMd.includes(condVar)) {
results.errors.push(
`Conditional Phase ${phase.number} condition variable '${condVar}' not found in SKILL.md`
);
}
}
}
return results;
}
```
## Step 4.5: SKILL.md Section Completeness
```javascript
function validateSkillMdSections(config) {
const skillDir = `.claude/skills/${config.skillName}`;
const results = { errors: [], warnings: [], info: [] };
const skillMd = Read(`${skillDir}/SKILL.md`);
// Required sections
const requiredSections = [
{ name: 'Architecture Overview', pattern: /## Architecture Overview/ },
{ name: 'Execution Flow', pattern: /## Execution Flow/ },
{ name: 'Core Rules', pattern: /## Core Rules/ },
{ name: 'Data Flow', pattern: /## Data Flow/ },
{ name: 'Error Handling', pattern: /## Error Handling/ }
];
// Recommended sections
const recommendedSections = [
{ name: 'Key Design Principles', pattern: /## Key Design Principles/ },
{ name: 'Input Processing', pattern: /## Input Processing/ },
{ name: 'TodoWrite Pattern', pattern: /## TodoWrite Pattern/ },
{ name: 'Coordinator Checklist', pattern: /## Coordinator Checklist/ },
{ name: 'Related Commands', pattern: /## Related Commands/ }
];
// Conditional sections
const conditionalSections = [
{ name: 'Auto Mode', pattern: /## Auto Mode/, condition: config.features.hasAutoMode },
{ name: 'Post-Phase Updates', pattern: /## Post-Phase Updates/, condition: config.features.hasPostPhaseUpdates }
];
for (const section of requiredSections) {
if (!section.pattern.test(skillMd)) {
results.errors.push(`Missing required section: ${section.name}`);
}
}
for (const section of recommendedSections) {
if (!section.pattern.test(skillMd)) {
results.warnings.push(`Missing recommended section: ${section.name}`);
}
}
for (const section of conditionalSections) {
if (section.condition && !section.pattern.test(skillMd)) {
results.warnings.push(`Missing conditional section: ${section.name} (feature enabled but section absent)`);
}
}
return results;
}
```
## Step 4.6: Aggregate Results and Report
```javascript
function generateValidationReport(config) {
const structural = validateStructure(config);
const references = validateReferences(config);
const content = validateContentQuality(config);
const dataFlow = validateDataFlow(config);
const sections = validateSkillMdSections(config);
// Aggregate
const allErrors = [
...structural.errors,
...references.errors,
...content.errors,
...dataFlow.errors,
...sections.errors
];
const allWarnings = [
...structural.warnings,
...references.warnings,
...content.warnings,
...dataFlow.warnings,
...sections.warnings
];
const allInfo = [
...structural.info,
...references.info,
...content.info,
...dataFlow.info,
...sections.info
];
// Quality gate
const gate = allErrors.length === 0 ? 'PASS' :
allErrors.length <= 2 ? 'REVIEW' : 'FAIL';
// Display report
const skillDir = `.claude/skills/${config.skillName}`;
console.log(`
╔══════════════════════════════════════╗
║ Workflow Skill Validation Report ║
╠══════════════════════════════════════╣
║ Skill: ${config.skillName.padEnd(28)}
║ Gate: ${gate.padEnd(28)}
╚══════════════════════════════════════╝
Structure:
${skillDir}/
├── SKILL.md ${fileExists(`${skillDir}/SKILL.md`) ? '✓' : '✗'}
└── phases/
${config.phases.map(p => {
const fn = `${String(p.number).padStart(2, '0')}-${p.slug}.md`;
return ` ├── ${fn.padEnd(30)} ${fileExists(`${skillDir}/phases/${fn}`) ? '✓' : '✗'}`;
}).join('\n')}
${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 ✓'}
${allInfo.length > 0 ? `Info:\n${allInfo.map(i => ` ${i}`).join('\n')}` : ''}
`);
return { gate, errors: allErrors, warnings: allWarnings, info: allInfo };
}
```
## Step 4.7: Error Recovery
If validation fails, offer recovery options:
```javascript
if (report.gate === 'FAIL') {
const recovery = AskUserQuestion({
questions: [{
question: `Validation found ${report.errors.length} errors. How to proceed?`,
header: "Recovery",
multiSelect: false,
options: [
{ label: "Auto-fix", description: "Attempt automatic fixes for common issues" },
{ label: "Regenerate phases", description: "Re-run Phase 3 with stricter preservation" },
{ label: "Accept as-is", description: "Proceed despite errors (manual fix later)" }
]
}]
});
if (recovery === 'Auto-fix') {
// Common auto-fixes:
// 1. Missing Next Phase links → add them
// 2. Missing Output sections → add from config
// 3. Missing Phase Reference table → generate from config
autoFixCommonIssues(config, report.errors);
// Re-validate
return generateValidationReport(config);
}
}
```
## Step 4.8: Integration Summary
```javascript
function displayIntegrationSummary(config) {
console.log(`
Integration Complete:
Location: .claude/skills/${config.skillName}/
Files: ${config.phases.length + 1} (SKILL.md + ${config.phases.length} phases)
Usage:
Trigger: ${config.triggers.map(t => `"${t}"`).join(', ')}
Auto: /${config.triggers[0]} --yes "task description"
Design Patterns Applied:
✓ Progressive phase loading (Ref: markers)
✓ Phase Reference Documents table
${config.features.hasTodoWriteSubTasks ? '✓' : '○'} TodoWrite attachment/collapse
${config.features.hasConditionalPhases ? '✓' : '○'} Conditional phase execution
${config.features.hasAutoMode ? '✓' : '○'} Auto mode (--yes flag)
${config.features.hasPostPhaseUpdates ? '✓' : '○'} Post-phase state updates
${config.features.hasPlanningNotes ? '✓' : '○'} Accumulated planning notes
Next Steps:
1. Review SKILL.md orchestrator logic
2. Review each phase file for completeness
3. Test skill invocation: /${config.triggers[0]} "test task"
4. Iterate based on execution results
`);
}
```
## Output
- **Report**: Validation results with quality gate (PASS/REVIEW/FAIL)
- **TodoWrite**: Mark Phase 4 completed (all tasks done)
## Completion
Workflow Skill Designer has completed. The generated skill package is ready at `.claude/skills/{skillName}/`.