docs(06): create phase plan

Phase 06: Coordination
- 3 plans in 3 waves
- 06-01: Coordination Events & Port (Wave 1)
- 06-02: CoordinationManager Adapter (Wave 2)
- 06-03: tRPC & CLI Integration (Wave 3)
- Ready for execution
This commit is contained in:
Lukas May
2026-01-30 20:58:23 +01:00
parent e941561ecf
commit 22572f410f
4 changed files with 584 additions and 4 deletions

View File

@@ -113,11 +113,13 @@ Plans:
**Goal**: Merge agent outputs into integration branch in dependency order, bounce conflicts back to agents
**Depends on**: Phase 5
**Requirements**: COORD-01, COORD-02
**Research**: Unlikely (git merge patterns, but conflict detection needs care)
**Plans**: TBD
**Research**: Unlikely (programmatic coordination - gastown reference shows merge orchestration is code, not agent loop)
**Plans**: 3 plans in 3 waves
Plans:
- [ ] 06-01: TBD
- [ ] 06-01: Coordination Events & Port (Wave 1)
- [ ] 06-02: CoordinationManager Adapter (Wave 2)
- [ ] 06-03: tRPC & CLI Integration (Wave 3)
### Phase 7: File System UI
**Goal**: Bidirectional sync between SQLite state and filesystem — agent messages as files, user responds via files
@@ -144,7 +146,7 @@ Phases execute in numeric order: 1 → 1.1 → 2 → 3 → 4 → 5 → 6 → 7
| 3. Git Integration | 2/2 | Complete | 2026-01-30 |
| 4. Agent Lifecycle | 4/4 | Complete | 2026-01-30 |
| 5. Task Dispatch | 5/5 | Complete | 2026-01-30 |
| 6. Coordination | 0/? | Not started | - |
| 6. Coordination | 0/3 | Not started | - |
| 7. File System UI | 0/? | Not started | - |
---

View File

@@ -0,0 +1,136 @@
---
phase: 06-coordination
plan: 01
type: execute
wave: 1
depends_on: []
files_modified: [src/coordination/types.ts, src/coordination/index.ts, src/events/types.ts, src/events/index.ts]
autonomous: true
---
<objective>
Add coordination domain events and CoordinationManager port interface.
Purpose: Establish the contract for merge coordination following hexagonal architecture patterns.
Output: Coordination types, CoordinationManager interface, and four merge lifecycle events.
</objective>
<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
# Prior phase context - git integration provides merge capability
@.planning/phases/03-git-integration/03-01-SUMMARY.md
@.planning/phases/03-git-integration/03-02-SUMMARY.md
# Existing patterns to follow
@src/events/types.ts
@src/dispatch/types.ts
@src/git/types.ts
</context>
<tasks>
<task type="auto">
<name>Task 1: Add coordination domain events to event types</name>
<files>src/events/types.ts, src/events/index.ts</files>
<action>
Add four coordination events following existing event patterns:
1. MergeQueuedEvent - when a completed task is queued for merge
- payload: { taskId, agentId, worktreeId, priority }
2. MergeStartedEvent - when merge attempt begins
- payload: { taskId, agentId, worktreeId, targetBranch }
3. MergeCompletedEvent - when merge succeeds
- payload: { taskId, agentId, worktreeId, targetBranch }
4. MergeConflictedEvent - when merge has conflicts (triggers bounce-back)
- payload: { taskId, agentId, worktreeId, targetBranch, conflictingFiles: string[] }
Add all four to DomainEventMap union type. Export from index.ts.
</action>
<verify>npm run build passes, grep shows all four events in types.ts</verify>
<done>Four merge events added to DomainEventMap, exported from events module</done>
</task>
<task type="auto">
<name>Task 2: Create CoordinationManager port interface</name>
<files>src/coordination/types.ts, src/coordination/index.ts</files>
<action>
Create src/coordination/ module following same pattern as src/dispatch/:
**types.ts:**
1. MergeQueueItem type:
- taskId: string
- agentId: string
- worktreeId: string
- priority: 'low' | 'medium' | 'high'
- queuedAt: Date
- dependsOn: string[] (task IDs that must merge first)
2. MergeStatus type: 'queued' | 'in_progress' | 'merged' | 'conflict'
3. MergeResult type (mirrors git MergeResult but with task context):
- taskId: string
- success: boolean
- conflicts?: string[]
- message: string
4. CoordinationManager interface:
- queueMerge(taskId: string): Promise<void>
Queue a completed task for merge. Extracts agent/worktree from task.
- getNextMergeable(): Promise<MergeQueueItem | null>
Returns next task ready to merge (all dependencies already merged).
- processMerges(targetBranch: string): Promise<MergeResult[]>
Process all ready merges in dependency order. Returns results.
- handleConflict(taskId: string, conflicts: string[]): Promise<void>
Create conflict-resolution task and assign back to agent.
- getQueueState(): Promise<{
queued: MergeQueueItem[];
inProgress: MergeQueueItem[];
merged: string[]; // task IDs
conflicted: Array<{ taskId: string; conflicts: string[] }>;
}>
**index.ts:**
Export all types and interface.
Include JSDoc comments explaining the port-adapter pattern.
</action>
<verify>npm run build passes, src/coordination/index.ts exports CoordinationManager</verify>
<done>CoordinationManager port interface created with full type definitions</done>
</task>
</tasks>
<verification>
Before declaring plan complete:
- [ ] npm run build succeeds
- [ ] Four merge events exist in src/events/types.ts
- [ ] CoordinationManager interface exists in src/coordination/types.ts
- [ ] All types exported from respective index.ts files
</verification>
<success_criteria>
- All tasks completed
- All verification checks pass
- No TypeScript errors
- Patterns match existing EventBus, DispatchManager, WorktreeManager
</success_criteria>
<output>
After completion, create `.planning/phases/06-coordination/06-01-SUMMARY.md`
</output>

View File

@@ -0,0 +1,203 @@
---
phase: 06-coordination
plan: 02
type: execute
wave: 2
depends_on: ["06-01"]
files_modified: [src/coordination/manager.ts, src/coordination/manager.test.ts, src/coordination/index.ts]
autonomous: true
---
<objective>
Implement DefaultCoordinationManager adapter with dependency-ordered merging and conflict bounce-back.
Purpose: Orchestrate merges in dependency order and handle conflicts by creating resolution tasks.
Output: Working CoordinationManager implementation with comprehensive tests.
</objective>
<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
# This plan's dependency
@.planning/phases/06-coordination/06-01-SUMMARY.md
# Interfaces we implement/use
@src/coordination/types.ts
@src/git/types.ts
@src/agent/types.ts
@src/db/schema.ts
# Patterns to follow
@src/dispatch/manager.ts
@src/git/manager.ts
</context>
<tasks>
<task type="auto">
<name>Task 1: Implement DefaultCoordinationManager with dependency-ordered merging</name>
<files>src/coordination/manager.ts</files>
<action>
Create DefaultCoordinationManager class implementing CoordinationManager:
**Constructor dependencies (optional injection, same pattern as DispatchManager):**
- worktreeManager?: WorktreeManager
- taskRepository?: TaskRepository
- agentRepository?: AgentRepository
- eventBus?: EventBus
**State:**
- mergeQueue: Map<string, MergeQueueItem> (in-memory, same as DispatchManager)
- mergedTasks: Set<string> (tracks successfully merged task IDs)
- conflictedTasks: Map<string, string[]> (taskId -> conflicting files)
**queueMerge(taskId):**
1. Look up task from repository to get dependencies
2. Look up agent assigned to task to get worktreeId
3. Create MergeQueueItem with dependsOn from task dependencies
4. Add to mergeQueue
5. Emit MergeQueuedEvent
**getNextMergeable():**
1. Filter queue for items where ALL dependsOn tasks are in mergedTasks
2. Sort by priority (high > medium > low), then by queuedAt (FIFO)
3. Return first item or null
**processMerges(targetBranch):**
1. Loop while getNextMergeable() returns items:
a. Mark item as in_progress
b. Emit MergeStartedEvent
c. Call worktreeManager.merge(item.worktreeId, targetBranch)
d. If success:
- Add taskId to mergedTasks
- Remove from queue
- Emit MergeCompletedEvent
e. If conflict:
- Add to conflictedTasks
- Remove from queue
- Emit MergeConflictedEvent
- Call handleConflict()
2. Return all MergeResults
**handleConflict(taskId, conflicts):**
1. Create a new task in the same plan as original task:
- name: "Resolve merge conflicts for {originalTaskName}"
- description: "Conflicts in: {conflicts.join(', ')}"
- type: 'auto'
- dependsOn: [] (no dependencies - can start immediately)
2. Assign new task to same agent that had the conflict
3. Emit TaskQueuedEvent for the new conflict-resolution task
**getQueueState():**
Return current state of all tracking structures.
</action>
<verify>npm run build passes</verify>
<done>DefaultCoordinationManager implements all CoordinationManager methods</done>
</task>
<task type="auto">
<name>Task 2: Implement conflict bounce-back task creation</name>
<files>src/coordination/manager.ts</files>
<action>
Enhance handleConflict to properly create conflict-resolution tasks:
1. Generate unique task ID (nanoid or uuid pattern from existing code)
2. Create task via taskRepository.create() with:
- planId: same as original task's planId
- name: "Resolve conflicts: {originalTask.name}"
- description: Include:
- List of conflicting files
- Original task context
- Instructions: "Resolve merge conflicts in the listed files, then mark task complete"
- type: 'auto'
- priority: 'high' (conflicts should be resolved quickly)
- status: 'pending'
3. Create message to agent via message system (if messageRepository available):
- senderType: 'user' (system-generated)
- recipientType: 'agent'
- recipientId: original agent ID
- type: 'info'
- content: Conflict details and resolution instructions
- requiresResponse: false
4. Update original task status to 'blocked' with reason
This enables the agent to pick up conflict resolution work automatically.
</action>
<verify>npm run build passes</verify>
<done>Conflict bounce-back creates new task and notifies agent</done>
</task>
<task type="auto">
<name>Task 3: Write tests for CoordinationManager</name>
<files>src/coordination/manager.test.ts, src/coordination/index.ts</files>
<action>
Create comprehensive tests following patterns from src/dispatch/manager.test.ts:
**Test categories:**
1. Queue management:
- queueMerge adds item to queue
- queueMerge emits MergeQueuedEvent
- getQueueState returns correct counts
2. Dependency ordering:
- getNextMergeable returns null when dependencies not met
- getNextMergeable returns item when all dependencies merged
- processMerges handles dependency chain correctly (A -> B -> C)
3. Priority ordering:
- High priority merges before medium/low
- Same priority follows FIFO
4. Conflict handling:
- processMerges detects conflicts from WorktreeManager
- handleConflict creates new task
- MergeConflictedEvent emitted with correct payload
- Conflicted task tracked in getQueueState
5. Success path:
- processMerges completes clean merges
- MergeCompletedEvent emitted
- Merged tasks tracked correctly
**Test setup:**
- Mock WorktreeManager (return success or conflict as needed)
- Mock repositories (in-memory or jest mocks)
- Use EventEmitterBus for event verification
Export DefaultCoordinationManager from index.ts.
</action>
<verify>npm test -- src/coordination passes with all tests green</verify>
<done>14+ tests covering queue, dependencies, conflicts, and success paths</done>
</task>
</tasks>
<verification>
Before declaring plan complete:
- [ ] npm run build succeeds
- [ ] npm test -- src/coordination passes
- [ ] DefaultCoordinationManager exported from src/coordination/index.ts
- [ ] All four merge events emitted at correct lifecycle points
</verification>
<success_criteria>
- All tasks completed
- All verification checks pass
- No TypeScript errors
- Tests cover dependency ordering and conflict bounce-back
- Patterns match DispatchManager implementation style
</success_criteria>
<output>
After completion, create `.planning/phases/06-coordination/06-02-SUMMARY.md`
</output>

View File

@@ -0,0 +1,239 @@
---
phase: 06-coordination
plan: 03
type: execute
wave: 3
depends_on: ["06-02"]
files_modified: [src/trpc/routers/coordination.ts, src/trpc/routers/index.ts, src/cli/commands/merge.ts, src/cli/commands/coordinate.ts, src/cli/index.ts]
autonomous: true
---
<objective>
Add tRPC procedures and CLI commands for merge coordination.
Purpose: Expose coordination capabilities through the CLI for user interaction.
Output: tRPC router for coordination and CLI commands (cw merge, cw coordinate).
</objective>
<execution_context>
@~/.claude/get-shit-done/workflows/execute-plan.md
@~/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
# This plan's dependencies
@.planning/phases/06-coordination/06-01-SUMMARY.md
@.planning/phases/06-coordination/06-02-SUMMARY.md
# Patterns to follow
@src/trpc/routers/task.ts
@src/trpc/routers/dispatch.ts
@src/cli/commands/dispatch.ts
@src/cli/commands/agent.ts
</context>
<tasks>
<task type="auto">
<name>Task 1: Add coordination tRPC procedures</name>
<files>src/trpc/routers/coordination.ts, src/trpc/routers/index.ts</files>
<action>
Create coordination router following patterns from dispatch.ts and task.ts:
**src/trpc/routers/coordination.ts:**
```typescript
import { z } from 'zod';
import { router, publicProcedure } from '../trpc';
export const coordinationRouter = router({
// Queue a completed task for merge
queueMerge: publicProcedure
.input(z.object({ taskId: z.string() }))
.mutation(async ({ ctx, input }) => {
// ctx.coordinationManager optional same pattern as other managers
if (!ctx.coordinationManager) {
throw new Error('CoordinationManager not available');
}
await ctx.coordinationManager.queueMerge(input.taskId);
return { success: true };
}),
// Process all ready merges
processMerges: publicProcedure
.input(z.object({
targetBranch: z.string().default('main')
}))
.mutation(async ({ ctx, input }) => {
if (!ctx.coordinationManager) {
throw new Error('CoordinationManager not available');
}
const results = await ctx.coordinationManager.processMerges(input.targetBranch);
return { results };
}),
// Get merge queue status
status: publicProcedure
.query(async ({ ctx }) => {
if (!ctx.coordinationManager) {
throw new Error('CoordinationManager not available');
}
return ctx.coordinationManager.getQueueState();
}),
// Get next mergeable task (for inspection)
nextMergeable: publicProcedure
.query(async ({ ctx }) => {
if (!ctx.coordinationManager) {
throw new Error('CoordinationManager not available');
}
return ctx.coordinationManager.getNextMergeable();
}),
});
```
**src/trpc/routers/index.ts:**
Add coordinationRouter to appRouter.
**src/trpc/context.ts (if exists):**
Add coordinationManager?: CoordinationManager to context type.
</action>
<verify>npm run build passes, coordinationRouter exported</verify>
<done>Coordination tRPC procedures available: queueMerge, processMerges, status, nextMergeable</done>
</task>
<task type="auto">
<name>Task 2: Add CLI commands for merge coordination</name>
<files>src/cli/commands/merge.ts, src/cli/commands/coordinate.ts, src/cli/index.ts</files>
<action>
Create CLI commands following patterns from dispatch.ts and agent.ts:
**src/cli/commands/merge.ts:**
```typescript
// cw merge queue <taskId> - Queue a task for merge
// cw merge status - Show merge queue status
// cw merge next - Show next mergeable task
import { Command } from 'commander';
import { createTRPCClient } from '../trpc-client';
export function createMergeCommand(): Command {
const merge = new Command('merge')
.description('Manage merge queue');
merge
.command('queue <taskId>')
.description('Queue a completed task for merge')
.action(async (taskId) => {
const client = createTRPCClient();
await client.coordination.queueMerge.mutate({ taskId });
console.log(`Task ${taskId} queued for merge`);
});
merge
.command('status')
.description('Show merge queue status')
.action(async () => {
const client = createTRPCClient();
const state = await client.coordination.status.query();
console.log('Merge Queue Status:');
console.log(` Queued: ${state.queued.length}`);
console.log(` In Progress: ${state.inProgress.length}`);
console.log(` Merged: ${state.merged.length}`);
console.log(` Conflicted: ${state.conflicted.length}`);
if (state.conflicted.length > 0) {
console.log('\nConflicts:');
for (const c of state.conflicted) {
console.log(` ${c.taskId}: ${c.conflicts.join(', ')}`);
}
}
});
merge
.command('next')
.description('Show next task ready to merge')
.action(async () => {
const client = createTRPCClient();
const next = await client.coordination.nextMergeable.query();
if (next) {
console.log(`Next mergeable: ${next.taskId} (priority: ${next.priority})`);
} else {
console.log('No tasks ready to merge');
}
});
return merge;
}
```
**src/cli/commands/coordinate.ts:**
```typescript
// cw coordinate [--target <branch>] - Process all ready merges
import { Command } from 'commander';
import { createTRPCClient } from '../trpc-client';
export function createCoordinateCommand(): Command {
return new Command('coordinate')
.description('Process all ready merges in dependency order')
.option('-t, --target <branch>', 'Target branch for merges', 'main')
.action(async (options) => {
const client = createTRPCClient();
console.log(`Processing merges to ${options.target}...`);
const { results } = await client.coordination.processMerges.mutate({
targetBranch: options.target
});
const succeeded = results.filter(r => r.success).length;
const conflicted = results.filter(r => !r.success).length;
console.log(`\nResults:`);
console.log(` Merged: ${succeeded}`);
console.log(` Conflicts: ${conflicted}`);
if (conflicted > 0) {
console.log('\nConflicted tasks (bounce-back tasks created):');
for (const r of results.filter(r => !r.success)) {
console.log(` ${r.taskId}: ${r.conflicts?.join(', ')}`);
}
}
});
}
```
**src/cli/index.ts:**
Register both commands with the CLI program.
</action>
<verify>npm run build passes, cw merge --help and cw coordinate --help work</verify>
<done>CLI commands available: cw merge (queue/status/next), cw coordinate</done>
</task>
</tasks>
<verification>
Before declaring plan complete:
- [ ] npm run build succeeds
- [ ] cw merge --help shows subcommands
- [ ] cw coordinate --help shows options
- [ ] tRPC coordination router accessible via client
</verification>
<success_criteria>
- All tasks completed
- All verification checks pass
- No TypeScript errors
- CLI commands follow existing patterns (dispatch, agent)
- COORD-01 and COORD-02 requirements satisfied
</success_criteria>
<output>
After completion, create `.planning/phases/06-coordination/06-03-SUMMARY.md`
</output>