Two agents report success. One changed the billing interface; the other changed the function that supplies it. Each tested a working copy that contained only its own edits. When the changes meet, the interface asks for a field the function no longer returns. Neither report was a lie. Neither established that the combined product worked.
Concurrent coding agents need explicit ownership, separate working state, agreed interfaces and one integration sequence. Parallelism can shorten independent work. It can also increase the amount of coordination needed to reach an accepted change. A team should measure the result after integration, including the review and repair burden, rather than count how many agents were active.
This chapter of The AI Software Factory addresses repository concurrency. The broader multi-agent coding team explains roles and handoffs; deterministic orchestration explains control flow. Here the question is physical and specific: which agent can change which files, against which baseline, and what happens when the changes meet? The billing example and all timing examples below are hypothetical.
Shared context does not mean shared authority
Giving several agents the same task description creates a common starting point. It does not tell them whether they may edit the same helper, regenerate the same lockfile or update the same configuration. An agent solving a reasonable local problem may widen its scope because the shared helper seems like the easiest route. Another may make a different, equally plausible choice.
The first coordination artifact should therefore be an ownership map. For each task, name the files or directories it may edit, the interfaces it must preserve and the conditions that require a handoff. A task can have broad read access and narrow write access. That distinction lets an agent understand the surrounding product without silently becoming its owner.
For a hypothetical subscription improvement, one worker owns the subscription status endpoint and its integration tests. Another owns the account page and its user-facing tests. A coordinator owns the shared response type and release configuration. If either worker needs a different response shape, it submits a proposal to the coordinator before changing that contract.
Ownership is a temporary coordination agreement, not a declaration that only one person can ever understand a module. Its purpose is to make the current change inspectable. When a task moves, the ownership map should move with it; old instructions left in an agent’s context can otherwise remain active after responsibility has changed.
Choose the baseline before dispatch
A worker’s report is meaningful only in relation to a known starting state. Record the commit or other reproducible baseline, the task specification and the accepted dependency versions. If the coordinator begins on one branch while a worker begins on another, a clean-looking diff may include unrelated changes.
Uncommitted work makes this question more delicate. A worker may need those changes to understand the real task, but a newly isolated checkout may not contain them. The coordinator should decide whether to preserve the current state as a reviewed checkpoint, give the worker a specific patch or postpone delegation until the baseline is clear. Quietly assuming that a new working copy includes the owner’s current edits is a route to accidental omission.
The baseline also belongs in the handoff report. A worker should say which starting state it used and whether it updated against later changes. If its work relies on another worker’s unmerged result, that dependency should be explicit. The coordinator can then choose a valid integration order rather than discover the dependency through a broken build.
Separate working directories protect files, not semantics
Git worktrees let a repository maintain multiple working directories associated with separate checked-out branches while sharing repository data. That provides a useful way to isolate concurrent edits. Git’s worktree documentation describes the mechanism and management commands. It does not claim that changes developed separately will integrate correctly.
A separate directory prevents one worker from overwriting the file another is currently editing. It also lets each worker run tools against a stable local view. Those are substantial benefits. They do not stop two workers from making incompatible assumptions about the same domain concept.
Suppose one worker interprets a subscription marked “past due” as still entitled to access, while another treats that status as immediate cancellation. Their files may never overlap. The merge may be mechanically clean. The product can still present a contradiction between the account page and access control.
Isolation should therefore accompany a short interface agreement. Describe meanings, allowed states, error behavior and compatibility expectations, not merely function names. If a response says active, explain whether that means paid, entitled or currently within a grace period. Different meanings require different fields or an explicit mapping.
For small, clearly separated editorial or data tasks, shared-directory work can be reasonable with strict file ownership. For code touching shared dependencies, independent branches and working directories often make review easier. The right choice depends on the change’s coupling, the available tooling and the cost of maintaining isolated environments.
Detect the files that attract collisions
Some files collect changes from almost every feature: package lockfiles, application routes, generated indexes, shared types, migration registries and global styles. Assigning two otherwise separate features can still produce competition over these files.
Mark them as integration-owned before work starts. A worker that needs a dependency can request the dependency with its reason and version constraints. The coordinator changes the package manifest and lockfile once, then communicates the accepted result. This avoids competing installations that each create a different graph.
Generated files deserve the same treatment. If three workers each regenerate a global catalog from their own incomplete branch, their outputs can erase one another’s entries. It is usually easier to merge source records first and generate the combined artifact afterward. The generation step should run from the state intended for review.
Database migrations are particularly sensitive because ordering, application state and production data matter. Workers can propose independent migrations, but a coordinator should inspect their combined order and compatibility. A file named with a later timestamp does not prove that it can run after the other change or that the previous application version can survive it.
The ownership map should distinguish source files, generated artifacts and operational actions. A worker may own the source for a deployment configuration without having authority to deploy it. Safe AI writes explains the commitment boundary; concurrency should preserve that boundary rather than expand permissions because a task is busy.
Dispatch artifacts that can be checked
“Improve billing” is an invitation to broad interpretation. A useful concurrent task is narrower: “Implement the subscription status endpoint against response contract version two, preserving the existing entitlement policy; own these files; add cases for the named states; report any policy ambiguity before changing it.”
The dispatch should include the intended behavior, exclusions, owned files, expected inputs and the evidence required at handoff. It should also say what to do when the task cannot remain within its boundary. The worker might return a contract-change proposal, a blocker with reproduction details or a smaller completed patch. It should not silently edit another worker’s module.
A report should connect evidence to the artifact it describes. “Tests passed” needs the test scope and the change state. A unit test for parsing a response says little about the page that consumes it. A successful build says little about whether a billing event is recorded only once. The coordinator needs enough detail to understand what remains untested.
Reports also need uncertainty. If the worker used a stubbed external service, say so. If a live check was unavailable, record that limit. If a test was already failing at baseline, preserve the reproduction rather than attributing every failure to the new change or dismissing it as unrelated without inspection.
Integrate in dependency order
A coordinator should have one integration lane. Accepted patches enter in an order that respects their dependencies, and the combined state receives checks before the next consequential action. Several agents committing independently to the same release branch make it harder to identify which change produced a failure.
For the subscription example, the agreed response contract enters first. The endpoint follows. The account page then integrates against that endpoint. The coordinator runs the focused combined checks and inspects the diff for unintended behavior. If the page introduces a new requirement, that requirement returns to the contract discussion rather than becoming a quiet last-minute exception.
GitHub pull requests provide a place to review diffs, discussion and checks before merging. Its pull request reference describes those review surfaces. The useful operating discipline is to attach acceptance evidence to the proposed change and inspect the combined result; simply opening a pull request does not supply that evidence.
Integration order does not require every task to run sequentially. A worker can draft documentation while another prepares tests. It means that the shared accepted state advances through an accountable sequence. Work remains parallel; commitment is coordinated.
A clean merge can still be a failed integration
Text conflicts are conspicuous. Semantic conflicts can survive until a customer uses the product. Look for changed assumptions about state, units, ownership, errors and timing. Those conflicts often appear across files that never collide.
A support dashboard may display a dollar amount while the endpoint returns cents. An export may use the customer’s timezone while a scheduled job groups events in UTC. One module may retry a write automatically while another assumes the first failure ended the operation. Each implementation can look sensible in isolation.
Combined tests should follow complete customer jobs across these boundaries. For billing, that may mean changing a plan, receiving the event, updating entitlement and showing the resulting state. Include a retry and a delayed event if those conditions matter to the promise. Behavior-based testing gives these checks their natural home.
Review the language as well as the code. A function named cancelled can conceal a distinction between cancellation requested and cancellation effective. A model-generated comment may confidently describe the wrong policy. Contract definitions and examples should make those meanings visible before the feature reaches a user.
Handle a collision without erasing evidence
When two workers change the same file despite the ownership agreement, stop the competing edits first. Preserve both diffs and identify what each was trying to achieve. Repeatedly asking each agent to “fix the conflict” while both continue editing can create an oscillation rather than a resolution.
The coordinator should separate compatible additions from incompatible decisions. Two new tests may coexist. Two different interpretations of access policy require a decision from the responsible owner. A merge tool can combine text; it cannot legitimately choose the business rule.
Once the rule is settled, assign one worker the reconciliation. Give it both proposals, the chosen behavior and the acceptance cases. The other worker can review the resulting patch without writing to the same file. This restores a single owner while retaining independent scrutiny.
A collision report can improve the next dispatch. Was the shared helper omitted from the ownership map? Did the interface contract lack an error state? Did one task become broader after the first test? The aim is to repair the task decomposition rather than treat every conflict as an individual agent failure.
Parallelism has an economic limit
A hypothetical feature takes six hours of implementation and two hours of integration when one worker handles it. Splitting the implementation among three workers might reduce the longest implementation path to three hours while increasing integration to four. Elapsed completion time becomes seven hours rather than eight, and total worker effort may rise. That can be worthwhile, but it is a different result from tripling productivity.
Measure accepted completion time, total model and tool cost, reviewer time, repair work and failure severity. Preserve a comparable baseline. Some tasks are excellent parallel candidates: independent route checks, separate modules with stable contracts, source research or review from different perspectives. Others are heavily coupled: a central state model, a broad migration or a small function whose behavior is still disputed.
The bottleneck may shift to the coordinator. Every worker returns a patch, a question and a claim of completion. If the owner cannot inspect them at the rate they arrive, additional workers increase the queue. A bounded number of active tasks can produce faster accepted output than an unrestricted swarm.
These observations are operating hypotheses, not a measured claim about Salars or a universal optimal team size. A team can run a small comparison using similar changes and inspect the results. It should avoid changing the staffing policy based only on one unusually easy or unusually difficult feature.
Check the task boundary when requirements change
An apparently independent feature can become coupled after new evidence arrives. A worker may discover that a shared parser has no reliable way to represent a missing currency. It should report the discovery with a reproduction and proposed contract change before expanding its edit scope. The coordinator can revise the ownership map, pause dependent work and distribute the new agreement. This costs time at the moment of discovery, but it makes the actual dependency visible. Continuing under the old task descriptions would leave every worker optimizing against a contract the product can no longer satisfy.
Preserve a stop and recovery path
A worker can lose its context, exceed its task boundary or become unavailable. The coordinator should be able to inspect its current changes without relying on a final narrative. Periodic checkpoints and a clear list of owned files make recovery possible.
Do not assume that an interrupted worker completed a write atomically. Inspect the working state, preserve useful changes and rerun relevant checks. If the agent returns later, tell it which responsibility has moved; otherwise it may resume editing files another worker now owns.
The same principle applies to branches. Before deleting an isolated checkout, ensure that accepted work is integrated and unaccepted work is either preserved for review or intentionally discarded. Cleanup should follow the team’s normal repository process. Temporary isolation is useful only if the evidence it contains is not lost during handoff.
A release should have one accountable owner even when many agents contributed. That owner verifies the intended artifact and the deployment result. A collection of locally successful reports cannot substitute for checking the state customers actually receive.
What Would We Do at Salars?
A proposed Salars Forge pilot would begin with one small app and a limited team. Each task would name an exact baseline, owned files, interfaces and acceptance evidence. The root coordinator would own shared configuration, manifests and integration. Independent workers would handle clearly separated implementation or review tasks.
For a proposed Supplier Margin Guard feature, one worker might implement a supplier-record parser while another drafts the merchant-facing explanation. A third could prepare independent cases from the agreed specification. The parser and explanation would use a shared evidence contract defining amounts, currencies, timestamps and missing values. No worker would gain permission to change live supplier terms or publish customer claims merely because it could edit code.
The experiment would retain total accepted-change cost, integration time and failures across boundaries. If coordination consumed the expected benefit, the next task would use fewer concurrent workers or a narrower split. Forge would treat team size as a decision to evaluate, not a badge of sophistication.
The next accepted change should have a traceable path from task to patch to combined verification. When that path is clear, multiple agents can add capacity without making responsibility disappear.
Sources
- Git: worktree documentation, read October 7, 2026, for separate working-directory mechanics.
- GitHub: pull request reference, read October 7, 2026, for review and check surfaces.
- Salars AI library, for related practical guides. The concurrency policies and examples here are proposed operating designs, not reported production measurements.
Loading comments…