mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-14 02:42:04 +08:00
- 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
13 KiB
13 KiB
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.mdas 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
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
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:
// 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
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.
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
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
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:
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
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:
- SKILL.md must NOT contain full execution detail (agent prompts, bash commands)
- SKILL.md MUST contain
Ref:markers pointing to phase files - SKILL.md MUST contain Phase Reference Documents table
- Every phase mentioned in Execution Flow must have a corresponding phase file
- 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.