unified-execute-with-file について
タスク JSON の計画を依存順に実行する開発ワークフロー用スキルです。実行後の収束条件確認と進捗記録を行い、ディレクトリまたは単一 JSON ファイルを受け付けます。
主な機能
- 01依存関係順の逐次実行
- 02実行後の収束条件チェック
- 03概要とイベントログの記録
- 04ドライランと自動コミット
- 05ディレクトリまたは単一ファイル入力
活用シーン
- 01複数タスクからなる開発計画の実行
- 02実行前の依存関係とファイル競合の確認
- 03ファイルを変更せずに計画をシミュレーション
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ catlog22/ claude-code-workflow --skill unified-execute-with-fileインストール後、Claude Code で/unified-execute-with-fileを入力して読み込まれたか確認します。
詳細
Unified-Execute-With-File ワークフロー
クイックスタート
.task/*.json ディレクトリを読み込み、収束の検証と進捗の追跡を行いながらタスクを順次実行する汎用実行エンジンです。
# Execute from lite-plan output
/codex:unified-execute-with-file PLAN=".workflow/.lite-plan/LPLAN-auth-2025-01-21/.task/"
# Execute from workflow session output
/codex:unified-execute-with-file PLAN=".workflow/active/WFS-xxx/.task/" --auto-commit
# Execute a single task JSON file
/codex:unified-execute-with-file PLAN=".workflow/active/WFS-xxx/.task/IMPL-001.json" --dry-run
# Auto-detect from .workflow/ directories
/codex:unified-execute-with-file
主なワークフロー:.task/*.json をスキャン → 検証 → 実行前分析 → 実行 → 収束の検証 → 進捗の追跡
主な機能:
- ディレクトリベース:個別のタスク JSON ファイルを含む
.task/ディレクトリを読み込みます - 収束を重視:実行後に各タスクの収束条件を検証します
- 逐次実行:依存関係を追跡しながら、トポロジカル順序でタスクを処理します
- 二重の進捗追跡:
execution.md(概要)とexecution-events.md(イベントストリーム) - 自動コミット:タスクごとに任意で Conventional Commits 形式のコミットを行います
- ドライランモード:変更を加えずに実行をシミュレートします
- 柔軟な入力:
.task/ディレクトリのパス、または単一の.jsonファイルのパスを受け付けます
入力形式:各タスクは .task/ ディレクトリ内の独立した JSON ファイルです(例:IMPL-001.json)。ほかの形式を .task/*.json に変換するには、あらかじめ plan-converter を使用してください。
概要
┌─────────────────────────────────────────────────────────────┐
│ UNIFIED EXECUTE WORKFLOW │
├─────────────────────────────────────────────────────────────┤
│ │
│ Phase 1: Load & Validate │
│ ├─ Scan .task/*.json (one task per file) │
│ ├─ Validate schema (id, title, depends_on, convergence) │
│ ├─ Detect cycles, build topological order │
│ └─ Initialize execution.md + execution-events.md │
│ │
│ Phase 2: Pre-Execution Analysis │
│ ├─ Check file conflicts (multiple tasks → same file) │
│ ├─ Verify file existence │
│ ├─ Generate feasibility report │
│ └─ User confirmation (unless dry-run) │
│ │
│ Phase 3: Serial Execution + Convergence Verification │
│ For each task in topological order: │
│ ├─ Check dependencies satisfied │
│ ├─ Record START event │
│ ├─ Execute directly (Read/Edit/Write/Grep/Glob/Bash) │
│ ├─ Verify convergence.criteria[] │
│ ├─ Run convergence.verification command │
│ ├─ Record COMPLETE/FAIL event with verification results │
│ ├─ Update _execution state in task JSON file │
│ └─ Auto-commit if enabled │
│ │
│ Phase 4: Completion │
│ ├─ Finalize execution.md with summary statistics │
│ ├─ Finalize execution-events.md with session footer │
│ ├─ Write back .task/*.json with _execution states │
│ └─ Offer follow-up actions │
│ │
└─────────────────────────────────────────────────────────────┘
出力構成
${projectRoot}/.workflow/.execution/EXEC-{slug}-{date}-{random}/
├── execution.md # Plan overview + task table + summary
└── execution-events.md # ⭐ Unified event log (single source of truth)
さらに、各ソース .task/*.json ファイルは _execution の状態でインプレース更新されます。
実装の詳細
セッションの初期化
ステップ 0:セッションを初期化
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
const projectRoot = Bash(`git rev-parse --show-toplevel 2>/dev/null || pwd`).trim()
// Parse arguments
const autoCommit = $ARGUMENTS.includes('--auto-commit')
const dryRun = $ARGUMENTS.includes('--dry-run')
const planMatch = $ARGUMENTS.match(/PLAN="([^"]+)"/) || $ARGUMENTS.match(/PLAN=(\S+)/)
let planPath = planMatch ? planMatch[1] : null
// Auto-detect if no PLAN specified
if (!planPath) {
// Search in order (most recent first):
// .workflow/active/*/.task/
// .workflow/.lite-plan/*/.task/
// .workflow/.req-plan/*/.task/
// .workflow/.planning/*/.task/
// Use most recently modified directory containing *.json files
}
// Resolve path
planPath = path.isAbsolute(planPath) ? planPath : `${projectRoot}/${planPath}`
// Generate session ID
const slug = path.basename(path.dirname(planPath)).toLowerCase().substring(0, 30)
const dateStr = getUtc8ISOString().substring(0, 10)
const random = Math.random().toString(36).substring(2, 9)
const sessionId = `EXEC-${slug}-${dateStr}-${random}`
const sessionFolder = `${projectRoot}/.workflow/.execution/${sessionId}`
Bash(`mkdir -p ${sessionFolder}`)
フェーズ 1:読み込みと検証
目的:.task/ ディレクトリをスキャンし、個別のタスク JSON ファイルを解析して、スキーマと依存関係を検証し、実行順序を構築します。
ステップ 1.1:.task/ ディレクトリをスキャンし、タスクファイルを解析
// Determine if planPath is a directory or single file
const isDirectory = planPath.endsWith('/') || Bash(`test -d "${planPath}" && echo dir || echo file`).trim() === 'dir'
let taskFiles, tasks
if (isDirectory) {
// Directory mode: scan for all *.json files
taskFiles = Glob('*.json', planPath)
if (taskFiles.length === 0) throw new Error(`No .json files found in ${planPath}`)
tasks = taskFiles.map(filePath => {
try {
const content = Read(filePath)
const task = JSON.parse(content)
task._source_file = filePath // Track source file for write-back
return task
} catch (e) {
throw new Error(`${path.basename(filePath)}: Invalid JSON - ${e.message}`)
}
})
} else {
// Single file mode: parse one task JSON
try {
const content = Read(planPath)
const task = JSON.parse(content)
task._source_file = planPath
tasks = [task]
} catch (e) {
throw new Error(`${path.basename(planPath)}: Invalid JSON - ${e.message}`)
}
}
if (tasks.length === 0) throw new Error('No tasks found')
ステップ 1.2:スキーマを検証
統合タスクスキーマに照らして検証します:~/.ccw/workflows/cli-templates/schemas/task-schema.json
const errors = []
tasks.forEach((task, i) => {
const src = task._source_file ? path.basename(task._source_file) : `Task ${i + 1}`
// Required fields (per task-schema.json)
if (!task.id) errors.push(`${src}: missing 'id'`)
if (!task.title) errors.push(`${src}: missing 'title'`)
if (!task.description) errors.push(`${src}: missing 'description'`)
if (!Array.isArray(task.depends_on)) errors.push(`${task.id || src}: missing 'depends_on' array`)
// Context block (optional but validated if present)
if (task.context) {
if (task.context.requirements && !Array.isArray(task.context.requirements))
errors.push(`${task.id}: context.requirements must be array`)
if (task.context.acceptance && !Array.isArray(task.context.acceptance))
errors.push(`${task.id}: context.acceptance must be array`)
if (task.context.focus_paths && !Array.isArray(task.context.focus_paths))
errors.push(`${task.id}: context.focus_paths must be array`)
}
// Convergence (required for execution verification)
if (!task.convergence) {
errors.push(`${task.id || src}: missing 'convergence'`)
} else {
if (!task.convergence.criteria?.length) errors.push(`${task.id}: empty convergence.criteria`)
if (!task.convergence.verification) errors.push(`${task.id}: missing convergence.verification`)
if (!task.convergence.definition_of_done) errors.push(`${task.id}: missing convergence.definition_of_done`)
}
// Flow control (optional but validated if present)
if (task.flow_control) {
if (task.flow_control.target_files && !Array.isArray(task.flow_control.target_files))
errors.push(`${task.id}: flow_control.target_files must be array`)
}
// New unified schema fields (backward compatible addition)
if (task.focus_paths && !Array.isArray(task.focus_paths))
errors.push(`${task.id}: focus_paths must be array`)
if (task.implementation && !Array.isArray(task.implementation))
errors.push(`${task.id}: implementation must be array`)
if (task.files && !Array.isArray(task.files))
errors.push(`${task.id}: files must be array`)
})
if (errors.length) {
// Report errors, stop execution
}
ステップ 1.3:実行順序を構築
// 1. Validate dependency references
const taskIds = new Set(tasks.map(t => t.id))
tasks.forEach(task => {
task.depends_on.forEach(dep => {
if (!taskIds.has(dep)) errors.push(`${task.id}: depends on unknown task '${dep}'`)
})
})
// 2. Detect cycles (DFS)
function detectCycles(tasks) {
const graph = new Map(tasks.map(t => [t.id, t.depends_on || []]))
const visited = new Set(), inStack = new Set(), cycles = []
function dfs(node, path) {
if (inStack.has(node)) { cycles.push([...path, node].join(' → ')); return }
if (visited.has(node)) return
visited.add(node); inStack.add(node)
;(graph.get(node) || []).forEach(dep => dfs(dep, [...path, node]))
inStack.delete(node)
}
tasks.forEach(t => { if (!visited.has(t.id)) dfs(t.id, []) })
return cycles
}
const cycles = detectCycles(tasks)
if (cycles.length) errors.push(`Circular dependencies: ${cycles.join('; ')}`)
// 3. Topological sort
function topoSort(tasks) {
const inDegree = new Map(tasks.map(t => [t.id, 0]))
tasks.forEach(t => t.depends_on.forEach(dep => {
inDegree.set(t.id, (inDegree.get(t.id) || 0) + 1)
}))
const queue = tasks.filter(t => inDegree.get(t.id) === 0).map(t => t.id)
const order = []
while (queue.length) {
const id = queue.shift()
order.push(id)
tasks.forEach(t => {
if (t.depends_on.includes(id)) {
inDegree.set(t.id, inDegree.get(t.id) - 1)
if (inDegree.get(t.id) === 0) queue.push(t.id)
}
})
}
return order
}
const executionOrder = topoSort(tasks)
ステップ 1.4:実行アーティファクトを初期化
// execution.md
const executionMd = `# Execution Overview
## Session Info
- **Session ID**: ${sessionId}
- **Plan Source**: ${planPath}
- **Started**: ${getUtc8ISOString()}
- **Total Tasks**: ${tasks.length}
- **Mode**: ${dryRun ? 'Dry-run (no changes)' : 'Direct inline execution'}
- **Auto-Commit**: ${autoCommit ? 'Enabled' : 'Disabled'}
## Task Overview
| # | ID | Title | Type | Priority | Effort | Dependencies | Status |
|---|-----|-------|------|----------|--------|--------------|--------|
${tasks.map((t, i) => `| ${i+1} | ${t.id} | ${t.title} | ${t.type || '-'} | ${t.priority || '-'} | ${t.effort || '-'} | ${t.depends_on.join(', ') || '-'} | pending |`).join('\n')}
## Pre-Execution Analysis
> Populated in Phase 2
## Execution Timeline
> Updated as tasks complete
## Execution Summary
> Updated after all tasks complete
`
Write(`${sessionFolder}/execution.md`, executionMd)
// execution-events.md
Write(`${sessionFolder}/execution-events.md`, `# Execution Events
**Session**: ${sessionId}
**Started**: ${getUtc8ISOString()}
**Source**: ${planPath}
---
`)
フェーズ 2:実行前分析
目的:実行前に実現可能性を検証し、問題を特定します。
ステップ 2.1:ファイルの競合を分析
const fileTaskMap = new Map() // file → [taskIds]
tasks.forEach(task => {
(task.files || []).forEach(f => {
const key = f.path
if (!fileTaskMap.has(key)) fileTaskMap.set(key, [])
fileTaskMap.get(key).push(task.id)
})
})
const conflicts = []
fileTaskMap.forEach((taskIds, file) => {
if (taskIds.length > 1) {
conflicts.push({ file, tasks: taskIds, resolution: 'Execute in dependency order' })
}
})
// Check file existence
const missingFiles = []
tasks.forEach(task => {
(task.files || []).forEach(f => {
if (f.action !== 'create' && !file_exists(f.path)) {
missingFiles.push({ file: f.path, task: task.id })
}
})
})
ステップ 2.2:execution.md に追記
// Replace "Pre-Execution Analysis" section with:
// - File Conflicts (list or "No conflicts")
// - Missing Files (list or "All files exist")
// - Dependency Validation (errors or "No issues")
// - Execution Order (numbered list)
ステップ 2.3:ユーザーの確認
if (!dryRun) {
request_user_input({
questions: [{
header: "Confirm",
id: "confirm_execute",
question: `Execute ${tasks.length} tasks?`,
options: [
{ label: "Execute (Recommended)", description: "Start serial execution" },
{ label: "Dry Run", description: "Simulate without changes" },
{ label: "Cancel", description: "Abort execution" }
]
}]
})
// answer.answers.confirm_execute.answers[0] → selected label
}
フェーズ 3:逐次実行と収束の検証
目的:タスクを順番に実行し、各タスクの実行後に収束を検証して、すべての状態を追跡します。
実行モデル:インラインで直接実行します。メインプロセスがファイルを直接読み取り、編集し、書き込みます。CLI への委譲は行いません。
ステップ 3.1:実行ループ
const completedTasks = new Set()
const failedTasks = new Set()
const skippedTasks = new Set()
for (const taskId of executionOrder) {
const task = tasks.find(t => t.id === taskId)
const startTime = getUtc8ISOString()
// 1. Check dependencies
const unmetDeps = task.depends_on.filter(dep => !completedTasks.has(dep))
if (unmetDeps.length) {
appendToEvents(task, 'BLOCKED', `Unmet dependencies: ${unmetDeps.join(', ')}`)
skippedTasks.add(task.id)
task._execution = { status: 'skipped', executed_at: startTime,
result: { success: false, error: `Blocked by: ${unmetDeps.join(', ')}` } }
continue
}
// 2. Record START event
appendToEvents(`## ${getUtc8ISOString()} — ${task.id}: ${task.title}
**Type**: ${task.type || '-'} | **Priority**: ${task.priority || '-'} | **Effort**: ${task.effort || '-'}
**Status**: ⏳ IN PROGRESS
**Files**: ${(task.files || []).map(f => f.path).join(', ') || 'To be determined'}
**Description**: ${task.description}
**Convergence Criteria**:
${task.convergence.criteria.map(c => `- [ ] ${c}`).join('\n')}
### Execution Log
`)
if (dryRun) {
// Simulate: mark as completed without changes
appendToEvents(`\n**Status**: ⏭ DRY RUN (no changes)\n\n---\n`)
task._execution = { status: 'completed', executed_at: startTime,
result: { success: true, summary: 'Dry run — no changes made' } }
completedTasks.add(task.id)
continue
}
// 3. Execute task directly
// - Read each file in task.files (if specified)
// - Analyze what changes satisfy task.description + task.convergence.criteria
// - If task.files has detailed changes, use them as guidance
// - Apply changes using Edit (preferred) or Write (for new files)
// - Use Grep/Glob/mcp__ace-tool for discovery if needed
// - Use Bash for build/test commands
// Dual-path field access (supports both unified and legacy 6-field schema)
// const targetFiles = task.files?.map(f => f.path) || task.flow_control?.target_files || []
// const acceptanceCriteria = task.convergence?.criteria || task.context?.acceptance || []
// const requirements = task.implementation || task.context?.requirements || []
// const focusPaths = task.focus_paths || task.context?.focus_paths || []
// 4. Verify convergence
const convergenceResults = verifyConvergence(task)
const endTime = getUtc8ISOString()
const filesModified = getModifiedFiles()
if (convergenceResults.allPassed) {
// 5a. Record SUCCESS
appendToEvents(`
**Status**: ✅ COMPLETED
**Duration**: ${calculateDuration(startTime, endTime)}
**Files Modified**: ${filesModified.join(', ')}
#### Changes Summary
${changeSummary}
#### Convergence Verification
${task.convergence.criteria.map((c, i) => `- [${convergenceResults.verified[i] ? 'x' : ' '}] ${c}`).join('\n')}
- **Verification**: ${convergenceResults.verificationOutput}
- **Definition of Done**: ${task.convergence.definition_of_done}
---
`)
task._execution = {
status: 'completed', executed_at: endTime,
result: {
success: true,
files_modified: filesModified,
summary: changeSummary,
convergence_verified: convergenceResults.verified
}
}
completedTasks.add(task.id)
} else {
// 5b. Record FAILURE
handleTaskFailure(task, convergenceResults, startTime, endTime)
}
// 6. Auto-commit if enabled
if (autoCommit && task._execution.status === 'completed') {
autoCommitTask(task, filesModified)
}
}
ステップ 3.2:収束の検証
function verifyConvergence(task) {
const results = {
verified: [], // boolean[] per criterion
verificationOutput: '', // output of verification command
allPassed: true
}
// 1. Check each criterion
// For each criterion in task.convergence.criteria:
// - If it references a testable condition, check it
// - If it's manual, mark as verified based on changes made
// - Record true/false per criterion
task.convergence.criteria.forEach(criterion => {
const passed = evaluateCriterion(criterion, task)
results.verified.push(passed)
if (!passed) results.allPassed = false
})
// 2. Run verification command (if executable)
const verification = task.convergence.verification
if (isExecutableCommand(verification)) {
try {
const output = Bash(verification, { timeout: 120000 })
results.verificationOutput = `${verification} → PASS`
} catch (e) {
results.verificationOutput = `${verification} → FAIL: ${e.message}`
results.allPassed = false
}
} else {
results.verificationOutput = `Manual: ${verification}`
}
return results
}
function isExecutableCommand(verification) {
// Detect executable patterns: npm, npx, jest, tsc, curl, pytest, go test, etc.
return /^(npm|npx|jest|tsc|eslint|pytest|go\s+test|cargo\s+test|curl|make)/.test(verification.trim())
}
ステップ 3.3:失敗時の処理
function handleTaskFailure(task, convergenceResults, startTime, endTime) {
appendToEvents(`
**Status**: ❌ FAILED
**Duration**: ${calculateDuration(startTime, endTime)}
**Error**: Convergence verification failed
#### Failed Criteria
${task.convergence.criteria.map((c, i) => `- [${convergenceResults.verified[i] ? 'x' : ' '}] ${c}`).join('\n')}
- **Verification**: ${convergenceResults.verificationOutput}
---
`)
task._execution = {
status: 'failed', executed_at: endTime,
result: {
success: false,
error: 'Convergence verification failed',
convergence_verified: convergenceResults.verified
}
}
failedTasks.add(task.id)
// Ask user
request_user_input({
questions: [{
header: "Failure",
id: "handle_failure",
question: `Task ${task.id} failed convergence verification. How to proceed?`,
options: [
{ label: "Skip & Continue (Recommended)", description: "Skip this task, continue with next" },
{ label: "Retry", description: "Retry this task" },
{ label: "Abort", description: "Stop execution, keep progress" }
]
}]
})
// answer.answers.handle_failure.answers[0] → selected label
}
ステップ 3.4:自動コミット
function autoCommitTask(task, filesModified) {
Bash(`git add ${filesModified.join(' ')}`)
const commitType = {
fix: 'fix', refactor: 'refactor', feature: 'feat',
enhancement: 'feat', testing: 'test', infrastructure: 'chore'
}[task.type] || 'chore'
const scope = inferScope(filesModified)
Bash(`git commit -m "$(cat <<'EOF'
${commitType}(${scope}): ${task.title}
Task: ${task.id}
Source: ${path.basename(planPath)}
EOF
)"`)
appendToEvents(`**Commit**: \`${commitType}(${scope}): ${task.title}\`\n`)
}
フェーズ 4:完了
目的:すべてのアーティファクトを確定し、実行状態を書き戻して、後続の操作を提示します。
ステップ 4.1:execution.md を確定
execution.md に概要統計を追記します:
const summary = `
## Execution Summary
- **Completed**: ${getUtc8ISOString()}
- **Total Tasks**: ${tasks.length}
- **Succeeded**: ${completedTasks.size}
- **Failed**: ${failedTasks.size}
- **Skipped**: ${skippedTasks.size}
- **Success Rate**: ${Math.round(completedTasks.size / tasks.length * 100)}%
### Task Results
| ID | Title | Status | Convergence | Files Modified |
|----|-------|--------|-------------|----------------|
${tasks.map(t => {
const ex = t._execution || {}
const convergenceStatus = ex.result?.convergence_verified
? `${ex.result.convergence_verified.filter(v => v).length}/${ex.result.convergence_verified.length}`
: '-'
return `| ${t.id} | ${t.title} | ${ex.status || 'pending'} | ${convergenceStatus} | ${(ex.result?.files_modified || []).join(', ') || '-'} |`
}).join('\n')}
${failedTasks.size > 0 ? `### Failed Tasks
${[...failedTasks].map(id => {
const t = tasks.find(t => t.id === id)
return `- **${t.id}**: ${t.title} — ${t._execution?.result?.error || 'Unknown'}`
}).join('\n')}
` : ''}
### Artifacts
- **Plan Source**: ${planPath}
- **Execution Overview**: ${sessionFolder}/execution.md
- **Execution Events**: ${sessionFolder}/execution-events.md
`
// Append to execution.md
ステップ 4.2:execution-events.md を確定
appendToEvents(`
---
# Session Summary
- **Session**: ${sessionId}
- **Completed**: ${getUtc8ISOString()}
- **Tasks**: ${completedTasks.size} completed, ${failedTasks.size} failed, ${skippedTasks.size} skipped
- **Total Events**: ${completedTasks.size + failedTasks.size + skippedTasks.size}
`)
ステップ 4.3:_execution を使って .task/*.json に書き戻す
各ソースタスク JSON ファイルを実行状態で更新します:
tasks.forEach(task => {
const filePath = task._source_file
if (!filePath) return
// Read current file to preserve formatting and non-execution fields
const current = JSON.parse(Read(filePath))
// Update _execution status and result
current._execution = {
status: task._execution?.status || 'pending',
executed_at: task._execution?.executed_at || null,
result: task._execution?.result || null
}
// Write back individual task file
Write(filePath, JSON.stringify(current, null, 2))
})
// Each task JSON file now has _execution: { status, executed_at, result }
ステップ 4.4:完了後のオプション
request_user_input({
questions: [{
header: "Post Execute",
id: "post_execute",
question: `Execution complete: ${completedTasks.size}/${tasks.length} succeeded. Next step?`,
options: [
{ label: "Done (Recommended)", description: "End workflow" },
{ label: "Retry Failed", description: `Re-execute ${failedTasks.size} failed tasks` },
{ label: "Create Issue", description: "Create issue from failed tasks" }
]
}]
})
// answer.answers.post_execute.answers[0] → selected label
| 選択項目 | アクション |
|---|---|
| 失敗したタスクを再試行 | _execution.status === 'failed' のタスクを抽出して再実行し、[RETRY] イベントを追記します |
| イベントを表示 | execution-events.md の内容を表示します |
| Issue を作成 | 失敗したタスクの詳細から Skill(skill="issue:new", args="...") を実行します |
| 完了 | アーティファクトのパスを表示し、セッション状態を同期して、ワークフローを終了します |
ステップ 4.5:セッション状態を同期
完了後(ユーザーの選択にかかわらず)、--dry-run が指定されていない場合:
$session-sync -y "Execution complete: {completed}/{total} tasks succeeded"
実行で得られた知見で specs/*.md を更新し、project-tech.json に開発インデックスのエントリーを追加します。
設定
| フラグ | デフォルト | 説明 |
|---|---|---|
PLAN="..." | 自動検出 | .task/ ディレクトリ、または単一のタスク .json ファイルへのパス |
--auto-commit | false | タスクの成功後に変更をコミットします |
--dry-run | false | 変更を加えずに実行をシミュレートします |
プランの自動検出順序
PLAN が指定されていない場合は、次の順序で .task/ ディレクトリを検索します(最新のものが先):
.workflow/active/*/.task/.workflow/.lite-plan/*/.task/.workflow/.req-plan/*/.task/.workflow/.planning/*/.task/
ソースが .task/*.json ではない場合:まず plan-converter を実行して .task/ ディレクトリを生成します。
エラー処理と復旧
| 状況 | 対応 | 復旧方法 |
|---|---|---|
| .task/ ディレクトリが見つからない | パスを含むエラーを報告 | パスを確認し、plan-converter を実行 |
| タスクファイルの JSON が無効 | ファイル名とエラーを報告 | タスク JSON ファイルを手動で修正 |
| 収束条件が不足している | 検証エラーを報告 | plan-converter を実行して収束条件を追加 |
| 循環依存 | 停止し、循環パスを報告 | タスク JSON の依存関係を修正 |
| タスクの実行に失敗 | events に記録し、ユーザーに確認 | 再試行、スキップ、承認、または中止 |
| 収束検証に失敗 | タスクを失敗としてマークし、ユーザーに確認 | コードを修正して再試行するか、承認 |
| 検証コマンドがタイムアウト | 未検証としてマーク | 手動での検証が必要 |
| 実行中にファイルの競合が発生 | events に記録 | 依存関係の順序で解決 |
| すべてのタスクに失敗 | 報告し、プランの見直しを提案 | 再分析または手動での介入 |
ベストプラクティス
実行前
- プランを検証:まず
--dry-runを使用して、プランの実行可能性を確認します - 収束条件を確認:すべてのタスクに意味のある収束基準があることを確認します
- 依存関係を確認:実行順序が妥当であることを確認します
- バックアップ:開始前に保留中の変更をコミットします
- 先に変換:ソースが
.task/形式ではない場合はplan-converterを使用します
実行中
- イベントを監視:リアルタイムの進捗を確認するには、execution-events.md を確認します
- 失敗に対応:判断を下す前に、収束の失敗を慎重に確認します
- コミットを確認:有効になっている場合は、自動コミットが正しいことを確認します
実行後
- 概要を確認:execution.md の統計情報と失敗したタスクを確認します
- 変更を検証:変更されたファイルが想定どおりであることを確認します
- タスクファイルを確認:
.task/*.jsonファイル内の_execution状態を確認します - 次のステップ:完了オプションを使用して後続の処理を行います
次に unified-execute-with-file を実行します:$PLAN