DorkOS
Guides

Workspaces

Give each task its own folder on disk, so agents never step on each other's files

Workspaces

DorkOS can give every task its own private copy of your repo. Ask for one workspace for issue DOR-84 and another for 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. Today, workspaces are created on request: a tool or script asks the server for one (the API below), and DorkOS provisions it. Nothing in the DorkOS app creates them on its own yet. If you never ask for one, sessions run in whatever folder they always did.

Quick look: what you'll see

Open the Workspaces tab on Home and you'll see every separate copy of your code that exists in your workspaces folder, grouped by project. Each row tells you its branch, how many files have unsaved changes, how it compares to the remote, and when it last got a commit. 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 the Workspaces tab on Home to see the real copies of your code sitting in your workspaces folder, grouped by the project folder they live in. Each row shows:

  • Folder: the copy's name, and where it is on disk.
  • Branch: the branch it has checked out. A copy parked on a specific commit instead of a branch reads "No branch".
  • Changes: how many files hold edits you haven't committed. "Clean" means none.
  • Compared to remote: how many commits it is ahead of or behind the branch it tracks. A branch that tracks nothing shows a dash, because there is nothing to compare it against. "Branch merged or deleted" means the branch it followed is gone from the remote, which usually means the pull request merged. Those are the copies you can most safely clean up.
  • Last commit: when work last landed there, so you can spot copies you're done with.

The page only reads. It never creates, changes, or deletes a copy. Other agents are working in these folders right now, so a stray click here can't cost anyone their work.

A folder DorkOS can't read shows up too, marked "Can't read", instead of quietly disappearing. That usually means the original repo moved or was deleted. It's the one folder you most want to know about, so it always gets a row.

The page also refuses to guess when it doesn't know. If a whole folder can't be opened, a note at the top says the list may be incomplete and names the folder. If the scan itself fails, you get "Couldn't check your worktrees" rather than an empty list, because "you have none" and "we couldn't look" are very different answers.

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 changes

That 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 status line stays quiet about git while the working tree is clean and you're on the default branch. If you'd rather always see it, open the Session panel from the at the end of the status line and pin the Git row.


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. Nothing in the DorkOS app sends a workspaceKey yet, so today binding happens only when you (or a tool you run) call the API directly. Here is the reference form.

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 caller has to ask again with an explicit force. Forcing deletes it permanently.
  • Pinning. Pin a workspace you want to keep. DorkOS does not reclaim old workspaces on a schedule yet; when retention cleanup does run, it never removes a pinned workspace. The pin shows in the status-bar chip tooltip.

Pinning protects against retention cleanup, not against an explicit remove. The two guards are independent: dirty-state protects unsaved work; pinning protects from reclamation policy.

Removing and pinning are API-only. Neither the Workspaces page nor anything else in the app can delete a checkout, so a mis-click can never take one out from under a running agent.

Providers

A workspace's provider determines how its checkout is created:

ProviderHow it's createdWhen to use it
worktreeA git worktree off the existing repo (shares the object store).Default. Fast, space-efficient, ideal for branches of the same repo.
cloneA 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 & pathPurpose
GET /api/workspaces/scanRead-only scan of the workspace root: every checkout on disk. Backs the Workspaces page.
GET /api/workspacesList workspaces (optionally ?projectKey=), each with attached sessions and dirty state.
GET /api/workspaces/resolveResolve a workspace from an absolute ?path=: powers the session status-bar indicator.
POST /api/workspaces/portsPreview the port block a given checkout path would receive.
POST /api/workspacesEnsure a workspace ({ projectKey, key, source, provider? }): provisions on first use.
GET /api/workspaces/:idFetch a single workspace.
POST /api/workspaces/:id/pinPin or unpin ({ pinned: boolean }).
DELETE /api/workspaces/:idRemove (?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.

Next Steps