# Tasks: Config Profile Multi-Repo Mounts ## T1: Backend — Refactor git mount resolution for mappings ### T1.1: Normalize legacy git mount format **File**: `apps/api/src/api/tool_instances.py` - Add `_normalize_git_mount(entry: dict) -> dict` helper - Converts `{"source_path": "...", "target_path": "..."}` to `{"mappings": [{...}]}` - Call normalization at the start of `_resolve_single_git_mount` ### T1.2: Extract clone logic **File**: `apps/api/src/api/tool_instances.py` - Create `_clone_git_repo(remote_url, branch, clone_parent) -> str` function - Move clone/pull logic from `_resolve_single_git_mount` into it - Returns `repo_path` (path to `repo-clone`) ### T1.3: Resolve mappings from cloned repo **File**: `apps/api/src/api/tool_instances.py` - Create `_resolve_git_mount_mappings(repo_path, mappings, working_directory) -> list[dict]` - Iterates over mappings, expands globs, resolves targets - Returns flat list of volume mount dicts ### T1.4: Wire it together **File**: `apps/api/src/api/tool_instances.py` - Update `_resolve_single_git_mount` to: 1. Normalize entry 2. Clone repo once 3. Resolve all mappings 4. Return flat volume mounts ### T1.5: Update merge logic **File**: `apps/api/src/services/config_profile_resolver.py` - Change `_merge_git_mounts` merge key from `(remote_url, target_path)` to `(remote_url, branch)` - When same repo+branch: concatenate `mappings` arrays - When different: append as separate entry ### T1.6: Add validation **File**: `apps/api/src/api/config_profiles.py` - Validate `git_mounts` on create/update: - `remote_url` required - Either `mappings` (non-empty array) OR (`source_path` + `target_path`) - Each mapping has `source_path` and `target_path` ### T1.7: Unit tests **File**: `apps/api/tests/unit/test_git_mounts.py` (new) - Test normalization: legacy → mappings - Test single clone with 3 mappings → 3 volume mounts - Test glob expansion within mapping - Test relative target resolution **File**: `apps/api/tests/unit/test_config_profile_resolver.py` - Update merge tests for new dedup key --- ## T2: Frontend — Git mount mappings editor ### T2.1: Update types **File**: `apps/web/src/api/config_profiles.ts` - Add `GitMountMapping` interface - Update `GitMountEntry` to have `mappings: GitMountMapping[]` - Keep optional `source_path`/`target_path` for backward compat ### T2.2: Auto-convert legacy entries on load **File**: `apps/web/src/components/config-profile-editor.tsx` or new `GitMountEditor.tsx` - On loading a profile, normalize any git_mount entries that lack `mappings` ### T2.3: Build mappings UI **File**: `apps/web/src/components/GitMountEditor.tsx` (new) - Render table/list of mappings per git mount entry - "Add mapping" button appends empty row - "Remove" button deletes a mapping row - Source path and target path inputs ### T2.4: Integrate into ConfigProfileEditor **File**: `apps/web/src/components/config-profile-editor.tsx` - Replace existing git_mounts flat form with GitMountEditor component - Ensure save sends correct JSON shape ### T2.5: Frontend tests **File**: `apps/web/src/components/GitMountEditor.test.tsx` (new) - Render with 2 mappings - Add mapping increases count - Remove mapping decreases count - Legacy entry auto-converts --- ## T3: Integration & Verification ### T3.1: Integration test **File**: `apps/api/tests/integration/test_config_profiles_git_mounts.py` (new) - Create profile with 2 mappings from same repo - Start instance - Verify single clone directory exists - Verify 2 bind mounts in compose file ### T3.2: Manual verification - Create a Config Profile with a monorepo git mount + 3 mappings - Create and start a pi-agent instance with the profile - Verify all 3 directories are mounted correctly - Verify legacy profile (single mapping) still works ### T3.3: Typecheck & tests ```bash cd apps/web && npm run typecheck cd apps/api && pytest tests/unit/test_git_mounts.py tests/unit/test_config_profile_resolver.py ``` --- ## Estimation | Task | Effort | Files | |------|--------|-------| | T1.1-T1.4 | 2h | 1 | | T1.5 | 1h | 1 | | T1.6 | 1h | 1 | | T1.7 | 2h | 2 | | T2.1-T2.4 | 3h | 3 | | T2.5 | 1h | 1 | | T3.1-T3.3 | 2h | 2 | | **Total** | **12h** | **11** | ## PR Strategy **Single PR** (~400 lines estimated, within review budget): - Backend changes (T1) - Frontend changes (T2) - Tests (T1.7, T2.5, T3.1) All changes are tightly coupled (backend schema + frontend UI + tests) so a single PR is appropriate.