# Task Branching Feature for Makima ## Overview Add the ability to branch/spin off tasks that resume from where another task ended, preserving both worktree state (file changes) and conversation context (what Claude discussed/discovered). **Key requirement:** The branched task should "remember" what was previously discussed, enabling exploration of alternative approaches from the same starting point. ## Integration with Contracts Tasks are grouped under **contracts** - organizational units with phases (research → specify → plan → execute → review). When branching: - **Inherit contract**: Branched tasks stay in the same contract as the source task by default - **Optional override**: User can choose to place the branch in a different contract - **Phase awareness**: The branch inherits the contract's current phase context ## Architecture Summary Since Claude Code is stateless (each invocation is fresh), we cannot replay the actual conversation. Instead, we: 1. Capture and store conversation turns (user messages + assistant responses) 2. When branching, inject a formatted transcript as context in the new task's plan 3. Copy the worktree state using existing `continue_from_task_id` mechanism ## Implementation Plan ### Phase 1: Capture Conversation History **1.1 Database Migration** Create `makima/migrations/20250111000000_add_task_conversations.sql`: ```sql CREATE TABLE IF NOT EXISTS task_conversations ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), task_id UUID NOT NULL REFERENCES tasks(id) ON DELETE CASCADE, turn_index INTEGER NOT NULL, role VARCHAR(32) NOT NULL, -- 'user', 'assistant' content TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ); CREATE INDEX idx_task_conversations_task_id ON task_conversations(task_id); ``` **1.2 Capture User Messages** Modify `makima/daemon/src/task/manager.rs`: - When sending initial plan to Claude, emit a `ConversationTurn` message to server - When forwarding user messages from `input_rx`, emit a `ConversationTurn` message **1.3 Capture Assistant Responses** Modify `makima/src/server/handlers/mesh_daemon.rs`: - Aggregate `TaskOutputEntry` messages with `message_type='assistant'` into conversation turns - Store in `task_conversations` table when a user message arrives (marks end of assistant turn) **1.4 New Protocol Message** Add to `makima/daemon/src/ws/protocol.rs` and `makima/src/server/protocol.rs`: ```rust ConversationTurn { task_id: Uuid, turn_index: i32, role: String, // "user" or "assistant" content: String, } ``` ### Phase 2: Branching Infrastructure **2.1 Database Migration** Create `makima/migrations/20250111000001_add_branching_fields.sql`: ```sql ALTER TABLE tasks ADD COLUMN branched_from_task_id UUID REFERENCES tasks(id) ON DELETE SET NULL; CREATE INDEX idx_tasks_branched_from ON tasks(branched_from_task_id) WHERE branched_from_task_id IS NOT NULL; ``` **2.2 Update Task Model** Modify `makima/src/db/models.rs`: ```rust pub struct Task { // ... existing fields ... pub branched_from_task_id: Option, } pub struct BranchTaskRequest { pub name: Option, pub plan: String, pub include_conversation: bool, // default true pub include_worktree: bool, // default true pub contract_id: Option, // if None, inherit from source task } ``` **2.3 New Branch Endpoint** Add to `makima/src/server/handlers/mesh.rs`: - `POST /api/v1/mesh/tasks/{id}/branch` handler - Validates source task exists and user has permission - Fetches conversation history from `task_conversations` - Creates new task with: - `branched_from_task_id` = source task ID - `continue_from_task_id` = source task ID (for worktree copying) - `contract_id` = request.contract_id OR source task's contract_id - Plan = formatted conversation context + new instructions ### Phase 3: Context Injection **3.1 Format Conversation Transcript** Add helper function in `makima/src/server/handlers/mesh.rs`: ```rust fn format_conversation_context(turns: Vec) -> String { // Format as: // ## Previous Conversation Context // // **User:** {message} // **Assistant:** {response} // ... // // --- } ``` **3.2 Prepend to Branched Task Plan** When creating a branched task, construct the plan as: ``` {formatted_conversation_context} ## New Instructions {user's new plan} ``` ### Phase 4: Frontend Integration **4.1 API Client** Add to `makima/frontend/src/lib/api.ts`: ```typescript branchTask(id: string, request: BranchTaskRequest): Promise ``` **4.2 Branch Button** Add to `makima/frontend/src/components/mesh/TaskDetail.tsx`: - "Branch" button in task actions - Opens dialog to enter new instructions - Checkboxes for "Include conversation" and "Include file changes" - Contract selector (defaults to current contract, allows choosing another) **4.3 Tree Visualization (Optional)** Show `branched_from_task_id` relationships in task list to visualize the branch tree. **4.4 Contract Tasks View** Update `makima/frontend/src/components/contracts/ContractDetail.tsx`: - Show branched tasks in the Tasks tab with visual indicators - Display branch relationships (e.g., "Branched from: Task X") ## Files to Modify ### Backend (Server) - `makima/src/db/models.rs` - Add `BranchTaskRequest`, extend `Task` - `makima/src/db/repository.rs` - Add conversation CRUD, branch query - `makima/src/server/handlers/mesh.rs` - Add `branch_task` handler - `makima/src/server/handlers/mesh_daemon.rs` - Store conversation turns - `makima/src/server/protocol.rs` - Add `ConversationTurn` message ### Backend (Daemon) - `makima/daemon/src/ws/protocol.rs` - Add `ConversationTurn` message - `makima/daemon/src/task/manager.rs` - Emit user messages as conversation turns ### Migrations - `makima/migrations/20250111000000_add_task_conversations.sql` - `makima/migrations/20250111000001_add_branching_fields.sql` ### Frontend - `makima/frontend/src/lib/api.ts` - Add `branchTask()` method and types - `makima/frontend/src/components/mesh/TaskDetail.tsx` - Add Branch button/dialog - `makima/frontend/src/components/contracts/ContractDetail.tsx` - Show branch relationships in Tasks tab ## Key Design Decisions 1. **Conversation as context, not replay** - We prepend a transcript to the plan rather than trying to inject messages into Claude Code (which only accepts user messages) 2. **Separate from parent-child hierarchy** - Using `branched_from_task_id` instead of `parent_task_id` to distinguish from orchestrator/subtask relationships 3. **Reuse existing worktree mechanism** - Set `continue_from_task_id` to copy files from source task 4. **Opt-in conversation/worktree** - Both are configurable per-branch request 5. **Contract inheritance** - Branched tasks inherit the source task's contract by default, but can be placed in a different contract if needed (e.g., branching research findings into a new execute-phase contract)