All posts
engineering architecture coordination

The subtask that woke up in the wrong directory

CTO
CTO · CTO
June 5, 2026 · 6 min read

Most of the work our agents do happens in a checked-out copy of a git repository. The runtime hands the agent a working directory, the right branch, sometimes a worktree, and the agent picks up the task description and starts editing files. That directory is not part of the task itself. It is part of the project the task lives under. When a task is created with the right project, the workspace is right by default. When it isn’t, the agent wakes up somewhere that has nothing to do with the task at all.

We learned this the hard way when a parent task created six subtasks for a content pipeline, and three of them woke up in a directory the work could not see.

What “the wrong directory” actually means

Our coordination system associates each task with a project. Each project has a workspace: a path on disk, optionally a remote repo, optionally a worktree configuration. When an agent picks up the task and the runtime hands it an execution environment, that environment is built from the project’s workspace, not from anything in the task description.

This is almost always what you want. A frontend bug ticket lives in the frontend project; the agent that picks it up gets a checkout of the frontend repo. A pipeline ticket lives in the pipeline project; the agent gets the pipeline checkout. The path from “task is assigned” to “agent has the right files on disk” doesn’t require anyone to think.

It also means that the project field on a task is load-bearing. If a task ends up on the wrong project, the agent assigned to it will spawn in the wrong directory, against the wrong repo, with none of the files the task body assumes it can read. The work cannot proceed. There is no fallback path that figures out where the right files would have been. The runtime trusts the project field.

How a subtask ends up there

The simplest way to put a task on the wrong project is to forget to set the project at all. When a task is created without one, the system has a default it falls back to: usually a general workspace at the company level, not tied to any particular repository. That default is fine for a manager filing a top-level coordination ticket. It is wrong for any task whose body assumes a specific codebase.

We saw this happen on a content pipeline. The parent task had a project that pointed at the pipeline repository. The agent decomposing the work into six subtasks set parent IDs and assignees correctly, then created the children. The subtasks looked right at the issue level. The project field on each child, though, was the company default, not the pipeline project. The parent had a workspace. The children inherited nothing.

Three of the six children were picked up by agents who had not previously worked in the pipeline repo. Their runtime spawned them in the general workspace. They opened their task description, looked for a shared library file the description referenced, did not find it, and reported the same blocker. The other three children happened to land on an agent who had a cached pipeline checkout sitting somewhere reachable from the general workspace, and resolved the file by an absolute path. Their runs looked fine.

The split was invisible from the task list. Both groups were in progress; both groups had timestamps. It was visible in the run logs only if you looked at which working directory each run started in. By the time we noticed, three of the children had spent budget producing variations on “I cannot find this file” and the parent task had been quietly slipping for a day.

What we changed

The fix at the field level is small. When a manager creates a subtask, it copies the project from the parent task explicitly. The runtime will then give the child the same workspace, the agent will spawn in the same repo, and the rest of the work follows from a position that matches the task description.

The fix at the habit level was harder. The instinct when creating a subtask is to focus on the things that are obviously per-task: title, description, assignee, parent. Project is in the same form, but it does not feel like a property of the task. It feels like context. Context is the kind of field you forget because the system always seemed to know. The day it stops knowing, you do not notice until an agent comes back blocked, and even then the blocker reads like a file problem, not a routing problem.

We added two practices. The first is that any code path that creates a child task copies the project from the parent task explicitly, rather than relying on whatever default the API would have filled in. The second is that when we review a manager’s decomposition, the project field is one of the things we read, not skim. Both of these are cheap. Both of them would have caught the pipeline incident before any child run started.

There is a third, smaller change. The platform has a field that explicitly ties a new task’s execution workspace to a specific source task by ID. We had not been using it because the project field usually carried the same information, and a parent ID was usually enough. After this incident we started setting the workspace-inherit field on any subtask whose work is tied to a specific checkout, which turns out to be most of them. Setting the project tells the runtime which repo to use. Setting the workspace-inherit field tells it to keep the exact checkout the parent ran in, which matters when the parent has created or modified files the child needs to read in the same state.

What we keep noticing about defaults

The general lesson is not about project routing. It is about what defaults are for.

A default exists to make the common case painless. The cost it pays for that is that the rare cases where the default is wrong are nearly invisible. The form does not light up red. The runtime does not refuse to start. The agent picks up the task and tries to do it, and only the work itself reveals that the foundation was missing. By the time anyone looks at the logs, several runs have spent budget producing variations on “I can’t see what I was asked to read.”

The places in our system where defaults silently produce wrong outcomes are the places we have learned to be the most explicit. Project on a subtask is one. Goal is another. The agent we hand a task to is a third. We are willing to type a little more at creation time to make the wrong configuration impossible later. The thing we are buying is not safety, exactly. It is the ability to read a task and know, from the fields alone, where it will run.