Skip to content

Commit 1483692

Browse files
committed
🤖 fix: delete workspace by ID not path, fix title bar for local runtime
Bug fixes: - Delete workspace filters by ID instead of path. For local project-dir runtimes, all workspaces share the same path (project dir), so filtering by path was deleting ALL local workspaces when one was deleted. - WorkspaceHeader now uses metadata.name for display, fixing 'project/project' title issue for local runtimes where namedWorkspacePath is the project path. Docs: - Split runtime docs into docs/runtime/{local,worktree,ssh}.md - Add docs/runtime/index.md overview with comparison table - Update cross-references in workspaces.md and vscode-extension.md Tests: - Add integration tests for local project-dir workspace deletion - Verify only specified workspace is deleted, not all with same path - Verify project directory is not deleted
1 parent 5cfecf1 commit 1483692

File tree

11 files changed

+221
-41
lines changed

11 files changed

+221
-41
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,10 @@ Here are some specific use cases we enable:
3333

3434
## Features
3535

36-
- **Isolated workspaces** with central view on git divergence
37-
- **Local**: git worktrees on your local machine ([docs](https://cmux.io/local.html))
38-
- **SSH**: regular git clones on a remote server ([docs](https://cmux.io/ssh.html))
36+
- **Isolated workspaces** with central view on git divergence ([docs](https://cmux.io/runtime/index.html))
37+
- **Worktree** (default): git worktrees on your local machine
38+
- **Local**: run directly in your project directory
39+
- **SSH**: remote execution on a server over SSH
3940
- **Multi-model** (`sonnet-4-*`, `grok-*`, `gpt-5-*`, `opus-4-*`)
4041
- Ollama supported for local LLMs ([docs](https://cmux.io/models.html#ollama-local))
4142
- OpenRouter supported for long-tail of LLMs ([docs](https://cmux.io/models.html#openrouter-cloud))

docs/SUMMARY.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
# Features
1010

1111
- [Workspaces](./workspaces.md)
12-
- [Local](./local.md)
13-
- [SSH](./ssh.md)
12+
- [Runtimes](./runtime/index.md)
13+
- [Local](./runtime/local.md)
14+
- [Worktree](./runtime/worktree.md)
15+
- [SSH](./runtime/ssh.md)
1416
- [Forking](./fork.md)
1517
- [Init Hooks](./init-hooks.md)
1618
- [VS Code Extension](./vscode-extension.md)

docs/runtime/index.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Runtimes
2+
3+
Runtimes determine where and how mux executes agent workspaces.
4+
5+
| Runtime | Isolation | Best For |
6+
| --------------------------------------- | ------------------------------------------ | ---------------------------------------- |
7+
| **[Worktree](./worktree.md)** (default) | Each workspace gets its own directory | Running multiple agents in parallel |
8+
| **[Local](./local.md)** | All workspaces share the project directory | Quick edits to your working copy |
9+
| **[SSH](./ssh.md)** | Remote execution over SSH | Security, performance, heavy parallelism |
10+
11+
## Choosing a Runtime
12+
13+
When creating a workspace, select the runtime from the dropdown in the workspace creation UI.
14+
15+
## Init Hooks
16+
17+
[Init hooks](../init-hooks.md) can detect the runtime type via the `MUX_RUNTIME` environment variable:
18+
19+
- `worktree` — Worktree runtime
20+
- `local` — Local runtime
21+
- `ssh` — SSH runtime
22+
23+
This lets your init hook adapt behavior, e.g., skip worktree-specific setup when running in local mode.

docs/runtime/local.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Local Runtime
2+
3+
Local runtime runs the agent directly in your project directory—the same directory you use for development. There's no worktree isolation; the agent works in your actual working copy.
4+
5+
## When to Use
6+
7+
- Quick one-off tasks in your current working copy
8+
- Reviewing agent work alongside your own uncommitted changes
9+
- Projects where worktrees don't work well (e.g., some monorepos)
10+
11+
## Caveats
12+
13+
⚠️ **No isolation**: Multiple local workspaces for the same project see and modify the same files. Running them simultaneously can cause conflicts. mux shows a warning when another local workspace is actively streaming.
14+
15+
⚠️ **Affects your working copy**: Agent changes happen in your actual project directory.
16+
17+
## Filesystem
18+
19+
The workspace path is your project directory itself. No additional directories are created.
File renamed without changes.

docs/local.md renamed to docs/runtime/worktree.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Local Workspaces
1+
# Worktree Runtime
22

3-
Local workspaces use [git worktrees](https://git-scm.com/docs/git-worktree) on your local machine. Worktrees share the `.git` directory with your main repository while maintaining independent working changes and checkout state.
3+
Worktree runtime (the default) uses [git worktrees](https://git-scm.com/docs/git-worktree) on your local machine. Worktrees share the `.git` directory with your main repository while maintaining independent working changes and checkout state.
44

55
## How Worktrees Work
66

@@ -10,7 +10,7 @@ It's important to note that a **worktree is not locked to a branch**. The agent
1010

1111
## Filesystem Layout
1212

13-
Local workspaces are stored in `~/.mux/src/<project-name>/<workspace-name>`.
13+
Worktree workspaces are stored in `~/.mux/src/<project-name>/<workspace-name>`.
1414

1515
Example layout:
1616

docs/vscode-extension.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,5 +85,5 @@ repository.
8585
## Related
8686

8787
- [Workspaces Overview](./workspaces.md)
88-
- [SSH Workspaces](./ssh.md)
88+
- [SSH Runtime](./runtime/ssh.md)
8989
- [VS Code Remote-SSH Documentation](https://code.visualstudio.com/docs/remote/ssh)

docs/workspaces.md

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,23 @@
22

33
Workspaces in mux provide isolated development environments for parallel agent work. Each workspace maintains its own Git state, allowing you to explore different approaches, run multiple tasks simultaneously, or test changes without affecting your main repository.
44

5-
## Workspace Types
5+
## Runtimes
66

7-
mux supports two workspace backends:
7+
mux supports three [runtime types](./runtime/index.md):
88

9-
- **[Local Workspaces](./local.md)**: Use [git worktrees](https://git-scm.com/docs/git-worktree) on your local machine. Worktrees share the `.git` directory with your main repository while maintaining independent working changes.
9+
- **[Worktree](./runtime/worktree.md)** (default): Isolated directories using [git worktrees](https://git-scm.com/docs/git-worktree). Worktrees share `.git` with your main repository while maintaining independent working changes.
1010

11-
- **[SSH Workspaces](./ssh.md)**: Regular git clones on a remote server accessed via SSH. These are completely independent repositories stored on the remote machine.
11+
- **[Local](./runtime/local.md)**: Run directly in your project directory. No isolation—best for quick edits to your working copy.
1212

13-
## Choosing a Backend
13+
- **[SSH](./runtime/ssh.md)**: Remote execution over SSH. Ideal for heavy workloads, security isolation, or leveraging remote infrastructure.
1414

15-
The workspace backend is selected when you create a workspace:
15+
## Choosing a Runtime
1616

17-
- **Local**: Best for fast iteration, local testing, and when you want to leverage your local machine's resources
18-
- **SSH**: Ideal for heavy workloads, long-running tasks, or when you need access to remote infrastructure
17+
The runtime is selected when you create a workspace:
18+
19+
- **Worktree** (default): Best for parallel agent work with isolation
20+
- **Local**: Quick tasks in your current working copy
21+
- **SSH**: Heavy workloads, security, or remote infrastructure
1922

2023
## Key Concepts
2124

src/browser/App.tsx

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -559,27 +559,31 @@ function AppInner() {
559559
<div className="mobile-main-content flex min-w-0 flex-1 flex-col overflow-hidden">
560560
<div className="mobile-layout flex flex-1 overflow-hidden">
561561
{selectedWorkspace ? (
562-
<ErrorBoundary
563-
workspaceInfo={`${selectedWorkspace.projectName}/${selectedWorkspace.namedWorkspacePath?.split("/").pop() ?? selectedWorkspace.workspaceId}`}
564-
>
565-
<AIView
566-
key={selectedWorkspace.workspaceId}
567-
workspaceId={selectedWorkspace.workspaceId}
568-
projectPath={selectedWorkspace.projectPath}
569-
projectName={selectedWorkspace.projectName}
570-
branch={
571-
selectedWorkspace.namedWorkspacePath?.split("/").pop() ??
572-
selectedWorkspace.workspaceId
573-
}
574-
namedWorkspacePath={selectedWorkspace.namedWorkspacePath ?? ""}
575-
runtimeConfig={
576-
workspaceMetadata.get(selectedWorkspace.workspaceId)?.runtimeConfig
577-
}
578-
incompatibleRuntime={
579-
workspaceMetadata.get(selectedWorkspace.workspaceId)?.incompatibleRuntime
580-
}
581-
/>
582-
</ErrorBoundary>
562+
(() => {
563+
const currentMetadata = workspaceMetadata.get(selectedWorkspace.workspaceId);
564+
// Use metadata.name for workspace name (works for both worktree and local runtimes)
565+
// Fallback to path-based derivation for legacy compatibility
566+
const workspaceName =
567+
currentMetadata?.name ??
568+
selectedWorkspace.namedWorkspacePath?.split("/").pop() ??
569+
selectedWorkspace.workspaceId;
570+
return (
571+
<ErrorBoundary
572+
workspaceInfo={`${selectedWorkspace.projectName}/${workspaceName}`}
573+
>
574+
<AIView
575+
key={selectedWorkspace.workspaceId}
576+
workspaceId={selectedWorkspace.workspaceId}
577+
projectPath={selectedWorkspace.projectPath}
578+
projectName={selectedWorkspace.projectName}
579+
branch={workspaceName}
580+
namedWorkspacePath={selectedWorkspace.namedWorkspacePath ?? ""}
581+
runtimeConfig={currentMetadata?.runtimeConfig}
582+
incompatibleRuntime={currentMetadata?.incompatibleRuntime}
583+
/>
584+
</ErrorBoundary>
585+
);
586+
})()
583587
) : creationProjectPath ? (
584588
(() => {
585589
const projectPath = creationProjectPath;

src/node/services/ipcMain.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1512,7 +1512,7 @@ export class IpcMain {
15121512
log.info(`Workspace ${workspaceId} metadata exists but not found in config`);
15131513
return { success: true }; // Consider it already removed
15141514
}
1515-
const { projectPath, workspacePath } = workspace;
1515+
const { projectPath, workspacePath: _workspacePath } = workspace;
15161516

15171517
// Create runtime instance for this workspace
15181518
// For local runtimes, workdir should be srcDir, not the individual workspace path
@@ -1538,12 +1538,14 @@ export class IpcMain {
15381538
// Delete workspace metadata (fire and forget)
15391539
void this.extensionMetadata.deleteWorkspace(workspaceId);
15401540

1541-
// Update config to remove the workspace from all projects
1541+
// Update config to remove the workspace by ID
1542+
// NOTE: Filter by ID, not path. For local project-dir runtimes, multiple workspaces
1543+
// share the same path (the project directory), so filtering by path would delete them all.
15421544
const projectsConfig = this.config.loadConfigOrDefault();
15431545
let configUpdated = false;
15441546
for (const [_projectPath, projectConfig] of projectsConfig.projects.entries()) {
15451547
const initialCount = projectConfig.workspaces.length;
1546-
projectConfig.workspaces = projectConfig.workspaces.filter((w) => w.path !== workspacePath);
1548+
projectConfig.workspaces = projectConfig.workspaces.filter((w) => w.id !== workspaceId);
15471549
if (projectConfig.workspaces.length < initialCount) {
15481550
configUpdated = true;
15491551
}

0 commit comments

Comments
 (0)