Quartet / Quintet

2026-09-04  ·  git · githubactions · design · claudecode

What Kills Parallel Development Is Always Shared Files

Has this ever happened to you when trying to run multiple tasks in parallel?

The cause is usually a shared file. And this can be avoided by how you split the work.

I’ve encountered this repeatedly when using AI to implement features in parallel, so I’ll outline patterns and countermeasures. This isn’t limited to AI; the same issues occur in human teams.

The Culprits Are Usually Predictable

The files that actually conflicted were almost always one of these five types:

They share a common trait: they are lists. A structure that adds one line every time a new feature is added will inevitably cause multiple people (or agents) to edit the same location simultaneously.

Worse yet, conflicts here are semantically harmless. Person A adds one line, Person B adds another. Keeping both results in the correct state. Yet Git cannot resolve them automatically, halting human progress.

Countermeasure 1: Tackle Shared Files First

This is the most effective approach. Isolate the task involving shared files and run it first.

Issue #10  Add three entries to route definitions       Scope: src/routes/index.ts
Issue #11  Implement settings page                      Scope: src/pages/settings/**   Depends on #10
Issue #12  Implement billing page                       Scope: src/pages/billing/**    Depends on #10
Issue #13  Implement notifications page                 Scope: src/pages/notifications/**  Depends on #10

#10 only requires "adding routes to screens that don’t exist yet," so it finishes in minutes. After that, #11, #12, and #13 do not touch any shared files, allowing them to run completely in parallel.

This won’t work if the order is reversed. If you implement #11 while also adding routes, all three will compete for the same file.

"Is it weird to add routes to non-existent screens?"

You might worry that this temporarily breaks the build. In reality, it passes if you leave placeholder components in place.

// src/pages/settings/index.tsx  ← #11 implements the actual content
export default function Settings() {
  return null;
}

Place empty boxes first. That alone enables parallelization.

Countermeasure 2: Adopt Structures Without Lists

If you can eliminate "list files" altogether, that is more fundamental.

It’s worth isolating this as a single task. Once done, future parallelization becomes much easier.

However, doing this abruptly in an existing project has a wide impact scope, so it’s good to have a criterion like "change the structure after three conflicts."

Countermeasure 3: Decide Not to Touch What You Can’t Touch

When having AI implement features, this is effective. Explicitly define the scope of responsibility, and stop and report if the scope is exceeded.

- Do not modify paths outside the Scope written in your assigned task
- If changes outside the Scope are required, stop implementation and report

If changes expand silently, information indicating that the split was wrong disappears. If it stops, you can fix the split there.

Here is a real example. During one task, a report came from the implementer:

tsc --noEmit cannot resolve types for node:path because @types/node is missing in devDependencies. I did not modify package.json as it is out of Scope. Please decide whether to isolate this as a separate task.

This is a deficiency in the foundation, not due to that specific task. If package.json had been modified without permission, unrelated changes would have mixed into that PR, blurring the review criteria. It was isolated as a separate task and fixed via an independent PR.

Countermeasure 4: Merge Serially

Even if splitting is correct, parallel merging ruins it.

Merging three PRs simultaneously can cause failures after all three are merged, even though each passed tests individually. And you cannot determine which one is the cause. You end up re-examining all three, making it slower than serial merging.

If you merge one by one, each subsequent PR is evaluated against the state of main at that time. If it breaks, you can confirm the previous single item was the cause.

Implementation in parallel, merging in serial. That is the practical conclusion.

Conflicts Are Symptoms, Not Causes

When conflicts occur repeatedly, improving how you resolve them is meaningless. Your splitting method is wrong.

The frequency of conflicts can serve as a metric for the quality of your split.

Frequency What It Indicates
Rarely happens Splitting is effective
Happens occasionally Unexpected dependencies exist. Resolving them per occurrence is sufficient
Happens every time Multiple tasks are competing for shared files. Re-evaluate the split

If it happens every time and you resolve it ad hoc, symptoms disappear but the cause remains, and costs continue to rise.

Summary

I have documented this splitting approach as a configuration for Claude Code’s sub-agents and published it under the MIT license.


I publish the configuration for splitting Claude Code into separate personas — Architect, Coder, Reviewer, Conflict Resolver — under MIT. Copy it, run ./setup.sh, and it works. It does not depend on your tech stack.

https://github.com/quintetkit/quartet

I built one real tool using nothing but this workflow. Every Issue, PR, review and merge is still there. The parts that went wrong were not deleted.

https://github.com/quintetkit/mdlinkcheck

The version that adds a UI Designer persona, review criteria, a per-Issue parallel execution script and a 10-chapter guide is on the product page.

The workflow itself is available

Quartet, the four-persona version, is published free under MIT. Quintet adds a UI Designer persona, review criteria, a per-Issue parallel execution script, and a 10-chapter guide.

See the free version Product page