{"slug": "one-worktree-per-task-where-a-coding-agent-s-work-actually-goes", "title": "One worktree per task: where a coding agent's work actually goes", "summary": "A developer built Ordewell, an Apache 2.0 tool that gives each parallel coding-agent task its own git worktree so concurrent sessions cannot silently overwrite each other's files. The system creates worktrees from the run's integration tip, links in ignored artifacts like node_modules and virtualenvs, and lands each task as a merge commit on an integration branch through a serialized queue, aborting and preserving refs when a task fails to land. Conflicts are surfaced to the user rather than resolved silently by a model.", "body_md": "Run two coding agents at once in the same checkout and you have two writers on one tree. Both sessions look fine, both print a marker, and one has already overwritten the other's file. The fix is not a better prompt, it is a boundary: every task gets its own git worktree, and the results stay apart until you decide what lands.\n\n**Disclosure:** I build Ordewell, so this is how it does it rather than a survey of the field. It is free and Apache 2.0. The mechanics matter whether or not you install it, because every harness that runs several sessions answers the same question.\n\nThe first version is a directory and a loop: several sessions run in the workspace root, and the prompt asks the planner to keep parallel tasks on different files. That is advice to a model, not a boundary.\n\nIt fails in both directions. Two tasks that genuinely need the same file get serialized behind an invented dependency, which costs the parallelism you were paying for. And when the overlap happens anyway, it fails silently: runner B rewrites the file runner A just changed, A's completion marker still appears, and A verifies as passed against a tree that no longer holds A's work. There is a second loss too: no per-task record of what changed, so no way to undo one task without unpicking the others.\n\nWhen the workspace is a git repository, each task runs in its own worktree, created from the integration tip of the run rather than from your working tree. The worktrees sit under `.ordewell/worktrees//-`, which is already git-ignored, and each task carries its own branch.\n\nThe runner is handed a `cwd` and nothing else. Git never enters the runner adapters, so Claude Code, Codex and OpenCode cannot develop three different ideas about how work is isolated. A workspace that holds more than one repository is treated as a group: one worktree per repository per task, all on the same branch name.\n\nA fresh worktree with no `node_modules` cannot run your tests, so ignored artifacts are linked in: dependency folders, virtualenvs, environment files, agent config directories. `.ordewell/` is never linked, because session and skills state belongs at the main root where a runner cannot corrupt it. A configured setup command replaces the linking where sharing is wrong.\n\nTwo details bite. Links are recorded per task, because an ignore rule such as `node_modules/` does not match a symlink, and without that record they would be committed into the task's branch. And a whole folder link is wrong for workspaces: npm and pnpm install a workspace package as a link inside `node_modules`, which through a folder link resolves from the main checkout, so a task changing a package tests its dependents against the stale copy there. Entries are mirrored one at a time instead, and workspace links are recreated to resolve inside the worktree.\n\nIsolation makes overlap safe. It does not make overlap free. Verdicts can arrive at the same moment, so landing is a queue: one task at a time, with the lowest plan order going first among the tasks already waiting.\n\nEach task lands as a merge commit on the run's integration branch, not as loose files copied over your code. A merge commit preserves any commits the runner made itself, shows who did what in `git log`, and leaves the task branch an ancestor, which is what makes deleting it safe.\n\nA task that did not land is not a lost cause. The merge is aborted and both refs are kept, so the work is still there to inspect, retry or hand to a repair attempt. Landing across several repositories is atomic: if one repository conflicts, the merges already made for that task in the others are rolled back, so the task is conflicted as a whole rather than half landed.\n\nResolving a conflict means deciding which of two changes wins. Handing that to a model silently rewrites a merge nobody reviewed, and it makes the outcome depend on a model's word, the thing an evidence based verdict exists to avoid.\n\nSo the conflict is surfaced with the files that conflicted, and resolving it is opt in. A bounded repair attempt can run as a new attempt of the conflicted task in its own worktree, and it still lands through the same queue with the same checks: its branch has to contain the tip the repair started from and add no leftover conflict markers. If the repair did not really bring the branch along, it conflicts again rather than being taken at its word.\n\nOrdewell never merges into the branch you have checked out on its own. That is the one irreversible step, and your tree may hold work in progress. A run ends with the integration branch parked for review, the base ref it came from, and a list of what landed.\n\nMerging on request preflights every repository first: no merge already in progress, no conflict against what you have checked out, no uncommitted edit to a file the merge would change. If any repository fails the preflight, nothing is merged anywhere. Discarding removes the worktrees and task branches, and never deletes landed work you have not merged yourself.\n\n```\n# a dirty tracked tree in any repo holds the whole run\nordewell run --stash\nordewell run --without-isolation\n\n# end of run: integration branches parked, one per repo\nordewell handoff review\nordewell handoff merge\nordewell handoff discard\n```\n\nThe decisions above are written down in the repository rather than summarised from memory: ADR 0013, worktree isolation, ADR 0014, multi-repo workspaces, ADR 0015, conflict repair, the isolation interface, and github.com/ordewell/ordewell.", "url": "https://wpnews.pro/news/one-worktree-per-task-where-a-coding-agent-s-work-actually-goes", "canonical_source": "https://dev.to/ordewell/one-worktree-per-task-where-a-coding-agents-work-actually-goes-1l9h", "published_at": "2026-09-29 13:03:36+00:00", "updated_at": "2026-09-29 13:16:40.209612+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools"], "entities": ["Ordewell", "Claude Code", "Codex", "OpenCode", "git"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/one-worktree-per-task-where-a-coding-agent-s-work-actually-goes", "markdown": "https://wpnews.pro/news/one-worktree-per-task-where-a-coding-agent-s-work-actually-goes.md", "text": "https://wpnews.pro/news/one-worktree-per-task-where-a-coding-agent-s-work-actually-goes.txt", "jsonld": "https://wpnews.pro/news/one-worktree-per-task-where-a-coding-agent-s-work-actually-goes.jsonld"}}