Files
Claude-Code-Workflow/.claude/skills/workflow-tune/phases/01-setup.md
catlog22 d5b6480528 feat: add workflow-tune skill for multi-step workflow pipeline optimization
New skill that executes workflow step chains sequentially, inspects artifacts,
analyzes quality via ccw cli resume chain (Gemini), and generates optimization
reports. Supports 4 input formats: pipe-separated commands, comma-separated
skills, JSON file, and natural language with semantic decomposition.

Key features:
- Orchestrator + 5-phase progressive loading architecture
- Intent-to-tool mapping with ambiguity resolution for NL input
- Command document generation with pre-execution confirmation loop
- Per-step analysis + cross-step synthesis via resume chain
- Auto-fix with user confirmation safety gate

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 14:55:47 +08:00

455 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 1: Setup
Initialize workspace, parse workflow definition, semantic decomposition for natural language, generate command document, user confirmation, create state and process log.
## Objective
- Parse workflow steps from user input (Format 1-3: direct parse, Format 4: semantic decomposition)
- Generate Command Document (formatted execution plan)
- User confirmation: Execute / Edit steps / Cancel
- Validate step commands/skill paths
- Create isolated workspace directory
- Initialize workflow-state.json and process-log.md
## Execution
### Step 1.1: Parse Input
```javascript
const args = $ARGUMENTS.trim();
// Detect input format
let steps = [];
let workflowName = 'unnamed-workflow';
let workflowContext = '';
// Format 1: JSON file (--file path)
const fileMatch = args.match(/--file\s+"?([^\s"]+)"?/);
if (fileMatch) {
const wfDef = JSON.parse(Read(fileMatch[1]));
workflowName = wfDef.name || 'unnamed-workflow';
workflowContext = wfDef.description || '';
steps = wfDef.steps;
}
// Format 2: Pipe-separated commands ("cmd1 | cmd2 | cmd3")
else if (args.includes('|')) {
const rawSteps = args.split(/(?:--context|--depth|-y|--yes|--auto-fix)\s+("[^"]*"|\S+)/)[0];
steps = rawSteps.split('|').map((cmd, i) => ({
name: `step-${i + 1}`,
type: cmd.trim().startsWith('/') ? 'skill'
: cmd.trim().startsWith('ccw cli') ? 'ccw-cli'
: 'command',
command: cmd.trim(),
expected_artifacts: [],
success_criteria: ''
}));
}
// Format 3: Comma-separated skill names (matches pattern: word,word or word-word,word-word)
else if (/^[\w-]+(,[\w-]+)+/.test(args.split(/\s/)[0])) {
const skillPart = args.match(/^([^\s]+)/);
const skillNames = skillPart ? skillPart[1].split(',') : [];
steps = skillNames.map((name, i) => {
const skillPath = name.startsWith('.claude/') ? name : `.claude/skills/${name}`;
return {
name: name.replace('.claude/skills/', ''),
type: 'skill',
command: `/${name.replace('.claude/skills/', '')}`,
skill_path: skillPath,
expected_artifacts: [],
success_criteria: ''
};
});
}
// Format 4: Natural language → semantic decomposition
else {
inputFormat = 'natural-language';
naturalLanguageInput = args.replace(/--\w+\s+"[^"]*"/g, '').replace(/--\w+\s+\S+/g, '').replace(/-y|--yes/g, '').trim();
// Steps will be populated in Step 1.1b
steps = [];
}
// Parse --context
const contextMatch = args.match(/--context\s+"([^"]+)"/);
workflowContext = contextMatch ? contextMatch[1] : workflowContext;
// Parse --depth
const depthMatch = args.match(/--depth\s+(quick|standard|deep)/);
if (depthMatch) {
workflowPreferences.analysisDepth = depthMatch[1];
}
// If no context provided, ask user
if (!workflowContext) {
const response = AskUserQuestion({
questions: [{
question: "请描述这个 workflow 的目标和预期效果:",
header: "Workflow Context",
multiSelect: false,
options: [
{ label: "General quality check", description: "通用质量检查,评估步骤间衔接" },
{ label: "Custom description", description: "自定义描述 workflow 目标" }
]
}]
});
workflowContext = response["Workflow Context"];
}
```
### Step 1.1b: Semantic Decomposition (Format 4 only)
> Skip this step if `inputFormat !== 'natural-language'`.
Decompose natural language input into a structured step chain by identifying intent verbs and mapping them to available tools/skills.
```javascript
if (inputFormat === 'natural-language') {
// Intent-to-tool mapping (regex patterns → tool config)
const intentMap = [
{ pattern: /分析|analyze|审查|inspect|scan/i, name: 'analyze', tool: 'gemini', mode: 'analysis', rule: 'analysis-analyze-code-patterns' },
{ pattern: /评审|review|code.?review/i, name: 'review', tool: 'gemini', mode: 'analysis', rule: 'analysis-review-code-quality' },
{ pattern: /诊断|debug|排查|diagnose/i, name: 'diagnose', tool: 'gemini', mode: 'analysis', rule: 'analysis-diagnose-bug-root-cause' },
{ pattern: /安全|security|漏洞|vulnerability/i, name: 'security-audit', tool: 'gemini', mode: 'analysis', rule: 'analysis-assess-security-risks' },
{ pattern: /性能|performance|perf/i, name: 'perf-analysis', tool: 'gemini', mode: 'analysis', rule: 'analysis-analyze-performance' },
{ pattern: /架构|architecture/i, name: 'arch-review', tool: 'gemini', mode: 'analysis', rule: 'analysis-review-architecture' },
{ pattern: /修复|fix|repair|解决/i, name: 'fix', tool: 'claude', mode: 'write', rule: 'development-debug-runtime-issues' },
{ pattern: /实现|implement|开发|create|新增/i, name: 'implement', tool: 'claude', mode: 'write', rule: 'development-implement-feature' },
{ pattern: /重构|refactor/i, name: 'refactor', tool: 'claude', mode: 'write', rule: 'development-refactor-codebase' },
{ pattern: /测试|test|generate.?test/i, name: 'test', tool: 'claude', mode: 'write', rule: 'development-generate-tests' },
{ pattern: /规划|plan|设计|design/i, name: 'plan', tool: 'gemini', mode: 'analysis', rule: 'planning-plan-architecture-design' },
{ pattern: /拆解|breakdown|分解/i, name: 'breakdown', tool: 'gemini', mode: 'analysis', rule: 'planning-breakdown-task-steps' },
];
// Segment input by Chinese/English delimiters: 、,,;然后/接着/最后/之后 etc.
const segments = naturalLanguageInput
.split(/[,;、]|(?:然后|接着|之后|最后|再|并|and then|then|finally|next)\s*/i)
.map(s => s.trim())
.filter(Boolean);
// Match each segment to an intent (with ambiguity resolution)
steps = segments.map((segment, i) => {
const allMatches = intentMap.filter(m => m.pattern.test(segment));
let matched = allMatches[0] || null;
// ★ Ambiguity resolution: if multiple intents match, ask user
if (allMatches.length > 1) {
const disambig = AskUserQuestion({
questions: [{
question: `"${segment}" 匹配到多个意图,请选择最符合的:`,
header: `Disambiguate Step ${i + 1}`,
multiSelect: false,
options: allMatches.map(m => ({
label: m.name,
description: `Tool: ${m.tool}, Mode: ${m.mode}, Rule: ${m.rule}`
}))
}]
});
const chosen = disambig[`Disambiguate Step ${i + 1}`];
matched = allMatches.find(m => m.name === chosen) || allMatches[0];
}
if (matched) {
// Extract target scope from segment (e.g., "分析 src 目录" → scope = "src")
const scopeMatch = segment.match(/(?:目录|文件|模块|directory|file|module)?\s*[:]?\s*(\S+)/);
const scope = scopeMatch ? scopeMatch[1].replace(/[的地得]$/, '') : '**/*';
return {
name: `${matched.name}`,
type: 'ccw-cli',
command: `ccw cli -p "${segment}" --tool ${matched.tool} --mode ${matched.mode} --rule ${matched.rule}`,
tool: matched.tool,
mode: matched.mode,
rule: matched.rule,
original_text: segment,
expected_artifacts: [],
success_criteria: ''
};
} else {
// Unmatched segment → generic analysis step
return {
name: `step-${i + 1}`,
type: 'ccw-cli',
command: `ccw cli -p "${segment}" --tool gemini --mode analysis`,
tool: 'gemini',
mode: 'analysis',
rule: 'universal-rigorous-style',
original_text: segment,
expected_artifacts: [],
success_criteria: ''
};
}
});
// Deduplicate: if same intent name appears twice, suffix with index
const nameCount = {};
steps.forEach(s => {
nameCount[s.name] = (nameCount[s.name] || 0) + 1;
if (nameCount[s.name] > 1) {
s.name = `${s.name}-${nameCount[s.name]}`;
}
});
// Set workflow context from the full natural language input
if (!workflowContext) {
workflowContext = naturalLanguageInput;
}
workflowName = 'nl-workflow'; // natural language derived
}
```
### Step 1.1c: Generate Command Document
Generate a formatted execution plan for user review. This runs for ALL input formats, not just Format 4.
```javascript
function generateCommandDoc(steps, workflowName, workflowContext, analysisDepth) {
const stepTable = steps.map((s, i) => {
const tool = s.tool || (s.type === 'skill' ? '-' : 'claude');
const mode = s.mode || (s.type === 'skill' ? '-' : 'write');
const cmdPreview = s.command.length > 60 ? s.command.substring(0, 57) + '...' : s.command;
return `| ${i + 1} | ${s.name} | ${s.type} | \`${cmdPreview}\` | ${tool} | ${mode} |`;
}).join('\n');
const flowDiagram = steps.map((s, i) => {
const arrow = i < steps.length - 1 ? '\n ↓' : '';
const feedsInto = i < steps.length - 1 ? `Feeds into: Step ${i + 2} (${steps[i + 1].name})` : 'Final step';
const originalText = s.original_text ? `\n Source: "${s.original_text}"` : '';
return `Step ${i + 1}: ${s.name}
Command: ${s.command}
Type: ${s.type} | Tool: ${s.tool || '-'} | Mode: ${s.mode || '-'}${originalText}
${feedsInto}${arrow}`;
}).join('\n');
const totalCli = steps.filter(s => s.type === 'ccw-cli').length;
const totalSkill = steps.filter(s => s.type === 'skill').length;
const totalCmd = steps.filter(s => s.type === 'command').length;
return `# Workflow Tune — Execution Plan
**Workflow**: ${workflowName}
**Goal**: ${workflowContext}
**Steps**: ${steps.length}
**Analysis Depth**: ${analysisDepth}
## Step Chain
| # | Name | Type | Command | Tool | Mode |
|---|------|------|---------|------|------|
${stepTable}
## Execution Flow
\`\`\`
${flowDiagram}
\`\`\`
## Estimated Scope
- CLI execute calls: ${totalCli}
- Skill invocations: ${totalSkill}
- Shell commands: ${totalCmd}
- Analysis calls (gemini --resume chain): ${steps.length} (per-step) + 1 (synthesis)
- Process documentation: process-log.md (accumulated)
- Final output: final-report.md with optimization recommendations
`;
}
const commandDoc = generateCommandDoc(steps, workflowName, workflowContext, workflowPreferences.analysisDepth);
// Output command document to user (direct text output)
// The orchestrator displays this as formatted text before confirmation
```
### Step 1.1d: Pre-Execution Confirmation
```javascript
// ★ Skip confirmation if -y/--yes auto mode
if (!workflowPreferences.autoYes) {
// Display commandDoc to user as formatted text output
// Then ask for confirmation
const confirmation = AskUserQuestion({
questions: [{
question: "确认执行以上 Workflow 调优计划?",
header: "Confirm Execution",
multiSelect: false,
options: [
{ label: "Execute (确认执行)", description: "按计划开始执行所有步骤" },
{ label: "Edit steps (修改步骤)", description: "调整步骤顺序、增删步骤、更换工具" },
{ label: "Cancel (取消)", description: "取消本次调优" }
]
}]
});
const choice = confirmation["Confirm Execution"];
if (choice.startsWith("Cancel")) {
// Abort: no workspace created, no state written
// Output: "Workflow tune cancelled."
return;
}
if (choice.startsWith("Edit")) {
// Enter edit loop: ask user what to change, apply, re-display, re-confirm
let editing = true;
while (editing) {
const editResponse = AskUserQuestion({
questions: [{
question: "请描述要修改的内容:\n" +
" - 删除步骤: '删除步骤2' 或 'remove step 2'\n" +
" - 添加步骤: '在步骤1后加入安全扫描' 或 'add security scan after step 1'\n" +
" - 修改工具: '步骤3改用codex' 或 'step 3 use codex'\n" +
" - 调换顺序: '步骤2和步骤3互换' 或 'swap step 2 and 3'\n" +
" - 修改命令: '步骤1命令改为 ccw cli -p \"...\" --tool gemini'",
header: "Edit Steps"
}]
});
const editText = editResponse["Edit Steps"];
// Apply edits to steps[] based on user instruction
// The orchestrator interprets the edit instruction and modifies steps:
//
// Delete: filter out the specified step, re-index
// Add: insert new step at specified position
// Modify tool: update the step's tool/mode/command
// Swap: exchange positions of two steps
// Modify command: replace command string
//
// After applying edits, re-generate command doc and re-display
const updatedCommandDoc = generateCommandDoc(steps, workflowName, workflowContext, workflowPreferences.analysisDepth);
// Display updatedCommandDoc to user
const reconfirm = AskUserQuestion({
questions: [{
question: "修改后的计划如上,是否确认?",
header: "Confirm Execution",
multiSelect: false,
options: [
{ label: "Execute (确认执行)", description: "按修改后的计划执行" },
{ label: "Edit more (继续修改)", description: "还需要调整" },
{ label: "Cancel (取消)", description: "取消本次调优" }
]
}]
});
const reChoice = reconfirm["Confirm Execution"];
if (reChoice.startsWith("Execute")) {
editing = false;
} else if (reChoice.startsWith("Cancel")) {
return; // Abort
}
// else: continue editing loop
}
}
// choice === "Execute" → proceed to workspace creation
}
// Save command doc for reference
// Will be written to workspace after Step 1.3
```
### Step 1.2: Validate Steps
```javascript
for (const step of steps) {
if (step.type === 'skill' && step.skill_path) {
const skillFiles = Glob(`${step.skill_path}/SKILL.md`);
if (skillFiles.length === 0) {
step.validation = 'warning';
step.validation_msg = `Skill not found: ${step.skill_path}`;
} else {
step.validation = 'ok';
}
} else {
// Command-type steps: basic validation (non-empty)
step.validation = step.command && step.command.trim() ? 'ok' : 'invalid';
}
}
const invalidSteps = steps.filter(s => s.validation === 'invalid');
if (invalidSteps.length > 0) {
throw new Error(`Invalid steps: ${invalidSteps.map(s => s.name).join(', ')}`);
}
```
### Step 1.3: Create Workspace
```javascript
const ts = Date.now();
const workDir = `.workflow/.scratchpad/workflow-tune-${ts}`;
Bash(`mkdir -p "${workDir}/steps"`);
// Create per-step directories
for (let i = 0; i < steps.length; i++) {
Bash(`mkdir -p "${workDir}/steps/step-${i + 1}/artifacts"`);
}
```
### Step 1.3b: Save Command Document
```javascript
// Save confirmed command doc to workspace for reference
Write(`${workDir}/command-doc.md`, commandDoc);
```
### Step 1.4: Initialize State
```javascript
const initialState = {
status: 'running',
started_at: new Date().toISOString(),
updated_at: new Date().toISOString(),
workflow_name: workflowName,
workflow_context: workflowContext,
analysis_depth: workflowPreferences.analysisDepth,
auto_fix: workflowPreferences.autoFix,
steps: steps.map((s, i) => ({
...s,
index: i,
status: 'pending',
execution: null,
analysis: null
})),
analysis_session_id: null, // ccw cli resume chain
process_log_entries: [],
synthesis: null,
errors: [],
error_count: 0,
max_errors: 3,
work_dir: workDir
};
Write(`${workDir}/workflow-state.json`, JSON.stringify(initialState, null, 2));
```
### Step 1.5: Initialize Process Log
```javascript
const processLog = `# Workflow Tune Process Log
**Workflow**: ${workflowName}
**Context**: ${workflowContext}
**Steps**: ${steps.length}
**Analysis Depth**: ${workflowPreferences.analysisDepth}
**Started**: ${new Date().toISOString()}
---
`;
Write(`${workDir}/process-log.md`, processLog);
```
## Output
- **Variables**: `workDir`, `steps[]`, `workflowContext`, `commandDoc`, initialized state
- **Files**: `workflow-state.json`, `process-log.md`, `command-doc.md`, per-step directories
- **User Confirmation**: Execution plan confirmed (or cancelled → abort)
- **TaskUpdate**: Mark Phase 1 completed, start Step Loop