{"slug": "my-agents-had-their-own-branches-they-did-not-have-their-own-time", "title": "My agents had their own branches. They did not have their own time.", "summary": "A developer built a multi-agent code factory using Google ADK and gemini-3.7-flash, where a manager agent delegates subtasks to engineer agents in isolated git worktrees and merges results behind a test gate. The project completed five subtasks in under a minute, but the developer found that dependency graphs and forbidden-file checks required explicit human-written rules, as models could not reliably derive them from build plans. The system now includes a diff-based guard that aborts runs if protected files are touched.", "body_md": "I spent a day building a code factory: a manager agent that reads a project's own build plan, works out what can be built in parallel, hands each subtask to an engineer in an isolated workspace, and merges the result behind a test gate.\n\nIt works. Five subtasks built, tested, merged and logged in under a minute, on a backlog that was written weeks before the factory existed.\n\nThree things about it were wrong on the way there. None of them showed up in the design, in review, or in the tests. All three showed up in the log, and two of them only because I went looking for something else.\n\nA manager agent on Google ADK, running `gemini-3.7-flash`\n\n. Six tools: read the graph, read what the human pointed at, delegate, poll, merge, finish. The engineers work in their own `git worktree`\n\non their own branch, run the tests for the area they touched, and commit. The manager merges to one trial branch, one at a time.\n\nThe design comes from a paper by Geng and Neubig on asynchronous software engineering agents, which measures something worth repeating: two runs on the same repository, the same model, differing only in which files got assigned, scored 8.7% and 34.3%. The expensive decision is not the code. It is what goes out next.\n\nSo that is the decision I gave to the model, and only that one.\n\nThe manager was supposed to read the dependency graph out of the build plan. That is a 1,300-line document with 115 open subtasks, written over three weeks by someone who knew exactly what depended on what.\n\nI searched it for every phrasing I could think of. **One subtask states its dependency in a form a machine can read.** One, in the whole document.\n\nThe order lives in the head of whoever wrote the plan, and a manager cannot get in there. An agent asked to \"derive the graph from the plan\" will find that single edge, invent the rest, and say nothing about which is which.\n\nSo the edges are now written by hand, per run, in a file the human can see and correct. The builder refuses a run where a subtask has no entry: an empty list means \"checked, independent\", and a missing entry means \"nobody looked\". Those are different things, and only one of them is safe.\n\nThe one edge the plan does state is the interesting one. Subtask 7.3 requires four subtasks from another phase that are not part of this run. Every run I have done leaves 7.3 alone and says why on the dashboard. A manager that had guessed the graph would have built it, against a service that does not exist yet.\n\nSome files must not be touched by an engineer. The build plan itself is the sharpest case: it holds every checkbox, every log line, and a running total that has to be added up by hand. Two writers on that file is exactly how it went wrong twice in this repository already, and neither time did git say anything, because the two writers touched different lines.\n\nThe first version of the manager's instruction said: do not touch these paths. That reads fine and is worth nothing. A model that can be asked not to do something can be argued into doing it, and the log will show a confident sentence either way.\n\nThe check now runs on the diff, in code, immediately before the merge:\n\n```\ngit diff --name-only base...branch | config.py --stand -\n```\n\nOne match and the run ends. Not a warning, not a retry, not a fix. The reason is not tidiness: once a forbidden file has been touched, I can no longer tell whether the bookkeeping is right, and a factory whose bookkeeping might be wrong is worse than no factory.\n\nThe path matcher has its own test table with 18 cases, and the ones that matter most are the **non**-matches. `services/watchdog/BUILDPLAN.md`\n\nis allowed, because only the one at the root is the status document. A pattern that is too wide stops a run over work that was always fine, and that costs exactly as much as a rule that does not fire.\n\nThis is the one I would have shipped.\n\nSomeone asked me a simple question: do the engineers work in their own branches? They do. Own branch, own worktree, visible in `git worktree list`\n\n. I pulled up the log to show it, and the log answered a question I had not asked.\n\n```\n15:22:02  eng-1  klaar      7.1 done\n15:22:03  eng-2  opgewarmd  worktree on proef/fase7-caid-eng-2\n```\n\nThe first engineer finished before the second one started. The workspaces were isolated, the branches were real, the merges were test-gated, and the whole thing ran one after the other. The engineer loop was synchronous, and nothing in the design, the dashboard or the tests had any opinion about that.\n\nThe paper this is built on is about *asynchronous* collaboration. Isolation without concurrency is branch-and-merge without the reason for it. And in a demo it would have been a claim I could not support: two lanes side by side on the screen, filling in sequence.\n\nEngineers now start in their own thread and the manager does not wait. Merging stays sequential, which is not an omission. Integration is one at a time and test-gated precisely so that building can be parallel.\n\nAfterwards the log interleaves, which is the only way I know to check it:\n\n```\n15:25:48  eng-2  begonnen\n15:25:48  eng-1  begonnen\n15:25:48  eng-1  toets      groen\n15:25:48  eng-2  toets      ...\n15:25:48  eng-1  commit     d53e7ba\n15:25:48  eng-2  commit     69e2bf1\n```\n\nAll three findings came out of one design decision I did get right, and it was the first one I made.\n\nEvery line in the log carries its source. **Reported** is what the agent says about itself: rich, early, and not to be trusted, because an agent that has lost the thread reports progress that is not there. **Measured** is what git says: thin, late, and impossible to fake. A commit exists or it does not.\n\nThe dashboard marks the two differently, and two of its eight warnings fire exactly where they disagree: an engineer that reports three times with no measured change, and silence on both sides past a threshold.\n\nFinding three was a timestamp comparison between two measured lines. If the log had held only what the agents said about themselves, the answer would have been \"yes, both engineers worked on it\", and that would have been true and useless.\n\nOne run, on one repository, on a backlog I chose. The paper behind it measures a spread from +30.7 to −10.5 percentage points *between repositories*, so a single result sits inside its own noise.\n\nThe headline numbers are worth reading carefully as well. The abstract reports +25.6 percentage points, and that is the weakest of the three models tested. For the strongest model the same table shows +6.1 and +6.0, at roughly two to four times the cost, and the wall-clock goes **up** in every row. Coordination buys accuracy, not speed. Anyone selling you the opposite has not read the runtime column.\n\nWhat I can say is narrower and I think more useful: the mechanism runs, the guardrail holds when tested against it, and the two failures I found were both invisible until something ran and wrote down what it actually did.\n\nBuilt at [Business Data Solutions](https://dev.to/), a Dutch consulting and training firm that helps organisations put their data to work. The factory runs against Plinkie, a price-comparison system we operate on Google Cloud, so the backlog it builds is a real one.\n\nIf you are working out where an agent belongs in your own delivery process, or where it does not, we are happy to think along. You can reach us through the [contact form](https://dev.to/#contact).\n\nWe wrote this piece for the purposes of entering the All Things Agentic Hackathon run by Google Cloud and Devpost.", "url": "https://wpnews.pro/news/my-agents-had-their-own-branches-they-did-not-have-their-own-time", "canonical_source": "https://dev.to/witekth/my-agents-had-their-own-branches-they-did-not-have-their-own-time-5bnj", "published_at": "2026-08-30 18:14:17+00:00", "updated_at": "2026-08-30 18:53:09.401384+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "mlops"], "entities": ["Google ADK", "gemini-3.7-flash", "Geng", "Neubig"], "alternates": {"html": "https://wpnews.pro/news/my-agents-had-their-own-branches-they-did-not-have-their-own-time", "markdown": "https://wpnews.pro/news/my-agents-had-their-own-branches-they-did-not-have-their-own-time.md", "text": "https://wpnews.pro/news/my-agents-had-their-own-branches-they-did-not-have-their-own-time.txt", "jsonld": "https://wpnews.pro/news/my-agents-had-their-own-branches-they-did-not-have-their-own-time.jsonld"}}