Skip to main content
One workspace is a nicer terminal. Five at once is the reason to install anything.

Why worktrees instead of branches

Switching branches in one checkout mutates shared state: the working tree, the index, node_modules, the dev server, and the agent’s idea of what it just wrote. An agent that is mid-turn when you switch branches produces garbage, and you find out at review time. A Git worktree gives each branch its own directory backed by the same object store. No stashing, no rebuilding on switch, and an agent can keep running in one workspace while you review another. The cost is disk and one dependency install per workspace — which is what [scripts] setup is for.

The four things that collide

1. Ports

Every workspace gets a reserved block of ports. Allocation starts at 42000, hands out 10 ports per workspace by default, skips blocks another workspace already holds, and skips blocks whose ports are actually in use. $ARCHDUCTOR_PORT is the base of the block.
Derive the rest from the base rather than hardcoding:
If two workspaces fight over a port, the run script hardcoded one. There is no other cause.

2. Gitignored local files

A new worktree contains tracked files only. Your .env, local config, and certificates are not there. Two sources of copy patterns, and they are combined, not ranked — the patterns from both are concatenated and matched against the repository’s gitignored files:
Lines starting with ! or # in .worktreeinclude are discarded, so gitignore-style negation does not work. Once a pattern matches, the file is copied — there is no way to exclude it again.
Only gitignored files are copied. Build output and dependency directories are deliberately excluded — reproducing them with [scripts] setup is faster and does not carry stale artifacts between branches.
If a workspace genuinely cannot start without a file, list it in env_file_refs. That turns a missing file into a launch failure with a clear message instead of an application that boots with empty configuration.

3. Two agents editing the same file

Nothing stops it, and nothing should — sometimes it is what you want. What Archductor does is tell you before you merge. The Changes panel shows sibling conflicts: other in-flight workspaces that touched files you also touched.
Check this before opening the pull request, not after CI turns red. When two workspaces genuinely overlap, the fix is usually to merge the smaller one first and rebase the other, not to coordinate the two agents. There is a lighter version of the same signal inside one workspace: declare what a session intends to touch and get an advisory warning when two sessions overlap.

4. You

The binding constraint is review capacity, not machine capacity. Four workspaces producing diffs faster than you can read them is worse than two, because unreviewed agent output accumulates into a merge problem you cannot delegate. Practical ceiling for one person: about as many workspaces as you can hold the intent of at once — usually three to five.

Moving between workspaces

mod is Cmd on macOS, Ctrl elsewhere. Rebind in Settings → Shortcuts. Overrides are stored per machine, not in .archductor/settings.toml — a keymap is a personal choice and should not travel with the repository. The format is action = chord, one per line or separated by ; or ,:
Every chord needs a modifier. Assigning a chord another action already holds clears the old binding rather than leaving the keymap ambiguous.

Layouts

Four built-in layouts, because “review three diffs” and “watch a long agent run” want different screens. Built-ins are immutable. Dragging, hiding, or resizing a panel while one is active forks it once into <name> edited, so Code always survives as a recovery baseline. Preset definitions sync through the daemon; which preset is active and how wide your regions are stay local to the device — the same layout should not follow you onto a laptop with a different screen.
set-default writes customization.view.default_layout_preset into the committed .archductor/settings.toml, preserving other keys. It is a team decision, so it belongs in the committed file.

Splitting and joining work

Fork a chat when a conversation is worth branching — you want a second approach from message 40 without losing the first.
The fork carries the conversation up to that point, so the new agent starts with the context rather than a summary of it. In the app it is on a message’s menu. Link workspaces when one needs to read another’s checkout — a frontend workspace that needs a backend branch still in flight. The target is symlinked into .context/linked-directories/<target>.
Both workspaces must be active. This is a read path for agents and build tooling, not a substitute for multi-repo projects — the product model is one repository per project. Duplicate a workspace to get the same starting point twice:

Testing in your real environment

Some setups only exist in the main checkout — a simulator, a docker-compose stack, a seeded database. Spotlight testing applies one workspace’s tracked changes onto the root checkout so you can exercise them there, then reverts.
It requires a clean root working tree and refuses if the workspace has no tracked changes. One repository has at most one active spotlight session; starting a second stops the first. A checkpoint is taken before the patch is applied.

Names

An unnamed workspace gets a city name (madrid, lisbon, …) chosen from the ones not currently in use, rather than workspace-3. Names are how you find things a week later.
Explicit --name and --branch always win.