- Add workspaces table migration (2026_06_01_add_workspaces) - Create Workspace model with repo_id, user_id, branch, path, status - Add workspace_id nullable FK to ToolInstance - Create GitService for clone/fetch/pull/branch_exists_remotely - Create WorkspaceManager for create/delete/sync lifecycle - Create workspace CRUD API with 409 handling for duplicates and instances - Wire workspace routes into FastAPI app - 17 tests passing (8 unit + 9 integration), 1 skipped Quality gates: ruff clean
5.0 KiB
Explore: Working Copies
Problem Statement
Currently, tool instances mount repositories directly. Each tool instance either:
- Mount mode: Bind-mounts the shared repo path (
/data/repos/<repo>) read-only - Clone mode: Clones the repo into the instance directory
This has several problems:
- Mount mode: Read-only, so users can't edit files in the tool
- Clone mode: Creates a full copy per instance, wasting disk space
- UI complexity: The create-instance form must ask "mount or clone?" and handle branch selection
- No persistence: Clone-mode repos live inside the instance directory and are lost on delete
- Race conditions: Multiple instances mounting the same repo can conflict
Proposed Solution: Working Copies
Introduce a Workspace as a first-class entity: a persistent, writable local clone of a repository that lives independently of any tool instance. Tool instances are then started on a working copy, which is mounted into the container.
Naming Candidates
| Name | Pros | Cons |
|---|---|---|
| Workspace | Common in IDEs; implies a working area | Conflicts with existing docs/features/workspace.md |
| Workspace | Common in IDEs (VS Code, JetBrains); implies a working area | May conflict with existing "workspace" terminology in docs |
| Checkout | Git-native term; implies a working tree | Too specific to git; implies a single commit/branch |
| Sandbox | Implies isolation and experimentation | Suggests throwaway/ephemeral, not persistent |
| Dev Copy | Simple and descriptive | Informal; "copy" still implies duplication |
| Project Clone | Clear relationship to project+repo | Clunky; two words |
| Branch | Git-native; each working copy is effectively a branch workspace | Too git-specific; may confuse with git branches |
Decision: "Workspace" — chosen by user despite existing docs/features/workspace.md. The existing workspace.md will be superseded/renamed to avoid confusion. — it's the most precise term. In SVN/Git parlance, a "working copy" is exactly what we want: a local, writable copy of a repository that you work on. The term is established enough that developers understand it, but not so overloaded in our domain that it conflicts.
Entity Model
Project
└── GitRepository (the canonical repo, read-only source)
└── WorkingCopy (writable local clone, 1+ per repo)
└── ToolInstance (mounts the working copy)
A Workspace:
- Has a
name(auto-generated or user-defined) - Has a
pathon disk (under/data/working-copies/<repo-id>/<copy-name>) - Has a
branch(the branch it's currently on) - Has a
status(ready, syncing, error) - Belongs to a
GitRepository - Belongs to a
User - Has many
ToolInstances
User Flow
- User navigates to Working Copies in the sidebar
- Sees list of working copies (or creates one from a repo)
- Clicks "New Workspace" → selects repo + branch → named copy created
- From a working copy, clicks "Start Tool" → selects tool type → instance starts with working copy mounted
- Multiple tool instances can share the same working copy (e.g., terminal + code-server side by side)
Benefits
- Writable by default: Working copies are clones, so tools can edit files
- Shared across instances: Multiple tools can mount the same working copy
- Persistent: Survives instance deletion
- Simplified UI: No more "mount vs clone" decision; tool creation is just "pick a working copy"
- Git operations: Working copies can support git push/pull/branch from the UI
- Disk efficient: One clone per working copy, not one per instance
Open Questions
- Should working copies auto-sync with the canonical repo?
- Should we support multiple working copies per repo (e.g., one per branch)?
- How do we handle merge conflicts if the canonical repo changes?
- Should working copies be scoped to a user or to a project?
- What happens to tool instances when a working copy is deleted?
- Should we pre-create a default working copy when a repo is added?
Migration Path
Existing tool instances that use clone_mode can be migrated:
- On first access, extract the cloned repo from the instance directory
- Move it to
/data/working-copies/... - Create a WorkingCopy record pointing to it
- Update the instance to mount the working copy path
Mount-mode instances can be converted on restart:
- Create a working copy from the canonical repo
- Switch the instance to mount the working copy instead
Scope for This Change
This change focuses on:
- Creating the WorkingCopy entity and database table
- Adding a Working Copies section to the UI (sidebar nav + list view)
- Updating tool instance creation to select a working copy instead of repo+clone_mode
- Updating compose generation to mount the working copy path
- Migrating existing clone_mode instances to use working copies
Out of scope (future changes):
- Auto-sync with canonical repo
- Git operations UI (push/pull/branch)
- Working copy sharing between users
- Pre-create default working copies