When multiple AI tasks run at the same time, they must not write to the same files simultaneously. dotbot solves this by giving every task its own git branch and its own git worktree — a full checkout of the repository in a separate directory on disk. Each task operates in complete isolation, with its own working tree, its own staged changes, and its own commit history. Shared infrastructure like the task queue, control directory, and product documents are linked in via directory junctions (Windows) or symlinks (macOS/Linux), so every task sees the same live state without duplicating data between worktrees.
How it works
Branch and worktree creation
When a task enters the analysing state, dotbot automatically creates a dedicated git branch and worktree for it:
-
Derives a branch name from the task’s short ID and a URL-safe slug of the task name:
For example:
task/a1b2c3d4-add-user-authentication
-
Creates a worktree path under a
worktrees/ directory next to the repo root:
../worktrees/{repo-name}/task-{short-id}-{slug}/
For example: ../worktrees/my-app/task-a1b2c3d4-add-user-authentication/
-
Runs
git worktree add -b <branch> <path> <base-branch> to create the branch and check it out in the new worktree directory.
-
Links shared infrastructure into the worktree via directory junctions or symlinks so the task process can access the MCP server, task queue, product documents, hooks, and settings from the central
.bot/ directory.
Task execution in isolation
The AI agent runs entirely within the worktree directory. It reads project files, edits code, and stages commits — all within that isolated tree. It cannot accidentally modify another task’s files because those files are in a different worktree on a different branch. The shared directories linked into the worktree let the agent communicate with the rest of the system (updating task state, reading product docs) without copying data between worktrees.
Completion and cleanup
When a task reaches done, dotbot automatically cleans up the worktree:
- Removes the directory junctions so git sees only the task’s own tracked files
- Rebases the task branch onto the current base branch (brings it up to date)
- Squash-merges the task branch into main — producing a single, clean commit
- Tags the merge commit with the task short ID:
feat: <task name> [task:XXXXXXXX]
- Deletes the task branch with
git branch -D
- Removes the worktree with
git worktree remove
- Removes the entry from the worktree map in
.bot/.control/
dotbot uses squash merges so every completed task produces exactly one commit on main, regardless of how many intermediate commits the AI made during implementation.
Example paths
Given a repository named my-app cloned at ~/projects/my-app, a task with short ID a1b2c3d4 and name “Add user authentication” produces:
| Item | Path |
|---|
| Branch | task/a1b2c3d4-add-user-authentication |
| Worktree | ~/projects/worktrees/my-app/task-a1b2c3d4-add-user-authentication/ |
| Merge commit tag | feat: Add user authentication [task:a1b2c3d4] |
A second concurrent task with short ID e5f6a7b8 and name “Fix login bug” runs simultaneously at:
| Item | Path |
|---|
| Branch | task/e5f6a7b8-fix-login-bug |
| Worktree | ~/projects/worktrees/my-app/task-e5f6a7b8-fix-login-bug/ |
Both tasks work in complete isolation with no risk of conflicting edits.
Benefits
Concurrent tasks without conflicts
Because each task has its own working tree, multiple tasks can edit different parts of the codebase at the same time. dotbot’s multi-slot execution model takes full advantage of this — you can run N analysis processes and N execution processes in parallel, shortening wall-clock time for large task queues.
Clean git history
Squash merges produce one logical commit per task on the main branch. The commit message includes the task name and short ID, so the history is readable and every change is traceable back to the task that produced it. To find all commits from a specific task, search git history for its ID tag:
feat: Add user authentication [task:a1b2c3d4]
Easy rollback
The task branch exists on disk from the moment analysing starts until the squash merge completes. If something goes wrong during implementation, you can inspect the branch, cherry-pick commits, or simply delete the branch and reset the task to todo to try again.
If a process crashes before the worktree is cleaned up, the branch and worktree directory remain on disk. Run dotbot doctor to detect orphaned worktrees and clean them up safely.
Shared infrastructure links
Each worktree contains the following directory links pointing back to the central .bot/ directory:
| Link in worktree | Points to |
|---|
.bot/.control/ | Central control directory (process registry, settings) |
.bot/workspace/tasks/ | Central task queue (todo, analysing, done, …) |
.bot/workspace/product/ | Shared product documents and research outputs |
.bot/hooks/ | Verify scripts, dev lifecycle hooks |
.bot/systems/ | MCP server, runtime, UI |
.bot/recipes/ | Agents, skills, prompts, standards |
.bot/settings/ | Settings defaults |
These links mean the MCP tools in each worktree process all read from and write to the same shared state. Task state transitions, question routing, and session tracking work correctly even when many tasks are running concurrently.
Relationship to multi-slot execution
Per-task worktree isolation is what makes multi-slot concurrent execution safe. Without isolation, two AI agents writing to the same working tree at the same time would produce merge conflicts, corrupt staged changes, or cause non-deterministic test results. With isolation, each slot operates independently and the only shared state is the task queue and product documents — both accessed through the directory links under controlled conditions.