mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-11 02:33:51 +08:00
revert: Restore lite-execute and schema to 196b805, keep 50k context protection
- Revert cost-aware batching and multi-agent parallelism in lite-execute - Remove execution_group and task complexity from schema - Remove execution_group rules from lite-plan - Keep 50k context threshold protection in lite-plan 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -149,14 +149,14 @@ Input Parsing:
|
|||||||
|
|
||||||
Execution:
|
Execution:
|
||||||
├─ Step 1: Initialize result tracking (previousExecutionResults = [])
|
├─ Step 1: Initialize result tracking (previousExecutionResults = [])
|
||||||
├─ Step 2: Task grouping & batch creation (cost-aware)
|
├─ Step 2: Task grouping & batch creation
|
||||||
│ ├─ Build hybrid dependencies (explicit depends_on + file conflicts via modification_points)
|
│ ├─ Extract explicit depends_on (no file/keyword inference)
|
||||||
│ ├─ Phase 1: Group by execution_group (explicit parallel groups)
|
│ ├─ Group: independent tasks → single parallel batch (maximize utilization)
|
||||||
│ ├─ Phase 2: Cost-aware batching (MAX_BATCH_COST=8, Low=1/Medium=2/High=4)
|
│ ├─ Group: dependent tasks → sequential phases (respect dependencies)
|
||||||
│ └─ Create TodoWrite list for batches
|
│ └─ Create TodoWrite list for batches
|
||||||
├─ Step 3: Launch execution
|
├─ Step 3: Launch execution
|
||||||
│ ├─ Parallel batches: ⚡ concurrent via multiple tool calls
|
│ ├─ Phase 1: All independent tasks (⚡ single batch, concurrent)
|
||||||
│ └─ Sequential batches: → one by one
|
│ └─ Phase 2+: Dependent tasks by dependency order
|
||||||
├─ Step 4: Track progress (TodoWrite updates per batch)
|
├─ Step 4: Track progress (TodoWrite updates per batch)
|
||||||
└─ Step 5: Code review (if codeReviewTool ≠ "Skip")
|
└─ Step 5: Code review (if codeReviewTool ≠ "Skip")
|
||||||
|
|
||||||
@@ -181,96 +181,67 @@ previousExecutionResults = []
|
|||||||
|
|
||||||
**Dependency Analysis & Grouping Algorithm**:
|
**Dependency Analysis & Grouping Algorithm**:
|
||||||
```javascript
|
```javascript
|
||||||
const MAX_BATCH_COST = 8 // Workload limit per batch (tunable)
|
// Use explicit depends_on from plan.json (no inference from file/keywords)
|
||||||
|
function extractDependencies(tasks) {
|
||||||
// Task cost based on complexity (Low=1, Medium=2, High=4)
|
|
||||||
function calculateTaskCost(task) {
|
|
||||||
const costs = { Low: 1, Medium: 2, High: 4 }
|
|
||||||
return costs[task.complexity] || 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build hybrid dependencies: explicit depends_on + implicit file conflicts
|
|
||||||
function buildDependencies(tasks) {
|
|
||||||
const taskIdToIndex = {}
|
const taskIdToIndex = {}
|
||||||
tasks.forEach((t, i) => { taskIdToIndex[t.id] = i })
|
tasks.forEach((t, i) => { taskIdToIndex[t.id] = i })
|
||||||
const fileOwner = {} // Track which task last modified each file
|
|
||||||
|
|
||||||
return tasks.map((task, i) => {
|
return tasks.map((task, i) => {
|
||||||
const deps = new Set()
|
// Only use explicit depends_on from plan.json
|
||||||
|
const deps = (task.depends_on || [])
|
||||||
// 1. Explicit depends_on
|
.map(depId => taskIdToIndex[depId])
|
||||||
;(task.depends_on || []).forEach(depId => {
|
.filter(idx => idx !== undefined && idx < i)
|
||||||
const idx = taskIdToIndex[depId]
|
return { ...task, taskIndex: i, dependencies: deps }
|
||||||
if (idx !== undefined && idx < i) deps.add(idx)
|
|
||||||
})
|
|
||||||
|
|
||||||
// 2. Implicit file conflicts via modification_points
|
|
||||||
;(task.modification_points || []).forEach(mp => {
|
|
||||||
if (fileOwner[mp.file] !== undefined && fileOwner[mp.file] !== i) {
|
|
||||||
deps.add(fileOwner[mp.file])
|
|
||||||
}
|
|
||||||
fileOwner[mp.file] = i
|
|
||||||
})
|
|
||||||
|
|
||||||
return { ...task, taskIndex: i, dependencies: [...deps], cost: calculateTaskCost(task) }
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group into cost-aware batches with execution_group priority
|
// Group into batches: maximize parallel execution
|
||||||
function createExecutionCalls(tasks, executionMethod) {
|
function createExecutionCalls(tasks, executionMethod) {
|
||||||
const tasksWithDeps = buildDependencies(tasks)
|
const tasksWithDeps = extractDependencies(tasks)
|
||||||
const processed = new Set()
|
const processed = new Set()
|
||||||
const calls = []
|
const calls = []
|
||||||
let parallelIdx = 1, sequentialIdx = 1
|
|
||||||
|
|
||||||
// Phase 1: Group by execution_group (explicit parallel groups)
|
// Phase 1: All independent tasks → single parallel batch (maximize utilization)
|
||||||
const groups = {}
|
const independentTasks = tasksWithDeps.filter(t => t.dependencies.length === 0)
|
||||||
tasksWithDeps.forEach(t => {
|
if (independentTasks.length > 0) {
|
||||||
if (t.execution_group) {
|
independentTasks.forEach(t => processed.add(t.taskIndex))
|
||||||
groups[t.execution_group] = groups[t.execution_group] || []
|
|
||||||
groups[t.execution_group].push(t)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Object.entries(groups).forEach(([groupId, groupTasks]) => {
|
|
||||||
groupTasks.forEach(t => processed.add(t.taskIndex))
|
|
||||||
calls.push({
|
calls.push({
|
||||||
method: executionMethod,
|
method: executionMethod,
|
||||||
executionType: "parallel",
|
executionType: "parallel",
|
||||||
groupId: `P${parallelIdx++}`,
|
groupId: "P1",
|
||||||
taskSummary: groupTasks.map(t => t.title).join(' | '),
|
taskSummary: independentTasks.map(t => t.title).join(' | '),
|
||||||
tasks: groupTasks
|
tasks: independentTasks
|
||||||
})
|
})
|
||||||
})
|
}
|
||||||
|
|
||||||
// Phase 2: Process remaining by dependency order with cost-aware batching
|
// Phase 2: Dependent tasks → sequential batches (respect dependencies)
|
||||||
|
let sequentialIndex = 1
|
||||||
let remaining = tasksWithDeps.filter(t => !processed.has(t.taskIndex))
|
let remaining = tasksWithDeps.filter(t => !processed.has(t.taskIndex))
|
||||||
|
|
||||||
while (remaining.length > 0) {
|
while (remaining.length > 0) {
|
||||||
const ready = remaining.filter(t => t.dependencies.every(d => processed.has(d)))
|
// Find tasks whose dependencies are all satisfied
|
||||||
if (ready.length === 0) { ready.push(...remaining) } // Break circular deps
|
const ready = remaining.filter(t =>
|
||||||
|
t.dependencies.every(d => processed.has(d))
|
||||||
|
)
|
||||||
|
|
||||||
// Cost-aware batch creation
|
if (ready.length === 0) {
|
||||||
let batch = [], batchCost = 0
|
console.warn('Circular dependency detected, forcing remaining tasks')
|
||||||
const stillReady = [...ready]
|
ready.push(...remaining)
|
||||||
while (stillReady.length > 0) {
|
|
||||||
const idx = stillReady.findIndex(t => batchCost + t.cost <= MAX_BATCH_COST)
|
|
||||||
if (idx === -1) break
|
|
||||||
const task = stillReady.splice(idx, 1)[0]
|
|
||||||
batch.push(task)
|
|
||||||
batchCost += task.cost
|
|
||||||
}
|
}
|
||||||
if (batch.length === 0) batch = [ready[0]] // At least one task
|
|
||||||
|
|
||||||
batch.forEach(t => processed.add(t.taskIndex))
|
// Group ready tasks (can run in parallel within this phase)
|
||||||
|
ready.forEach(t => processed.add(t.taskIndex))
|
||||||
calls.push({
|
calls.push({
|
||||||
method: executionMethod,
|
method: executionMethod,
|
||||||
executionType: batch.length > 1 ? "parallel" : "sequential",
|
executionType: ready.length > 1 ? "parallel" : "sequential",
|
||||||
groupId: batch.length > 1 ? `P${parallelIdx++}` : `S${sequentialIdx++}`,
|
groupId: ready.length > 1 ? `P${calls.length + 1}` : `S${sequentialIndex++}`,
|
||||||
taskSummary: batch.map(t => t.title).join(batch.length > 1 ? ' | ' : ' → '),
|
taskSummary: ready.map(t => t.title).join(ready.length > 1 ? ' | ' : ' → '),
|
||||||
tasks: batch
|
tasks: ready
|
||||||
})
|
})
|
||||||
|
|
||||||
remaining = remaining.filter(t => !processed.has(t.taskIndex))
|
remaining = remaining.filter(t => !processed.has(t.taskIndex))
|
||||||
}
|
}
|
||||||
|
|
||||||
return calls
|
return calls
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,30 +258,14 @@ TodoWrite({
|
|||||||
|
|
||||||
### Step 3: Launch Execution
|
### Step 3: Launch Execution
|
||||||
|
|
||||||
**Execution Flow**: Parallel batches concurrently (multiple agents) → Sequential batches in order
|
**Execution Flow**: Parallel batches concurrently → Sequential batches in order
|
||||||
|
|
||||||
**Unified executeBatch dispatcher**:
|
|
||||||
```javascript
|
|
||||||
// Dispatch batch to appropriate executor (Agent or Codex)
|
|
||||||
function executeBatch(batch) {
|
|
||||||
if (batch.method === "Agent") {
|
|
||||||
return executeBatchAgent(batch) // See Option A below
|
|
||||||
} else {
|
|
||||||
return executeBatchCodex(batch) // See Option B below
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Execution orchestration**:
|
|
||||||
```javascript
|
```javascript
|
||||||
const parallel = executionCalls.filter(c => c.executionType === "parallel")
|
const parallel = executionCalls.filter(c => c.executionType === "parallel")
|
||||||
const sequential = executionCalls.filter(c => c.executionType === "sequential")
|
const sequential = executionCalls.filter(c => c.executionType === "sequential")
|
||||||
|
|
||||||
// Phase 1: Launch all parallel batches (MULTIPLE CONCURRENT AGENTS)
|
// Phase 1: Launch all parallel batches (single message with multiple tool calls)
|
||||||
// Each batch → separate agent instance → true parallelism
|
|
||||||
if (parallel.length > 0) {
|
if (parallel.length > 0) {
|
||||||
TodoWrite({ todos: executionCalls.map(c => ({ status: c.executionType === "parallel" ? "in_progress" : "pending" })) })
|
TodoWrite({ todos: executionCalls.map(c => ({ status: c.executionType === "parallel" ? "in_progress" : "pending" })) })
|
||||||
// Promise.all dispatches each batch to its own agent concurrently
|
|
||||||
parallelResults = await Promise.all(parallel.map(c => executeBatch(c)))
|
parallelResults = await Promise.all(parallel.map(c => executeBatch(c)))
|
||||||
previousExecutionResults.push(...parallelResults)
|
previousExecutionResults.push(...parallelResults)
|
||||||
TodoWrite({ todos: executionCalls.map(c => ({ status: parallel.includes(c) ? "completed" : "pending" })) })
|
TodoWrite({ todos: executionCalls.map(c => ({ status: parallel.includes(c) ? "completed" : "pending" })) })
|
||||||
@@ -353,12 +308,10 @@ ${task.acceptance.map((criterion, i) => `${i + 1}. ${criterion}`).join('\n')}
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
// executeBatch(batch) - called for each parallel/sequential batch
|
Task(
|
||||||
function executeBatchAgent(batch) {
|
subagent_type="code-developer",
|
||||||
return Task(
|
description="Implement planned tasks",
|
||||||
subagent_type="code-developer",
|
prompt=`
|
||||||
description=`Implement batch ${batch.groupId}: ${batch.taskSummary}`,
|
|
||||||
prompt=`
|
|
||||||
${originalUserInput ? `## Original User Request\n${originalUserInput}\n\n` : ''}
|
${originalUserInput ? `## Original User Request\n${originalUserInput}\n\n` : ''}
|
||||||
|
|
||||||
## Implementation Plan
|
## Implementation Plan
|
||||||
@@ -366,8 +319,8 @@ function executeBatchAgent(batch) {
|
|||||||
**Summary**: ${planObject.summary}
|
**Summary**: ${planObject.summary}
|
||||||
**Approach**: ${planObject.approach}
|
**Approach**: ${planObject.approach}
|
||||||
|
|
||||||
## Batch ${batch.groupId}: Task Breakdown (${batch.tasks.length} tasks)
|
## Task Breakdown (${planObject.tasks.length} tasks)
|
||||||
${batch.tasks.map((task, i) => formatTaskForAgent(task, i)).join('\n')}
|
${planObject.tasks.map((task, i) => formatTaskForAgent(task, i)).join('\n')}
|
||||||
|
|
||||||
${previousExecutionResults.length > 0 ? `\n## Previous Execution Results\n${previousExecutionResults.map(result => `
|
${previousExecutionResults.length > 0 ? `\n## Previous Execution Results\n${previousExecutionResults.map(result => `
|
||||||
[${result.executionId}] ${result.status}
|
[${result.executionId}] ${result.status}
|
||||||
@@ -408,11 +361,10 @@ ${result.notes ? `Notes: ${result.notes}` : ''}
|
|||||||
Read exploration files for comprehensive context from multiple angles.` : ''}
|
Read exploration files for comprehensive context from multiple angles.` : ''}
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
MUST complete ALL ${batch.tasks.length} tasks in batch ${batch.groupId}.
|
MUST complete ALL ${planObject.tasks.length} tasks listed above in this single execution.
|
||||||
Return only after all tasks in this batch are fully implemented and tested.
|
Return only after all tasks are fully implemented and tested.
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Result Collection**: After completion, collect result following `executionResult` structure (see Data Structures section)
|
**Result Collection**: After completion, collect result following `executionResult` structure (see Data Structures section)
|
||||||
@@ -444,11 +396,7 @@ ${task.acceptance.map((criterion, i) => ` - ${criterion}`).join('\n')}
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
// executeBatch(batch) - called for each parallel/sequential batch
|
codex --full-auto exec "
|
||||||
const timeoutByComplexity = { "Low": 2400000, "Medium": 3600000, "High": 6000000 }
|
|
||||||
|
|
||||||
function executeBatchCodex(batch) {
|
|
||||||
return Bash(`codex --full-auto exec "
|
|
||||||
${originalUserInput ? `## Original User Request\n${originalUserInput}\n\n` : ''}
|
${originalUserInput ? `## Original User Request\n${originalUserInput}\n\n` : ''}
|
||||||
|
|
||||||
## Implementation Plan
|
## Implementation Plan
|
||||||
@@ -456,8 +404,8 @@ ${originalUserInput ? `## Original User Request\n${originalUserInput}\n\n` : ''}
|
|||||||
TASK: ${planObject.summary}
|
TASK: ${planObject.summary}
|
||||||
APPROACH: ${planObject.approach}
|
APPROACH: ${planObject.approach}
|
||||||
|
|
||||||
### Batch ${batch.groupId}: Task Breakdown (${batch.tasks.length} tasks)
|
### Task Breakdown (${planObject.tasks.length} tasks)
|
||||||
${batch.tasks.map((task, i) => formatTaskForCodex(task, i)).join('\n')}
|
${planObject.tasks.map((task, i) => formatTaskForCodex(task, i)).join('\n')}
|
||||||
|
|
||||||
${previousExecutionResults.length > 0 ? `\n### Previous Execution Results\n${previousExecutionResults.map(result => `
|
${previousExecutionResults.length > 0 ? `\n### Previous Execution Results\n${previousExecutionResults.map(result => `
|
||||||
[${result.executionId}] ${result.status}
|
[${result.executionId}] ${result.status}
|
||||||
@@ -501,15 +449,30 @@ Read exploration files for comprehensive architectural, pattern, and constraint
|
|||||||
` : ''}
|
` : ''}
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
MUST complete ALL ${batch.tasks.length} tasks in batch ${batch.groupId}.
|
MUST complete ALL ${planObject.tasks.length} tasks listed above in this single execution.
|
||||||
Return only after all tasks in this batch are fully implemented and tested.
|
Return only after all tasks are fully implemented and tested.
|
||||||
|
|
||||||
Complexity: ${planObject.complexity}
|
Complexity: ${planObject.complexity}
|
||||||
" --skip-git-repo-check -s danger-full-access`, { timeout: timeoutByComplexity[planObject.complexity] || 3600000 })
|
" --skip-git-repo-check -s danger-full-access
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: Timeout based on complexity (Low=40min, Medium=60min, High=100min) is handled in `executeBatchCodex`.
|
**Execution with tracking**:
|
||||||
|
```javascript
|
||||||
|
// Launch CLI in foreground (NOT background)
|
||||||
|
// Timeout based on complexity: Low=40min, Medium=60min, High=100min
|
||||||
|
const timeoutByComplexity = {
|
||||||
|
"Low": 2400000, // 40 minutes
|
||||||
|
"Medium": 3600000, // 60 minutes
|
||||||
|
"High": 6000000 // 100 minutes
|
||||||
|
}
|
||||||
|
|
||||||
|
bash_result = Bash(
|
||||||
|
command=cli_command,
|
||||||
|
timeout=timeoutByComplexity[planObject.complexity] || 3600000
|
||||||
|
)
|
||||||
|
|
||||||
|
// Update TodoWrite when execution completes
|
||||||
|
```
|
||||||
|
|
||||||
**Result Collection**: After completion, analyze output and collect result following `executionResult` structure
|
**Result Collection**: After completion, analyze output and collect result following `executionResult` structure
|
||||||
|
|
||||||
@@ -576,8 +539,8 @@ codex --full-auto exec "[Verify plan acceptance criteria at ${plan.json}]" --ski
|
|||||||
## Best Practices
|
## Best Practices
|
||||||
|
|
||||||
**Input Modes**: In-memory (lite-plan), prompt (standalone), file (JSON/text)
|
**Input Modes**: In-memory (lite-plan), prompt (standalone), file (JSON/text)
|
||||||
**Task Grouping**: Hybrid dependencies (explicit depends_on + file conflicts) + execution_group priority + cost-aware batching (MAX_BATCH_COST=8)
|
**Task Grouping**: Based on explicit depends_on only; independent tasks run in single parallel batch
|
||||||
**Execution**: Parallel batches via single Claude message with multiple tool calls; cost balances workload (Low=1, Medium=2, High=4)
|
**Execution**: All independent tasks launch concurrently via single Claude message with multiple tool calls
|
||||||
|
|
||||||
## Error Handling
|
## Error Handling
|
||||||
|
|
||||||
|
|||||||
@@ -415,8 +415,6 @@ Generate plan.json with:
|
|||||||
3. **Substantial tasks**: Each task should represent 15-60 minutes of work
|
3. **Substantial tasks**: Each task should represent 15-60 minutes of work
|
||||||
4. **True dependencies only**: Only use depends_on when Task B cannot start without Task A's output
|
4. **True dependencies only**: Only use depends_on when Task B cannot start without Task A's output
|
||||||
5. **Prefer parallel**: Most tasks should be independent (no depends_on)
|
5. **Prefer parallel**: Most tasks should be independent (no depends_on)
|
||||||
6. **Explicit parallel groups**: Assign same `execution_group` ID (e.g., "group-1") to tasks that can run concurrently; null for others
|
|
||||||
7. **Task complexity**: Set `complexity` (Low/Medium/High) for workload balancing - executor uses cost units (1/2/4)
|
|
||||||
|
|
||||||
## Execution
|
## Execution
|
||||||
1. Read ALL exploration files for comprehensive context
|
1. Read ALL exploration files for comprehensive context
|
||||||
|
|||||||
@@ -118,15 +118,6 @@
|
|||||||
"pattern": "^T[0-9]+$"
|
"pattern": "^T[0-9]+$"
|
||||||
},
|
},
|
||||||
"description": "Task IDs this task depends on (e.g., ['T1', 'T2'])"
|
"description": "Task IDs this task depends on (e.g., ['T1', 'T2'])"
|
||||||
},
|
|
||||||
"execution_group": {
|
|
||||||
"type": ["string", "null"],
|
|
||||||
"description": "Parallel execution group ID. Tasks with same group ID run concurrently. null = use depends_on logic"
|
|
||||||
},
|
|
||||||
"complexity": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["Low", "Medium", "High"],
|
|
||||||
"description": "Task complexity for workload balancing (Low=1, Medium=2, High=4 cost units)"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user