Task Coordination Skill
Purpose
Break work into small tasks, execute each in a clean subagent using the Task tool, and use memory as the coordination layer to track progress and enable parallel execution.
Critical Architecture Principles
1. ✅ Clean Context Per Task
Each task runs in a fresh subagent with minimal context:
- •Use Task tool to spawn clean agent
- •Agent loads ONLY what it needs from memory
- •No large context passed in prompts
- •Context window stays small and efficient
2. ✅ Memory as Coordination Layer
Memory is the single source of truth:
- •Task status tracked in memory
- •Results saved to memory immediately
- •Next agent loads from memory, not from previous agent
- •Enables pause/resume of work
3. ✅ Parallel Execution
Run multiple subagents simultaneously:
- •Independent tasks run in parallel
- •Use single message with multiple Task tool calls
- •Each subagent works on different task
- •All save to memory when complete
4. ✅ Verification Loop with Task Tracking
If user stops to correct:
- •Save current task status to memory
- •Fix the issue
- •Load pending tasks from memory
- •Continue with remaining tasks
Task Lifecycle
1. Break Work into Tasks
javascript
// High-level agent breaks work into tasks
const tasks = [
{
id: 'task_001',
name: 'Plan feature structure',
agent: 'work-planner-agent',
dependencies: [],
status: 'pending',
context_needed: {
feature_name: 'inventory',
requirements: 'CRUD for products'
}
},
{
id: 'task_002',
name: 'Implement backend API',
agent: 'dotnet-engineer-agent',
dependencies: ['task_001'], // Needs planning complete
status: 'pending',
context_needed: {
service: 'inventory',
load_from_memory: ['feature_plan', 'architectural_decisions']
}
},
{
id: 'task_003',
name: 'Implement frontend UI',
agent: 'ui-engineer-agent',
dependencies: ['task_001'], // Needs planning, NOT backend (can run parallel)
status: 'pending',
context_needed: {
service: 'inventory',
load_from_memory: ['feature_plan', 'component_patterns']
}
},
{
id: 'task_004',
name: 'QA backend',
agent: 'qa-backend-engineer',
dependencies: ['task_002'], // Needs backend complete
status: 'pending',
context_needed: {
service: 'inventory',
load_from_memory: ['service_api_info']
}
},
{
id: 'task_005',
name: 'QA frontend',
agent: 'qa-frontend-engineer',
dependencies: ['task_003'], // Needs frontend complete
status: 'pending',
context_needed: {
service: 'inventory',
load_from_memory: ['service_ui_info', 'docker_ips']
}
},
{
id: 'task_006',
name: 'Verify complete',
agent: 'verification-agent',
dependencies: ['task_004', 'task_005'], // Needs both QA complete
status: 'pending',
context_needed: {
service: 'inventory',
load_from_memory: ['qa_results_backend', 'qa_results_frontend']
}
}
]
// Save to memory
memory_save_task_list({
feature: 'inventory_management',
tasks: tasks,
created: new Date().toISOString()
})
2. Execute Tasks in Parallel
javascript
// Get tasks ready to run (dependencies met)
const readyTasks = tasks.filter(t =>
t.status === 'pending' &&
t.dependencies.every(dep => isComplete(dep))
)
// Launch all ready tasks in PARALLEL using single message with multiple Task calls
// IMPORTANT: Use single message to launch all parallel tasks
if (readyTasks.length > 0) {
console.log(`Launching ${readyTasks.length} tasks in parallel:`)
readyTasks.forEach(task => {
console.log(`- ${task.name} (${task.agent})`)
})
// Update status before launch
readyTasks.forEach(task => {
memory_update_task(task.id, {
status: 'running',
started: new Date().toISOString()
})
})
// Launch ALL in single message (see example below)
}
Example Parallel Launch:
code
I'm launching 2 tasks in parallel:
- Task 002: Implement backend API (dotnet-engineer-agent)
- Task 003: Implement frontend UI (ui-engineer-agent)
[Use Task tool twice in SAME MESSAGE]
Task 1:
Use the dotnet-engineer-agent to:
1. Load feature plan from memory: memory_get_feature('inventory_management')
2. Load architectural decisions from memory: memory_get_decisions()
3. Implement inventory API with CRUD endpoints
4. Save API details to memory when complete
5. Mark task_002 as complete in memory
Context to load from memory:
- Feature plan: inventory_management
- Service: inventory
- Load only what's needed for backend
Task 2:
Use the ui-engineer-agent to:
1. Load feature plan from memory: memory_get_feature('inventory_management')
2. Load component patterns from memory: memory_get_component_patterns()
3. Implement inventory UI with CRUD interface
4. Save UI details to memory when complete
5. Mark task_003 as complete in memory
Context to load from memory:
- Feature plan: inventory_management
- Service: inventory
- Load only what's needed for frontend
3. Each Subagent Works with Minimal Context
javascript
// Inside dotnet-engineer-agent subagent (clean context)
// Step 1: Load ONLY what I need from memory
const featurePlan = memory_get_feature('inventory_management')
const decisions = memory_get_decisions()
const existingService = memory_get_service('inventory')
// Step 2: Do the work
// ... implement API ...
// Step 3: Save results to memory
memory_save_service({
name: 'inventory',
api: {
endpoints: [...],
database: 'stylemate_inventory',
// ... other details
}
})
// Step 4: Mark task complete
memory_update_task('task_002', {
status: 'completed',
completed: new Date().toISOString(),
results: {
endpoints_created: 5,
tests_passing: true
}
})
// Return summary (not full details, those are in memory)
return "✅ Task 002 complete: Inventory API created with 5 endpoints. Details saved to memory."
4. Verification Loop with Pause/Resume
javascript
// User interrupts: "Wait, the database schema needs a 'sku' field"
// Current state in memory:
// task_002: completed ✅
// task_003: running 🔄
// task_004: pending ⏸️
// task_005: pending ⏸️
// task_006: pending ⏸️
// Handle interruption:
console.log('User correction requested. Current state:')
const tasks = memory_get_task_list('inventory_management')
tasks.forEach(t => console.log(`${t.id}: ${t.status}`))
// Fix the issue
console.log('Fixing database schema...')
// ... add 'sku' field ...
memory_update_service('inventory', {
api: {
database_schema: {
products: {
columns: [..., 'sku: string']
}
}
}
})
// Mark task as needs re-test
memory_update_task('task_002', {
status: 'needs_retest',
correction: 'Added sku field to schema'
})
// Continue with pending tasks
const pendingTasks = tasks.filter(t => t.status === 'pending')
console.log(`Continuing with ${pendingTasks.length} pending tasks...`)
// ... launch next batch ...
Task Tracking Schema
Task Schema
typescript
interface Task {
id: string // task_001, task_002, etc.
name: string // Human-readable task name
agent: string // Which agent executes this
dependencies: string[] // Task IDs that must complete first
status: 'pending' | 'running' | 'completed' | 'failed' | 'needs_retest'
context_needed: {
[key: string]: any // Minimal context needed
load_from_memory: string[] // What to load from memory
}
created: string // ISO timestamp
started?: string // When execution started
completed?: string // When execution finished
results?: any // Summary results (details in memory)
error?: string // Error if failed
correction?: string // If needs_retest, what was fixed
}
interface TaskList {
feature: string // Feature name
tasks: Task[] // All tasks
created: string // When task list created
status: 'in_progress' | 'completed' | 'paused'
current_phase?: string // planning, development, qa, verification
}
Memory Operations for Task Coordination
Save Task List
javascript
memory_save_task_list({
feature: 'inventory_management',
tasks: [...],
status: 'in_progress',
current_phase: 'planning'
})
Update Task Status
javascript
memory_update_task(task_id, {
status: 'completed',
completed: new Date().toISOString(),
results: { summary: '...' }
})
Get Tasks Ready to Run
javascript
const tasks = memory_get_task_list('inventory_management')
const ready = tasks.tasks.filter(t =>
t.status === 'pending' &&
t.dependencies.every(dep =>
tasks.tasks.find(d => d.id === dep)?.status === 'completed'
)
)
Get Pending Tasks
javascript
const pending = memory_get_tasks_by_status('inventory_management', 'pending')
const running = memory_get_tasks_by_status('inventory_management', 'running')
const failed = memory_get_tasks_by_status('inventory_management', 'failed')
Orchestration Pattern
software-engineer-agent as Orchestrator
javascript
// Phase 1: Create task plan
const tasks = createTaskPlan(userRequest)
memory_save_task_list({ feature: featureName, tasks })
// Phase 2: Execute tasks in waves (respecting dependencies)
while (hasIncompleteTasks()) {
// Get tasks ready to run
const ready = getReadyTasks()
if (ready.length === 0) {
// Check for failures
const failed = getFailedTasks()
if (failed.length > 0) {
console.log('Tasks failed:', failed)
break
}
// All done!
break
}
// Launch parallel tasks in SINGLE MESSAGE
console.log(`Launching ${ready.length} tasks in parallel...`)
// IMPORTANT: Use single message with multiple Task tool calls
ready.forEach(task => {
// Mark as running
memory_update_task(task.id, { status: 'running' })
})
// Use Task tool for each (in same message)
// ... Task tool calls ...
// Wait for all to complete (they update memory)
// Check results
ready.forEach(task => {
const updated = memory_get_task(task.id)
if (updated.status === 'completed') {
console.log(`✅ ${task.name} completed`)
} else if (updated.status === 'failed') {
console.log(`❌ ${task.name} failed: ${updated.error}`)
}
})
}
// Phase 3: Final verification
const allTasks = memory_get_task_list(featureName)
const completed = allTasks.tasks.filter(t => t.status === 'completed')
const failed = allTasks.tasks.filter(t => t.status === 'failed')
console.log(`Summary: ${completed.length}/${allTasks.tasks.length} tasks completed`)
if (failed.length === 0) {
memory_update_task_list(featureName, { status: 'completed' })
console.log('✅ All tasks completed successfully!')
} else {
console.log('❌ Some tasks failed:', failed.map(t => t.name))
}
Benefits of This Architecture
✅ Small Context Windows
- •Each subagent loads only what it needs
- •No large prompts passed around
- •Context stays small and efficient
- •Better performance, less token usage
✅ Parallel Execution
- •Independent tasks run simultaneously
- •Faster completion
- •Better resource utilization
- •Scalable to many tasks
✅ Pause/Resume Capability
- •User can stop to correct
- •Work state preserved in memory
- •Other tasks continue or pause cleanly
- •No lost context
✅ Clean Separation
- •Each subagent is independent
- •No context pollution
- •Easier debugging
- •Clear responsibility
✅ Memory as Single Source of Truth
- •All state in memory
- •Agents coordinate through memory
- •No context passing between agents
- •Enables distributed execution
Example: Complete Feature with Parallel Tasks
javascript
// User request: "Add inventory management feature"
// software-engineer-agent:
// Step 1: Create task plan
const tasks = [
{ id: 'task_001', name: 'Plan feature', agent: 'work-planner-agent', dependencies: [] },
{ id: 'task_002', name: 'Backend API', agent: 'dotnet-engineer-agent', dependencies: ['task_001'] },
{ id: 'task_003', name: 'Frontend UI', agent: 'ui-engineer-agent', dependencies: ['task_001'] },
{ id: 'task_004', name: 'QA Backend', agent: 'qa-backend-engineer', dependencies: ['task_002'] },
{ id: 'task_005', name: 'QA Frontend', agent: 'qa-frontend-engineer', dependencies: ['task_003'] },
{ id: 'task_006', name: 'Verify', agent: 'verification-agent', dependencies: ['task_004', 'task_005'] }
]
memory_save_task_list({ feature: 'inventory', tasks })
// Step 2: Wave 1 - Planning (1 task)
// Launch: work-planner-agent via Task tool
// Planner loads decisions from memory, saves plan to memory, marks task_001 complete
// Step 3: Wave 2 - Development (2 tasks in PARALLEL)
// Launch: dotnet-engineer-agent + ui-engineer-agent in SINGLE MESSAGE
// Backend: loads plan from memory, implements API, saves to memory, marks task_002 complete
// Frontend: loads plan from memory, implements UI, saves to memory, marks task_003 complete
// Step 4: Wave 3 - QA (2 tasks in PARALLEL)
// Launch: qa-backend-engineer + qa-frontend-engineer in SINGLE MESSAGE
// Backend QA: loads API info from memory, tests, saves results, marks task_004 complete
// Frontend QA: loads UI info + Docker IPs from memory, tests, saves results, marks task_005 complete
// Step 5: Wave 4 - Verification (1 task)
// Launch: verification-agent via Task tool
// Verification: loads both QA results from memory, verifies, marks task_006 complete
// Done! All tasks completed with minimal context and maximum parallelism
User Correction During Execution
javascript
// Scenario: User stops after task_003 completes
// Current state:
// task_001: completed ✅
// task_002: completed ✅
// task_003: completed ✅
// task_004: running 🔄
// task_005: running 🔄
// task_006: pending ⏸️
// User: "Wait, the frontend needs a barcode scanner component"
// software-engineer-agent:
console.log('User correction requested.')
const taskList = memory_get_task_list('inventory')
console.log('Current task status:')
taskList.tasks.forEach(t => console.log(`${t.id}: ${t.status}`))
// Mark frontend task for correction
memory_update_task('task_003', {
status: 'needs_correction',
correction: 'Add barcode scanner component'
})
// QA tasks will need re-run
memory_update_task('task_005', {
status: 'pending', // Reset to pending
note: 'Waiting for frontend correction'
})
// Add barcode scanner
console.log('Adding barcode scanner component...')
// Launch ui-engineer-agent again via Task tool with correction
// UI engineer loads existing UI from memory, adds scanner, saves update
// Re-run frontend QA
console.log('Re-running frontend QA...')
// Launch qa-frontend-engineer via Task tool
// QA loads updated UI from memory, tests scanner, saves results
// Continue with verification
console.log('Continuing with verification...')
// Launch verification-agent via Task tool
// Verification loads all QA results from memory, verifies complete
Implementation Checklist
- • Task schema defined
- • Memory operations for tasks defined
- • Parallel execution pattern defined
- • Verification loop with pause/resume defined
- • Implement in software-engineer-agent
- • Update all agents to save/mark tasks
- • Test parallel execution
- • Test pause/resume capability
This skill enables efficient, parallel, pause-able work execution with minimal context per agent.