Workspaces
Create, organize, and manage isolated coding workspaces with git worktree support.
Workspaces
Each workspace is an isolated coding context with its own terminal tabs, pane layout, git branch, and browser state. Workspaces appear in the sidebar and persist across restarts.
Creating Workspaces
Click the + button in the sidebar or use the project onboarding wizard to create a new workspace. Codemux uses a prompt-first flow — you describe what you want to do, and Codemux sets up the workspace around that.
Prompt-First Creation
The workspace creation dialog centers on a prompt textarea ("What do you want to do?"). From this single dialog you can:
- Describe your task — Type what you're working on (e.g., "Add dark mode support")
- Auto-generated branch name — Codemux generates a branch name from your prompt using AI (see below)
- Pick a device — A compact pill at the left of the bottom bar selects where the workspace runs. Defaults to Local Device; a submenu lists any SSH hosts you've registered in Settings → Hosts
- Pick an agent — Select which AI agent to launch (Claude Code, Codex, OpenCode, Gemini, Antigravity, Copilot, Cursor Agent, Amp, Grok, Droid, Mastracode, Pi, or a custom preset)
- Pick a model — A model pill next to the agent picker lets you choose the model, reasoning effort, and (for Claude) context window before launch, instead of starting with the default and restarting. Appears only for agents Codemux has model data for — Claude, Codex, OpenCode, Gemini. See Model Selection below
- Choose a project and base branch — The project picker shows active and recent projects
- Attach files or link a PR — Optional context for the agent
The prompt becomes the agent's initial task when the workspace opens. Press Ctrl+Enter to create.
New branches start from a freshly fetched origin/<base> tip — Codemux runs a quick scoped fetch (capped at 10 seconds, never prompts for credentials) before branching, and falls back to your local base branch when offline or in a local-only repo.
Model Selection
The model pill next to the agent picker lets you choose the model, reasoning effort, and context window before the agent launches — no need to start with the default, stop the agent, switch models, and resend your prompt.
- When it shows — Only for agents Codemux has model data for: any preset whose command launches
claude,codex,opencode, orgemini. Custom presets that launch one of these CLIs light it up automatically; everything else hides the pill. - Model — Lists are live wherever possible: OpenCode harvests its connected providers, Codex reads
model/list, Claude pulls its supported models from the CLI (with anANTHROPIC_API_KEYREST fallback and a maintained list), and Gemini usesGEMINI_API_KEY(falling back to a maintained list). Long rosters get search + favorites + provider grouping; short ones show a flat list. - Reasoning — Shown for Claude and Codex. The available levels come from the selected model, so Sonnet and Opus show different choices — including Claude's top Ultracode rung, which is offered on any model that supports Extra High. OpenCode and Gemini have no reasoning control, so the row is hidden. See Reasoning Effort.
- Context window — Claude only. Pick
200Kor1Mfor models that support the larger window. - Default — Leaving the pill on "Default" emits no flags, so the launch is identical to before this feature existed. Your last pick per agent family is remembered and restored next time.
AI Branch Name Generation
When you type a task description, Codemux auto-generates a git branch name:
- AI-generated — Uses Claude CLI to generate a short 2-4 word hyphenated branch name from your prompt (e.g., "add-dark-mode")
- Random fallback — If AI is unavailable, generates a random
adjective-nounpair (e.g., "swift-reef", "bold-gate") - Custom override — You can always edit the branch name manually
- Deconfliction — Names are sanitized and checked against existing branches. Conflicts get a
-2,-3suffix
Other Creation Methods
You can also create workspaces by:
- From branch — Select an existing branch from the dropdown; creates a git worktree. The branch picker is a derivative-branch picker with icons, recency-based sorting, and a Worktree tab for browsing existing worktrees.
- From PR — Link a pull request from the
+menu to set the branch automatically.
Attaching Context To The Prompt
The prompt input on the workspace-creation dialog accepts:
- File picker — click the paperclip / attach button to attach files from your workspace
- GitHub issue / PR linking — searchable picker shows your repo's open issues and PRs (with state-colored icons); the linked item's context is injected into the agent prompt. Linking an issue auto-fills a deterministic branch name, so if that issue (or the typed branch) already has a workspace, the dialog tells you up front and offers to Open it instead of silently switching to the existing one and dropping the message you just typed
- Clipboard paste — paste images directly into the prompt textarea with
Ctrl+V. Useful for screenshots fromgrim, the Windows Snipping Tool, or anything else that puts an image on your clipboard
Each workspace gets its own terminal tabs and pane layouts.
Checkout Default Branch
Every primary workspace (the one rooted at the original checkout, not a worktree) has a Checkout default branch action in its sidebar context menu. One-click way to switch back to main (or whatever your configured default base branch is) without dropping to a terminal.
Empty Workspace State
When a workspace has no panes open, it shows a centered logo with clickable quick-action buttons:
- Open Terminal — also bound globally to
Ctrl+T - Open Browser
- Open in Editor
- Search Files — also bound globally to
Ctrl+Shift+P
A "Delete workspace" option is also available at the bottom. For the full list of global key bindings, see Keyboard Shortcuts.
Layout Presets
Layouts are available when an agent or script creates a workspace through MCP or the CLI — there is no layout picker in the workspace-creation dialog. New workspaces open with a single terminal pane; split them yourself with Ctrl+Shift+D / Ctrl+Shift+E.
| Preset | Description |
|---|---|
| Single | 1 terminal pane |
| Pair | 2 panes side by side |
| Quad | 4 panes in a grid |
| Six | 6 panes (3x2) |
| Eight | 8 panes (4x2) |
| Shell + Browser | Terminal on the left, browser on the right |
| Empty | No panes |
Agent Presets
The + launcher in the title bar ("Launch an agent") is how you start an agent. It's a searchable popover — placeholder "Launch an agent…" — in four parts:
- GUI — chat presets, which open an Agent Chat pane in a new tab. Marked
in app. - CLI agents — terminal presets, pinned ones first. Selecting one opens it in a new tab; hold Shift to open it as a split pane instead. Marked
terminal. - Panes — plain Terminal and Browser.
- Manage presets… — a sticky footer row that jumps to Settings → Presets.
Hover any row for a pin toggle that promotes that preset to a one-click tile in the title bar.
On a draft (before the workspace exists), the launcher has no Panes section — there's no live surface yet — and picking a preset materializes the draft into a workspace running just that preset.
Twelve coding-agent CLIs ship as pinned builtins:
- Claude Code —
claude --dangerously-skip-permissions - Codex —
codex --dangerously-bypass-approvals-and-sandbox - OpenCode —
opencode - Gemini —
gemini --yolo - Antigravity —
agy --dangerously-skip-permissions - Copilot —
copilot --allow-all - Cursor Agent —
cursor-agent --yolo - Amp —
amp --dangerously-allow-all - Grok —
grok --always-approve - Droid —
droid(autonomy injected via a runtime--settingsfile) - Mastracode —
mastracode - Pi —
pi
Each agent preset launches in its CLI's skip-permissions / auto-approve mode so you don't have to confirm individual tool calls. You can create custom presets with your own commands, icons, and launch modes (split pane or new tab). The agent picker in the workspace creation dialog also uses these presets. See Terminal → Preset Bar for the full flag rationale per agent.
Open In External Editor
The IDE launcher in the title bar (and the Open in editor entry in the sidebar context menu) opens the current workspace in your preferred external editor. Codemux probes for 19 editors on launch via which so PATHEXT, .cmd shims, and JetBrains Toolbox shims all resolve without special casing:
| Group | Editors |
|---|---|
| VS Code family | VS Code, Cursor, Windsurf, Trae, VSCodium |
| Modern editors | Zed, Lapce |
| JetBrains | Fleet, IntelliJ IDEA, PyCharm, PhpStorm, WebStorm, GoLand, RubyMine, CLion, Rider, DataGrip, Android Studio |
| Other | Sublime Text |
Only families with at least one installed editor render in the launcher — no empty headers. On Windows, fallback paths cover per-user installs that don't always land on PATH (Windsurf, Trae, Lapce).
The Workspace Inbox
The expanded sidebar is a flat inbox, not a per-project tree. Every active workspace renders as a multi-line card:
- Repo eyebrow — project avatar and name.
- Work title — the linked issue's title (with its
#number) while an agent is live; the worktree name otherwise. - Blocker line — on a needs-input workspace, a red-tinted card carrying "Waiting for your input".
- Meta line — mono text with the branch,
↑ahead, and+/−diff counts on the left; a PR chip, the provider logo(s) in use, a remote indicator, and a notification badge right-aligned in a fixed column, so chips line up down the list. The ahead/diff numbers can be hidden via Settings → Appearance → Sidebar → Show git stats; the branch always shows. - Unread marker — an ember dot and a bold title when the agent produced output since you last opened that workspace. The workspace you're currently in is never unread.
- State cluster (right side) —
Workingwith a configurable indicator glyph, a pulsingNeeds you, a steady cyanMonitoring(see Agent Status),Done · review, or an elapsed-idle time. On hover this swaps to a ✓ Settle and Snooze pair.Done · reviewsurvives a quit and relaunch, so a finished workspace still reads as finished next launch; it clears when you open the workspace. Working and Needs-you states are not restored — those processes are gone.
Above the cards sit a search button (which opens the command palette), a new
agent button, and a project-filter dropdown with an Add repository (+)
button.
Pinning
Any workspace can be pinned from its right-click menu — the entry sits at the top of the menu on all three row shapes (active card, settled row, snoozed row). Pinned workspaces render as cards in a dedicated block above every normal active card, separated by a thin hairline that only draws when there is something below it.
Ordering inside the pinned block is the same stored creation order the normal list uses, not pin-click time, so pinning several workspaces in a row does not make each new pin jump ahead of the others.
Pinning is durable: it survives restarts, and archiving then restoring a workspace preserves both its pinned state and its original pin timestamp. Pinned cards stay visible in the collapsed rail.
A pin suppresses Settle and Snooze (both the hover actions and the menu entries disappear — Mark unread stays), excludes the workspace from bulk parking, and excludes it from auto-settle. The card's eyebrow carries a pin glyph and a direct Unpin action on hover or keyboard focus.
Pinning is a visibility override, not a lifecycle change. An already-settled or snoozed workspace keeps its shelf entry underneath and returns to it when unpinned. The override is against parking only — the settle safety net and the snooze wake sweep still update the entry underneath a pinned card, so unpinning reveals the current lifecycle rather than a stale one. (The cosmetic "Woke" pill is suppressed while pinned, since the card never left the list.)
Unsent drafts
A block labelled Unsent drafts sits above the inbox, listing chat drafts you started but never sent — each with an amber pen glyph, the project it's aimed at (or Home), an attachment count, and a preview of the first line you typed.
A draft only appears once it has content you wrote — text or at least one attachment. Picking a provider, model, or checkout doesn't create a row, so opening the composer and changing your mind leaves nothing behind. Hover a row for ✕ to discard it. The preview of the draft you're actively typing in is frozen, so the sidebar doesn't repaint on every keystroke.
Drafts respect the active project filter and sort newest first. In the collapsed rail they show as the project avatar with the pen overlay.
What a card tells you at a glance
The eyebrow on each card carries the live state:
| State | Reads |
|---|---|
| Working | Working plus elapsed time — Working 11m |
| Needs you | Needs you, with a pulsing dot |
| Monitoring | Monitoring, with a steady dot (deliberately not animated) |
| Done · review | Done · review |
| Idle | just the time since it settled — 26m |
Elapsed time is written compactly: 45s, 12m, 3h20m, 2d4h. Only the word is
announced to screen readers — the ticking number isn't, so a live region doesn't
narrate every second.
Ranking, not hiding
A card that is quietly working, monitoring, or idle — and isn't active, selected, unread, or newly woken — recedes: its avatar, name, title, git facts, and chips all dim.
Two deliberate exceptions:
- The live status readout never dims. A receding card still paints "Working 11m" at full strength, so the one thing that changes stays legible.
- Hover or focus restores everything, as does opening its Snooze menu.
Nothing is ever hidden — only ranked.
Needs you
While any workspace is waiting on input, a pinned NEEDS YOU · N strip sits in
the sticky header. Each entry is a jump-link — project avatar, blocker text, and age
— that activates the blocked workspace and scrolls its card into view; the card
itself is never moved or reordered. Entries are ordered oldest-blocked first so
the thing that has been waiting longest is on top, capped at 4 rows with a
+N more below line. The header count always reports the true total, and the strip
respects the active project filter.
Wrapping up
Active cards are split into two tiers by a static Wrapping up divider. A card drops below it when its pull request is open (not draft, not merged or closed), its agent is idle, and it has no unread output — work that is essentially done but not yet parked. Nothing is hidden or collapsed: the divider has no disclosure control, and cards below it keep Settle, Snooze, the right-click menu, their jump slot, and selection. Send a follow-up and the agent goes back to work, returning the card to the top tier on its own.
Hover details
Hovering any workspace surface — an active card, a settled row, a snoozed row, or a collapsed-rail avatar — opens a read-only details card showing the repo, providers, and live agent state with elapsed time (Working 11m), the full untruncated title, the linked issue, then whichever of these rows apply:
Branch, Uncommitted +A −D, Changed files, Ahead, Behind (or a
single Working tree · clean row), Pull request #42 · open, PR branch
(only when it differs from the checked-out one), Issue, Port(s),
Processes, Location (This device / host name / host · in place),
Hosting (e.g. GitLab · gitlab.acme.com, once the checkout has been
classified), and Notifications muted. The footer is the real path on disk
($HOME shown as ~, wrapped rather than truncated).
Processes counts what is actually listening: one per distinct process id, plus
one per distinct Docker-published host port. A port merely declared in
.codemux/ports.json counts zero — declaring a port isn't proof of a listener. See
Port Detection.
Its text can be selected and copied. Parked rows report their real agent state — a settled workspace can still be running.
Selecting several at once
Cmd/Ctrl-click toggles a row into a selection and Shift-click selects a range. Active cards, snoozed rows, and settled rows all participate, and ranges cover only rows currently on screen — nothing behind Show more or inside a collapsed shelf is ever silently included. Right-click inside a selection of two or more for a bulk menu offering Settle (n) and Snooze (n). A plain click, an activation, or a project-filter change clears the selection; selection lasts for the session only.
Settling
Settle sweeps a finished card out of the active list into a Settled shelf at the bottom. It is purely visual — nothing is archived, closed, or deleted, and Un-settle brings it back.
- Settle and Snooze are both blocked while a workspace is working or waiting on you, so live work can't be buried. This applies to bulk actions too: a selection containing even one working or blocked workspace offers neither verb, and the menu says so rather than hiding the entry. A monitoring workspace is not live work in this sense — it can be settled and snoozed normally.
- Pinned workspaces are exempt from both verbs and from bulk parking; see Pinning.
- A settled workspace whose agent starts working again automatically resurfaces.
- Auto-settle sweeps an idle card after N idle days — configurable at Settings → Appearance → Sidebar → Auto-settle idle work (Off / 1d / 3d / 7d / 14d, default 3d) — or once its PR merges or closes and it has then been idle for an hour, so coming back to a merged workspace for a review comment or a revert doesn't snap it out of sight while you're still reading. Un-settling a card pins it active: auto-settle won't touch it again until its agent actually runs.
- Idle time and unread status are tracked by Codemux itself and persist across restarts and app updates — updating no longer resets every workspace's idle clock. Workspaces predating this get dated once, at boot, from their last git commit (falling back to folder modification time); when neither is knowable the workspace is treated as unknown-idle and is never auto-settled. Remote and attach-in-place workspaces never get a stamp, so they never auto-settle.
- A settled or snoozed row is itself a button — click it (or press Enter/Space) to open that workspace without un-settling or waking it. Un-settle and Wake now are separate hover controls.
- Settling or snoozing the workspace you're currently viewing moves you to the next active card. Parking a background workspace, or a background auto-settle sweep, never moves you.
- The settled list shows 10 rows, then pages in more via Show N more (X hidden). Paging resets when you change the project filter.
- Both shelves have a disclosure header — Settled starts open, Snoozed starts closed. Collapse state and the paging window reset each launch. Whichever shelf it's in, the workspace you currently have open always renders.
Settled rows are dimmed until you hover them. The shelf is history, so at rest it reads as one grey block rather than a list competing with live work: the repo avatar desaturates, the title drops to a fainter tone, and the PR badge gives up its open/merged/closed color. Hover or keyboard focus restores all three at once — nothing is hidden, only ranked.
Four kinds of row stay bright, and they are exactly the rows the active cards keep bright too, so one workspace can't read as "wants you" on a card and "history" on a row: the workspace you currently have open, any row ticked for a bulk action, a row holding unread output, and a row in review status. (Review matters because the settle safety net deliberately leaves finished-and-wants-review work parked.)
The PR badge itself now renders identically on active cards and settled rows — no bordered, tinted box on one and a bare icon on the other — so settling a card no longer looks like the badge changed when only the tier did.
Snoozing
Snooze parks a card until a time you pick, for work you'll come back to rather than work that's done. The hover cluster offers it beside ✓ Settle, with four presets — In 1 hour, This evening (18:00), Tomorrow (09:00), and Next week (Mon 09:00) — each showing the concrete local wake instant beside it. "This evening" is hidden unless it's at least an hour out, and "Next week" is hidden when it would land on the same day as "Tomorrow".
Snoozed workspaces move to a collapsible Snoozed shelf above Settled, collapsed
by default and ordered soonest-wake-first. Each row shows the time until it wakes
(45s, 12m, 3h20m, 2d4h, then now) with a hover-revealed Wake now.
Snoozes persist across restarts.
A snoozed workspace whose agent starts working or asks for input wakes immediately, wake time or not. A card that returns on its own — by wake time or by that early hand-raise — carries a green Woke pill; an explicit Wake now doesn't. The badge clears when you visit the workspace.
Jumping to a workspace
Alt+1 through Alt+9 activate the Nth visible card (filter-scoped; parked
rows — settled and snoozed — excluded). Numbering runs across both tiers, so a card
below the Wrapping up divider still gets a digit. Holding the modifier overlays
numbered badges on the first nine cards — whichever modifier the shortcut is
actually bound to, so rebinding it to Ctrl makes Ctrl reveal them (a chord using
neither shows no badges). Ctrl+1..9 remain terminal-tab switches.
The footer
A fixed footer row carries Automations, Workspaces, a Ports popover, and a gear Menu (Settings, command palette, keyboard shortcuts, documentation, report issue, version, sign out).
The full labeled detail for the workspace you're currently looking at lives in the sidebar hover card and, in a chat pane, the Context Row — see Where Workspace Status Lives.
Renaming a Workspace
Press F2 to rename the active workspace, or pick Rename workspace from a sidebar card's right-click menu or a row's dropdown in the Workspaces Overview.
The dialog is subtitled with the project and branch, takes up to 48 characters, and
tells you plainly what it will and won't touch — Branch stays feature/auth, or
"Only the workspace label changes" when there is no branch.
It renames the label and nothing else. No branch is renamed, no directory is moved. Two workspaces in the same project can't share a name (case-insensitively) — "Another workspace already uses this name" — but the same name in a different project is fine.
Removing Workspaces
Removing a workspace is a two-tier model: a frictionless, always-reversible archive is the primary action, and a destructive delete is demoted behind an explicit confirm.
Archive (primary)
Right-click a workspace card and select Archive Workspace. (The old hover-reveal archive button is gone — hovering a card now reveals the ✓ Settle and Snooze controls instead, which are separate, purely visual actions.) Archiving removes the workspace from the sidebar but touches nothing on disk: files, branch, and worktree stay exactly where they are. An undo toast lets you reverse it immediately.
Every local workspace is archivable, including the primary repo-root workspace. Two kinds are the exception and get a plain Close instead:
- Attach-in-place workspaces — no local files, so closing is just a detach
- Remote workspaces — their durable home is the cross-device sync registry
Archive Project is currently unavailable — it was a project-header action, and the sidebar no longer has project rows. Archive workspaces individually.
Restore from Settings → Archive
Archived workspaces live in Settings → Archive, grouped by project with a branch chip, a relative archived-time, and a stale hint for entries older than 30 days. Click Unarchive to restore one: the on-disk worktree is reused where it still exists, otherwise the branch is checked out fresh. A restored workspace keeps its title, files, branch, and worktree, but opens with a fresh single-pane layout.
The archive list is device-local — it does not sync across devices.
Delete (destructive)
Worktree workspaces expose Delete Worktree… via the context menu. This opens a destructive confirm dialog with an "Also delete local branch" checkbox (enabled by default), and permanently removes the worktree directory. Archived worktree entries can be deleted the same way from Settings → Archive.
The primary repo-root workspace can never be deleted — only archived.
Unpushed Commit Warnings
A non-forced delete of a workspace with uncommitted changes or unpushed commits is refused before anything is removed. The dialog stays open, shows the reason, and offers an explicit Force delete to override — preventing accidental data loss.
Context Menu
Right-click any workspace in the sidebar — an active card, a settled row, or a snoozed row — to:
- Pin workspace / Unpin workspace (see Pinning)
- Un-settle / Wake now (the entries that bring work back come first)
- Settle / Snooze until… (hidden on a pinned workspace)
- Mark unread — re-flag a card you've already read; offered only on cards that don't already read as unread, and cleared by opening the workspace
- Project "<name>" — set the project's avatar image or color (see Project Avatars)
- Rename the workspace
- Open in external editor
- Copy branch name
- Check out the default branch (non-worktree workspaces)
- Re-run Setup
- Mute / unmute notifications
- Move to device… / Pull back to this device
- Archive the workspace (or Close, for remote and attach-in-place workspaces)
- Delete Worktree… (worktree workspaces)
Where Workspace Status Lives
Codemux used to reserve a full-width status strip along the bottom of the work surface. That bar was removed — panes now use the entire available height, and the same detail is carried where you are already looking:
- Hover a workspace in the sidebar for a details card with the untruncated title, full git detail (branch, base, ahead / behind, uncommitted count), ports, location, and the real path. It appears on every sidebar surface — active card, settled row, snoozed row, and rail avatar.
- In an Agent Chat pane, the branch, PR, and status detail render inline beneath the composer as the Context Row — next to the conversation they belong to.
- In a terminal pane, the header shows a compact working-directory chip when the session's live cwd differs from the workspace root, plus a background browser indicator when the agent has one open.
Setup & Teardown Scripts
Configure commands that run automatically when workspaces open or close. Two configuration methods:
File-based (.codemux/config.json)
Add a .codemux/config.json to your project root:
{
"setup": ["npm install", "npm run build"],
"teardown": ["docker compose down"],
"run": "npm run dev"
}setup— Runs when the workspace is createdteardown— Runs when the workspace closesrun— The dev command for the Run button (Ctrl+Shift+G)
Database-based (Settings)
Configure scripts in Settings > Projects. Database settings apply when no .codemux/config.json exists. File config takes precedence.
Docker Compose Support
Scripts automatically receive these environment variables:
CODEMUX_ROOT_PATH— Full path to the git rootCODEMUX_WORKSPACE_PATH— Full path to the workspace directory
Setup Banner
When a project has worktree workspaces but no setup scripts configured, a banner appears in the sidebar suggesting you configure automation. Dismiss it per-project or click "Configure" to open Settings.
Project Detection
Codemux detects the project root for each workspace by walking up from the workspace directory to find the git root. This works correctly for worktree workspaces — the project root is the main repository, not the worktree directory.
Keyboard Shortcuts
| Shortcut | Action |
|---|---|
| Ctrl+] | Next workspace |
| Ctrl+[ | Previous workspace |
| F2 | Rename the active workspace |
| Alt+1 … Alt+9 | Jump to the Nth visible card |
See Also
- Workspaces Overview — account-wide view across every device with push/pull/adopt actions.
- Settings → Hosts — register an SSH host before pushing a workspace to it.