# Session Branch Selection Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Replace free-text branch input with a dropdown of available branches and add "Create new branch" functionality in the session creation form. **Architecture:** Frontend fetches branches from existing API, displays them in a dropdown with a "Create new branch..." option. When creating a new branch, frontend sends both base branch and new branch name to backend. Backend clones the base branch then creates a local branch in the cloned workspace. **Tech Stack:** React + TypeScript (frontend), FastAPI + Python (backend), Git via subprocess --- ## File Structure - `apps/web/src/api/git_repositories.ts` — Add `listRepositoryBranches` API function - `apps/web/src/pages/sessions.tsx` — Replace branch input with dropdown + new branch form - `apps/api/src/api/tool_instances.py` — Extend `CreateInstanceRequest`, add local branch creation - `apps/web/src/api/sessions.ts` — Update `createInstance` signature to accept `newBranch` --- ### Task 1: Add Branch Listing API to Frontend **Files:** - Modify: `apps/web/src/api/git_repositories.ts` - [ ] **Step 1: Add Branch types and listRepositoryBranches function** Add after the existing imports and before `export interface CommitHistoryEntry`: ```typescript export interface Branch { name: string; is_default: boolean; last_commit: string | null; } export interface BranchesResponse { branches: Branch[]; default_branch: string; } export async function listRepositoryBranches( projectId: string, repoId: string ): Promise { const response = await apiClient.get( `/projects/${projectId}/repositories/${repoId}/branches` ); return response.data; } ``` - [ ] **Step 2: Commit** ```bash git add apps/web/src/api/git_repositories.ts git commit -m "feat: add branch listing API function" ``` --- ### Task 2: Update Backend Request Model and Clone Logic **Files:** - Modify: `apps/api/src/api/tool_instances.py` - [ ] **Step 1: Extend CreateInstanceRequest with new_branch field** Change the `CreateInstanceRequest` class (around line 55-64): ```python class CreateInstanceRequest(BaseModel): """Request body for creating a tool instance.""" model_config = {"extra": "ignore"} tool_type_id: str = Field(description="UUID of the tool type to instantiate") display_name: str | None = Field(default=None, description="Optional display name for the instance") clone_mode: str = Field(default="mount", description="Repository access mode: 'mount' or 'clone'") branch: str | None = Field(default="main", description="Branch to clone (when clone_mode='clone')") new_branch: str | None = Field(default=None, description="Create a new local branch after cloning") ``` - [ ] **Step 2: Add local branch creation after clone** After the clone block (around line 248), add: ```python # Create new local branch if requested if data.clone_mode == "clone" and data.new_branch: try: result = subprocess.run( ["git", "-C", repo_path, "checkout", "-b", data.new_branch], capture_output=True, text=True, ) if result.returncode != 0: logger.error("Failed to create branch %s: %s", data.new_branch, result.stderr) raise RuntimeError(f"Failed to create branch: {result.stderr}") logger.info("Created local branch %s in cloned repository", data.new_branch) except Exception as exc: logger.exception("Failed to create local branch: %s", exc) raise HTTPException( status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=f"Failed to create local branch: {exc}" ) ``` - [ ] **Step 3: Update ToolInstance record to store new branch name** Change the instance creation (around line 321): ```python branch=data.new_branch if data.new_branch else (data.branch if data.clone_mode == "clone" else None), ``` - [ ] **Step 4: Commit** ```bash git add apps/api/src/api/tool_instances.py git commit -m "feat: support creating local branch during session creation - Add new_branch field to CreateInstanceRequest - Run git checkout -b after cloning when new_branch is provided - Store new branch name in ToolInstance record" ``` --- ### Task 3: Update Frontend API to Support newBranch **Files:** - Modify: `apps/web/src/api/sessions.ts` - [ ] **Step 1: Update createInstance signature** Change the function signature (around line 44): ```typescript export async function createInstance( projectId: string, repoId: string, toolTypeId: string, displayName?: string, cloneMode?: string, branch?: string, newBranch?: string ): Promise { const response = await apiClient.post( `/projects/${projectId}/repositories/${repoId}/instances`, { tool_type_id: toolTypeId, display_name: displayName, clone_mode: cloneMode || "mount", branch: branch || undefined, new_branch: newBranch || undefined, } ); return response.data; } ``` - [ ] **Step 2: Commit** ```bash git add apps/web/src/api/sessions.ts git commit -m "feat: add newBranch parameter to createInstance" ``` --- ### Task 4: Update Session Creation UI **Files:** - Modify: `apps/web/src/pages/sessions.tsx` - [ ] **Step 1: Add new imports** Add to existing imports: ```typescript import { listRepositoryBranches, type Branch } from "../api/git_repositories"; ``` - [ ] **Step 2: Add state variables** Add after `const [sshKeys, setSshKeys] = useState([]);` (around line 44): ```typescript const [branches, setBranches] = useState([]); const [isLoadingBranches, setIsLoadingBranches] = useState(false); const [isCreatingNewBranch, setIsCreatingNewBranch] = useState(false); const [newBranchName, setNewBranchName] = useState(""); const [baseBranch, setBaseBranch] = useState(""); ``` - [ ] **Step 3: Add branch loading effect** Add after the `loadSshKeys` effect (around line 117): ```typescript useEffect(() => { const loadBranches = async () => { if (!selectedRepo || !selectedProject || cloneMode !== "clone") { setBranches([]); setIsCreatingNewBranch(false); setNewBranchName(""); setBaseBranch(""); return; } setIsLoadingBranches(true); try { const data = await listRepositoryBranches(selectedProject, selectedRepo); setBranches(data.branches); const defaultBranch = data.default_branch; setBaseBranch(defaultBranch); if (!branch || !data.branches.find((b) => b.name === branch)) { setBranch(defaultBranch); } } catch { setBranches([]); } finally { setIsLoadingBranches(false); } }; void loadBranches(); }, [selectedRepo, selectedProject, cloneMode]); ``` - [ ] **Step 4: Replace branch input with dropdown** Replace the branch input section (around lines 686-696): ```tsx {cloneMode === "clone" && ( <> {isCreatingNewBranch && ( <> )} {selectedRepo && (
{(() => { const repo = repositories.find((r) => r.id === selectedRepo); if (!repo) return null; if (repo.ssh_key_id) { const key = sshKeys.find((k) => k.id === repo.ssh_key_id); return ( SSH key: {key?.name || "Assigned"} ); } return ( No SSH key assigned to this repository. Clone mode requires an SSH key. ); })()}
)} )} ``` - [ ] **Step 5: Update handleCreate to pass newBranch** Change the `createInstance` call (around line 210): ```typescript const instance = await createInstance( selectedProject, selectedRepo, selectedToolType, displayName || undefined, cloneMode, isCreatingNewBranch ? baseBranch : branch, isCreatingNewBranch ? newBranchName : undefined ); ``` - [ ] **Step 6: Reset new branch state on successful creation** In the success handler (around line 227), add: ```typescript setIsCreatingNewBranch(false); setNewBranchName(""); setBaseBranch(""); setBranches([]); ``` - [ ] **Step 7: Commit** ```bash git add apps/web/src/pages/sessions.tsx git commit -m "feat: add branch dropdown and new branch creation UI - Replace free-text branch input with dropdown of available branches - Add 'Create new branch...' option with name and base branch inputs - Load branches from API when repository is selected in clone mode - Pass newBranch parameter to createInstance API" ``` --- ### Task 5: Verify and Test - [ ] **Step 1: Check TypeScript compilation** ```bash cd apps/web && npm run typecheck ``` Expected: No errors - [ ] **Step 2: Check Python syntax** ```bash cd apps/api && python -m py_compile src/api/tool_instances.py ``` Expected: No errors - [ ] **Step 3: Run backend tests if available** ```bash cd apps/api && pytest src/tests/ -v -k "instance" || echo "No instance tests found" ``` - [ ] **Step 4: Commit** ```bash git add -A git commit -m "test: verify branch selection implementation compiles" ``` --- ## Spec Coverage Check | Spec Requirement | Task | |---|---| | Branch dropdown with available branches | Task 4 | | "Create new branch..." option | Task 4 | | New branch name input | Task 4 | | Base branch dropdown | Task 4 | | Backend clone + local branch creation | Task 2 | | Frontend API integration | Task 1, 3 | ## Placeholder Scan - No TBD, TODO, or "implement later" references - All code is complete and copy-paste ready - No vague instructions like "add appropriate error handling" ## Type Consistency Check - `Branch` interface used consistently in Task 1 and Task 4 - `new_branch` / `newBranch` naming consistent between frontend and backend - `CreateInstanceRequest` fields match API call in `sessions.ts`