From 72ffccd248b4a95a19813c37d7405fd00a046e09 Mon Sep 17 00:00:00 2001 From: Ammar Date: Mon, 27 Oct 2025 01:43:24 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20Fix=20system=20message=20to=20co?= =?UTF-8?q?nditionally=20describe=20workspace=20type?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/AGENTS.md | 6 +++--- docs/fork.md | 2 +- docs/instruction-files.md | 12 ++++-------- docs/intro.md | 2 +- docs/system-prompt.md | 18 ++++++++++++++++-- docs/workspaces.md | 12 ++++++++---- src/App.tsx | 2 +- src/components/ForceDeleteModal.tsx | 4 ++-- src/components/Modal.stories.tsx | 2 +- src/components/NewWorkspaceModal.tsx | 7 ++++--- src/config.ts | 4 ++-- src/services/ipcMain.ts | 4 ++-- src/stores/WorkspaceStore.test.ts | 6 +++--- src/types/project.ts | 2 +- src/types/workspace.ts | 2 +- 15 files changed, 50 insertions(+), 35 deletions(-) diff --git a/docs/AGENTS.md b/docs/AGENTS.md index 2d4242255..3a6dd36cc 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -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//` - Workspace directories for git worktrees +- `~/.cmux/src//` - Local workspace directories (git worktrees) - `~/.cmux/sessions//chat.jsonl` - Session chat histories ## Documentation Guidelines @@ -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 @@ -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 diff --git a/docs/fork.md b/docs/fork.md index 29418de65..28a982e5f 100644 --- a/docs/fork.md +++ b/docs/fork.md @@ -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: diff --git a/docs/instruction-files.md b/docs/instruction-files.md index fbdb3a26c..c9ea13e41 100644 --- a/docs/instruction-files.md +++ b/docs/instruction-files.md @@ -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**: `/AGENTS.md` (+ optional `AGENTS.local.md`) — if exists - - **Project**: `/AGENTS.md` (+ optional `AGENTS.local.md`) — fallback if workspace doesn't exist +1. `~/.cmux/AGENTS.md` (+ optional `AGENTS.local.md`) — global defaults +2. `/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. @@ -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) diff --git a/docs/intro.md b/docs/intro.md index 196434bd5..2e8511e18 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -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? diff --git a/docs/system-prompt.md b/docs/system-prompt.md index 1abf72f65..a166ef2c6 100644 --- a/docs/system-prompt.md +++ b/docs/system-prompt.md @@ -33,8 +33,11 @@ Use GitHub-style \`
/\` tags to create collapsible sections for `; -function buildEnvironmentContext(workspacePath: string): string { - return ` +function buildEnvironmentContext(runtime: Runtime, workspacePath: string): string { + const isWorktree = runtime instanceof LocalRuntime; + + if (isWorktree) { + return ` You are in a git worktree at ${workspacePath} @@ -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 `; + } else { + return ` + +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 + +`; + } } ``` diff --git a/docs/workspaces.md b/docs/workspaces.md index 3fd268169..31f5028ad 100644 --- a/docs/workspaces.md +++ b/docs/workspaces.md @@ -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 @@ -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//`. +Local workspaces are stored in `~/.cmux/src//`. + +SSH workspaces are stored on the remote machine at `~/workspace//` (or your configured remote path). Example layout: diff --git a/src/App.tsx b/src/App.tsx index 1d8f2111c..dbed6f47f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -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); diff --git a/src/components/ForceDeleteModal.tsx b/src/components/ForceDeleteModal.tsx index d2da541bd..b183dace6 100644 --- a/src/components/ForceDeleteModal.tsx +++ b/src/components/ForceDeleteModal.tsx @@ -47,7 +47,7 @@ export const ForceDeleteModal: React.FC = ({ = ({ This action cannot be undone - 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. diff --git a/src/components/Modal.stories.tsx b/src/components/Modal.stories.tsx index f6460fd90..15bd4d662 100644 --- a/src/components/Modal.stories.tsx +++ b/src/components/Modal.stories.tsx @@ -106,7 +106,7 @@ export const WithInfoBox: Story = { <>

- This operation will create a new git worktree at ~/cmux/project/branch + This operation will create a new workspace at ~/cmux/project/branch

Existing files will not be affected.

diff --git a/src/components/NewWorkspaceModal.tsx b/src/components/NewWorkspaceModal.tsx index 0d9e85305..9b1d7e51f 100644 --- a/src/components/NewWorkspaceModal.tsx +++ b/src/components/NewWorkspaceModal.tsx @@ -137,8 +137,9 @@ const NewWorkspaceModal: React.FC = ({ About Workspaces:
    -
  • Uses git worktrees (separate directories sharing .git)
  • -
  • All committed changes visible across all worktrees
  • +
  • Isolated directories for parallel development
  • +
  • Local: git worktrees sharing .git (fast, efficient)
  • +
  • SSH: independent git clones on remote server
  • Agent can switch branches freely during session
  • Define branching strategy in AGENTS.md
@@ -243,7 +244,7 @@ const NewWorkspaceModal: React.FC = ({ )} -

This will create a git worktree at:

+

This will create a workspace at:

{runtimeMode === RUNTIME_MODE.SSH ? `${sshHost || ""}:~/cmux/${branchName || ""}` diff --git a/src/config.ts b/src/config.ts index 91512ca9b..3c2359614 100644 --- a/src/config.ts +++ b/src/config.ts @@ -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). */ @@ -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 diff --git a/src/services/ipcMain.ts b/src/services/ipcMain.ts index d32fc4f2e..c73644150 100644 --- a/src/services/ipcMain.ts +++ b/src/services/ipcMain.ts @@ -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, @@ -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 { diff --git a/src/stores/WorkspaceStore.test.ts b/src/stores/WorkspaceStore.test.ts index c29f73205..83e02dad7 100644 --- a/src/stores/WorkspaceStore.test.ts +++ b/src/stores/WorkspaceStore.test.ts @@ -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); @@ -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, }; @@ -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, }; diff --git a/src/types/project.ts b/src/types/project.ts index 3de56e7d1..e3e5e7ece 100644 --- a/src/types/project.ts +++ b/src/types/project.ts @@ -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 */ diff --git a/src/types/workspace.ts b/src/types/workspace.ts index 718ddf19e..e892e0962 100644 --- a/src/types/workspace.ts +++ b/src/types/workspace.ts @@ -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) */