
Skill Tuning
- 79 installs
- 2.1k repo stars
- Updated June 18, 2026
- catlog22/claude-code-workflow
Support for skill-tuning
About
Provides workflow support for skill-tuning. Solo builders use this to streamline development.
- skill-tuning
Skill Tuning by the numbers
- 79 all-time installs (skills.sh)
- Ranked #1,455 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/catlog22/claude-code-workflow --skill skill-tuningAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 79 |
|---|---|
| repo stars | ★ 2.1k |
| Last updated | June 18, 2026 |
| Repository | catlog22/claude-code-workflow ↗ |
What it does
Support for skill-tuning
Files
Skill Tuning
Autonomous diagnosis and optimization for skill execution issues.
Architecture
┌─────────────────────────────────────────────────────┐
│ Phase 0: Read Specs (mandatory) │
│ → problem-taxonomy.md, tuning-strategies.md │
└─────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────┐
│ Orchestrator (state-driven) │
│ Read state → Select action → Execute → Update → ✓ │
└─────────────────────────────────────────────────────┘
↓ ↓
┌──────────────────────┐ ┌──────────────────┐
│ Diagnosis Phase │ │ Gemini CLI │
│ • Context │ │ Deep analysis │
│ • Memory │ │ (on-demand) │
│ • DataFlow │ │ │
│ • Agent │ │ Complex issues │
│ • Docs │ │ Architecture │
│ • Token Usage │ │ Performance │
└──────────────────────┘ └──────────────────┘
↓
┌───────────────────┐
│ Fix & Verify │
│ Apply → Re-test │
└───────────────────┘Core Issues Detected
| Priority | Problem | Root Cause | Fix Strategy |
|---|---|---|---|
| P0 | Authoring Violation | Intermediate files, state bloat, file relay | eliminate_intermediate, minimize_state |
| P1 | Data Flow Disruption | Scattered state, inconsistent formats | state_centralization, schema_enforcement |
| P2 | Agent Coordination | Fragile chains, no error handling | error_wrapping, result_validation |
| P3 | Context Explosion | Unbounded history, full content passing | sliding_window, path_reference |
| P4 | Long-tail Forgetting | Early constraint loss | constraint_injection, checkpoint_restore |
| P5 | Token Consumption | Verbose prompts, state bloat | prompt_compression, lazy_loading |
Problem Categories (Detailed Specs)
See specs/problem-taxonomy.md for:
- Detection patterns (regex/checks)
- Severity calculations
- Impact assessments
Tuning Strategies (Detailed Specs)
See specs/tuning-strategies.md for:
- 10+ strategies per category
- Implementation patterns
- Verification methods
Workflow
| Step | Action | Orchestrator Decision | Output |
|---|---|---|---|
| 1 | action-init | status='pending' | Backup, session created |
| 2 | action-analyze-requirements | After init | Required dimensions + coverage |
| 3 | Diagnosis (6 types) | Focus areas | state.diagnosis.{type} |
| 4 | action-gemini-analysis | Critical issues OR user request | Deep findings |
| 5 | action-generate-report | All diagnosis complete | state.final_report |
| 6 | action-propose-fixes | Issues found | state.proposed_fixes[] |
| 7 | action-apply-fix | Pending fixes | Applied + verified |
| 8 | action-complete | Quality gates pass | session.status='completed' |
Action Reference
| Category | Actions | Purpose |
|---|---|---|
| Setup | action-init | Initialize backup, session state |
| Analysis | action-analyze-requirements | Decompose user request via Gemini CLI |
| Diagnosis | action-diagnose-{context,memory,dataflow,agent,docs,token_consumption} | Detect category-specific issues |
| Deep Analysis | action-gemini-analysis | Gemini CLI: complex/critical issues |
| Reporting | action-generate-report | Consolidate findings → final_report |
| Fixing | action-propose-fixes, action-apply-fix | Generate + apply fixes |
| Verify | action-verify | Re-run diagnosis, check gates |
| Exit | action-complete, action-abort | Finalize or rollback |
Full action details: phases/actions/
State Management
Single source of truth: .workflow/.scratchpad/skill-tuning-{ts}/state.json
{
"status": "pending|running|completed|failed",
"target_skill": { "name": "...", "path": "..." },
"diagnosis": {
"context": {...},
"memory": {...},
"dataflow": {...},
"agent": {...},
"docs": {...},
"token_consumption": {...}
},
"issues": [{"id":"...", "severity":"...", "category":"...", "strategy":"..."}],
"proposed_fixes": [...],
"applied_fixes": [...],
"quality_gate": "pass|fail",
"final_report": "..."
}See phases/state-schema.md for complete schema.
Orchestrator Logic
See phases/orchestrator.md for:
- Decision logic (termination checks → action selection)
- State transitions
- Error recovery
Key Principles
1. Problem-First: Diagnosis before any fix 2. Data-Driven: Record traces, token counts, snapshots 3. Iterative: Multiple rounds until quality gates pass 4. Reversible: All changes with backup checkpoints 5. Non-Invasive: Minimal changes, maximum clarity
Usage Examples
# Basic skill diagnosis
/skill-tuning "Fix memory leaks in my skill"
# Deep analysis with Gemini
/skill-tuning "Architecture issues in async workflow"
# Focus on specific areas
/skill-tuning "Optimize token consumption and fix agent coordination"
# Custom issue
/skill-tuning "My skill produces inconsistent outputs"Output
After completion, review:
.workflow/.scratchpad/skill-tuning-{ts}/state.json- Full state with final_reportstate.final_report- Markdown summary (in state.json)state.applied_fixes- List of applied fixes with verification results
Reference Documents
| Document | Purpose |
|---|---|
| specs/problem-taxonomy.md | Classification + detection patterns |
| specs/tuning-strategies.md | Fix implementation guide |
| specs/dimension-mapping.md | Dimension ↔ Spec mapping |
| specs/quality-gates.md | Quality verification criteria |
| phases/orchestrator.md | Workflow orchestration |
| phases/state-schema.md | State structure definition |
| phases/actions/ | Individual action implementations |
Action: Abort
Abort the tuning session due to unrecoverable errors.
Purpose
- Safely terminate on critical failures
- Preserve diagnostic information for debugging
- Ensure backup remains available
- Notify user of failure reason
Preconditions
- [ ] state.error_count >= state.max_errors
- [ ] OR critical failure detected
Execution
async function execute(state, workDir) {
console.log('Aborting skill tuning session...');
const errors = state.errors;
const targetSkill = state.target_skill;
// Generate abort report
const abortReport = `# Skill Tuning Aborted
**Target Skill**: ${targetSkill?.name || 'Unknown'}
**Aborted At**: ${new Date().toISOString()}
**Reason**: Too many errors or critical failure
---
## Error Log
${errors.length === 0 ? '_No errors recorded_' :
errors.map((err, i) => `
### Error ${i + 1}
- **Action**: ${err.action}
- **Message**: ${err.message}
- **Time**: ${err.timestamp}
- **Recoverable**: ${err.recoverable ? 'Yes' : 'No'}
`).join('\n')}
---
## Session State at Abort
- **Status**: ${state.status}
- **Iteration Count**: ${state.iteration_count}
- **Completed Actions**: ${state.completed_actions.length}
- **Issues Found**: ${state.issues.length}
- **Fixes Applied**: ${state.applied_fixes.length}
---
## Recovery Options
### Option 1: Restore Original Skill
If any changes were made, restore from backup:
\`\`\`bash
cp -r "${state.backup_dir}/${targetSkill?.name || 'backup'}-backup"/* "${targetSkill?.path || 'target'}/"
\`\`\`
### Option 2: Resume from Last State
The session state is preserved at:
\`${workDir}/state.json\`
To resume:
1. Fix the underlying issue
2. Reset error_count in state.json
3. Re-run skill-tuning with --resume flag
### Option 3: Manual Investigation
Review the following files:
- Diagnosis results: \`${workDir}/diagnosis/*.json\`
- Error log: \`${workDir}/errors.json\`
- State snapshot: \`${workDir}/state.json\`
---
## Diagnostic Information
### Last Successful Action
${state.completed_actions.length > 0 ? state.completed_actions[state.completed_actions.length - 1] : 'None'}
### Current Action When Failed
${state.current_action || 'Unknown'}
### Partial Diagnosis Results
- Context: ${state.diagnosis.context ? 'Completed' : 'Not completed'}
- Memory: ${state.diagnosis.memory ? 'Completed' : 'Not completed'}
- Data Flow: ${state.diagnosis.dataflow ? 'Completed' : 'Not completed'}
- Agent: ${state.diagnosis.agent ? 'Completed' : 'Not completed'}
---
*Skill tuning aborted - please review errors and retry*
`;
// Write abort report
Write(`${workDir}/abort-report.md`, abortReport);
// Save error log
Write(`${workDir}/errors.json`, JSON.stringify(errors, null, 2));
// Notify user
await AskUserQuestion({
questions: [{
question: `Skill tuning aborted due to ${errors.length} errors. Would you like to restore the original skill?`,
header: 'Restore',
multiSelect: false,
options: [
{ label: 'Yes, restore', description: 'Restore original skill from backup' },
{ label: 'No, keep changes', description: 'Keep any partial changes made' }
]
}]
}).then(async response => {
if (response['Restore'] === 'Yes, restore') {
// Restore from backup
if (state.backup_dir && targetSkill?.path) {
Bash(`cp -r "${state.backup_dir}/${targetSkill.name}-backup"/* "${targetSkill.path}/"`);
console.log('Original skill restored from backup.');
}
}
}).catch(() => {
// User cancelled, don't restore
});
return {
stateUpdates: {
status: 'failed',
completed_at: new Date().toISOString()
},
outputFiles: [`${workDir}/abort-report.md`, `${workDir}/errors.json`],
summary: `Tuning aborted: ${errors.length} errors. Check abort-report.md for details.`
};
}State Updates
return {
stateUpdates: {
status: 'failed',
completed_at: '<timestamp>'
}
};Output
- File:
abort-report.md - Location:
${workDir}/abort-report.md
Error Handling
This action should not fail - it's the final error handler.
Next Actions
- None (terminal state)
Action: Analyze Requirements
将用户问题描述拆解为多个分析维度,匹配 Spec,评估覆盖度,检测歧义。
Purpose
- 将单一用户描述拆解为多个独立关注维度
- 为每个维度匹配 problem-taxonomy(检测)+ tuning-strategies(修复)
- 以"有修复策略"为标准判断是否满足需求
- 检测歧义并在必要时请求用户澄清
Preconditions
- [ ]
state.status === 'running' - [ ]
state.target_skill !== null - [ ]
state.completed_actions.includes('action-init') - [ ]
!state.completed_actions.includes('action-analyze-requirements')
Execution
Phase 1: 维度拆解 (Gemini CLI)
调用 Gemini 对用户描述进行语义分析,拆解为独立维度:
async function analyzeDimensions(state, workDir) {
const prompt = `
PURPOSE: 分析用户问题描述,拆解为独立的关注维度
TASK:
• 识别用户描述中的多个关注点(每个关注点应该是独立的、可单独分析的)
• 为每个关注点提取关键词(中英文均可)
• 推断可能的问题类别:
- context_explosion: 上下文/Token 相关
- memory_loss: 遗忘/约束丢失相关
- dataflow_break: 状态/数据流相关
- agent_failure: Agent/子任务相关
- prompt_quality: 提示词/输出质量相关
- architecture: 架构/结构相关
- performance: 性能/效率相关
- error_handling: 错误/异常处理相关
- output_quality: 输出质量/验证相关
- user_experience: 交互/体验相关
• 评估推断置信度 (0-1)
INPUT:
User description: ${state.user_issue_description}
Target skill: ${state.target_skill.name}
Skill structure: ${JSON.stringify(state.target_skill.phases)}
MODE: analysis
CONTEXT: @specs/problem-taxonomy.md @specs/dimension-mapping.md
EXPECTED: JSON (不要包含 markdown 代码块标记)
{
"dimensions": [
{
"id": "DIM-001",
"description": "关注点的简短描述",
"keywords": ["关键词1", "关键词2"],
"inferred_category": "问题类别",
"confidence": 0.85,
"reasoning": "推断理由"
}
],
"analysis_notes": "整体分析说明"
}
RULES:
- 每个维度必须独立,不重叠
- 低于 0.5 置信度的推断应标注需要澄清
- 如果用户描述非常模糊,至少提取一个 "general" 维度
`;
const cliCommand = `ccw cli -p "${escapeForShell(prompt)}" --tool gemini --mode analysis --cd "${state.target_skill.path}"`;
console.log('Phase 1: 执行 Gemini 维度拆解分析...');
const result = Bash({
command: cliCommand,
run_in_background: true,
timeout: 300000
});
return result;
}Phase 2: Spec 匹配
基于 specs/category-mappings.json 配置为每个维度匹配检测模式和修复策略:
// 加载集中式映射配置
const mappings = JSON.parse(Read('specs/category-mappings.json'));
function matchSpecs(dimensions) {
return dimensions.map(dim => {
// 匹配 taxonomy pattern
const taxonomyMatch = findTaxonomyMatch(dim.inferred_category);
// 匹配 strategy
const strategyMatch = findStrategyMatch(dim.inferred_category);
// 判断是否满足(核心标准:有修复策略)
const hasFix = strategyMatch !== null && strategyMatch.strategies.length > 0;
return {
dimension_id: dim.id,
taxonomy_match: taxonomyMatch,
strategy_match: strategyMatch,
has_fix: hasFix,
needs_gemini_analysis: taxonomyMatch === null || mappings.categories[dim.inferred_category]?.needs_gemini_analysis
};
});
}
function findTaxonomyMatch(category) {
const config = mappings.categories[category];
if (!config || config.pattern_ids.length === 0) return null;
return {
category: category,
pattern_ids: config.pattern_ids,
severity_hint: config.severity_hint
};
}
function findStrategyMatch(category) {
const config = mappings.categories[category];
if (!config) {
// Fallback to custom from config
return mappings.fallback;
}
return {
strategies: config.strategies,
risk_levels: config.risk_levels
};
}Phase 3: 覆盖度评估
评估所有维度的 Spec 覆盖情况:
function evaluateCoverage(specMatches) {
const total = specMatches.length;
const withDetection = specMatches.filter(m => m.taxonomy_match !== null).length;
const withFix = specMatches.filter(m => m.has_fix).length;
const rate = total > 0 ? Math.round((withFix / total) * 100) : 0;
let status;
if (rate >= 80) {
status = 'satisfied';
} else if (rate >= 50) {
status = 'partial';
} else {
status = 'unsatisfied';
}
return {
total_dimensions: total,
with_detection: withDetection,
with_fix_strategy: withFix,
coverage_rate: rate,
status: status
};
}Phase 4: 歧义检测
识别需要用户澄清的歧义点:
function detectAmbiguities(dimensions, specMatches) {
const ambiguities = [];
for (const dim of dimensions) {
const match = specMatches.find(m => m.dimension_id === dim.id);
// 检测1: 低置信度 (< 0.5)
if (dim.confidence < 0.5) {
ambiguities.push({
dimension_id: dim.id,
type: 'vague_description',
description: `维度 "${dim.description}" 描述模糊,推断置信度低 (${dim.confidence})`,
possible_interpretations: suggestInterpretations(dim),
needs_clarification: true
});
}
// 检测2: 无匹配类别
if (!match || (!match.taxonomy_match && !match.strategy_match)) {
ambiguities.push({
dimension_id: dim.id,
type: 'no_category_match',
description: `维度 "${dim.description}" 无法匹配到已知问题类别`,
possible_interpretations: ['custom'],
needs_clarification: true
});
}
// 检测3: 关键词冲突(可能属于多个类别)
if (dim.keywords.length > 3 && hasConflictingKeywords(dim.keywords)) {
ambiguities.push({
dimension_id: dim.id,
type: 'conflicting_keywords',
description: `维度 "${dim.description}" 的关键词可能指向多个不同问题`,
possible_interpretations: inferMultipleCategories(dim.keywords),
needs_clarification: true
});
}
}
return ambiguities;
}
function suggestInterpretations(dim) {
// 基于 mappings 配置推荐可能的解释
const categories = Object.keys(mappings.categories).filter(
cat => cat !== 'authoring_principles_violation' // 排除内部检测类别
);
return categories.slice(0, 4); // 返回最常见的 4 个作为选项
}
function hasConflictingKeywords(keywords) {
// 检查关键词是否指向不同方向
const categoryHints = keywords.map(k => getKeywordCategoryHint(k));
const uniqueCategories = [...new Set(categoryHints.filter(c => c))];
return uniqueCategories.length > 1;
}
function getKeywordCategoryHint(keyword) {
// 从 mappings.keywords 构建查找表(合并中英文关键词)
const keywordMap = {
...mappings.keywords.chinese,
...mappings.keywords.english
};
return keywordMap[keyword.toLowerCase()];
}User Interaction
如果检测到需要澄清的歧义,暂停并询问用户:
async function handleAmbiguities(ambiguities, dimensions) {
const needsClarification = ambiguities.filter(a => a.needs_clarification);
if (needsClarification.length === 0) {
return null; // 无需澄清
}
const questions = needsClarification.slice(0, 4).map(a => {
const dim = dimensions.find(d => d.id === a.dimension_id);
return {
question: `关于 "${dim.description}",您具体指的是?`,
header: a.dimension_id,
options: a.possible_interpretations.map(interp => ({
label: getCategoryLabel(interp),
description: getCategoryDescription(interp)
})),
multiSelect: false
};
});
return await AskUserQuestion({ questions });
}
function getCategoryLabel(category) {
// 从 mappings 配置加载标签
return mappings.category_labels_chinese[category] || category;
}
function getCategoryDescription(category) {
// 从 mappings 配置加载描述
return mappings.category_descriptions[category] || 'Requires further analysis';
}Output
State Updates
return {
stateUpdates: {
requirement_analysis: {
status: ambiguities.some(a => a.needs_clarification) ? 'needs_clarification' : 'completed',
analyzed_at: new Date().toISOString(),
dimensions: dimensions,
spec_matches: specMatches,
coverage: coverageResult,
ambiguities: ambiguities
},
// 根据分析结果自动优化 focus_areas
focus_areas: deriveOptimalFocusAreas(specMatches)
},
outputFiles: [
`${workDir}/requirement-analysis.json`,
`${workDir}/requirement-analysis.md`
],
summary: generateSummary(dimensions, coverageResult, ambiguities)
};
function deriveOptimalFocusAreas(specMatches) {
const coreCategories = ['context', 'memory', 'dataflow', 'agent'];
const matched = specMatches
.filter(m => m.taxonomy_match !== null)
.map(m => {
// 映射到诊断 focus_area
const category = m.taxonomy_match.category;
if (category === 'context_explosion' || category === 'performance') return 'context';
if (category === 'memory_loss') return 'memory';
if (category === 'dataflow_break') return 'dataflow';
if (category === 'agent_failure' || category === 'error_handling') return 'agent';
return null;
})
.filter(f => f && coreCategories.includes(f));
// 去重
return [...new Set(matched)];
}
function generateSummary(dimensions, coverage, ambiguities) {
const dimCount = dimensions.length;
const coverageStatus = coverage.status;
const ambiguityCount = ambiguities.filter(a => a.needs_clarification).length;
let summary = `分析完成:${dimCount} 个维度`;
summary += `,覆盖度 ${coverage.coverage_rate}% (${coverageStatus})`;
if (ambiguityCount > 0) {
summary += `,${ambiguityCount} 个歧义点待澄清`;
}
return summary;
}Output Files
requirement-analysis.json
{
"timestamp": "2024-01-01T00:00:00Z",
"target_skill": "skill-name",
"user_description": "原始用户描述",
"dimensions": [...],
"spec_matches": [...],
"coverage": {...},
"ambiguities": [...],
"derived_focus_areas": [...]
}requirement-analysis.md
# 需求分析报告
## 用户描述
> ${user_issue_description}
## 维度拆解
| ID | 描述 | 类别 | 置信度 |
|----|------|------|--------|
| DIM-001 | ... | ... | 0.85 |
## Spec 匹配
| 维度 | 检测模式 | 修复策略 | 是否满足 |
|------|----------|----------|----------|
| DIM-001 | CTX-001,002 | sliding_window | ✓ |
## 覆盖度评估
- 总维度数: N
- 有检测手段: M
- 有修复策略: K (满足标准)
- 覆盖率: X%
- 状态: satisfied/partial/unsatisfied
## 歧义点
(如有)Error Handling
| Error | Recovery |
|---|---|
| Gemini CLI 超时 | 重试一次,仍失败则使用简化分析 |
| JSON 解析失败 | 尝试修复 JSON 或使用默认维度 |
| 无法匹配任何类别 | 全部归类为 custom,触发 Gemini 深度分析 |
Next Actions
- 如果
requirement_analysis.status === 'completed': 继续到action-diagnose-* - 如果
requirement_analysis.status === 'needs_clarification': 等待用户澄清后重新执行 - 如果
coverage.status === 'unsatisfied': 自动触发action-gemini-analysis进行深度分析
Action: Apply Fix
Apply a selected fix to the target skill with backup and rollback capability.
Purpose
- Apply fix changes to target skill files
- Create backup before modifications
- Track applied fixes for verification
- Support rollback if needed
Preconditions
- [ ] state.status === 'running'
- [ ] state.pending_fixes.length > 0
- [ ] state.proposed_fixes contains the fix to apply
Execution
async function execute(state, workDir) {
const pendingFixes = state.pending_fixes;
const proposedFixes = state.proposed_fixes;
const targetPath = state.target_skill.path;
const backupDir = state.backup_dir;
if (pendingFixes.length === 0) {
return {
stateUpdates: {},
outputFiles: [],
summary: 'No pending fixes to apply'
};
}
// Get next fix to apply
const fixId = pendingFixes[0];
const fix = proposedFixes.find(f => f.id === fixId);
if (!fix) {
return {
stateUpdates: {
pending_fixes: pendingFixes.slice(1),
errors: [...state.errors, {
action: 'action-apply-fix',
message: `Fix ${fixId} not found in proposals`,
timestamp: new Date().toISOString(),
recoverable: true
}]
},
outputFiles: [],
summary: `Fix ${fixId} not found, skipping`
};
}
console.log(`Applying fix ${fix.id}: ${fix.description}`);
// Create fix-specific backup
const fixBackupDir = `${backupDir}/before-${fix.id}`;
Bash(`mkdir -p "${fixBackupDir}"`);
const appliedChanges = [];
let success = true;
for (const change of fix.changes) {
try {
// Resolve file path (handle wildcards)
let targetFiles = [];
if (change.file.includes('*')) {
targetFiles = Glob(`${targetPath}/${change.file}`);
} else {
targetFiles = [`${targetPath}/${change.file}`];
}
for (const targetFile of targetFiles) {
// Backup original
const relativePath = targetFile.replace(targetPath + '/', '');
const backupPath = `${fixBackupDir}/${relativePath}`;
if (Glob(targetFile).length > 0) {
const originalContent = Read(targetFile);
Bash(`mkdir -p "$(dirname "${backupPath}")"`);
Write(backupPath, originalContent);
}
// Apply change based on action type
if (change.action === 'modify' && change.diff) {
// For now, append the diff as a comment/note
// Real implementation would parse and apply the diff
const existingContent = Read(targetFile);
// Simple diff application: look for context and apply
// This is a simplified version - real implementation would be more sophisticated
const newContent = existingContent + `\n\n<!-- Applied fix ${fix.id}: ${fix.description} -->\n`;
Write(targetFile, newContent);
appliedChanges.push({
file: relativePath,
action: 'modified',
backup: backupPath
});
} else if (change.action === 'create') {
Write(targetFile, change.new_content || '');
appliedChanges.push({
file: relativePath,
action: 'created',
backup: null
});
}
}
} catch (error) {
console.log(`Error applying change to ${change.file}: ${error.message}`);
success = false;
}
}
// Record applied fix
const appliedFix = {
fix_id: fix.id,
applied_at: new Date().toISOString(),
success: success,
backup_path: fixBackupDir,
verification_result: 'pending',
rollback_available: true,
changes_made: appliedChanges
};
// Update applied fixes log
const appliedFixesPath = `${workDir}/fixes/applied-fixes.json`;
let existingApplied = [];
try {
existingApplied = JSON.parse(Read(appliedFixesPath));
} catch (e) {
existingApplied = [];
}
existingApplied.push(appliedFix);
Write(appliedFixesPath, JSON.stringify(existingApplied, null, 2));
return {
stateUpdates: {
applied_fixes: [...state.applied_fixes, appliedFix],
pending_fixes: pendingFixes.slice(1) // Remove applied fix from pending
},
outputFiles: [appliedFixesPath],
summary: `Applied fix ${fix.id}: ${success ? 'success' : 'partial'}, ${appliedChanges.length} files modified`
};
}State Updates
return {
stateUpdates: {
applied_fixes: [...existingApplied, newAppliedFix],
pending_fixes: remainingPendingFixes
}
};Rollback Function
async function rollbackFix(fixId, state, workDir) {
const appliedFix = state.applied_fixes.find(f => f.fix_id === fixId);
if (!appliedFix || !appliedFix.rollback_available) {
throw new Error(`Cannot rollback fix ${fixId}`);
}
const backupDir = appliedFix.backup_path;
const targetPath = state.target_skill.path;
// Restore from backup
const backupFiles = Glob(`${backupDir}/**/*`);
for (const backupFile of backupFiles) {
const relativePath = backupFile.replace(backupDir + '/', '');
const targetFile = `${targetPath}/${relativePath}`;
const content = Read(backupFile);
Write(targetFile, content);
}
return {
stateUpdates: {
applied_fixes: state.applied_fixes.map(f =>
f.fix_id === fixId
? { ...f, rollback_available: false, verification_result: 'rolled_back' }
: f
)
}
};
}Error Handling
| Error Type | Recovery |
|---|---|
| File not found | Skip file, log warning |
| Write permission error | Retry with sudo or report |
| Backup creation failed | Abort fix, don't modify |
Next Actions
- If pending_fixes.length > 0: action-apply-fix (continue)
- If all fixes applied: action-verify
Action: Complete
Finalize the tuning session with summary report and cleanup.
Purpose
- Generate final summary report
- Record tuning statistics
- Clean up temporary files (optional)
- Provide recommendations for future maintenance
Preconditions
- [ ] state.status === 'running'
- [ ] quality_gate === 'pass' OR max_iterations reached
Execution
async function execute(state, workDir) {
console.log('Finalizing skill tuning session...');
const targetSkill = state.target_skill;
const startTime = new Date(state.started_at);
const endTime = new Date();
const duration = Math.round((endTime - startTime) / 1000);
// Generate final summary
const summary = `# Skill Tuning Summary
**Target Skill**: ${targetSkill.name}
**Path**: ${targetSkill.path}
**Session Duration**: ${duration} seconds
**Completed**: ${endTime.toISOString()}
---
## Final Status
| Metric | Value |
|--------|-------|
| Final Health Score | ${state.quality_score}/100 |
| Quality Gate | ${state.quality_gate.toUpperCase()} |
| Total Iterations | ${state.iteration_count} |
| Issues Found | ${state.issues.length + state.applied_fixes.flatMap(f => f.issues_resolved || []).length} |
| Issues Resolved | ${state.applied_fixes.flatMap(f => f.issues_resolved || []).length} |
| Fixes Applied | ${state.applied_fixes.length} |
| Fixes Verified | ${state.applied_fixes.filter(f => f.verification_result === 'pass').length} |
---
## Diagnosis Summary
| Area | Issues Found | Severity |
|------|--------------|----------|
| Context Explosion | ${state.diagnosis.context?.issues_found || 'N/A'} | ${state.diagnosis.context?.severity || 'N/A'} |
| Long-tail Forgetting | ${state.diagnosis.memory?.issues_found || 'N/A'} | ${state.diagnosis.memory?.severity || 'N/A'} |
| Data Flow | ${state.diagnosis.dataflow?.issues_found || 'N/A'} | ${state.diagnosis.dataflow?.severity || 'N/A'} |
| Agent Coordination | ${state.diagnosis.agent?.issues_found || 'N/A'} | ${state.diagnosis.agent?.severity || 'N/A'} |
---
## Applied Fixes
${state.applied_fixes.length === 0 ? '_No fixes applied_' :
state.applied_fixes.map((fix, i) => `
### ${i + 1}. ${fix.fix_id}
- **Applied At**: ${fix.applied_at}
- **Success**: ${fix.success ? 'Yes' : 'No'}
- **Verification**: ${fix.verification_result}
- **Rollback Available**: ${fix.rollback_available ? 'Yes' : 'No'}
`).join('\n')}
---
## Remaining Issues
${state.issues.length === 0 ? '✅ All issues resolved!' :
`${state.issues.length} issues remain:\n\n` +
state.issues.map(issue =>
`- **[${issue.severity.toUpperCase()}]** ${issue.description} (${issue.id})`
).join('\n')}
---
## Recommendations
${generateRecommendations(state)}
---
## Backup Information
Original skill files backed up to:
\`${state.backup_dir}\`
To restore original skill:
\`\`\`bash
cp -r "${state.backup_dir}/${targetSkill.name}-backup"/* "${targetSkill.path}/"
\`\`\`
---
## Session Files
| File | Description |
|------|-------------|
| ${workDir}/tuning-report.md | Full diagnostic report |
| ${workDir}/diagnosis/*.json | Individual diagnosis results |
| ${workDir}/fixes/fix-proposals.json | Proposed fixes |
| ${workDir}/fixes/applied-fixes.json | Applied fix history |
| ${workDir}/tuning-summary.md | This summary |
---
*Skill tuning completed by skill-tuning*
`;
Write(`${workDir}/tuning-summary.md`, summary);
// Update final state
return {
stateUpdates: {
status: 'completed',
completed_at: endTime.toISOString()
},
outputFiles: [`${workDir}/tuning-summary.md`],
summary: `Tuning complete: ${state.quality_gate} with ${state.quality_score}/100 health score`
};
}
function generateRecommendations(state) {
const recommendations = [];
// Based on remaining issues
if (state.issues.some(i => i.type === 'context_explosion')) {
recommendations.push('- **Context Management**: Consider implementing a context summarization agent to prevent token growth');
}
if (state.issues.some(i => i.type === 'memory_loss')) {
recommendations.push('- **Constraint Tracking**: Add explicit constraint injection to each phase prompt');
}
if (state.issues.some(i => i.type === 'dataflow_break')) {
recommendations.push('- **State Centralization**: Migrate to single state.json with schema validation');
}
if (state.issues.some(i => i.type === 'agent_failure')) {
recommendations.push('- **Error Handling**: Wrap all Task calls in try-catch blocks');
}
// General recommendations
if (state.iteration_count >= state.max_iterations) {
recommendations.push('- **Deep Refactoring**: Consider architectural review if issues persist after multiple iterations');
}
if (state.quality_score < 80) {
recommendations.push('- **Regular Tuning**: Schedule periodic skill-tuning runs to catch issues early');
}
if (recommendations.length === 0) {
recommendations.push('- Skill is in good health! Monitor for regressions during future development.');
}
return recommendations.join('\n');
}State Updates
return {
stateUpdates: {
status: 'completed',
completed_at: '<timestamp>'
}
};Output
- File:
tuning-summary.md - Location:
${workDir}/tuning-summary.md - Format: Markdown
Error Handling
| Error Type | Recovery |
|---|---|
| Summary write failed | Write to alternative location |
Next Actions
- None (terminal state)
Action: Diagnose Agent Coordination
Analyze target skill for agent coordination failures - call chain fragility and result passing issues.
Purpose
- Detect fragile agent call patterns
- Identify result passing issues
- Find missing error handling in agent calls
- Analyze agent return format consistency
Preconditions
- [ ] state.status === 'running'
- [ ] state.target_skill.path is set
- [ ] 'agent' in state.focus_areas OR state.focus_areas is empty
Detection Patterns
Pattern 1: Unhandled Agent Failures
# Task calls without try-catch or error handling
/Task\s*\(\s*\{[^}]*\}\s*\)(?![^;]*catch)/Pattern 2: Missing Return Validation
# Agent result used directly without validation
/const\s+\w+\s*=\s*await?\s*Task\([^)]+\);\s*(?!.*(?:if|try|JSON\.parse))/Pattern 3: Inconsistent Agent Configuration
# Different agent configurations in same skill
/subagent_type:\s*['"](\w+)['"]/gPattern 4: Deeply Nested Agent Calls
# Agent calling another agent (nested)
/Task\s*\([^)]*prompt:[^)]*Task\s*\(/Execution
async function execute(state, workDir) {
const skillPath = state.target_skill.path;
const startTime = Date.now();
const issues = [];
const evidence = [];
console.log(`Diagnosing agent coordination in ${skillPath}...`);
// 1. Find all Task/agent calls
const allFiles = Glob(`${skillPath}/**/*.md`);
const agentCalls = [];
const agentTypes = new Set();
for (const file of allFiles) {
const content = Read(file);
const relativePath = file.replace(skillPath + '/', '');
// Find Task calls
const taskMatches = content.matchAll(/Task\s*\(\s*\{([^}]+)\}/g);
for (const match of taskMatches) {
const config = match[1];
// Extract agent type
const typeMatch = config.match(/subagent_type:\s*['"]([^'"]+)['"]/);
const agentType = typeMatch ? typeMatch[1] : 'unknown';
agentTypes.add(agentType);
// Check for error handling context
const hasErrorHandling = /try\s*\{.*Task|\.catch\(|await\s+Task.*\.then/s.test(
content.slice(Math.max(0, match.index - 100), match.index + match[0].length + 100)
);
// Check for result validation
const hasResultValidation = /JSON\.parse|if\s*\(\s*result|result\s*\?\./s.test(
content.slice(match.index, match.index + match[0].length + 200)
);
// Check for background execution
const runsInBackground = /run_in_background:\s*true/.test(config);
agentCalls.push({
file: relativePath,
agentType,
hasErrorHandling,
hasResultValidation,
runsInBackground,
config: config.slice(0, 200)
});
}
}
// 2. Analyze agent call patterns
const totalCalls = agentCalls.length;
const callsWithoutErrorHandling = agentCalls.filter(c => !c.hasErrorHandling);
const callsWithoutValidation = agentCalls.filter(c => !c.hasResultValidation);
// Issue: Missing error handling
if (callsWithoutErrorHandling.length > 0) {
issues.push({
id: `AGT-${issues.length + 1}`,
type: 'agent_failure',
severity: callsWithoutErrorHandling.length > 2 ? 'high' : 'medium',
location: { file: 'multiple' },
description: `${callsWithoutErrorHandling.length}/${totalCalls} agent calls lack error handling`,
evidence: callsWithoutErrorHandling.slice(0, 3).map(c =>
`${c.file}: ${c.agentType}`
),
root_cause: 'Agent failures not caught, may crash workflow',
impact: 'Unhandled agent errors cause cascading failures',
suggested_fix: 'Wrap Task calls in try-catch with graceful fallback'
});
evidence.push({
file: 'multiple',
pattern: 'missing_error_handling',
context: `${callsWithoutErrorHandling.length} calls affected`,
severity: 'high'
});
}
// Issue: Missing result validation
if (callsWithoutValidation.length > 0) {
issues.push({
id: `AGT-${issues.length + 1}`,
type: 'agent_failure',
severity: 'medium',
location: { file: 'multiple' },
description: `${callsWithoutValidation.length}/${totalCalls} agent calls lack result validation`,
evidence: callsWithoutValidation.slice(0, 3).map(c =>
`${c.file}: ${c.agentType} result not validated`
),
root_cause: 'Agent results used directly without type checking',
impact: 'Invalid agent output may corrupt state',
suggested_fix: 'Add JSON.parse with try-catch and schema validation'
});
}
// 3. Check for inconsistent agent types usage
if (agentTypes.size > 3 && state.target_skill.execution_mode === 'autonomous') {
issues.push({
id: `AGT-${issues.length + 1}`,
type: 'agent_failure',
severity: 'low',
location: { file: 'multiple' },
description: `Using ${agentTypes.size} different agent types`,
evidence: [...agentTypes].slice(0, 5),
root_cause: 'Multiple agent types increase coordination complexity',
impact: 'Different agent behaviors may cause inconsistency',
suggested_fix: 'Standardize on fewer agent types with clear roles'
});
}
// 4. Check for nested agent calls
for (const file of allFiles) {
const content = Read(file);
const relativePath = file.replace(skillPath + '/', '');
// Detect nested Task calls
const hasNestedTask = /Task\s*\([^)]*prompt:[^)]*Task\s*\(/s.test(content);
if (hasNestedTask) {
issues.push({
id: `AGT-${issues.length + 1}`,
type: 'agent_failure',
severity: 'high',
location: { file: relativePath },
description: 'Nested agent calls detected',
evidence: ['Agent prompt contains another Task call'],
root_cause: 'Agent calls another agent, creating deep nesting',
impact: 'Context explosion, hard to debug, unpredictable behavior',
suggested_fix: 'Flatten agent calls, use orchestrator to coordinate'
});
}
}
// 5. Check SKILL.md for agent configuration consistency
const skillMd = Read(`${skillPath}/SKILL.md`);
// Check if allowed-tools includes Task
const allowedTools = skillMd.match(/allowed-tools:\s*([^\n]+)/i);
if (allowedTools && !allowedTools[1].includes('Task') && totalCalls > 0) {
issues.push({
id: `AGT-${issues.length + 1}`,
type: 'agent_failure',
severity: 'medium',
location: { file: 'SKILL.md' },
description: 'Agent tool used but not declared in allowed-tools',
evidence: [`${totalCalls} Task calls found, but Task not in allowed-tools`],
root_cause: 'Tool declaration mismatch',
impact: 'May cause runtime permission issues',
suggested_fix: 'Add Task to allowed-tools in SKILL.md front matter'
});
}
// 6. Check for agent result format consistency
const returnFormats = new Set();
for (const file of allFiles) {
const content = Read(file);
// Look for return format definitions
const returnMatch = content.match(/\[RETURN\][^[]*|return\s*\{[^}]+\}/gi);
if (returnMatch) {
returnMatch.forEach(r => {
const format = r.includes('JSON') ? 'json' :
r.includes('summary') ? 'summary' :
r.includes('file') ? 'file_path' : 'other';
returnFormats.add(format);
});
}
}
if (returnFormats.size > 2) {
issues.push({
id: `AGT-${issues.length + 1}`,
type: 'agent_failure',
severity: 'medium',
location: { file: 'multiple' },
description: 'Inconsistent agent return formats',
evidence: [...returnFormats],
root_cause: 'Different agents return data in different formats',
impact: 'Orchestrator must handle multiple format types',
suggested_fix: 'Standardize return format: {status, output_file, summary}'
});
}
// 7. Calculate severity
const criticalCount = issues.filter(i => i.severity === 'critical').length;
const highCount = issues.filter(i => i.severity === 'high').length;
const severity = criticalCount > 0 ? 'critical' :
highCount > 1 ? 'high' :
highCount > 0 ? 'medium' :
issues.length > 0 ? 'low' : 'none';
// 8. Write diagnosis result
const diagnosisResult = {
status: 'completed',
issues_found: issues.length,
severity: severity,
execution_time_ms: Date.now() - startTime,
details: {
patterns_checked: [
'error_handling',
'result_validation',
'agent_type_consistency',
'nested_calls',
'return_format_consistency'
],
patterns_matched: evidence.map(e => e.pattern),
evidence: evidence,
agent_analysis: {
total_agent_calls: totalCalls,
unique_agent_types: agentTypes.size,
calls_without_error_handling: callsWithoutErrorHandling.length,
calls_without_validation: callsWithoutValidation.length,
agent_types_used: [...agentTypes]
},
recommendations: [
callsWithoutErrorHandling.length > 0
? 'Add try-catch to all Task calls' : null,
callsWithoutValidation.length > 0
? 'Add result validation with JSON.parse and schema check' : null,
agentTypes.size > 3
? 'Consolidate agent types for consistency' : null
].filter(Boolean)
}
};
Write(`${workDir}/diagnosis/agent-diagnosis.json`,
JSON.stringify(diagnosisResult, null, 2));
return {
stateUpdates: {
'diagnosis.agent': diagnosisResult,
issues: [...state.issues, ...issues]
},
outputFiles: [`${workDir}/diagnosis/agent-diagnosis.json`],
summary: `Agent diagnosis: ${issues.length} issues found (severity: ${severity})`
};
}State Updates
return {
stateUpdates: {
'diagnosis.agent': {
status: 'completed',
issues_found: <count>,
severity: '<critical|high|medium|low|none>',
// ... full diagnosis result
},
issues: [...existingIssues, ...newIssues]
}
};Error Handling
| Error Type | Recovery |
|---|---|
| Regex match error | Use simpler patterns |
| File access error | Skip and continue |
Next Actions
- Success: action-generate-report
- Skipped: If 'agent' not in focus_areas
Action: Diagnose Context Explosion
Analyze target skill for context explosion issues - token accumulation and multi-turn dialogue bloat.
Purpose
- Detect patterns that cause context growth
- Identify multi-turn accumulation points
- Find missing context compression mechanisms
- Measure potential token waste
Preconditions
- [ ] state.status === 'running'
- [ ] state.target_skill.path is set
- [ ] 'context' in state.focus_areas OR state.focus_areas is empty
Detection Patterns
Pattern 1: Unbounded History Accumulation
# Patterns that suggest history accumulation
/\bhistory\b.*\.push\b/
/\bmessages\b.*\.concat\b/
/\bconversation\b.*\+=\b/
/\bappend.*context\b/iPattern 2: Full Content Passing
# Patterns that pass full content instead of references
/Read\([^)]+\).*\+.*Read\(/
/JSON\.stringify\(.*state\)/ # Full state serialization
/\$\{.*content\}/ # Template literal with full contentPattern 3: Missing Summarization
# Absence of compression/summarization
# Check for lack of: summarize, compress, truncate, slicePattern 4: Agent Return Bloat
# Agent returning full content instead of path + summary
/return\s*\{[^}]*content:/
/return.*JSON\.stringify/Execution
async function execute(state, workDir) {
const skillPath = state.target_skill.path;
const startTime = Date.now();
const issues = [];
const evidence = [];
console.log(`Diagnosing context explosion in ${skillPath}...`);
// 1. Scan all phase files
const phaseFiles = Glob(`${skillPath}/phases/**/*.md`);
for (const file of phaseFiles) {
const content = Read(file);
const relativePath = file.replace(skillPath + '/', '');
// Check Pattern 1: History accumulation
const historyPatterns = [
/history\s*[.=].*push|concat|append/gi,
/messages\s*=\s*\[.*\.\.\..*messages/gi,
/conversation.*\+=/gi
];
for (const pattern of historyPatterns) {
const matches = content.match(pattern);
if (matches) {
issues.push({
id: `CTX-${issues.length + 1}`,
type: 'context_explosion',
severity: 'high',
location: { file: relativePath },
description: 'Unbounded history accumulation detected',
evidence: matches.slice(0, 3),
root_cause: 'History/messages array grows without bounds',
impact: 'Token count increases linearly with iterations',
suggested_fix: 'Implement sliding window or summarization'
});
evidence.push({
file: relativePath,
pattern: 'history_accumulation',
context: matches[0],
severity: 'high'
});
}
}
// Check Pattern 2: Full content passing
const contentPatterns = [
/Read\s*\([^)]+\)\s*[\+,]/g,
/JSON\.stringify\s*\(\s*state\s*\)/g,
/\$\{[^}]*content[^}]*\}/g
];
for (const pattern of contentPatterns) {
const matches = content.match(pattern);
if (matches) {
issues.push({
id: `CTX-${issues.length + 1}`,
type: 'context_explosion',
severity: 'medium',
location: { file: relativePath },
description: 'Full content passed instead of reference',
evidence: matches.slice(0, 3),
root_cause: 'Entire file/state content included in prompts',
impact: 'Unnecessary token consumption',
suggested_fix: 'Pass file paths and summaries instead of full content'
});
evidence.push({
file: relativePath,
pattern: 'full_content_passing',
context: matches[0],
severity: 'medium'
});
}
}
// Check Pattern 3: Missing summarization
const hasSummarization = /summariz|compress|truncat|slice.*context/i.test(content);
const hasLongPrompts = content.length > 5000;
if (hasLongPrompts && !hasSummarization) {
issues.push({
id: `CTX-${issues.length + 1}`,
type: 'context_explosion',
severity: 'medium',
location: { file: relativePath },
description: 'Long phase file without summarization mechanism',
evidence: [`File length: ${content.length} chars`],
root_cause: 'No context compression for large content',
impact: 'Potential token overflow in long sessions',
suggested_fix: 'Add context summarization before passing to agents'
});
}
// Check Pattern 4: Agent return bloat
const returnPatterns = /return\s*\{[^}]*(?:content|full_output|complete_result):/g;
const returnMatches = content.match(returnPatterns);
if (returnMatches) {
issues.push({
id: `CTX-${issues.length + 1}`,
type: 'context_explosion',
severity: 'high',
location: { file: relativePath },
description: 'Agent returns full content instead of path+summary',
evidence: returnMatches.slice(0, 3),
root_cause: 'Agent output includes complete content',
impact: 'Context bloat when orchestrator receives full output',
suggested_fix: 'Return {output_file, summary} instead of {content}'
});
}
}
// 2. Calculate severity
const criticalCount = issues.filter(i => i.severity === 'critical').length;
const highCount = issues.filter(i => i.severity === 'high').length;
const severity = criticalCount > 0 ? 'critical' :
highCount > 2 ? 'high' :
highCount > 0 ? 'medium' :
issues.length > 0 ? 'low' : 'none';
// 3. Write diagnosis result
const diagnosisResult = {
status: 'completed',
issues_found: issues.length,
severity: severity,
execution_time_ms: Date.now() - startTime,
details: {
patterns_checked: [
'history_accumulation',
'full_content_passing',
'missing_summarization',
'agent_return_bloat'
],
patterns_matched: evidence.map(e => e.pattern),
evidence: evidence,
recommendations: [
issues.length > 0 ? 'Implement context summarization agent' : null,
highCount > 0 ? 'Add sliding window for conversation history' : null,
evidence.some(e => e.pattern === 'full_content_passing')
? 'Refactor to pass file paths instead of content' : null
].filter(Boolean)
}
};
Write(`${workDir}/diagnosis/context-diagnosis.json`,
JSON.stringify(diagnosisResult, null, 2));
return {
stateUpdates: {
'diagnosis.context': diagnosisResult,
issues: [...state.issues, ...issues],
'issues_by_severity.critical': state.issues_by_severity.critical + criticalCount,
'issues_by_severity.high': state.issues_by_severity.high + highCount
},
outputFiles: [`${workDir}/diagnosis/context-diagnosis.json`],
summary: `Context diagnosis: ${issues.length} issues found (severity: ${severity})`
};
}State Updates
return {
stateUpdates: {
'diagnosis.context': {
status: 'completed',
issues_found: <count>,
severity: '<critical|high|medium|low|none>',
// ... full diagnosis result
},
issues: [...existingIssues, ...newIssues]
}
};Error Handling
| Error Type | Recovery |
|---|---|
| File read error | Skip file, log warning |
| Pattern matching error | Use fallback patterns |
| Write error | Retry to alternative path |
Next Actions
- Success: action-diagnose-memory (or next in focus_areas)
- Skipped: If 'context' not in focus_areas
Action: Diagnose Data Flow Issues
Analyze target skill for data flow disruption - state inconsistencies and format variations.
Purpose
- Detect inconsistent data formats between phases
- Identify scattered state storage
- Find missing data contracts
- Measure state transition integrity
Preconditions
- [ ] state.status === 'running'
- [ ] state.target_skill.path is set
- [ ] 'dataflow' in state.focus_areas OR state.focus_areas is empty
Detection Patterns
Pattern 1: Multiple Storage Locations
# Data written to multiple paths without centralization
/Write\s*\(\s*[`'"][^`'"]+[`'"]/gPattern 2: Inconsistent Field Names
# Same concept with different names: title/name, id/identifierPattern 3: Missing Schema Validation
# Absence of validation before state write
# Look for lack of: validate, schema, check, verifyPattern 4: Format Transformation Without Normalization
# Direct JSON.parse without error handling or normalization
/JSON\.parse\([^)]+\)(?!\s*\|\|)/Execution
async function execute(state, workDir) {
const skillPath = state.target_skill.path;
const startTime = Date.now();
const issues = [];
const evidence = [];
console.log(`Diagnosing data flow in ${skillPath}...`);
// 1. Collect all Write operations to map data storage
const allFiles = Glob(`${skillPath}/**/*.md`);
const writeLocations = [];
const readLocations = [];
for (const file of allFiles) {
const content = Read(file);
const relativePath = file.replace(skillPath + '/', '');
// Find Write operations
const writeMatches = content.matchAll(/Write\s*\(\s*[`'"]([^`'"]+)[`'"]/g);
for (const match of writeMatches) {
writeLocations.push({
file: relativePath,
target: match[1],
isStateFile: match[1].includes('state.json') || match[1].includes('config.json')
});
}
// Find Read operations
const readMatches = content.matchAll(/Read\s*\(\s*[`'"]([^`'"]+)[`'"]/g);
for (const match of readMatches) {
readLocations.push({
file: relativePath,
source: match[1]
});
}
}
// 2. Check for scattered state storage
const stateTargets = writeLocations
.filter(w => w.isStateFile)
.map(w => w.target);
const uniqueStateFiles = [...new Set(stateTargets)];
if (uniqueStateFiles.length > 2) {
issues.push({
id: `DF-${issues.length + 1}`,
type: 'dataflow_break',
severity: 'high',
location: { file: 'multiple' },
description: `State stored in ${uniqueStateFiles.length} different locations`,
evidence: uniqueStateFiles.slice(0, 5),
root_cause: 'No centralized state management',
impact: 'State inconsistency between phases',
suggested_fix: 'Centralize state to single state.json with state manager'
});
evidence.push({
file: 'multiple',
pattern: 'scattered_state',
context: uniqueStateFiles.join(', '),
severity: 'high'
});
}
// 3. Check for inconsistent field naming
const fieldNamePatterns = {
'name_vs_title': [/\.name\b/, /\.title\b/],
'id_vs_identifier': [/\.id\b/, /\.identifier\b/],
'status_vs_state': [/\.status\b/, /\.state\b/],
'error_vs_errors': [/\.error\b/, /\.errors\b/]
};
const fieldUsage = {};
for (const file of allFiles) {
const content = Read(file);
const relativePath = file.replace(skillPath + '/', '');
for (const [patternName, patterns] of Object.entries(fieldNamePatterns)) {
for (const pattern of patterns) {
if (pattern.test(content)) {
if (!fieldUsage[patternName]) fieldUsage[patternName] = [];
fieldUsage[patternName].push({
file: relativePath,
pattern: pattern.toString()
});
}
}
}
}
for (const [patternName, usages] of Object.entries(fieldUsage)) {
const uniquePatterns = [...new Set(usages.map(u => u.pattern))];
if (uniquePatterns.length > 1) {
issues.push({
id: `DF-${issues.length + 1}`,
type: 'dataflow_break',
severity: 'medium',
location: { file: 'multiple' },
description: `Inconsistent field naming: ${patternName.replace('_vs_', ' vs ')}`,
evidence: usages.slice(0, 3).map(u => `${u.file}: ${u.pattern}`),
root_cause: 'Same concept referred to with different field names',
impact: 'Data may be lost during field access',
suggested_fix: `Standardize to single field name, add normalization function`
});
}
}
// 4. Check for missing schema validation
for (const file of allFiles) {
const content = Read(file);
const relativePath = file.replace(skillPath + '/', '');
// Find JSON.parse without validation
const unsafeParses = content.match(/JSON\.parse\s*\([^)]+\)(?!\s*\?\?|\s*\|\|)/g);
const hasValidation = /validat|schema|type.*check/i.test(content);
if (unsafeParses && unsafeParses.length > 0 && !hasValidation) {
issues.push({
id: `DF-${issues.length + 1}`,
type: 'dataflow_break',
severity: 'medium',
location: { file: relativePath },
description: 'JSON parsing without validation',
evidence: unsafeParses.slice(0, 2),
root_cause: 'No schema validation after parsing',
impact: 'Invalid data may propagate through phases',
suggested_fix: 'Add schema validation after JSON.parse'
});
}
}
// 5. Check state schema if exists
const stateSchemaFile = Glob(`${skillPath}/phases/state-schema.md`)[0];
if (stateSchemaFile) {
const schemaContent = Read(stateSchemaFile);
// Check for type definitions
const hasTypeScript = /interface\s+\w+|type\s+\w+\s*=/i.test(schemaContent);
const hasValidationFunction = /function\s+validate|validateState/i.test(schemaContent);
if (hasTypeScript && !hasValidationFunction) {
issues.push({
id: `DF-${issues.length + 1}`,
type: 'dataflow_break',
severity: 'low',
location: { file: 'phases/state-schema.md' },
description: 'Type definitions without runtime validation',
evidence: ['TypeScript interfaces defined but no validation function'],
root_cause: 'Types are compile-time only, not enforced at runtime',
impact: 'Schema violations may occur at runtime',
suggested_fix: 'Add validateState() function using Zod or manual checks'
});
}
} else if (state.target_skill.execution_mode === 'autonomous') {
issues.push({
id: `DF-${issues.length + 1}`,
type: 'dataflow_break',
severity: 'high',
location: { file: 'phases/' },
description: 'Autonomous skill missing state-schema.md',
evidence: ['No state schema definition found'],
root_cause: 'State structure undefined for orchestrator',
impact: 'Inconsistent state handling across actions',
suggested_fix: 'Create phases/state-schema.md with explicit type definitions'
});
}
// 6. Check read-write alignment
const writtenFiles = new Set(writeLocations.map(w => w.target));
const readFiles = new Set(readLocations.map(r => r.source));
const writtenButNotRead = [...writtenFiles].filter(f =>
!readFiles.has(f) && !f.includes('output') && !f.includes('report')
);
if (writtenButNotRead.length > 0) {
issues.push({
id: `DF-${issues.length + 1}`,
type: 'dataflow_break',
severity: 'low',
location: { file: 'multiple' },
description: 'Files written but never read',
evidence: writtenButNotRead.slice(0, 3),
root_cause: 'Orphaned output files',
impact: 'Wasted storage and potential confusion',
suggested_fix: 'Remove unused writes or add reads where needed'
});
}
// 7. Calculate severity
const criticalCount = issues.filter(i => i.severity === 'critical').length;
const highCount = issues.filter(i => i.severity === 'high').length;
const severity = criticalCount > 0 ? 'critical' :
highCount > 1 ? 'high' :
highCount > 0 ? 'medium' :
issues.length > 0 ? 'low' : 'none';
// 8. Write diagnosis result
const diagnosisResult = {
status: 'completed',
issues_found: issues.length,
severity: severity,
execution_time_ms: Date.now() - startTime,
details: {
patterns_checked: [
'scattered_state',
'inconsistent_naming',
'missing_validation',
'read_write_alignment'
],
patterns_matched: evidence.map(e => e.pattern),
evidence: evidence,
data_flow_map: {
write_locations: writeLocations.length,
read_locations: readLocations.length,
unique_state_files: uniqueStateFiles.length
},
recommendations: [
uniqueStateFiles.length > 2 ? 'Implement centralized state manager' : null,
issues.some(i => i.description.includes('naming'))
? 'Create normalization layer for field names' : null,
issues.some(i => i.description.includes('validation'))
? 'Add Zod or JSON Schema validation' : null
].filter(Boolean)
}
};
Write(`${workDir}/diagnosis/dataflow-diagnosis.json`,
JSON.stringify(diagnosisResult, null, 2));
return {
stateUpdates: {
'diagnosis.dataflow': diagnosisResult,
issues: [...state.issues, ...issues]
},
outputFiles: [`${workDir}/diagnosis/dataflow-diagnosis.json`],
summary: `Data flow diagnosis: ${issues.length} issues found (severity: ${severity})`
};
}State Updates
return {
stateUpdates: {
'diagnosis.dataflow': {
status: 'completed',
issues_found: <count>,
severity: '<critical|high|medium|low|none>',
// ... full diagnosis result
},
issues: [...existingIssues, ...newIssues]
}
};Error Handling
| Error Type | Recovery |
|---|---|
| Glob pattern error | Use fallback patterns |
| File read error | Skip and continue |
Next Actions
- Success: action-diagnose-agent (or next in focus_areas)
- Skipped: If 'dataflow' not in focus_areas
Action: Diagnose Documentation Structure
检测目标 skill 中的文档冗余和冲突问题。
Purpose
- 检测重复定义(State Schema、映射表、类型定义等)
- 检测冲突定义(优先级定义不一致、实现与文档漂移等)
- 生成合并和解决冲突的建议
Preconditions
- [ ]
state.status === 'running' - [ ]
state.target_skill !== null - [ ]
!state.diagnosis.docs - [ ] 用户指定 focus_areas 包含 'docs' 或 'all',或需要全面诊断
Detection Patterns
DOC-RED-001: 核心定义重复
检测 State Schema、核心接口等在多处定义:
async function detectDefinitionDuplicates(skillPath) {
const patterns = [
{ name: 'state_schema', regex: /interface\s+(TuningState|State)\s*\{/g },
{ name: 'fix_strategy', regex: /type\s+FixStrategy\s*=/g },
{ name: 'issue_type', regex: /type:\s*['"]?(context_explosion|memory_loss|dataflow_break)/g }
];
const files = Glob('**/*.md', { cwd: skillPath });
const duplicates = [];
for (const pattern of patterns) {
const matches = [];
for (const file of files) {
const content = Read(`${skillPath}/${file}`);
if (pattern.regex.test(content)) {
matches.push({ file, pattern: pattern.name });
}
}
if (matches.length > 1) {
duplicates.push({
type: pattern.name,
files: matches.map(m => m.file),
severity: 'high'
});
}
}
return duplicates;
}DOC-RED-002: 硬编码配置重复
检测 action 文件中硬编码与 spec 文档的重复:
async function detectHardcodedDuplicates(skillPath) {
const actionFiles = Glob('phases/actions/*.md', { cwd: skillPath });
const specFiles = Glob('specs/*.md', { cwd: skillPath });
const duplicates = [];
for (const actionFile of actionFiles) {
const content = Read(`${skillPath}/${actionFile}`);
// 检测硬编码的映射对象
const hardcodedPatterns = [
/const\s+\w*[Mm]apping\s*=\s*\{/g,
/patternMapping\s*=\s*\{/g,
/strategyMapping\s*=\s*\{/g
];
for (const pattern of hardcodedPatterns) {
if (pattern.test(content)) {
duplicates.push({
type: 'hardcoded_mapping',
file: actionFile,
description: '硬编码映射可能与 specs/ 中的定义重复',
severity: 'high'
});
}
}
}
return duplicates;
}DOC-CON-001: 优先级定义冲突
检测 P0-P3 等优先级在不同文件中的定义不一致:
async function detectPriorityConflicts(skillPath) {
const files = Glob('**/*.md', { cwd: skillPath });
const priorityDefs = {};
const priorityPattern = /\*\*P(\d+)\*\*[:\s]+([^\|]+)/g;
for (const file of files) {
const content = Read(`${skillPath}/${file}`);
let match;
while ((match = priorityPattern.exec(content)) !== null) {
const priority = `P${match[1]}`;
const definition = match[2].trim();
if (!priorityDefs[priority]) {
priorityDefs[priority] = [];
}
priorityDefs[priority].push({ file, definition });
}
}
const conflicts = [];
for (const [priority, defs] of Object.entries(priorityDefs)) {
const uniqueDefs = [...new Set(defs.map(d => d.definition))];
if (uniqueDefs.length > 1) {
conflicts.push({
key: priority,
definitions: defs,
severity: 'critical'
});
}
}
return conflicts;
}DOC-CON-002: 实现与文档漂移
检测硬编码与文档表格的不一致:
async function detectImplementationDrift(skillPath) {
// 比较 category-mappings.json 与 specs/*.md 中的表格
const mappingsFile = `${skillPath}/specs/category-mappings.json`;
if (!fileExists(mappingsFile)) {
return []; // 无集中配置,跳过
}
const mappings = JSON.parse(Read(mappingsFile));
const conflicts = [];
// 与 dimension-mapping.md 对比
const dimMapping = Read(`${skillPath}/specs/dimension-mapping.md`);
for (const [category, config] of Object.entries(mappings.categories)) {
// 检查策略是否在文档中提及
for (const strategy of config.strategies || []) {
if (!dimMapping.includes(strategy)) {
conflicts.push({
type: 'mapping',
key: `${category}.strategies`,
issue: `策略 ${strategy} 在 JSON 中定义但未在文档中提及`
});
}
}
}
return conflicts;
}Execution
async function executeDiagnosis(state, workDir) {
console.log('=== Diagnosing Documentation Structure ===');
const skillPath = state.target_skill.path;
const issues = [];
// 1. 检测冗余
const definitionDups = await detectDefinitionDuplicates(skillPath);
const hardcodedDups = await detectHardcodedDuplicates(skillPath);
for (const dup of [...definitionDups, ...hardcodedDups]) {
issues.push({
id: `DOC-RED-${issues.length + 1}`,
type: 'doc_redundancy',
severity: dup.severity,
location: { files: dup.files || [dup.file] },
description: dup.description || `${dup.type} 在多处定义`,
evidence: dup.files || [dup.file],
root_cause: '缺乏单一真相来源',
impact: '维护困难,易产生不一致',
suggested_fix: 'consolidate_to_ssot'
});
}
// 2. 检测冲突
const priorityConflicts = await detectPriorityConflicts(skillPath);
const driftConflicts = await detectImplementationDrift(skillPath);
for (const conflict of priorityConflicts) {
issues.push({
id: `DOC-CON-${issues.length + 1}`,
type: 'doc_conflict',
severity: 'critical',
location: { files: conflict.definitions.map(d => d.file) },
description: `${conflict.key} 在不同文件中定义不一致`,
evidence: conflict.definitions.map(d => `${d.file}: ${d.definition}`),
root_cause: '定义更新后未同步',
impact: '行为不可预测',
suggested_fix: 'reconcile_conflicting_definitions'
});
}
// 3. 生成报告
const severity = issues.some(i => i.severity === 'critical') ? 'critical' :
issues.some(i => i.severity === 'high') ? 'high' :
issues.length > 0 ? 'medium' : 'none';
const result = {
status: 'completed',
issues_found: issues.length,
severity: severity,
execution_time_ms: Date.now() - startTime,
details: {
patterns_checked: ['DOC-RED-001', 'DOC-RED-002', 'DOC-CON-001', 'DOC-CON-002'],
patterns_matched: issues.map(i => i.id.split('-').slice(0, 2).join('-')),
evidence: issues.flatMap(i => i.evidence),
recommendations: generateRecommendations(issues)
},
redundancies: issues.filter(i => i.type === 'doc_redundancy'),
conflicts: issues.filter(i => i.type === 'doc_conflict')
};
// 写入诊断结果
Write(`${workDir}/diagnosis/docs-diagnosis.json`, JSON.stringify(result, null, 2));
return {
stateUpdates: {
'diagnosis.docs': result,
issues: [...state.issues, ...issues]
},
outputFiles: [`${workDir}/diagnosis/docs-diagnosis.json`],
summary: `文档诊断完成:发现 ${issues.length} 个问题 (${severity})`
};
}
function generateRecommendations(issues) {
const recommendations = [];
if (issues.some(i => i.type === 'doc_redundancy')) {
recommendations.push('使用 consolidate_to_ssot 策略合并重复定义');
recommendations.push('考虑创建 specs/category-mappings.json 集中管理配置');
}
if (issues.some(i => i.type === 'doc_conflict')) {
recommendations.push('使用 reconcile_conflicting_definitions 策略解决冲突');
recommendations.push('建立文档同步检查机制');
}
return recommendations;
}Output
State Updates
{
stateUpdates: {
'diagnosis.docs': {
status: 'completed',
issues_found: N,
severity: 'critical|high|medium|low|none',
redundancies: [...],
conflicts: [...]
},
issues: [...existingIssues, ...newIssues]
}
}Output Files
${workDir}/diagnosis/docs-diagnosis.json- 完整诊断结果
Error Handling
| Error | Recovery |
|---|---|
| 文件读取失败 | 记录警告,继续处理其他文件 |
| 正则匹配超时 | 跳过该模式,记录 skipped |
| JSON 解析失败 | 跳过配置对比,仅进行模式检测 |
Next Actions
- 如果发现 critical 问题 → 优先进入 action-propose-fixes
- 如果无问题 → 继续下一个诊断或 action-generate-report
Action: Diagnose Long-tail Forgetting
Analyze target skill for long-tail effect and constraint forgetting issues.
Purpose
- Detect loss of early instructions in long execution chains
- Identify missing constraint propagation mechanisms
- Find weak goal alignment between phases
- Measure instruction retention across phases
Preconditions
- [ ] state.status === 'running'
- [ ] state.target_skill.path is set
- [ ] 'memory' in state.focus_areas OR state.focus_areas is empty
Detection Patterns
Pattern 1: Missing Constraint References
# Phases that don't reference original requirements
# Look for absence of: requirements, constraints, original, initial, user_requestPattern 2: Goal Drift
# Later phases focus on immediate task without global context
/\[TASK\][^[]*(?!\[CONSTRAINTS\]|\[REQUIREMENTS\])/Pattern 3: No Checkpoint Mechanism
# Absence of state preservation at key points
# Look for lack of: checkpoint, snapshot, preserve, restorePattern 4: Implicit State Passing
# State passed implicitly through conversation rather than explicitly
/(?<!state\.)context\./Execution
async function execute(state, workDir) {
const skillPath = state.target_skill.path;
const startTime = Date.now();
const issues = [];
const evidence = [];
console.log(`Diagnosing long-tail forgetting in ${skillPath}...`);
// 1. Analyze phase chain for constraint propagation
const phaseFiles = Glob(`${skillPath}/phases/*.md`)
.filter(f => !f.includes('orchestrator') && !f.includes('state-schema'))
.sort();
// Extract phase order (for sequential) or action dependencies (for autonomous)
const isAutonomous = state.target_skill.execution_mode === 'autonomous';
// 2. Check each phase for constraint awareness
let firstPhaseConstraints = [];
for (let i = 0; i < phaseFiles.length; i++) {
const file = phaseFiles[i];
const content = Read(file);
const relativePath = file.replace(skillPath + '/', '');
const phaseNum = i + 1;
// Extract constraints from first phase
if (i === 0) {
const constraintMatch = content.match(/\[CONSTRAINTS?\]([^[]*)/i);
if (constraintMatch) {
firstPhaseConstraints = constraintMatch[1]
.split('\n')
.filter(l => l.trim().startsWith('-'))
.map(l => l.trim().replace(/^-\s*/, ''));
}
}
// Check if later phases reference original constraints
if (i > 0 && firstPhaseConstraints.length > 0) {
const mentionsConstraints = firstPhaseConstraints.some(c =>
content.toLowerCase().includes(c.toLowerCase().slice(0, 20))
);
if (!mentionsConstraints) {
issues.push({
id: `MEM-${issues.length + 1}`,
type: 'memory_loss',
severity: 'high',
location: { file: relativePath, phase: `Phase ${phaseNum}` },
description: `Phase ${phaseNum} does not reference original constraints`,
evidence: [`Original constraints: ${firstPhaseConstraints.slice(0, 3).join(', ')}`],
root_cause: 'Constraint information not propagated to later phases',
impact: 'May produce output violating original requirements',
suggested_fix: 'Add explicit constraint injection or reference to state.original_constraints'
});
evidence.push({
file: relativePath,
pattern: 'missing_constraint_reference',
context: `Phase ${phaseNum} of ${phaseFiles.length}`,
severity: 'high'
});
}
}
// Check for goal drift - task without constraints
const hasTask = /\[TASK\]/i.test(content);
const hasConstraints = /\[CONSTRAINTS?\]|\[REQUIREMENTS?\]|\[RULES?\]/i.test(content);
if (hasTask && !hasConstraints && i > 1) {
issues.push({
id: `MEM-${issues.length + 1}`,
type: 'memory_loss',
severity: 'medium',
location: { file: relativePath },
description: 'Phase has TASK but no CONSTRAINTS/RULES section',
evidence: ['Task defined without boundary constraints'],
root_cause: 'Agent may not adhere to global constraints',
impact: 'Potential goal drift from original intent',
suggested_fix: 'Add [CONSTRAINTS] section referencing global rules'
});
}
// Check for checkpoint mechanism
const hasCheckpoint = /checkpoint|snapshot|preserve|savepoint/i.test(content);
const isKeyPhase = i === Math.floor(phaseFiles.length / 2) || i === phaseFiles.length - 1;
if (isKeyPhase && !hasCheckpoint && phaseFiles.length > 3) {
issues.push({
id: `MEM-${issues.length + 1}`,
type: 'memory_loss',
severity: 'low',
location: { file: relativePath },
description: 'Key phase without checkpoint mechanism',
evidence: [`Phase ${phaseNum} is a key milestone but has no state preservation`],
root_cause: 'Cannot recover from failures or verify constraint adherence',
impact: 'No rollback capability if constraints violated',
suggested_fix: 'Add checkpoint before major state changes'
});
}
}
// 3. Check for explicit state schema with constraints field
const stateSchemaFile = Glob(`${skillPath}/phases/state-schema.md`)[0];
if (stateSchemaFile) {
const schemaContent = Read(stateSchemaFile);
const hasConstraintsField = /constraints|requirements|original_request/i.test(schemaContent);
if (!hasConstraintsField) {
issues.push({
id: `MEM-${issues.length + 1}`,
type: 'memory_loss',
severity: 'medium',
location: { file: 'phases/state-schema.md' },
description: 'State schema lacks constraints/requirements field',
evidence: ['No dedicated field for preserving original requirements'],
root_cause: 'State structure does not support constraint persistence',
impact: 'Constraints may be lost during state transitions',
suggested_fix: 'Add original_requirements field to state schema'
});
}
}
// 4. Check SKILL.md for constraint enforcement in execution flow
const skillMd = Read(`${skillPath}/SKILL.md`);
const hasConstraintVerification = /constraint.*verif|verif.*constraint|quality.*gate/i.test(skillMd);
if (!hasConstraintVerification && phaseFiles.length > 3) {
issues.push({
id: `MEM-${issues.length + 1}`,
type: 'memory_loss',
severity: 'medium',
location: { file: 'SKILL.md' },
description: 'No constraint verification step in execution flow',
evidence: ['Execution flow lacks quality gate or constraint check'],
root_cause: 'No mechanism to verify output matches original intent',
impact: 'Constraint violations may go undetected',
suggested_fix: 'Add verification phase comparing output to original requirements'
});
}
// 5. Calculate severity
const criticalCount = issues.filter(i => i.severity === 'critical').length;
const highCount = issues.filter(i => i.severity === 'high').length;
const severity = criticalCount > 0 ? 'critical' :
highCount > 2 ? 'high' :
highCount > 0 ? 'medium' :
issues.length > 0 ? 'low' : 'none';
// 6. Write diagnosis result
const diagnosisResult = {
status: 'completed',
issues_found: issues.length,
severity: severity,
execution_time_ms: Date.now() - startTime,
details: {
patterns_checked: [
'constraint_propagation',
'goal_drift',
'checkpoint_mechanism',
'state_schema_constraints'
],
patterns_matched: evidence.map(e => e.pattern),
evidence: evidence,
phase_analysis: {
total_phases: phaseFiles.length,
first_phase_constraints: firstPhaseConstraints.length,
phases_with_constraint_ref: phaseFiles.length - issues.filter(i =>
i.description.includes('does not reference')).length
},
recommendations: [
highCount > 0 ? 'Implement constraint injection at each phase' : null,
issues.some(i => i.description.includes('checkpoint'))
? 'Add checkpoint/restore mechanism' : null,
issues.some(i => i.description.includes('State schema'))
? 'Add original_requirements to state schema' : null
].filter(Boolean)
}
};
Write(`${workDir}/diagnosis/memory-diagnosis.json`,
JSON.stringify(diagnosisResult, null, 2));
return {
stateUpdates: {
'diagnosis.memory': diagnosisResult,
issues: [...state.issues, ...issues]
},
outputFiles: [`${workDir}/diagnosis/memory-diagnosis.json`],
summary: `Memory diagnosis: ${issues.length} issues found (severity: ${severity})`
};
}State Updates
return {
stateUpdates: {
'diagnosis.memory': {
status: 'completed',
issues_found: <count>,
severity: '<critical|high|medium|low|none>',
// ... full diagnosis result
},
issues: [...existingIssues, ...newIssues]
}
};Error Handling
| Error Type | Recovery |
|---|---|
| Phase file read error | Skip file, continue analysis |
| No phases found | Report as structure issue |
Next Actions
- Success: action-diagnose-dataflow (or next in focus_areas)
- Skipped: If 'memory' not in focus_areas
Action: Diagnose Token Consumption
Analyze target skill for token consumption inefficiencies and output optimization opportunities.
Purpose
Detect patterns that cause excessive token usage:
- Verbose prompts without compression
- Large state objects with unnecessary fields
- Full content passing instead of references
- Unbounded arrays without sliding windows
- Redundant file I/O (write-then-read patterns)
Detection Patterns
| Pattern ID | Name | Detection Logic | Severity |
|---|---|---|---|
| TKN-001 | Verbose Prompts | Prompt files > 4KB or high static/variable ratio | medium |
| TKN-002 | Excessive State Fields | State schema > 15 top-level keys | medium |
| TKN-003 | Full Content Passing | Read() result embedded directly in prompt | high |
| TKN-004 | Unbounded Arrays | .push/concat without .slice(-N) | high |
| TKN-005 | Redundant Write→Read | Write(file) followed by Read(file) | medium |
Execution Steps
async function diagnoseTokenConsumption(state, workDir) {
const issues = [];
const evidence = [];
const skillPath = state.target_skill.path;
// 1. Scan for verbose prompts (TKN-001)
const mdFiles = Glob(`${skillPath}/**/*.md`);
for (const file of mdFiles) {
const content = Read(file);
if (content.length > 4000) {
evidence.push({
file: file,
pattern: 'TKN-001',
severity: 'medium',
context: `File size: ${content.length} chars (threshold: 4000)`
});
}
}
// 2. Check state schema field count (TKN-002)
const stateSchema = Glob(`${skillPath}/**/state-schema.md`)[0];
if (stateSchema) {
const schemaContent = Read(stateSchema);
const fieldMatches = schemaContent.match(/^\s*\w+:/gm) || [];
if (fieldMatches.length > 15) {
evidence.push({
file: stateSchema,
pattern: 'TKN-002',
severity: 'medium',
context: `State has ${fieldMatches.length} fields (threshold: 15)`
});
}
}
// 3. Detect full content passing (TKN-003)
const fullContentPattern = /Read\([^)]+\)\s*[\+,]|`\$\{.*Read\(/g;
for (const file of mdFiles) {
const content = Read(file);
const matches = content.match(fullContentPattern);
if (matches) {
evidence.push({
file: file,
pattern: 'TKN-003',
severity: 'high',
context: `Full content passing detected: ${matches[0]}`
});
}
}
// 4. Detect unbounded arrays (TKN-004)
const unboundedPattern = /\.(push|concat)\([^)]+\)(?!.*\.slice)/g;
for (const file of mdFiles) {
const content = Read(file);
const matches = content.match(unboundedPattern);
if (matches) {
evidence.push({
file: file,
pattern: 'TKN-004',
severity: 'high',
context: `Unbounded array growth: ${matches[0]}`
});
}
}
// 5. Detect write-then-read patterns (TKN-005)
const writeReadPattern = /Write\([^)]+\)[\s\S]{0,100}Read\([^)]+\)/g;
for (const file of mdFiles) {
const content = Read(file);
const matches = content.match(writeReadPattern);
if (matches) {
evidence.push({
file: file,
pattern: 'TKN-005',
severity: 'medium',
context: `Write-then-read pattern detected`
});
}
}
// Calculate severity
const highCount = evidence.filter(e => e.severity === 'high').length;
const mediumCount = evidence.filter(e => e.severity === 'medium').length;
let severity = 'none';
if (highCount > 0) severity = 'high';
else if (mediumCount > 2) severity = 'medium';
else if (mediumCount > 0) severity = 'low';
return {
status: 'completed',
issues_found: evidence.length,
severity: severity,
execution_time_ms: Date.now() - startTime,
details: {
patterns_checked: ['TKN-001', 'TKN-002', 'TKN-003', 'TKN-004', 'TKN-005'],
patterns_matched: [...new Set(evidence.map(e => e.pattern))],
evidence: evidence,
recommendations: generateRecommendations(evidence)
}
};
}
function generateRecommendations(evidence) {
const recs = [];
const patterns = [...new Set(evidence.map(e => e.pattern))];
if (patterns.includes('TKN-001')) {
recs.push('Apply prompt_compression: Extract static instructions to templates, use placeholders');
}
if (patterns.includes('TKN-002')) {
recs.push('Apply state_field_reduction: Remove debug/cache fields, consolidate related fields');
}
if (patterns.includes('TKN-003')) {
recs.push('Apply lazy_loading: Pass file paths instead of content, let agents read if needed');
}
if (patterns.includes('TKN-004')) {
recs.push('Apply sliding_window: Add .slice(-N) to array operations to bound growth');
}
if (patterns.includes('TKN-005')) {
recs.push('Apply output_minimization: Use in-memory data passing, eliminate temporary files');
}
return recs;
}Output
Write diagnosis result to ${workDir}/diagnosis/token-consumption-diagnosis.json:
{
"status": "completed",
"issues_found": 3,
"severity": "medium",
"execution_time_ms": 1500,
"details": {
"patterns_checked": ["TKN-001", "TKN-002", "TKN-003", "TKN-004", "TKN-005"],
"patterns_matched": ["TKN-001", "TKN-003"],
"evidence": [
{
"file": "phases/orchestrator.md",
"pattern": "TKN-001",
"severity": "medium",
"context": "File size: 5200 chars (threshold: 4000)"
}
],
"recommendations": [
"Apply prompt_compression: Extract static instructions to templates"
]
}
}State Update
updateState({
diagnosis: {
...state.diagnosis,
token_consumption: diagnosisResult
}
});Fix Strategies Mapping
| Pattern | Strategy | Implementation |
|---|---|---|
| TKN-001 | prompt_compression | Extract static text to variables, use template inheritance |
| TKN-002 | state_field_reduction | Audit and consolidate fields, remove non-essential data |
| TKN-003 | lazy_loading | Pass paths instead of content, agents load when needed |
| TKN-004 | sliding_window | Add .slice(-N) after push/concat operations |
| TKN-005 | output_minimization | Use return values instead of file relay |
Action: Gemini Analysis
动态调用 Gemini CLI 进行深度分析,根据用户需求或诊断结果选择分析类型。
Role
- 接收用户指定的分析需求或从诊断结果推断需求
- 构建适当的 CLI 命令
- 执行分析并解析结果
- 更新状态以供后续动作使用
Preconditions
state.status === 'running'- 满足以下任一条件:
state.gemini_analysis_requested === true(用户请求)state.issues.some(i => i.severity === 'critical')(发现严重问题)state.analysis_type !== null(已指定分析类型)
Analysis Types
1. root_cause - 问题根因分析
针对用户描述的问题进行深度分析。
const analysisPrompt = `
PURPOSE: Identify root cause of skill execution issue: ${state.user_issue_description}
TASK:
• Analyze skill structure at: ${state.target_skill.path}
• Identify anti-patterns in phase files
• Trace data flow through state management
• Check agent coordination patterns
MODE: analysis
CONTEXT: @**/*.md
EXPECTED: JSON with structure:
{
"root_causes": [
{ "id": "RC-001", "description": "...", "severity": "high", "evidence": ["file:line"] }
],
"patterns_found": [
{ "pattern": "...", "type": "anti-pattern|best-practice", "locations": [] }
],
"recommendations": [
{ "priority": 1, "action": "...", "rationale": "..." }
]
}
RULES: Focus on execution flow, state management, agent coordination
`;2. architecture - 架构审查
评估 skill 的整体架构设计。
const analysisPrompt = `
PURPOSE: Review skill architecture for: ${state.target_skill.name}
TASK:
• Evaluate phase decomposition and responsibility separation
• Check state schema design and data flow
• Assess agent coordination and error handling
• Review scalability and maintainability
MODE: analysis
CONTEXT: @**/*.md
EXPECTED: Markdown report with sections:
- Executive Summary
- Phase Architecture Assessment
- State Management Evaluation
- Agent Coordination Analysis
- Improvement Recommendations (prioritized)
RULES: Focus on modularity, extensibility, maintainability
`;3. prompt_optimization - 提示词优化
分析和优化 phase 中的提示词。
const analysisPrompt = `
PURPOSE: Optimize prompts in skill phases for better output quality
TASK:
• Analyze existing prompts for clarity and specificity
• Identify ambiguous instructions
• Check output format specifications
• Evaluate constraint communication
MODE: analysis
CONTEXT: @phases/**/*.md
EXPECTED: JSON with structure:
{
"prompt_issues": [
{ "file": "...", "issue": "...", "severity": "...", "suggestion": "..." }
],
"optimized_prompts": [
{ "file": "...", "original": "...", "optimized": "...", "rationale": "..." }
]
}
RULES: Preserve intent, improve clarity, add structured output requirements
`;4. performance - 性能分析
分析 Token 消耗和执行效率。
const analysisPrompt = `
PURPOSE: Analyze performance bottlenecks in skill execution
TASK:
• Estimate token consumption per phase
• Identify redundant data passing
• Check for unnecessary full-content transfers
• Evaluate caching opportunities
MODE: analysis
CONTEXT: @**/*.md
EXPECTED: JSON with structure:
{
"token_estimates": [
{ "phase": "...", "estimated_tokens": 1000, "breakdown": {} }
],
"bottlenecks": [
{ "type": "...", "location": "...", "impact": "high|medium|low", "fix": "..." }
],
"optimization_suggestions": []
}
RULES: Focus on token efficiency, reduce redundancy
`;5. custom - 自定义分析
用户指定的自定义分析需求。
const analysisPrompt = `
PURPOSE: ${state.custom_analysis_purpose}
TASK: ${state.custom_analysis_tasks}
MODE: analysis
CONTEXT: @**/*.md
EXPECTED: ${state.custom_analysis_expected}
RULES: ${state.custom_analysis_rules || 'Follow best practices'}
`;Execution
async function executeGeminiAnalysis(state, workDir) {
// 1. 确定分析类型
const analysisType = state.analysis_type || determineAnalysisType(state);
// 2. 构建 prompt
const prompt = buildAnalysisPrompt(analysisType, state);
// 3. 构建 CLI 命令
const cliCommand = `ccw cli -p "${escapeForShell(prompt)}" --tool gemini --mode analysis --cd "${state.target_skill.path}"`;
console.log(`Executing Gemini analysis: ${analysisType}`);
console.log(`Command: ${cliCommand}`);
// 4. 执行 CLI (后台运行)
const result = Bash({
command: cliCommand,
run_in_background: true,
timeout: 300000 // 5 minutes
});
// 5. 等待结果
// 注意: 根据 CLAUDE.md 指引,CLI 后台执行后应停止轮询
// 结果会在 CLI 完成后写入 state
return {
stateUpdates: {
gemini_analysis: {
type: analysisType,
status: 'running',
started_at: new Date().toISOString(),
task_id: result.task_id
}
},
outputFiles: [],
summary: `Gemini ${analysisType} analysis started in background`
};
}
function determineAnalysisType(state) {
// 根据状态推断分析类型
if (state.user_issue_description && state.user_issue_description.length > 100) {
return 'root_cause';
}
if (state.issues.some(i => i.severity === 'critical')) {
return 'root_cause';
}
if (state.focus_areas.includes('architecture')) {
return 'architecture';
}
if (state.focus_areas.includes('prompt')) {
return 'prompt_optimization';
}
if (state.focus_areas.includes('performance')) {
return 'performance';
}
return 'root_cause'; // 默认
}
function buildAnalysisPrompt(type, state) {
const templates = {
root_cause: () => `
PURPOSE: Identify root cause of skill execution issue: ${state.user_issue_description}
TASK: • Analyze skill structure • Identify anti-patterns • Trace data flow issues • Check agent coordination
MODE: analysis
CONTEXT: @**/*.md
EXPECTED: JSON { root_causes: [], patterns_found: [], recommendations: [] }
RULES: Focus on execution flow, be specific about file:line locations
`,
architecture: () => `
PURPOSE: Review skill architecture for ${state.target_skill.name}
TASK: • Evaluate phase decomposition • Check state design • Assess agent coordination • Review extensibility
MODE: analysis
CONTEXT: @**/*.md
EXPECTED: Markdown architecture assessment report
RULES: Focus on modularity and maintainability
`,
prompt_optimization: () => `
PURPOSE: Optimize prompts in skill for better output quality
TASK: • Analyze prompt clarity • Check output specifications • Evaluate constraint handling
MODE: analysis
CONTEXT: @phases/**/*.md
EXPECTED: JSON { prompt_issues: [], optimized_prompts: [] }
RULES: Preserve intent, improve clarity
`,
performance: () => `
PURPOSE: Analyze performance bottlenecks in skill
TASK: • Estimate token consumption • Identify redundancy • Check data transfer efficiency
MODE: analysis
CONTEXT: @**/*.md
EXPECTED: JSON { token_estimates: [], bottlenecks: [], optimization_suggestions: [] }
RULES: Focus on token efficiency
`,
custom: () => `
PURPOSE: ${state.custom_analysis_purpose}
TASK: ${state.custom_analysis_tasks}
MODE: analysis
CONTEXT: @**/*.md
EXPECTED: ${state.custom_analysis_expected}
RULES: ${state.custom_analysis_rules || 'Best practices'}
`
};
return templates[type]();
}
function escapeForShell(str) {
// 转义 shell 特殊字符
return str.replace(/"/g, '\\"').replace(/\$/g, '\\$').replace(/`/g, '\\`');
}Output
State Updates
{
gemini_analysis: {
type: 'root_cause' | 'architecture' | 'prompt_optimization' | 'performance' | 'custom',
status: 'running' | 'completed' | 'failed',
started_at: '2024-01-01T00:00:00Z',
completed_at: '2024-01-01T00:05:00Z',
task_id: 'xxx',
result: { /* 分析结果 */ },
error: null
},
// 分析结果合并到 issues
issues: [
...state.issues,
...newIssuesFromAnalysis
]
}Output Files
${workDir}/diagnosis/gemini-analysis-${type}.json- 原始分析结果${workDir}/diagnosis/gemini-analysis-${type}.md- 格式化报告
Post-Execution
分析完成后: 1. 解析 CLI 输出为结构化数据 2. 提取新发现的 issues 合并到 state.issues 3. 更新 recommendations 到 state 4. 触发下一步动作 (通常是 action-generate-report 或 action-propose-fixes)
Error Handling
| Error | Recovery |
|---|---|
| CLI 超时 | 重试一次,仍失败则跳过 Gemini 分析 |
| 解析失败 | 保存原始输出,手动处理 |
| 无结果 | 标记为 skipped,继续流程 |
User Interaction
如果 state.analysis_type === null 且无法自动推断,询问用户:
AskUserQuestion({
questions: [{
question: '请选择 Gemini 分析类型',
header: '分析类型',
options: [
{ label: '问题根因分析', description: '深度分析用户描述的问题' },
{ label: '架构审查', description: '评估整体架构设计' },
{ label: '提示词优化', description: '分析和优化 phase 提示词' },
{ label: '性能分析', description: '分析 Token 消耗和执行效率' }
],
multiSelect: false
}]
});Action: Generate Consolidated Report
Generate a comprehensive tuning report merging all diagnosis results with prioritized recommendations.
Purpose
- Merge all diagnosis results into unified report
- Prioritize issues by severity and impact
- Generate actionable recommendations
- Create human-readable markdown report
Preconditions
- [ ] state.status === 'running'
- [ ] All diagnoses in focus_areas are completed
- [ ] state.issues.length > 0 OR generate summary report
Execution
async function execute(state, workDir) {
console.log('Generating consolidated tuning report...');
const targetSkill = state.target_skill;
const issues = state.issues;
// 1. Group issues by type
const issuesByType = {
context_explosion: issues.filter(i => i.type === 'context_explosion'),
memory_loss: issues.filter(i => i.type === 'memory_loss'),
dataflow_break: issues.filter(i => i.type === 'dataflow_break'),
agent_failure: issues.filter(i => i.type === 'agent_failure')
};
// 2. Group issues by severity
const issuesBySeverity = {
critical: issues.filter(i => i.severity === 'critical'),
high: issues.filter(i => i.severity === 'high'),
medium: issues.filter(i => i.severity === 'medium'),
low: issues.filter(i => i.severity === 'low')
};
// 3. Calculate overall health score
const weights = { critical: 25, high: 15, medium: 5, low: 1 };
const deductions = Object.entries(issuesBySeverity)
.reduce((sum, [sev, arr]) => sum + arr.length * weights[sev], 0);
const healthScore = Math.max(0, 100 - deductions);
// 4. Generate report content
const report = `# Skill Tuning Report
**Target Skill**: ${targetSkill.name}
**Path**: ${targetSkill.path}
**Execution Mode**: ${targetSkill.execution_mode}
**Generated**: ${new Date().toISOString()}
---
## Executive Summary
| Metric | Value |
|--------|-------|
| Health Score | ${healthScore}/100 |
| Total Issues | ${issues.length} |
| Critical | ${issuesBySeverity.critical.length} |
| High | ${issuesBySeverity.high.length} |
| Medium | ${issuesBySeverity.medium.length} |
| Low | ${issuesBySeverity.low.length} |
### User Reported Issue
> ${state.user_issue_description}
### Overall Assessment
${healthScore >= 80 ? '✅ Skill is in good health with minor issues.' :
healthScore >= 60 ? '⚠️ Skill has significant issues requiring attention.' :
healthScore >= 40 ? '🔶 Skill has serious issues affecting reliability.' :
'❌ Skill has critical issues requiring immediate fixes.'}
---
## Diagnosis Results
### Context Explosion Analysis
${state.diagnosis.context ?
`- **Status**: ${state.diagnosis.context.status}
- **Severity**: ${state.diagnosis.context.severity}
- **Issues Found**: ${state.diagnosis.context.issues_found}
- **Key Findings**: ${state.diagnosis.context.details.recommendations.join('; ') || 'None'}` :
'_Not analyzed_'}
### Long-tail Memory Analysis
${state.diagnosis.memory ?
`- **Status**: ${state.diagnosis.memory.status}
- **Severity**: ${state.diagnosis.memory.severity}
- **Issues Found**: ${state.diagnosis.memory.issues_found}
- **Key Findings**: ${state.diagnosis.memory.details.recommendations.join('; ') || 'None'}` :
'_Not analyzed_'}
### Data Flow Analysis
${state.diagnosis.dataflow ?
`- **Status**: ${state.diagnosis.dataflow.status}
- **Severity**: ${state.diagnosis.dataflow.severity}
- **Issues Found**: ${state.diagnosis.dataflow.issues_found}
- **Key Findings**: ${state.diagnosis.dataflow.details.recommendations.join('; ') || 'None'}` :
'_Not analyzed_'}
### Agent Coordination Analysis
${state.diagnosis.agent ?
`- **Status**: ${state.diagnosis.agent.status}
- **Severity**: ${state.diagnosis.agent.severity}
- **Issues Found**: ${state.diagnosis.agent.issues_found}
- **Key Findings**: ${state.diagnosis.agent.details.recommendations.join('; ') || 'None'}` :
'_Not analyzed_'}
---
## Critical & High Priority Issues
${issuesBySeverity.critical.length + issuesBySeverity.high.length === 0 ?
'_No critical or high priority issues found._' :
[...issuesBySeverity.critical, ...issuesBySeverity.high].map((issue, i) => `
### ${i + 1}. [${issue.severity.toUpperCase()}] ${issue.description}
- **ID**: ${issue.id}
- **Type**: ${issue.type}
- **Location**: ${typeof issue.location === 'object' ? issue.location.file : issue.location}
- **Root Cause**: ${issue.root_cause}
- **Impact**: ${issue.impact}
- **Suggested Fix**: ${issue.suggested_fix}
**Evidence**:
${issue.evidence.map(e => `- \`${e}\``).join('\n')}
`).join('\n')}
---
## Medium & Low Priority Issues
${issuesBySeverity.medium.length + issuesBySeverity.low.length === 0 ?
'_No medium or low priority issues found._' :
[...issuesBySeverity.medium, ...issuesBySeverity.low].map((issue, i) => `
### ${i + 1}. [${issue.severity.toUpperCase()}] ${issue.description}
- **ID**: ${issue.id}
- **Type**: ${issue.type}
- **Suggested Fix**: ${issue.suggested_fix}
`).join('\n')}
---
## Recommended Fix Order
Based on severity and dependencies, apply fixes in this order:
${[...issuesBySeverity.critical, ...issuesBySeverity.high, ...issuesBySeverity.medium]
.slice(0, 10)
.map((issue, i) => `${i + 1}. **${issue.id}**: ${issue.suggested_fix}`)
.join('\n')}
---
## Quality Gates
| Gate | Threshold | Current | Status |
|------|-----------|---------|--------|
| Critical Issues | 0 | ${issuesBySeverity.critical.length} | ${issuesBySeverity.critical.length === 0 ? '✅ PASS' : '❌ FAIL'} |
| High Issues | ≤ 2 | ${issuesBySeverity.high.length} | ${issuesBySeverity.high.length <= 2 ? '✅ PASS' : '❌ FAIL'} |
| Health Score | ≥ 60 | ${healthScore} | ${healthScore >= 60 ? '✅ PASS' : '❌ FAIL'} |
**Overall Quality Gate**: ${
issuesBySeverity.critical.length === 0 &&
issuesBySeverity.high.length <= 2 &&
healthScore >= 60 ? '✅ PASS' : '❌ FAIL'}
---
*Report generated by skill-tuning*
`;
// 5. Write report
Write(`${workDir}/tuning-report.md`, report);
// 6. Calculate quality gate
const qualityGate = issuesBySeverity.critical.length === 0 &&
issuesBySeverity.high.length <= 2 &&
healthScore >= 60 ? 'pass' :
healthScore >= 40 ? 'review' : 'fail';
return {
stateUpdates: {
quality_score: healthScore,
quality_gate: qualityGate,
issues_by_severity: {
critical: issuesBySeverity.critical.length,
high: issuesBySeverity.high.length,
medium: issuesBySeverity.medium.length,
low: issuesBySeverity.low.length
}
},
outputFiles: [`${workDir}/tuning-report.md`],
summary: `Report generated: ${issues.length} issues, health score ${healthScore}/100, gate: ${qualityGate}`
};
}State Updates
return {
stateUpdates: {
quality_score: <0-100>,
quality_gate: '<pass|review|fail>',
issues_by_severity: { critical: N, high: N, medium: N, low: N }
}
};Error Handling
| Error Type | Recovery |
|---|---|
| Write error | Retry to alternative path |
| Empty issues | Generate summary with no issues |
Next Actions
- If issues.length > 0: action-propose-fixes
- If issues.length === 0: action-complete
Action: Initialize Tuning Session
Initialize the skill-tuning session by collecting target skill information, creating work directories, and setting up initial state.
Purpose
- Identify target skill to tune
- Collect user's problem description
- Create work directory structure
- Backup original skill files
- Initialize state for orchestrator
Preconditions
- [ ] state.status === 'pending'
Execution
async function execute(state, workDir) {
// 1. Ask user for target skill
const skillInput = await AskUserQuestion({
questions: [{
question: "Which skill do you want to tune?",
header: "Target Skill",
multiSelect: false,
options: [
{ label: "Specify path", description: "Enter skill directory path" }
]
}]
});
const skillPath = skillInput["Target Skill"];
// 2. Validate skill exists and read structure
const skillMdPath = `${skillPath}/SKILL.md`;
if (!Glob(`${skillPath}/SKILL.md`).length) {
throw new Error(`Invalid skill path: ${skillPath} - SKILL.md not found`);
}
// 3. Read skill metadata
const skillMd = Read(skillMdPath);
const frontMatterMatch = skillMd.match(/^---\n([\s\S]*?)\n---/);
const skillName = frontMatterMatch
? frontMatterMatch[1].match(/name:\s*(.+)/)?.[1]?.trim()
: skillPath.split('/').pop();
// 4. Detect execution mode
const hasOrchestrator = Glob(`${skillPath}/phases/orchestrator.md`).length > 0;
const executionMode = hasOrchestrator ? 'autonomous' : 'sequential';
// 5. Scan skill structure
const phases = Glob(`${skillPath}/phases/**/*.md`).map(f => f.replace(skillPath + '/', ''));
const specs = Glob(`${skillPath}/specs/**/*.md`).map(f => f.replace(skillPath + '/', ''));
// 6. Ask for problem description
const issueInput = await AskUserQuestion({
questions: [{
question: "Describe the issue or what you want to optimize:",
header: "Issue",
multiSelect: false,
options: [
{ label: "Context grows too large", description: "Token explosion over multiple turns" },
{ label: "Instructions forgotten", description: "Early constraints lost in long execution" },
{ label: "Data inconsistency", description: "State format changes between phases" },
{ label: "Agent failures", description: "Sub-agent calls fail or return unexpected results" }
]
}]
});
// 7. Ask for focus areas
const focusInput = await AskUserQuestion({
questions: [{
question: "Which areas should be diagnosed? (Select all that apply)",
header: "Focus",
multiSelect: true,
options: [
{ label: "context", description: "Context explosion analysis" },
{ label: "memory", description: "Long-tail forgetting analysis" },
{ label: "dataflow", description: "Data flow analysis" },
{ label: "agent", description: "Agent coordination analysis" }
]
}]
});
const focusAreas = focusInput["Focus"] || ['context', 'memory', 'dataflow', 'agent'];
// 8. Create backup
const backupDir = `${workDir}/backups/${skillName}-backup`;
Bash(`mkdir -p "${backupDir}"`);
Bash(`cp -r "${skillPath}"/* "${backupDir}/"`);
// 9. Return state updates
return {
stateUpdates: {
status: 'running',
started_at: new Date().toISOString(),
target_skill: {
name: skillName,
path: skillPath,
execution_mode: executionMode,
phases: phases,
specs: specs
},
user_issue_description: issueInput["Issue"],
focus_areas: Array.isArray(focusAreas) ? focusAreas : [focusAreas],
work_dir: workDir,
backup_dir: backupDir
},
outputFiles: [],
summary: `Initialized tuning for "${skillName}" (${executionMode} mode), focus: ${focusAreas.join(', ')}`
};
}State Updates
return {
stateUpdates: {
status: 'running',
started_at: '<timestamp>',
target_skill: {
name: '<skill-name>',
path: '<skill-path>',
execution_mode: '<sequential|autonomous>',
phases: ['...'],
specs: ['...']
},
user_issue_description: '<user description>',
focus_areas: ['context', 'memory', ...],
work_dir: '<work-dir>',
backup_dir: '<backup-dir>'
}
};Error Handling
| Error Type | Recovery |
|---|---|
| Skill path not found | Ask user to re-enter valid path |
| SKILL.md missing | Suggest path correction |
| Backup creation failed | Retry with alternative location |
Next Actions
- Success: Continue to first diagnosis action based on focus_areas
- Failure: action-abort
Action: Propose Fixes
Generate fix proposals for identified issues with implementation strategies.
Purpose
- Create fix strategies for each issue
- Generate implementation plans
- Estimate risk levels
- Allow user to select fixes to apply
Preconditions
- [ ] state.status === 'running'
- [ ] state.issues.length > 0
- [ ] action-generate-report completed
Fix Strategy Catalog
Context Explosion Fixes
| Strategy | Description | Risk |
|---|---|---|
context_summarization | Add summarizer agent between phases | low |
sliding_window | Keep only last N turns in context | low |
structured_state | Replace text context with JSON state | medium |
path_reference | Pass file paths instead of content | low |
Memory Loss Fixes
| Strategy | Description | Risk |
|---|---|---|
constraint_injection | Add constraints to each phase prompt | low |
checkpoint_restore | Save state at milestones | low |
goal_embedding | Track goal similarity throughout | medium |
state_constraints_field | Add constraints field to state schema | low |
Data Flow Fixes
| Strategy | Description | Risk |
|---|---|---|
state_centralization | Single state.json for all data | medium |
schema_enforcement | Add Zod validation | low |
field_normalization | Normalize field names | low |
transactional_updates | Atomic state updates | medium |
Agent Coordination Fixes
| Strategy | Description | Risk |
|---|---|---|
error_wrapping | Add try-catch to all Task calls | low |
result_validation | Validate agent returns | low |
orchestrator_refactor | Centralize agent coordination | high |
flatten_nesting | Remove nested agent calls | medium |
Execution
async function execute(state, workDir) {
console.log('Generating fix proposals...');
const issues = state.issues;
const fixes = [];
// Group issues by type for batch fixes
const issuesByType = {
context_explosion: issues.filter(i => i.type === 'context_explosion'),
memory_loss: issues.filter(i => i.type === 'memory_loss'),
dataflow_break: issues.filter(i => i.type === 'dataflow_break'),
agent_failure: issues.filter(i => i.type === 'agent_failure')
};
// Generate fixes for context explosion
if (issuesByType.context_explosion.length > 0) {
const ctxIssues = issuesByType.context_explosion;
if (ctxIssues.some(i => i.description.includes('history accumulation'))) {
fixes.push({
id: `FIX-${fixes.length + 1}`,
issue_ids: ctxIssues.filter(i => i.description.includes('history')).map(i => i.id),
strategy: 'sliding_window',
description: 'Implement sliding window for conversation history',
rationale: 'Prevents unbounded context growth by keeping only recent turns',
changes: [{
file: 'phases/orchestrator.md',
action: 'modify',
diff: `+ const MAX_HISTORY = 5;
+ state.history = state.history.slice(-MAX_HISTORY);`
}],
risk: 'low',
estimated_impact: 'Reduces token usage by ~50%',
verification_steps: ['Run skill with 10+ iterations', 'Verify context size stable']
});
}
if (ctxIssues.some(i => i.description.includes('full content'))) {
fixes.push({
id: `FIX-${fixes.length + 1}`,
issue_ids: ctxIssues.filter(i => i.description.includes('content')).map(i => i.id),
strategy: 'path_reference',
description: 'Pass file paths instead of full content',
rationale: 'Agents can read files when needed, reducing prompt size',
changes: [{
file: 'phases/*.md',
action: 'modify',
diff: `- prompt: \${content}
+ prompt: Read file at: \${filePath}`
}],
risk: 'low',
estimated_impact: 'Significant token reduction',
verification_steps: ['Verify agents can still access needed content']
});
}
}
// Generate fixes for memory loss
if (issuesByType.memory_loss.length > 0) {
const memIssues = issuesByType.memory_loss;
if (memIssues.some(i => i.description.includes('constraint'))) {
fixes.push({
id: `FIX-${fixes.length + 1}`,
issue_ids: memIssues.filter(i => i.description.includes('constraint')).map(i => i.id),
strategy: 'constraint_injection',
description: 'Add constraint injection to all phases',
rationale: 'Ensures original requirements are visible in every phase',
changes: [{
file: 'phases/*.md',
action: 'modify',
diff: `+ [CONSTRAINTS]
+ Original requirements from state.original_requirements:
+ \${JSON.stringify(state.original_requirements)}`
}],
risk: 'low',
estimated_impact: 'Improves constraint adherence',
verification_steps: ['Run skill with specific constraints', 'Verify output matches']
});
}
if (memIssues.some(i => i.description.includes('State schema'))) {
fixes.push({
id: `FIX-${fixes.length + 1}`,
issue_ids: memIssues.filter(i => i.description.includes('schema')).map(i => i.id),
strategy: 'state_constraints_field',
description: 'Add original_requirements field to state schema',
rationale: 'Preserves original intent throughout execution',
changes: [{
file: 'phases/state-schema.md',
action: 'modify',
diff: `+ original_requirements: string[]; // User's original constraints
+ goal_summary: string; // One-line goal statement`
}],
risk: 'low',
estimated_impact: 'Enables constraint tracking',
verification_steps: ['Verify state includes requirements after init']
});
}
}
// Generate fixes for data flow
if (issuesByType.dataflow_break.length > 0) {
const dfIssues = issuesByType.dataflow_break;
if (dfIssues.some(i => i.description.includes('multiple locations'))) {
fixes.push({
id: `FIX-${fixes.length + 1}`,
issue_ids: dfIssues.filter(i => i.description.includes('location')).map(i => i.id),
strategy: 'state_centralization',
description: 'Centralize all state to single state.json',
rationale: 'Single source of truth prevents inconsistencies',
changes: [{
file: 'phases/*.md',
action: 'modify',
diff: `- Write(\`\${workDir}/config.json\`, ...)
+ updateState({ config: ... }) // Use state manager`
}],
risk: 'medium',
estimated_impact: 'Eliminates state fragmentation',
verification_steps: ['Verify all reads come from state.json', 'Test state persistence']
});
}
if (dfIssues.some(i => i.description.includes('validation'))) {
fixes.push({
id: `FIX-${fixes.length + 1}`,
issue_ids: dfIssues.filter(i => i.description.includes('validation')).map(i => i.id),
strategy: 'schema_enforcement',
description: 'Add Zod schema validation',
rationale: 'Runtime validation catches schema violations',
changes: [{
file: 'phases/state-schema.md',
action: 'modify',
diff: `+ import { z } from 'zod';
+ const StateSchema = z.object({...});
+ function validateState(s) { return StateSchema.parse(s); }`
}],
risk: 'low',
estimated_impact: 'Catches invalid state early',
verification_steps: ['Test with invalid state input', 'Verify error thrown']
});
}
}
// Generate fixes for agent coordination
if (issuesByType.agent_failure.length > 0) {
const agentIssues = issuesByType.agent_failure;
if (agentIssues.some(i => i.description.includes('error handling'))) {
fixes.push({
id: `FIX-${fixes.length + 1}`,
issue_ids: agentIssues.filter(i => i.description.includes('error')).map(i => i.id),
strategy: 'error_wrapping',
description: 'Wrap all Task calls in try-catch',
rationale: 'Prevents cascading failures from agent errors',
changes: [{
file: 'phases/*.md',
action: 'modify',
diff: `+ try {
const result = await Agent({...});
+ if (!result) throw new Error('Empty result');
+ } catch (e) {
+ updateState({ errors: [...errors, e.message], error_count: error_count + 1 });
+ }`
}],
risk: 'low',
estimated_impact: 'Improves error resilience',
verification_steps: ['Simulate agent failure', 'Verify graceful handling']
});
}
if (agentIssues.some(i => i.description.includes('nested'))) {
fixes.push({
id: `FIX-${fixes.length + 1}`,
issue_ids: agentIssues.filter(i => i.description.includes('nested')).map(i => i.id),
strategy: 'flatten_nesting',
description: 'Flatten nested agent calls',
rationale: 'Reduces complexity and context explosion',
changes: [{
file: 'phases/orchestrator.md',
action: 'modify',
diff: `// Instead of agent calling agent:
// Agent A returns {needs_agent_b: true}
// Orchestrator sees this and calls Agent B next`
}],
risk: 'medium',
estimated_impact: 'Reduces nesting depth',
verification_steps: ['Verify no nested Task calls', 'Test agent chaining via orchestrator']
});
}
}
// Write fix proposals
Write(`${workDir}/fixes/fix-proposals.json`, JSON.stringify(fixes, null, 2));
// Ask user to select fixes to apply
const fixOptions = fixes.slice(0, 4).map(f => ({
label: f.id,
description: `[${f.risk.toUpperCase()} risk] ${f.description}`
}));
if (fixOptions.length > 0) {
const selection = await AskUserQuestion({
questions: [{
question: 'Which fixes would you like to apply?',
header: 'Fixes',
multiSelect: true,
options: fixOptions
}]
});
const selectedFixIds = Array.isArray(selection['Fixes'])
? selection['Fixes']
: [selection['Fixes']];
return {
stateUpdates: {
proposed_fixes: fixes,
pending_fixes: selectedFixIds.filter(id => id && fixes.some(f => f.id === id))
},
outputFiles: [`${workDir}/fixes/fix-proposals.json`],
summary: `Generated ${fixes.length} fix proposals, ${selectedFixIds.length} selected for application`
};
}
return {
stateUpdates: {
proposed_fixes: fixes,
pending_fixes: []
},
outputFiles: [`${workDir}/fixes/fix-proposals.json`],
summary: `Generated ${fixes.length} fix proposals (none selected)`
};
}State Updates
return {
stateUpdates: {
proposed_fixes: [...fixes],
pending_fixes: [...selectedFixIds]
}
};Error Handling
| Error Type | Recovery |
|---|---|
| No issues to fix | Skip to action-complete |
| User cancels selection | Set pending_fixes to empty |
Next Actions
- If pending_fixes.length > 0: action-apply-fix
- If pending_fixes.length === 0: action-complete
Action: Verify Applied Fixes
Verify that applied fixes resolved the targeted issues.
Purpose
- Re-run relevant diagnostics
- Compare before/after issue counts
- Update verification status
- Determine if more iterations needed
Preconditions
- [ ] state.status === 'running'
- [ ] state.applied_fixes.length > 0
- [ ] Some applied_fixes have verification_result === 'pending'
Execution
async function execute(state, workDir) {
console.log('Verifying applied fixes...');
const appliedFixes = state.applied_fixes.filter(f => f.verification_result === 'pending');
if (appliedFixes.length === 0) {
return {
stateUpdates: {},
outputFiles: [],
summary: 'No fixes pending verification'
};
}
const verificationResults = [];
for (const fix of appliedFixes) {
const proposedFix = state.proposed_fixes.find(f => f.id === fix.fix_id);
if (!proposedFix) {
verificationResults.push({
fix_id: fix.fix_id,
result: 'fail',
reason: 'Fix definition not found'
});
continue;
}
// Determine which diagnosis to re-run based on fix strategy
const strategyToDiagnosis = {
'context_summarization': 'context',
'sliding_window': 'context',
'structured_state': 'context',
'path_reference': 'context',
'constraint_injection': 'memory',
'checkpoint_restore': 'memory',
'goal_embedding': 'memory',
'state_constraints_field': 'memory',
'state_centralization': 'dataflow',
'schema_enforcement': 'dataflow',
'field_normalization': 'dataflow',
'transactional_updates': 'dataflow',
'error_wrapping': 'agent',
'result_validation': 'agent',
'orchestrator_refactor': 'agent',
'flatten_nesting': 'agent'
};
const diagnosisType = strategyToDiagnosis[proposedFix.strategy];
// For now, do a lightweight verification
// Full implementation would re-run the specific diagnosis
// Check if the fix was actually applied (look for markers)
const targetPath = state.target_skill.path;
const fixMarker = `Applied fix ${fix.fix_id}`;
let fixFound = false;
const allFiles = Glob(`${targetPath}/**/*.md`);
for (const file of allFiles) {
const content = Read(file);
if (content.includes(fixMarker)) {
fixFound = true;
break;
}
}
if (fixFound) {
// Verify by checking if original issues still exist
const relatedIssues = proposedFix.issue_ids;
const originalIssueCount = relatedIssues.length;
// Simplified verification: assume fix worked if marker present
// Real implementation would re-run diagnosis patterns
verificationResults.push({
fix_id: fix.fix_id,
result: 'pass',
reason: `Fix applied successfully, addressing ${originalIssueCount} issues`,
issues_resolved: relatedIssues
});
} else {
verificationResults.push({
fix_id: fix.fix_id,
result: 'fail',
reason: 'Fix marker not found in target files'
});
}
}
// Update applied fixes with verification results
const updatedAppliedFixes = state.applied_fixes.map(fix => {
const result = verificationResults.find(v => v.fix_id === fix.fix_id);
if (result) {
return {
...fix,
verification_result: result.result
};
}
return fix;
});
// Calculate new quality score
const passedFixes = verificationResults.filter(v => v.result === 'pass').length;
const totalFixes = verificationResults.length;
const verificationRate = totalFixes > 0 ? (passedFixes / totalFixes) * 100 : 100;
// Recalculate issues (remove resolved ones)
const resolvedIssueIds = verificationResults
.filter(v => v.result === 'pass')
.flatMap(v => v.issues_resolved || []);
const remainingIssues = state.issues.filter(i => !resolvedIssueIds.includes(i.id));
// Recalculate quality score
const weights = { critical: 25, high: 15, medium: 5, low: 1 };
const deductions = remainingIssues.reduce((sum, issue) =>
sum + (weights[issue.severity] || 0), 0);
const newHealthScore = Math.max(0, 100 - deductions);
// Determine new quality gate
const remainingCritical = remainingIssues.filter(i => i.severity === 'critical').length;
const remainingHigh = remainingIssues.filter(i => i.severity === 'high').length;
const newQualityGate = remainingCritical === 0 && remainingHigh <= 2 && newHealthScore >= 60
? 'pass'
: newHealthScore >= 40 ? 'review' : 'fail';
// Increment iteration count
const newIterationCount = state.iteration_count + 1;
// Ask user if they want to continue
let continueIteration = false;
if (newQualityGate !== 'pass' && newIterationCount < state.max_iterations) {
const continueResponse = await AskUserQuestion({
questions: [{
question: `Verification complete. Quality gate: ${newQualityGate}. Continue with another iteration?`,
header: 'Continue',
multiSelect: false,
options: [
{ label: 'Yes', description: `Run iteration ${newIterationCount + 1}` },
{ label: 'No', description: 'Finish with current state' }
]
}]
});
continueIteration = continueResponse['Continue'] === 'Yes';
}
// If continuing, reset diagnosis for re-evaluation
const diagnosisReset = continueIteration ? {
'diagnosis.context': null,
'diagnosis.memory': null,
'diagnosis.dataflow': null,
'diagnosis.agent': null
} : {};
return {
stateUpdates: {
applied_fixes: updatedAppliedFixes,
issues: remainingIssues,
quality_score: newHealthScore,
quality_gate: newQualityGate,
iteration_count: newIterationCount,
...diagnosisReset,
issues_by_severity: {
critical: remainingIssues.filter(i => i.severity === 'critical').length,
high: remainingIssues.filter(i => i.severity === 'high').length,
medium: remainingIssues.filter(i => i.severity === 'medium').length,
low: remainingIssues.filter(i => i.severity === 'low').length
}
},
outputFiles: [],
summary: `Verified ${totalFixes} fixes: ${passedFixes} passed. Score: ${newHealthScore}, Gate: ${newQualityGate}, Iteration: ${newIterationCount}`
};
}State Updates
return {
stateUpdates: {
applied_fixes: [...updatedWithVerificationResults],
issues: [...remainingIssues],
quality_score: newScore,
quality_gate: newGate,
iteration_count: iteration + 1
}
};Error Handling
| Error Type | Recovery |
|---|---|
| Re-diagnosis fails | Mark as 'inconclusive' |
| File access error | Skip file verification |
Next Actions
- If quality_gate === 'pass': action-complete
- If user chose to continue: restart diagnosis cycle
- If max_iterations reached: action-complete
Skill Authoring Principles
Skill 撰写首要准则。所有诊断和优化以此为纲。
---
核心原则
简洁高效 → 去除无关存储 → 去除中间存储 → 上下文流转---
1. 简洁高效
原则:最小化实现,只做必要的事
| DO | DON'T |
|---|---|
| 单一职责阶段 | 臃肿的多功能阶段 |
| 直接的数据路径 | 迂回的处理流程 |
| 必要的字段 | 冗余的 schema 定义 |
| 精准的 prompt | 过度详细的指令 |
检测模式:
- Phase 文件 > 200 行 → 需拆分
- State schema 字段 > 20 个 → 需精简
- 同一数据多处定义 → 需去重
---
2. 去除无关存储
原则:不存储不需要的数据
| DO | DON'T |
|---|---|
| 只存最终结果 | 存储调试信息 |
| 存路径引用 | 存完整内容副本 |
| 存必要索引 | 存全量历史 |
检测模式:
// BAD: 存储完整内容
state.full_analysis_result = longAnalysisOutput;
// GOOD: 存路径 + 摘要
state.analysis = {
path: `${workDir}/analysis.json`,
summary: extractSummary(output),
key_findings: extractFindings(output)
};反模式清单:
state.debug_*→ 删除state.*_history(无限增长) → 限制或删除state.*_cache(会话内) → 改用内存变量- 重复字段 → 合并
---
3. 去除中间存储
原则:避免临时文件和中间状态文件
| DO | DON'T |
|---|---|
| 直接传递结果 | 写文件再读文件 |
| 函数返回值 | 中间 JSON 文件 |
| 管道处理 | 阶段性存储 |
检测模式:
// BAD: 中间文件
Write(`${workDir}/temp-step1.json`, step1Result);
const step1 = Read(`${workDir}/temp-step1.json`);
const step2Result = process(step1);
Write(`${workDir}/temp-step2.json`, step2Result);
// GOOD: 直接流转
const step1Result = await executeStep1();
const step2Result = process(step1Result);
const finalResult = finalize(step2Result);
Write(`${workDir}/final-output.json`, finalResult); // 只存最终结果允许的存储:
- 最终输出(用户需要的结果)
- 检查点(长流程恢复用,可选)
- 备份(修改前的原始文件)
禁止的存储:
temp-*.jsonintermediate-*.jsonstep[N]-output.json*-draft.md
---
4. 上下文流转
原则:通过上下文传递而非文件
| DO | DON'T |
|---|---|
| 函数参数传递 | 全局状态读写 |
| 返回值链式处理 | 文件中转 |
| prompt 内嵌数据 | 指向外部文件 |
模式:
// 上下文流转模式
async function executePhase(context) {
const { previousResult, constraints, config } = context;
const result = await Agent({
subagent_type: 'universal-executor',
description: 'Execute phase with context passing',
run_in_background: false,
prompt: `
[CONTEXT]
Previous: ${JSON.stringify(previousResult)}
Constraints: ${constraints.join(', ')}
[TASK]
Process and return result directly.
`
});
return {
...context,
currentResult: result,
completed: ['phase-name']
};
}
// 链式执行
let ctx = initialContext;
ctx = await executePhase1(ctx);
ctx = await executePhase2(ctx);
ctx = await executePhase3(ctx);
// ctx 包含完整上下文,无中间文件State 最小化:
// 只存必要状态
interface MinimalState {
status: 'pending' | 'running' | 'completed';
target: { name: string; path: string };
result_path: string; // 最终结果路径
error?: string;
}---
应用场景
诊断时检查
| 检查项 | 违反时标记 |
|---|---|
| Phase 内写入 temp 文件 | unnecessary_storage |
| State 包含 *_history 无限数组 | unbounded_state |
| 文件写入后立即读取 | redundant_io |
| 多阶段传递完整内容 | context_bloat |
优化策略
| 问题 | 策略 |
|---|---|
| 中间文件过多 | eliminate_intermediate_files |
| State 膨胀 | minimize_state_schema |
| 重复存储 | deduplicate_storage |
| 文件中转 | context_passing |
---
合规检查清单
□ 无 temp/intermediate 文件写入
□ State schema < 15 个字段
□ 无重复数据存储
□ Phase 间通过上下文/返回值传递
□ 只存最终结果文件
□ 无无限增长的数组
□ 无调试字段残留