mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-12 02:37:45 +08:00
refactor: Update task structure and grouping principles in planning and execution schemas for clarity and consistency
This commit is contained in:
@@ -150,12 +150,13 @@ Input Parsing:
|
|||||||
Execution:
|
Execution:
|
||||||
├─ Step 1: Initialize result tracking (previousExecutionResults = [])
|
├─ Step 1: Initialize result tracking (previousExecutionResults = [])
|
||||||
├─ Step 2: Task grouping & batch creation
|
├─ Step 2: Task grouping & batch creation
|
||||||
│ ├─ Infer dependencies (same file → sequential, keywords → sequential)
|
│ ├─ Extract explicit depends_on (no file/keyword inference)
|
||||||
│ ├─ Group into batches (parallel: independent, sequential: dependent)
|
│ ├─ Group: independent tasks → single parallel batch (maximize utilization)
|
||||||
|
│ ├─ 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
|
||||||
│ ├─ Phase 1: All parallel batches (⚡ concurrent via multiple tool calls)
|
│ ├─ Phase 1: All independent tasks (⚡ single batch, concurrent)
|
||||||
│ └─ Phase 2: 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")
|
||||||
|
|
||||||
@@ -180,66 +181,68 @@ previousExecutionResults = []
|
|||||||
|
|
||||||
**Dependency Analysis & Grouping Algorithm**:
|
**Dependency Analysis & Grouping Algorithm**:
|
||||||
```javascript
|
```javascript
|
||||||
// Infer dependencies: same file → sequential, keywords (use/integrate) → sequential
|
// Use explicit depends_on from plan.json (no inference from file/keywords)
|
||||||
function inferDependencies(tasks) {
|
function extractDependencies(tasks) {
|
||||||
return tasks.map((task, i) => {
|
const taskIdToIndex = {}
|
||||||
const deps = []
|
tasks.forEach((t, i) => { taskIdToIndex[t.id] = i })
|
||||||
const file = task.file || task.title.match(/in\s+([^\s:]+)/)?.[1]
|
|
||||||
const keywords = (task.description || task.title).toLowerCase()
|
|
||||||
|
|
||||||
for (let j = 0; j < i; j++) {
|
return tasks.map((task, i) => {
|
||||||
const prevFile = tasks[j].file || tasks[j].title.match(/in\s+([^\s:]+)/)?.[1]
|
// Only use explicit depends_on from plan.json
|
||||||
if (file && prevFile === file) deps.push(j) // Same file
|
const deps = (task.depends_on || [])
|
||||||
else if (/use|integrate|call|import/.test(keywords)) deps.push(j) // Keyword dependency
|
.map(depId => taskIdToIndex[depId])
|
||||||
}
|
.filter(idx => idx !== undefined && idx < i)
|
||||||
return { ...task, taskIndex: i, dependencies: deps }
|
return { ...task, taskIndex: i, dependencies: deps }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Group into batches: independent → parallel [P1,P2...], dependent → sequential [S1,S2...]
|
// Group into batches: maximize parallel execution
|
||||||
function createExecutionCalls(tasks, executionMethod) {
|
function createExecutionCalls(tasks, executionMethod) {
|
||||||
const tasksWithDeps = inferDependencies(tasks)
|
const tasksWithDeps = extractDependencies(tasks)
|
||||||
const maxBatch = executionMethod === "Codex" ? 4 : 7
|
|
||||||
const calls = []
|
|
||||||
const processed = new Set()
|
const processed = new Set()
|
||||||
|
const calls = []
|
||||||
|
|
||||||
// Parallel: independent tasks, different files, max batch size
|
// Phase 1: All independent tasks → single parallel batch (maximize utilization)
|
||||||
const parallelGroups = []
|
const independentTasks = tasksWithDeps.filter(t => t.dependencies.length === 0)
|
||||||
tasksWithDeps.forEach(t => {
|
if (independentTasks.length > 0) {
|
||||||
if (t.dependencies.length === 0 && !processed.has(t.taskIndex)) {
|
independentTasks.forEach(t => processed.add(t.taskIndex))
|
||||||
const group = [t]
|
calls.push({
|
||||||
processed.add(t.taskIndex)
|
method: executionMethod,
|
||||||
tasksWithDeps.forEach(o => {
|
executionType: "parallel",
|
||||||
if (!o.dependencies.length && !processed.has(o.taskIndex) &&
|
groupId: "P1",
|
||||||
group.length < maxBatch && t.file !== o.file) {
|
taskSummary: independentTasks.map(t => t.title).join(' | '),
|
||||||
group.push(o)
|
tasks: independentTasks
|
||||||
processed.add(o.taskIndex)
|
})
|
||||||
}
|
|
||||||
})
|
|
||||||
parallelGroups.push(group)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 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 results
|
// Phase 2: Dependent tasks → sequential batches (respect dependencies)
|
||||||
return [
|
let sequentialIndex = 1
|
||||||
...parallelGroups.map((g, i) => ({
|
let remaining = tasksWithDeps.filter(t => !processed.has(t.taskIndex))
|
||||||
method: executionMethod, executionType: "parallel", groupId: `P${i+1}`,
|
|
||||||
taskSummary: g.map(t => t.title).join(' | '), tasks: g
|
while (remaining.length > 0) {
|
||||||
})),
|
// Find tasks whose dependencies are all satisfied
|
||||||
...calls.map(c => ({ ...c, method: executionMethod, taskSummary: c.tasks.map(t => t.title).join(' → ') }))
|
const ready = remaining.filter(t =>
|
||||||
]
|
t.dependencies.every(d => processed.has(d))
|
||||||
|
)
|
||||||
|
|
||||||
|
if (ready.length === 0) {
|
||||||
|
console.warn('Circular dependency detected, forcing remaining tasks')
|
||||||
|
ready.push(...remaining)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Group ready tasks (can run in parallel within this phase)
|
||||||
|
ready.forEach(t => processed.add(t.taskIndex))
|
||||||
|
calls.push({
|
||||||
|
method: executionMethod,
|
||||||
|
executionType: ready.length > 1 ? "parallel" : "sequential",
|
||||||
|
groupId: ready.length > 1 ? `P${calls.length + 1}` : `S${sequentialIndex++}`,
|
||||||
|
taskSummary: ready.map(t => t.title).join(ready.length > 1 ? ' | ' : ' → '),
|
||||||
|
tasks: ready
|
||||||
|
})
|
||||||
|
|
||||||
|
remaining = remaining.filter(t => !processed.has(t.taskIndex))
|
||||||
|
}
|
||||||
|
|
||||||
|
return calls
|
||||||
}
|
}
|
||||||
|
|
||||||
executionCalls = createExecutionCalls(planObject.tasks, executionMethod).map(c => ({ ...c, id: `[${c.groupId}]` }))
|
executionCalls = createExecutionCalls(planObject.tasks, executionMethod).map(c => ({ ...c, id: `[${c.groupId}]` }))
|
||||||
@@ -536,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)
|
||||||
**Batch Limits**: Agent 7 tasks, CLI 4 tasks
|
**Task Grouping**: Based on explicit depends_on only; independent tasks run in single parallel batch
|
||||||
**Execution**: Parallel batches use single Claude message with multiple tool calls (no concurrency limit)
|
**Execution**: All independent tasks launch concurrently via single Claude message with multiple tool calls
|
||||||
|
|
||||||
## Error Handling
|
## Error Handling
|
||||||
|
|
||||||
|
|||||||
@@ -373,16 +373,28 @@ ${complexity}
|
|||||||
Generate plan.json with:
|
Generate plan.json with:
|
||||||
- summary: 2-3 sentence overview
|
- summary: 2-3 sentence overview
|
||||||
- approach: High-level implementation strategy (incorporating insights from all exploration angles)
|
- approach: High-level implementation strategy (incorporating insights from all exploration angles)
|
||||||
- tasks: 3-10 structured tasks with:
|
- tasks: 3-7 structured tasks (**IMPORTANT: group by feature/module, NOT by file**)
|
||||||
- title, file, action, description
|
- **Task Granularity Principle**: Each task = one complete feature unit or module
|
||||||
- implementation (3-7 steps)
|
- title: action verb + target module/feature (e.g., "Implement auth token refresh")
|
||||||
|
- scope: module path (src/auth/) or feature name, prefer module-level over single file
|
||||||
|
- action, description
|
||||||
|
- modification_points: ALL files to modify for this feature (group related changes)
|
||||||
|
- implementation (3-7 steps covering all modification_points)
|
||||||
- reference (pattern, files, examples)
|
- reference (pattern, files, examples)
|
||||||
- acceptance (2-4 criteria)
|
- acceptance (2-4 criteria for the entire feature)
|
||||||
|
- depends_on: task IDs this task depends on (use sparingly, only for true dependencies)
|
||||||
- estimated_time, recommended_execution, complexity
|
- estimated_time, recommended_execution, complexity
|
||||||
- _metadata:
|
- _metadata:
|
||||||
- timestamp, source, planning_mode
|
- timestamp, source, planning_mode
|
||||||
- exploration_angles: ${JSON.stringify(manifest.explorations.map(e => e.angle))}
|
- exploration_angles: ${JSON.stringify(manifest.explorations.map(e => e.angle))}
|
||||||
|
|
||||||
|
## Task Grouping Rules
|
||||||
|
1. **Group by feature**: All changes for one feature = one task (even if 3-5 files)
|
||||||
|
2. **Avoid file-per-task**: Do NOT create separate tasks for each file
|
||||||
|
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
|
||||||
|
5. **Prefer parallel**: Most tasks should be independent (no depends_on)
|
||||||
|
|
||||||
## Execution
|
## Execution
|
||||||
1. Read ALL exploration files for comprehensive context
|
1. Read ALL exploration files for comprehensive context
|
||||||
2. Execute CLI planning using Gemini (Qwen fallback)
|
2. Execute CLI planning using Gemini (Qwen fallback)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
"maxItems": 10,
|
"maxItems": 10,
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["id", "title", "file", "action", "description", "implementation", "acceptance"],
|
"required": ["id", "title", "scope", "action", "description", "implementation", "acceptance"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"id": {
|
"id": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -36,11 +36,15 @@
|
|||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Task title (action verb + target)"
|
"description": "Task title (action verb + target module/feature)"
|
||||||
|
},
|
||||||
|
"scope": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Task scope: module path (src/auth/), feature name, or single file. Prefer module/feature level over single file."
|
||||||
},
|
},
|
||||||
"file": {
|
"file": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Target file path for this task"
|
"description": "Primary file (deprecated, use scope + modification_points instead)"
|
||||||
},
|
},
|
||||||
"action": {
|
"action": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -53,13 +57,14 @@
|
|||||||
},
|
},
|
||||||
"modification_points": {
|
"modification_points": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
"minItems": 1,
|
||||||
"items": {
|
"items": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": ["file", "target", "change"],
|
"required": ["file", "target", "change"],
|
||||||
"properties": {
|
"properties": {
|
||||||
"file": {
|
"file": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "File path"
|
"description": "File path within scope"
|
||||||
},
|
},
|
||||||
"target": {
|
"target": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@@ -71,7 +76,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "Precise modification points with file:target:change format"
|
"description": "All modification points for this task. Group related changes (same feature/module) into one task with multiple modification_points."
|
||||||
},
|
},
|
||||||
"implementation": {
|
"implementation": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
|
|||||||
Reference in New Issue
Block a user