Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ Verify with React DevTools Profiler - MarkdownCore should only re-render when co
- `src/App.tsx` - Main React component
- `src/config.ts` - Configuration management
- `~/.cmux/config.json` - User configuration file
- `~/.cmux/src/<project_name>/<branch>` - Workspace directories for git worktrees
- `~/.cmux/src/<project_name>/<branch>` - Local workspace directories (git worktrees)
- `~/.cmux/sessions/<workspace_id>/chat.jsonl` - Session chat histories

## Documentation Guidelines
Expand Down Expand Up @@ -137,7 +137,7 @@ in `/tmp/ai-sdk-docs/**.mdx`.
## Key Features

- Projects sidebar (left panel)
- Workspaces using git worktrees
- Workspaces (local uses git worktrees, SSH uses remote git clones)
- Configuration persisted to `~/.cmux/config.json`

## Performance Patterns
Expand Down Expand Up @@ -179,7 +179,7 @@ This project uses **Make** as the primary build orchestrator. See `Makefile` for

- When refactoring, use `git mv` to preserve file history instead of rewriting files from scratch

**⚠️ NEVER kill the running cmux process** - The main cmux instance is used for active development. Use `make test` or `make typecheck` to verify changes instead of starting the app in test worktrees.
**⚠️ NEVER kill the running cmux process** - The main cmux instance is used for active development. Use `make test` or `make typecheck` to verify changes instead of starting the app in test workspaces.

## Testing

Expand Down
2 changes: 1 addition & 1 deletion docs/fork.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Forking Workspaces

Use `/fork` to clone a workspace with its full conversation history and UI state. The forked workspace gets a new git worktree on a new branch.
Use `/fork` to clone a workspace with its full conversation history and UI state. The forked workspace gets a new workspace on a new branch (using the same backend as the current workspace).

Usage:

Expand Down
12 changes: 4 additions & 8 deletions docs/instruction-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@

## Overview

cmux layers instructions from two sources:
cmux layers instructions from two locations:

1. **Global**: `~/.cmux/AGENTS.md` (+ optional `AGENTS.local.md`) — always included
2. **Project**: Either workspace OR project AGENTS.md (not both):
- **Workspace**: `<workspace>/AGENTS.md` (+ optional `AGENTS.local.md`) — if exists
- **Project**: `<project>/AGENTS.md` (+ optional `AGENTS.local.md`) — fallback if workspace doesn't exist
1. `~/.cmux/AGENTS.md` (+ optional `AGENTS.local.md`) — global defaults
2. `<workspace>/AGENTS.md` (+ optional `AGENTS.local.md`) — workspace-specific context

Priority within each location: `AGENTS.md` → `AGENT.md` → `CLAUDE.md` (first match wins). If the base file is found, cmux also appends `AGENTS.local.md` from the same directory when present.

**Fallback behavior**: Workspace instructions **replace** project instructions (not layered). If a workspace doesn't have AGENTS.md, the project root's AGENTS.md is used. This is particularly useful for SSH workspaces where files may not be fully cloned yet.

## Mode Prompts

> Use mode-specific sections to optimize context and customize the behavior specific modes.
Expand All @@ -23,7 +19,7 @@ cmux reads mode context from sections inside your instruction files. Add a headi

Rules:

- Project instructions (workspace or project fallback) are checked first, then global instructions
- Workspace instructions are checked first, then global instructions
- The first matching section wins (at most one section is used)
- The section's content is everything until the next heading of the same or higher level
- Missing sections are ignored (no error)
Expand Down
2 changes: 1 addition & 1 deletion docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

![cmux product screenshot](img/product-hero.webp)

**cmux** (Coding Agent Multiplexer) is a cross-platform desktop application for AI-assisted development with git worktree integration.
**cmux** (Coding Agent Multiplexer) is a cross-platform desktop application for AI-assisted development with isolated workspace management.

## What is cmux?

Expand Down
18 changes: 16 additions & 2 deletions docs/system-prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@ Use GitHub-style \`<details>/<summary>\` tags to create collapsible sections for
</prelude>
`;

function buildEnvironmentContext(workspacePath: string): string {
return `
function buildEnvironmentContext(runtime: Runtime, workspacePath: string): string {
const isWorktree = runtime instanceof LocalRuntime;

if (isWorktree) {
return `
<environment>
You are in a git worktree at ${workspacePath}

Expand All @@ -44,5 +47,16 @@ You are in a git worktree at ${workspacePath}
- You are meant to do your work isolated from the user and other agents
</environment>
`;
} else {
return `
<environment>
You are in a git repository at ${workspacePath}

- This IS a git repository - run git commands directly (no cd needed)
- Tools run here automatically
- You are meant to do your work isolated from the user and other agents
</environment>
`;
}
}
```
12 changes: 8 additions & 4 deletions docs/workspaces.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
# Workspaces

Currently, cmux supports one Workspace backend: [git worktrees](https://git-scm.com/docs/git-worktree).
cmux supports multiple workspace backends for different use cases:

We plan on adding support for SSH and Docker backends in the near future for
additional isolation and security.
- **Local workspaces**: [git worktrees](https://git-scm.com/docs/git-worktree) on your local machine
- **SSH workspaces**: Regular git clones on a remote server accessed via SSH

The backend is selected based on your runtime configuration. Local workspaces use git worktrees which share the `.git` directory with your main repository, while SSH workspaces are independent git clones on the remote machine.

## Basics of worktrees

Expand Down Expand Up @@ -43,7 +45,9 @@ dev server (e.g. `bun dev`) there directly and observe the agent's work in real-

## Filesystem Layout

All worktrees are stored in `~/.cmux/src/<project-name>/<workspace-name>`.
Local workspaces are stored in `~/.cmux/src/<project-name>/<workspace-name>`.

SSH workspaces are stored on the remote machine at `~/workspace/<project-name>/<workspace-name>` (or your configured remote path).

Example layout:

Expand Down
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ function AppInner() {

const openWorkspaceInTerminal = useCallback(
(workspaceId: string) => {
// Look up workspace metadata to get the worktree path (directory uses workspace name)
// Look up workspace metadata to get the workspace path (directory uses workspace name)
const metadata = workspaceMetadata.get(workspaceId);
if (metadata) {
void window.api.workspace.openTerminal(metadata.namedWorkspacePath);
Expand Down
4 changes: 2 additions & 2 deletions src/components/ForceDeleteModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export const ForceDeleteModal: React.FC<ForceDeleteModalProps> = ({
<Modal
isOpen={isOpen}
title="Force Delete Workspace?"
subtitle="The worktree could not be removed normally"
subtitle="The workspace could not be removed normally"
onClose={onClose}
maxWidth="600px"
isLoading={isDeleting}
Expand All @@ -60,7 +60,7 @@ export const ForceDeleteModal: React.FC<ForceDeleteModalProps> = ({
<WarningBox>
<WarningTitle>This action cannot be undone</WarningTitle>
<WarningText>
Force deleting will permanently remove the worktree and may discard uncommitted work or
Force deleting will permanently remove the workspace and may discard uncommitted work or
lose data.
</WarningText>
</WarningBox>
Expand Down
2 changes: 1 addition & 1 deletion src/components/Modal.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export const WithInfoBox: Story = {
<>
<ModalInfo>
<p>
This operation will create a new git worktree at <code>~/cmux/project/branch</code>
This operation will create a new workspace at <code>~/cmux/project/branch</code>
</p>
<p>Existing files will not be affected.</p>
</ModalInfo>
Expand Down
7 changes: 4 additions & 3 deletions src/components/NewWorkspaceModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,9 @@ const NewWorkspaceModal: React.FC<NewWorkspaceModalProps> = ({
<Tooltip width="wide" position="bottom" interactive>
<strong>About Workspaces:</strong>
<ul className="my-1 pl-4">
<li>Uses git worktrees (separate directories sharing .git)</li>
<li>All committed changes visible across all worktrees</li>
<li>Isolated directories for parallel development</li>
<li>Local: git worktrees sharing .git (fast, efficient)</li>
<li>SSH: independent git clones on remote server</li>
<li>Agent can switch branches freely during session</li>
<li>Define branching strategy in AGENTS.md</li>
</ul>
Expand Down Expand Up @@ -243,7 +244,7 @@ const NewWorkspaceModal: React.FC<NewWorkspaceModalProps> = ({
)}

<ModalInfo id={infoId}>
<p>This will create a git worktree at:</p>
<p>This will create a workspace at:</p>
<code className="block break-all">
{runtimeMode === RUNTIME_MODE.SSH
? `${sshHost || "<host>"}:~/cmux/${branchName || "<branch-name>"}`
Expand Down
4 changes: 2 additions & 2 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ export class Config {
}

/**
* Get the workspace worktree path for a given directory name.
* Get the workspace directory path for a given directory name.
* The directory name is the workspace name (branch name).
*/

Expand Down Expand Up @@ -200,7 +200,7 @@ export class Config {
* - Worktree directory name: uses workspace.name (the branch name)
* - Workspace ID: stable random identifier for identity and sessions (not used for directories)
*
* Backend: Uses getWorkspacePath(metadata.projectPath, metadata.name) for worktree directory paths
* Backend: Uses getWorkspacePath(metadata.projectPath, metadata.name) for workspace directory paths
* Frontend: Gets enriched metadata with paths via IPC (FrontendWorkspaceMetadata)
*
* WorkspaceMetadata.workspacePath is deprecated and will be removed. Use computed
Expand Down
4 changes: 2 additions & 2 deletions src/services/ipcMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ export class IpcMain {
// Generate stable workspace ID for the new workspace
const newWorkspaceId = this.config.generateStableId();

// Create new git worktree branching from source workspace's branch
// Create new workspace branching from source workspace's branch
const result = await createWorktree(this.config, foundProjectPath, newName, {
trunkBranch: sourceBranch,
directoryName: newName,
Expand Down Expand Up @@ -603,7 +603,7 @@ export class IpcMain {
}
} catch (copyError) {
// If copy fails, clean up everything we created
// 1. Remove the git worktree
// 1. Remove the workspace
await removeWorktree(foundProjectPath, newWorkspacePath);
// 2. Remove the session directory (may contain partial copies)
try {
Expand Down
6 changes: 3 additions & 3 deletions src/stores/WorkspaceStore.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function createAndAddWorkspace(
name: options.name ?? `test-branch-${workspaceId}`,
projectName: options.projectName ?? "test-project",
projectPath: options.projectPath ?? "/path/to/project",
namedWorkspacePath: options.namedWorkspacePath ?? "/path/to/worktree",
namedWorkspacePath: options.namedWorkspacePath ?? "/path/to/workspace",
createdAt: options.createdAt ?? new Date().toISOString(),
};
store.addWorkspace(metadata);
Expand Down Expand Up @@ -83,7 +83,7 @@ describe("WorkspaceStore", () => {
name: "test-branch",
projectName: "test-project",
projectPath: "/path/to/project",
namedWorkspacePath: "/path/to/worktree",
namedWorkspacePath: "/path/to/workspace",
createdAt,
};

Expand All @@ -110,7 +110,7 @@ describe("WorkspaceStore", () => {
name: "test-branch-2",
projectName: "test-project",
projectPath: "/path/to/project",
namedWorkspacePath: "/path/to/worktree",
namedWorkspacePath: "/path/to/workspace",
createdAt,
};

Expand Down
2 changes: 1 addition & 1 deletion src/types/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import type { RuntimeConfig } from "./runtime";
* For legacy entries, metadata is read from ~/.cmux/sessions/{workspaceId}/metadata.json
*/
export interface Workspace {
/** Absolute path to workspace worktree - REQUIRED for backward compatibility */
/** Absolute path to workspace directory - REQUIRED for backward compatibility */
path: string;

/** Stable workspace ID (10 hex chars for new workspaces) - optional for legacy */
Expand Down
2 changes: 1 addition & 1 deletion src/types/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export interface WorkspaceMetadata {
/** Project name extracted from project path (for display) */
projectName: string;

/** Absolute path to the project (needed to compute worktree path) */
/** Absolute path to the project (needed to compute workspace path) */
projectPath: string;

/** ISO 8601 timestamp of when workspace was created (optional for backward compatibility) */
Expand Down