Two AI Agents, One Migration Chain
Everyone publishes what worked. This publishes what broke, and the rule it became.
Two AI workers were asked to move in parallel. That sounded efficient until both reached the same migration chain. They each created revision 0066. The deploy stopped because the database no longer had one unambiguous next step.
One worker also edited a file it should never have touched. It had not disobeyed a warning; it had never received the warning. Ownership was implicit, and sub-agents inherit no context.
Parallel code work is safe only when the paths and the serial bottlenecks are explicit.
- Why do parallel agents collide on migrations?
- How should prompts declare ownership?
- What should an integrator own after workers report back?

The collision was deterministic
The workers were not sharing a conversation. Each saw its own task and its own local truth. The schema change looked like ordinary work: create the next migration, run the tests, report back.
But a migration revision is not an ordinary file. It is a link in a chain. Two workers choosing the next identifier at the same time produce two branches, even if their schema edits do not overlap line by line. The result was duplicate heads and a blocked deployment.
The second failure was more instructive. A do-not-edit file existed, but the worker had never seen that boundary. “Do not touch the protected file” was true in the coordinator’s head and absent from the worker’s prompt. The system had a policy without inheritance.
The fix is intentionally less magical than the failure. It does not ask a language model to infer ownership from the task description. It makes the boundary part of the interface, so a worker can refuse an out-of-scope request without guessing.
The prompt contract became literal
The parallel-agent rule now says that two concurrent agents must not be able to reach the same file, subsystem, migration chain, or schema. Disjointness is declared in each prompt, never assumed.
Every prompt restates the owned paths as an explicit glob list. It says the worker may edit only those paths. It names everything else as forbidden. If the task needs a file outside the owned paths, the worker stops and reports back rather than “just checking” or editing it.
The prompt also carries the project root and slug, the do-not-edit list, and two negative instructions: the worker does not create or edit migrations, and it does not spawn further sub-agents. This looks repetitive because it is repetitive. Repetition is how context crosses an agent boundary.
The migration lock
Migration revisions are now created by exactly one actor, serially, after every parallel worker has reported back. Workers emit a migration intent: a plain-text description of the schema delta. They do not emit a revision file or a revision identifier.
The integrator reads those intents, assigns the revision ids, runs the full suite, and merges the work. Before the merge, alembic heads must return exactly 1 head. More than one means stop the wave and reconcile serially.
That is a small constraint with a large payoff. Parallelism remains available for independent application code, tests, documentation, and analysis. The one resource that must be serialized is serialized. The system stops asking a distributed set of workers to coordinate a globally ordered chain by accident.
This division also improves recovery. When a serial resource is blocked, the integrator has a clear queue of intents to reconcile instead of a pile of competing files whose authors no longer share the same assumptions.
Serial ownership makes the final check observable and repeatable.
The handoff is the interface
I used to think the integration point was the merge. It is earlier than that. The integration point is the worker’s report.
A useful report says what path changed, what contract it exercised, and what migration intent the integrator must apply later. It does not smuggle in a new revision file for someone else to discover during merge conflict resolution.
That makes the integrator a real role rather than a person who presses merge after the fact. The integrator owns ordering, the final revision ids, the full suite, and the one-head check. Workers own bounded edits and evidence about those edits.
The operating rule
I still use parallel agents. I just no longer parallelize the parts that are inherently serial. Every worker receives the same boundary in its own prompt. Migration work stops at intent. One integrator assigns revisions and checks that the chain has exactly one head.
The durable lesson is not “never use two agents.” It is “never let two agents believe they own the same ordered resource.”
If you run agents, do this
- Declare owned paths and forbidden paths in every prompt.
- Restate do-not-edit files because workers inherit no context.
- Tell workers not to create migrations or spawn agents.
- Collect migration intent, never parallel revision files.
- Let one integrator assign revisions serially.
- Require
alembic headsto return exactly 1 head before merge.
