Workspaces
DorkOS gives every task its own folder on disk, so agents never step on each other's files
Workspaces
DorkOS gives every task its own private copy of your repo, automatically. Start a session on issue DOR-84 and a second one on DOR-91, and each gets its own folder, its own dev-server ports, and its own uncommitted changes. Neither can step on the other.
That folder is called a workspace. Workspaces are on by default: the first time a session works on a specific issue or spec, DorkOS provisions one behind the scenes. If you never touch this feature, nothing changes, sessions run in whatever folder they always did.
Quick look: what you'll see
Open Workspaces from the sidebar and you'll see a card per checkout: which project it belongs to, its status, whether it has uncommitted changes, and which sessions are currently using it. While you work, the session's status bar shows a small chip like ⎇ DOR-84 · core · ● 3 changes, so you always know which workspace a session is sitting in. Both are covered in detail below.
Why workspaces exist
If two agents edit the same folder at the same time, bad things happen: racing commits, half-staged files, a dev server rebuilding out from under the other agent. Nobody wants to debug that. The fix is one checkout, one writer: give every task its own folder.
Doing that by hand means creating a git worktree (a second working copy of your repo that shares history with the original, so you're not re-cloning gigabytes for every task), picking a dev-server port that isn't already taken, and remembering to clean it up without losing uncommitted work. Workspaces automate all of it:
- Isolation: each task gets its own checkout, so parallel sessions never share a folder.
- Collision-free ports: the server hands each workspace its own block of ports, so two workspaces can both run a dev server at once.
- Dirty-safe cleanup: removing a workspace refuses to delete unsaved work unless you explicitly say to.
- Visibility: the Workspaces page and the session status bar show you what exists and where each session is working.
A workspace is just a folder. A session is "in" a workspace when its working directory (the folder it's running commands in) points at one, nothing else about the session changes.
The /workspaces page
Open Workspaces from the sidebar to see every managed checkout, grouped by project. Each card shows the workspace's identity, status, provider, its primary port, and whether it has uncommitted changes or is pinned. Below the divider, the card lists the sessions currently attached to it, click one to jump straight into that session, opened in the workspace's checkout.
Each card has two actions:
- Pin / Unpin: protect the workspace from automatic cleanup.
- Remove: delete the checkout. This is dirty-safe (see Pinning and cleanup below), so a stray click can't destroy work you haven't saved.
The page answers "what workspaces exist for this work, and which sessions are using them?", not "show me every directory on disk." It's scoped to what DorkOS manages.
Knowing which workspace you're in
When a session's working directory is a managed workspace, the Git Status item in the session status bar leads with the workspace identity instead of a bare branch name:
⎇ DOR-84 · core · ● 3 changesThat reads as: you're in the DOR-84 workspace of the core project, with 3 uncommitted changes. (Yes, DOR-84 is a real ticket. We used it while building this feature and never got around to swapping in a placeholder.) Hovering the chip reveals the branch, provider, allocated ports, and pinned state. If the session is in an ordinary folder instead of a managed workspace, the item just shows the normal branch chip, nothing changes.
The Git Status item is shown on desktop-width layouts. If you don't see it, enable it from the status-bar configuration popover.
Reference
Most people never need what's below. This is the developer-facing tail, for anyone scripting against the API or tuning config.json.
Anatomy of a workspace
Every workspace has a stable identity and a provisioned checkout:
Prop
Type
The projectKey + key pair is unique, so asking for the same unit of work twice returns the same workspace rather than provisioning a duplicate.
Binding a session to a workspace
Binding is opt-in, and most people never do it by hand, the DorkOS client sends this automatically when you start work on an issue or spec through the UI. It's shown here as the reference form, for anyone calling the API directly.
When you send a message to a session, include a workspaceKey (and optionally a workspaceProvider) and the server will ensure the workspace exists, provisioning it on first use, then run the turn with the workspace's checkout as the working directory and its port block injected into the environment:
curl -X POST http://localhost:4242/api/sessions/{sessionId}/messages \
-H "Content-Type: application/json" \
-d '{
"content": "Start on the workspace manager",
"workspaceKey": "DOR-84",
"workspaceProvider": "worktree"
}'Omit workspaceKey and the session runs in whatever cwd it already had, the path is byte-for-byte unchanged. If the WorkspaceManager is disabled, or fails to provision for any reason, the turn falls back to the supplied cwd instead of erroring, so binding can never break a session.
Ports
Each workspace reserves a contiguous block of ports so multiple workspaces can run dev servers simultaneously without clashing. Ports derive from the workspace's portBase:
Prop
Type
The server allocates the lowest free block, so two workspaces are guaranteed disjoint ports. With the default portBase of 4250 and a block size of 10, the first workspace gets 4250/4251/4252, the next 4260/4261/4262, and so on. The allocated values are written into the workspace's .env file, so a dev server started inside the checkout picks them up automatically, no manual port-hunting required.
Pinning and cleanup
Removing a workspace deletes its checkout, so it's deliberately conservative:
- Dirty-safe removal. Remove first checks the checkout for uncommitted, untracked, or unpushed work. If any exists, the request is refused and the UI re-prompts with an explicit force confirmation rather than silently destroying work, so you can't fat-finger delete on something you haven't saved. Forcing deletes it permanently.
- Pinning. A pinned workspace is exempt from automatic cleanup. Pin a workspace you want to keep around regardless of retention policy; the pin persists and shows on the card and in the status-bar chip tooltip.
Pinning protects against automatic cleanup, not against an explicit remove. The two guards are independent: dirty-state protects unsaved work; pinning protects from reclamation policy.
Providers
A workspace's provider determines how its checkout is created:
| Provider | How it's created | When to use it |
|---|---|---|
| worktree | A git worktree off the existing repo (shares the object store). | Default. Fast, space-efficient, ideal for branches of the same repo. |
| clone | A full git clone into the workspace path. | When you need a fully independent copy rather than a linked worktree. |
The default provider is configurable (workspace.defaultProvider); callers can override it per-request with workspaceProvider.
Configuration Reference
Workspaces are configured under workspace in ~/.dork/config.json:
Prop
Type
API Reference
All endpoints are under /api/workspaces:
| Method & path | Purpose |
|---|---|
GET /api/workspaces | List workspaces (optionally ?projectKey=), each with attached sessions and dirty state. |
GET /api/workspaces/resolve | Resolve a workspace from an absolute ?path=: powers the session status-bar indicator. |
POST /api/workspaces/ports | Preview the port block a given checkout path would receive. |
POST /api/workspaces | Ensure a workspace ({ projectKey, key, source, provider? }): provisions on first use. |
GET /api/workspaces/:id | Fetch a single workspace. |
POST /api/workspaces/:id/pin | Pin or unpin ({ pinned: boolean }). |
DELETE /api/workspaces/:id | Remove (?force=true to override a dirty refusal). |
DELETE returns 200 with { removed: false, blocked: 'dirty' } when it refuses a dirty
workspace (not a 4xx), so clients can distinguish "blocked, ask to force" from a real error.
A 404 means the workspace genuinely doesn't exist.