diff --git a/.claude/commands/workflow/lite-execute.md b/.claude/commands/workflow/lite-execute.md index 4432024b..3ae7f259 100644 --- a/.claude/commands/workflow/lite-execute.md +++ b/.claude/commands/workflow/lite-execute.md @@ -185,276 +185,107 @@ Execution Complete previousExecutionResults = [] ``` -### Step 2: Intelligent Task Grouping & Execution Planning +### Step 2: Task Grouping & Batch Creation -**Operations**: -- Analyze task dependencies and file targets -- Group tasks based on context similarity and dependencies -- Support parallel execution for independent tasks -- Respect task limits per execution (Agent: 7 tasks, CLI: 4 tasks) - -**Task Analysis & Grouping**: +**Dependency Analysis & Grouping Algorithm**: ```javascript -// Extract file path from task for dependency analysis -function getTaskFile(task) { - return task.file || task.title.match(/in\s+([^\s:]+)/)?.[1] || null -} - -// Infer dependencies from task descriptions and file paths +// Infer dependencies: same file → sequential, keywords (use/integrate) → sequential function inferDependencies(tasks) { - return tasks.map((task, index) => { - const dependencies = [] - const taskFile = getTaskFile(task) - const keywords = task.description?.toLowerCase() || task.title.toLowerCase() + return tasks.map((task, i) => { + const deps = [] + const file = task.file || task.title.match(/in\s+([^\s:]+)/)?.[1] + const keywords = (task.description || task.title).toLowerCase() - // Check previous tasks for dependencies - for (let i = 0; i < index; i++) { - const prevTask = tasks[i] - const prevFile = getTaskFile(prevTask) - - // Same file modification → sequential dependency - if (taskFile && prevFile === taskFile) { - dependencies.push(i) - continue - } - - // Keyword-based dependency detection - if (keywords.includes('use') || keywords.includes('integrate') || - keywords.includes('call') || keywords.includes('import')) { - const prevTitle = prevTask.title.toLowerCase() - if (keywords.includes(prevTitle.split(' ')[0])) { - dependencies.push(i) - } - } + for (let j = 0; j < i; j++) { + const prevFile = tasks[j].file || tasks[j].title.match(/in\s+([^\s:]+)/)?.[1] + if (file && prevFile === file) deps.push(j) // Same file + else if (/use|integrate|call|import/.test(keywords)) deps.push(j) // Keyword dependency } - - return { ...task, taskIndex: index, dependencies } + return { ...task, taskIndex: i, dependencies: deps } }) } -// Group tasks into execution batches +// Group into batches: independent → parallel [P1,P2...], dependent → sequential [S1,S2...] function createExecutionCalls(tasks, executionMethod) { const tasksWithDeps = inferDependencies(tasks) - const maxTasksPerCall = executionMethod === "Codex" ? 4 : 7 + const maxBatch = executionMethod === "Codex" ? 4 : 7 const calls = [] const processed = new Set() - // Phase 1: Group independent tasks for parallel execution + // Parallel: independent tasks, different files, max batch size const parallelGroups = [] - tasksWithDeps.forEach(task => { - if (task.dependencies.length === 0 && !processed.has(task.taskIndex)) { - const group = [task] - processed.add(task.taskIndex) - - // Find other independent tasks with different files for parallel batch - const taskFile = getTaskFile(task) - tasksWithDeps.forEach(other => { - if (other.dependencies.length === 0 && - !processed.has(other.taskIndex) && - group.length < maxTasksPerCall) { - const otherFile = getTaskFile(other) - // Only group if different files (avoid conflicts) - if (!taskFile || !otherFile || taskFile !== otherFile) { - group.push(other) - processed.add(other.taskIndex) - } + tasksWithDeps.forEach(t => { + if (t.dependencies.length === 0 && !processed.has(t.taskIndex)) { + const group = [t] + processed.add(t.taskIndex) + tasksWithDeps.forEach(o => { + if (!o.dependencies.length && !processed.has(o.taskIndex) && + group.length < maxBatch && t.file !== o.file) { + group.push(o) + processed.add(o.taskIndex) } }) - parallelGroups.push(group) } }) - // Phase 2: Group dependent tasks sequentially - const dependentTasks = tasksWithDeps.filter(t => !processed.has(t.taskIndex)) - const sequentialBatches = [] - while (dependentTasks.length > 0) { - const batch = [] - const batchIndices = new Set() - - for (const task of dependentTasks) { - // Can add to batch if dependencies are already processed - const depsProcessed = task.dependencies.every(dep => - processed.has(dep) || batchIndices.has(dep) - ) - - if (depsProcessed && batch.length < maxTasksPerCall) { - batch.push(task) - batchIndices.add(task.taskIndex) - processed.add(task.taskIndex) - } - } - - if (batch.length === 0) break // Prevent infinite loop - sequentialBatches.push(batch) - dependentTasks.splice(0, dependentTasks.length, - ...dependentTasks.filter(t => !processed.has(t.taskIndex)) + // Sequential: dependent tasks, batch when deps satisfied + const remaining = tasksWithDeps.filter(t => !processed.has(t.taskIndex)) + while (remaining.length > 0) { + const batch = remaining.filter((t, i) => + i < maxBatch && t.dependencies.every(d => processed.has(d)) ) + if (!batch.length) break + batch.forEach(t => processed.add(t.taskIndex)) + calls.push({ executionType: "sequential", groupId: `S${calls.length + 1}`, tasks: batch }) + remaining.splice(0, remaining.length, ...remaining.filter(t => !processed.has(t.taskIndex))) } - // Combine parallel and sequential batches - parallelGroups.forEach((group, i) => { - calls.push({ - method: executionMethod === "Codex" ? "Codex" : "Agent", - executionType: "parallel", - groupId: `P${i + 1}`, - taskSummary: group.map(t => t.title).join(' | '), - tasks: group - }) - }) - - sequentialBatches.forEach((batch, i) => { - calls.push({ - method: executionMethod === "Codex" ? "Codex" : "Agent", - executionType: "sequential", - groupId: `S${i + 1}`, - taskSummary: batch.map(t => t.title).join(' → '), - tasks: batch - }) - }) - - return calls + // Combine results + return [ + ...parallelGroups.map((g, i) => ({ + method: executionMethod, executionType: "parallel", groupId: `P${i+1}`, + taskSummary: g.map(t => t.title).join(' | '), tasks: g + })), + ...calls.map(c => ({ ...c, method: executionMethod, taskSummary: c.tasks.map(t => t.title).join(' → ') })) + ] } -// Create execution calls with IDs and execution method -executionCalls = createExecutionCalls(planObject.tasks, executionMethod).map((call, index) => ({ - ...call, - id: `[${call.groupId}]` -})) +executionCalls = createExecutionCalls(planObject.tasks, executionMethod).map(c => ({ ...c, id: `[${c.groupId}]` })) -// Create TodoWrite list with execution type indicators TodoWrite({ - todos: executionCalls.map(call => { - const typeIcon = call.executionType === "parallel" ? "⚡" : "→" - const typeLabel = call.executionType === "parallel" ? "Parallel" : "Sequential" - return { - content: `${typeIcon} ${call.id} [${typeLabel}] (${call.tasks.length} tasks: ${call.taskSummary})`, - status: "pending", - activeForm: `Executing ${call.id} - ${typeLabel} batch (${call.tasks.length} tasks)` - } - }) + todos: executionCalls.map(c => ({ + content: `${c.executionType === "parallel" ? "⚡" : "→"} ${c.id} (${c.tasks.length} tasks)`, + status: "pending", + activeForm: `Executing ${c.id}` + })) }) ``` -**Grouping Strategy Examples**: - -```javascript -// Example 1: Independent tasks, different files → Parallel groups -Tasks: [ - { title: "Create auth.ts", file: "src/auth.ts" }, - { title: "Create utils.ts", file: "src/utils.ts" }, - { title: "Create types.ts", file: "src/types.ts" } -] -Result: [P1] ⚡ Parallel (3 tasks) - -// Example 2: Same file modifications → Sequential batch -Tasks: [ - { title: "Add function in auth.ts", file: "src/auth.ts" }, - { title: "Update function in auth.ts", file: "src/auth.ts" } -] -Result: [S1] → Sequential (2 tasks) - -// Example 3: Mixed dependencies → Multiple batches -Tasks: [ - { title: "Create base.ts", file: "src/base.ts" }, // No deps - { title: "Create helper.ts", file: "src/helper.ts" }, // No deps - { title: "Use base in main.ts", file: "src/main.ts" }, // Depends on base.ts - { title: "Use helper in app.ts", file: "src/app.ts" } // Depends on helper.ts -] -Result: - [P1] ⚡ Parallel (2 tasks: base.ts | helper.ts) - [P2] ⚡ Parallel (2 tasks: main.ts | app.ts) - -// Example 4: Exceeds batch limit → Multiple batches -Agent (7 tasks max): 10 tasks → [P1: 7 tasks] + [P2: 3 tasks] -Codex (4 tasks max): 10 tasks → [P1: 4 tasks] + [P2: 4 tasks] + [P3: 2 tasks] -``` - -**TodoWrite Display Examples**: -``` -Parallel execution (independent files): -[ ] ⚡ [P1] [Parallel] (3 tasks: Create auth.ts | Create utils.ts | Create types.ts) - -Sequential execution (same file or dependencies): -[ ] → [S1] [Sequential] (2 tasks: Add function in auth.ts → Update function in auth.ts) - -Mixed execution (multiple batches): -[ ] ⚡ [P1] [Parallel] (4 tasks: Create base.ts | Create helper.ts | Create config.ts | Create types.ts) -[ ] ⚡ [P2] [Parallel] (3 tasks: Use base in main.ts | Use helper in app.ts | Use config in index.ts) -[ ] → [S1] [Sequential] (2 tasks: Integrate components → Add tests) -``` - ### Step 3: Launch Execution -**Execution Strategy**: -- **Parallel batches**: Launch all parallel batches simultaneously (CLI has no concurrency limit) -- **Sequential batches**: Execute in order, waiting for previous completion -- **Mixed workflow**: Process parallel groups first, then sequential groups - -**Execution Loop**: +**Execution Flow**: Parallel batches concurrently → Sequential batches in order ```javascript -// Phase 1: Launch all parallel batches concurrently -const parallelCalls = executionCalls.filter(c => c.executionType === "parallel") -const sequentialCalls = executionCalls.filter(c => c.executionType === "sequential") +const parallel = executionCalls.filter(c => c.executionType === "parallel") +const sequential = executionCalls.filter(c => c.executionType === "sequential") -if (parallelCalls.length > 0) { - // Mark all parallel calls as in_progress - TodoWrite({ - todos: executionCalls.map(call => ({ - content: `${call.executionType === "parallel" ? "⚡" : "→"} ${call.id} [${call.executionType}] (${call.tasks.length} tasks)`, - status: call.executionType === "parallel" ? "in_progress" : "pending", - activeForm: `Executing ${call.id}` - })) - }) - - // Launch all parallel batches using single message with multiple tool calls - // Use Task tool or Bash tool to launch each parallel execution - // Collect results as they complete - - parallelResults = await Promise.all(parallelCalls.map(call => executeBatch(call))) +// Phase 1: Launch all parallel batches (single message with multiple tool calls) +if (parallel.length > 0) { + TodoWrite({ todos: executionCalls.map(c => ({ status: c.executionType === "parallel" ? "in_progress" : "pending" })) }) + parallelResults = await Promise.all(parallel.map(c => executeBatch(c))) previousExecutionResults.push(...parallelResults) - - // Mark parallel calls as completed - TodoWrite({ - todos: executionCalls.map(call => ({ - content: `${call.executionType === "parallel" ? "⚡" : "→"} ${call.id} [${call.executionType}] (${call.tasks.length} tasks)`, - status: parallelCalls.includes(call) ? "completed" : "pending", - activeForm: `Executing ${call.id}` - })) - }) + TodoWrite({ todos: executionCalls.map(c => ({ status: parallel.includes(c) ? "completed" : "pending" })) }) } -// Phase 2: Execute sequential batches in order -for (const call of sequentialCalls) { - // Update TodoWrite: mark current sequential call in_progress - TodoWrite({ - todos: executionCalls.map(c => ({ - content: `${c.executionType === "parallel" ? "⚡" : "→"} ${c.id} [${c.executionType}] (${c.tasks.length} tasks)`, - status: c === call ? "in_progress" : (parallelCalls.includes(c) ? "completed" : "pending"), - activeForm: `Executing ${c.id}` - })) - }) - - // Launch sequential execution with previousExecutionResults context +// Phase 2: Execute sequential batches one by one +for (const call of sequential) { + TodoWrite({ todos: executionCalls.map(c => ({ status: c === call ? "in_progress" : "..." })) }) result = await executeBatch(call) previousExecutionResults.push(result) - - // Update TodoWrite: mark completed - TodoWrite({ - todos: executionCalls.map(c => ({ - content: `${c.executionType === "parallel" ? "⚡" : "→"} ${c.id} [${c.executionType}] (${c.tasks.length} tasks)`, - status: c.id <= call.id ? "completed" : "pending", - activeForm: `Executing ${c.id}` - })) - }) + TodoWrite({ todos: executionCalls.map(c => ({ status: "completed" or "pending" })) }) } ``` -**Important Notes**: -- Parallel batches use single Claude message with multiple Bash/Task tool calls -- CLI tools (Codex/Gemini/Qwen) execute in foreground (NOT background) -- Each batch receives `previousExecutionResults` for context continuity - **Option A: Agent Execution** When to use: @@ -617,35 +448,9 @@ bash_result = Bash( **Result Collection**: After completion, analyze output and collect result following `executionResult` structure -### Step 4: Track Execution Progress +### Step 4: Progress Tracking -**Real-time TodoWrite Updates** at batch level: - -```javascript -// Parallel batches executing concurrently -TodoWrite({ - todos: [ - { content: "⚡ [P1] [Parallel] (4 tasks)", status: "in_progress", activeForm: "Executing P1" }, - { content: "⚡ [P2] [Parallel] (3 tasks)", status: "in_progress", activeForm: "Executing P2" }, - { content: "→ [S1] [Sequential] (2 tasks)", status: "pending", activeForm: "..." } - ] -}) - -// After parallel completion, sequential execution -TodoWrite({ - todos: [ - { content: "⚡ [P1] [Parallel] (4 tasks)", status: "completed", activeForm: "..." }, - { content: "⚡ [P2] [Parallel] (3 tasks)", status: "completed", activeForm: "..." }, - { content: "→ [S1] [Sequential] (2 tasks)", status: "in_progress", activeForm: "Executing S1" } - ] -}) -``` - -**User Visibility**: -- Parallel batches show simultaneous execution (multiple "in_progress" at once) -- Sequential batches execute one at a time -- Icons distinguish parallel (⚡) from sequential (→) -- Task count shows batch size for each execution group +Progress tracked at batch level (not individual task level). Icons: ⚡ (parallel, concurrent), → (sequential, one-by-one) ### Step 5: Code Review (Optional) @@ -706,50 +511,9 @@ codex --full-auto exec "[Verify task.json acceptance criteria at ${task.json}]" ## Best Practices -### Execution Intelligence - -1. **Intelligent Task Grouping**: Dependency-aware task allocation - - Same file modifications → Sequential batch - - Different files + no dependencies → Parallel batch - - Respects batch limits: Agent (7 tasks), CLI (4 tasks) - - Infers dependencies from file paths and keywords - -2. **Parallel Execution**: Maximize throughput for independent tasks - - All parallel batches launch simultaneously - - No concurrency limit for CLI tools - - Reduces total execution time for independent work - - Uses single Claude message with multiple tool calls - -3. **Context Continuity**: Each batch receives previous results - - Prevents duplication across batches - - Maintains coherent implementation flow - - Builds on completed work from parallel/sequential batches - -4. **Flexible Execution**: Multiple input modes supported - - In-memory: Seamless lite-plan integration - - Prompt: Quick standalone execution - - File: Intelligent format detection - - Enhanced Task JSON (lite-plan export): Full plan extraction - - Plain text: Uses as prompt - -### Task Management - -1. **Smart Batch Creation**: Automatic dependency analysis - - File path extraction and comparison - - Keyword-based dependency inference - - Context signature grouping (same files = sequential) - - Batch size optimization per execution method - -2. **Live Progress Tracking**: Real-time batch-level updates - - Visual distinction: ⚡ (parallel) vs → (sequential) - - Shows concurrent execution for parallel batches - - Clear batch completion tracking - - Task count per batch for progress visibility - -3. **Execution Strategies**: - - Parallel-first: All independent batches execute concurrently - - Sequential-after: Dependent batches execute in order - - Context passing: Each batch receives all previous results +**Input Modes**: In-memory (lite-plan), prompt (standalone), file (JSON/text) +**Batch Limits**: Agent 7 tasks, CLI 4 tasks +**Execution**: Parallel batches use single Claude message with multiple tool calls (no concurrency limit) ## Error Handling