October 30, 2026

10x Your Modernization Efforts With Multi-Agent Teams

One agent porting one file at a time stalls fast. Teams getting big gains split the work across an orchestrator, parallel porters, a test writer and an independent reviewer. Here is how that setup works and where the speed-up really comes from.

10x Your Modernization Efforts With Multi-Agent Teams

Most teams try AI on an application migration the same way: one chat, one agent, one file at a time. It works for a demo. Then the codebase turns out to have 400 components, a router nobody fully understands and a service layer with side effects in every getter, and the single agent becomes the bottleneck. It forgets what it ported yesterday, repeats the same mistakes, and marks its own homework.

The teams getting large gains don't use a smarter agent. They use more agents with narrower jobs, coordinated around a plan. This post covers how that setup works, where the speed-up really comes from, and what has to be true before you get anything close to 10x.

Why one agent stalls

A single agent doing a migration carries the whole project in one context window: the old code, the new code, the conventions, the test output and its own earlier decisions. As the window fills, quality drops. It starts to drift from conventions it set itself, and it re-reads files it already understood.

It also works in series. Port, test, fix, review, then the next unit. Even if each step is fast, the project's speed is the sum of every step.

And when the same agent that wrote the code reviews it, it mostly agrees with itself. The bugs that matter most in a migration, small behavior differences between old and new, are exactly the ones its own reasoning has already explained away.

The multi-agent setup for application migration

An orchestrator holding the unit graph and work queue sends work to an inventory agent, two porter agents and a test-writer agent. All of them hand results to an independent parity reviewer, and anything that fails goes back to the queue

A working setup has five roles. Each is an agent with its own context, its own instructions and a narrow set of tools.

  • Orchestrator. Owns the plan: the list of units, their dependencies and their status. It hands out work and never writes app code.
  • Inventory agent. Read-only. Maps every route, component, service, global and hidden wiring point before anyone writes a line. Its output is the unit graph.
  • Porters. Each takes one unit at a time and moves it to the target stack, following a shared conventions file. Several run at once.
  • Test writer. Captures what the old unit does today, as characterization tests, before or alongside the port.
  • Parity reviewer. A fresh agent that sees only the old code, the new code and the test results, and reports concrete differences with a file, line and failing scenario.

Split by unit, not by step. Give a porter a whole component with its tests, not "all the templates" across the app.

Where the speed-up actually comes from

Line chart of modeled speed-up against the number of porter agents, using Amdahl's law. With 95% of units independent, 16 porters give about 9.1 times; with 80% about 4.0 times; with 50% about 1.9 times

The chart above is a simple model (Amdahl's law), but the shape holds on real projects. Parallel porters only help when the units they work on don't depend on each other. If unit 6 needs unit 2's new API, it waits. So the real driver of throughput is the unit graph: how well the inventory step breaks the app into pieces that can move independently.

The other multiplier is less obvious: fewer re-dos. Each agent's context stays small and focused, so the work is more consistent. The reviewer catches parity bugs while the unit is still fresh, not at user testing three months later. In practice, avoided rework is often worth more than raw parallelism.

Bar chart of modeled elapsed hours to migrate 120 units: one agent 180 hours, 4 porters and 1 reviewer 84 hours, 8 porters and 1 reviewer still 84 hours because review is the bottleneck, 4 or 8 porters with 2 reviewers 60 hours, 8 porters and 4 reviewers 48 hours

Review capacity matters just as much. In the model above, doubling porters from four to eight with a single reviewer saves nothing: the reviewer is the bottleneck. Adding reviewers is what moves the number.

“Adding manpower to a late software project makes it later.” — Fred Brooks, The Mythical Man-Month

Put together, a well-cut graph, several porters and an early independent review can turn a project measured in quarters into one measured in weeks. A badly cut graph with ten agents is just ten agents waiting on each other.

Five rules that make it work

“There is nothing so useless as doing efficiently that which should not be done at all.” — Peter Drucker

  1. Inventory before you port. No porter starts until the unit graph exists. The graph decides the order, the parallelism and what "done" means.
  2. One shared conventions file. Naming, state management, styling, error handling, folder layout. Every porter reads it, and the reviewer checks against it.
  3. Small, verifiable units. A unit should be portable and reviewable on its own: one route, one component tree, one service. If a reviewer can't judge it in one pass, it's too big.
  4. Maker and checker never share a context. The reviewer gets no access to the porter's reasoning, only the evidence.
  5. Durable state outside the agents. Unit status, decisions and open findings live in files in the repo, not in any agent's memory. Any agent can be restarted without losing the project.

Which model for which agent

Running one flagship model for every role is the simplest setup, and the most wasteful. Roles need different things. The orchestrator and the inventory agent make the decisions everything else depends on, so they get the deepest reasoning: Fable 5.1 or Opus 5.5. Porters and the test writer do high-volume, well-specified work against a conventions file, which is what Sonnet 5.5 is good at. Checking whether a finding reproduces is a narrow yes-or-no task for a fast model like Haiku 5.5.

Bar chart of an example setup, agent calls per migrated unit by role: orchestrator 1 call on Fable 5.1, inventory 0.17 calls on Opus 5.5, porters 3 calls on Sonnet 5.5, test writer 1 call on Sonnet 5.5, parity reviewer 1.3 calls on GPT-6 Astra, finding verifier 1.5 calls on Haiku 5.5, each with an alternative model

The reviewer is the one place to deliberately switch model families. If Claude models write the code, a reviewer such as OpenAI's GPT-6 Astra is less likely to share their blind spots, and the reverse holds too. Treat the chart as a starting point, not a rule. Swap models per role as you measure what each one gets right on your codebase.

Modeled share of agent calls for a 120-unit migration. One flagship for every role: Fable 5.1 handles 100% of calls. Tiered by role: Fable 5.1 13%, Opus 5.5 2%, GPT-6 Astra 16%, Sonnet 5.5 50%, Haiku 5.5 19%

In this model, tiering moves about 70% of calls to Sonnet 5.5 and Haiku 5.5, while every decision that shapes the project still goes through a top-tier model.

Where it goes wrong

Two porters editing the same shared file is the most common failure. Give shared modules (the router, the store, the design system) a single owner, and have porters ask for changes through the orchestrator.

The second is review becoming the bottleneck. If four porters each produce a unit an hour and the reviewer takes two hours per unit, you've built a queue, not a pipeline. Run more than one reviewer, or keep units small enough to review quickly.

The third is trusting green checks. A porter can make tests pass by changing the tests. Lock characterization tests once they're written, and treat any change to them as a finding in its own right.

Start with a pilot

Don't switch a whole program to multi-agent on day one. Pick one slice of the app, ten to twenty units with a mix of easy and awkward ones, and run the full setup on it: inventory, conventions file, porters, test writer and reviewer.

Track three numbers during the pilot: how many units pass review first time, how many reviewer findings turn out to be real, and how long units wait in the review queue. The first tells you whether your conventions and unit sizes work. The second tells you whether to trust the reviewer. The third tells you how many reviewers to run before you add porters.

Scale porters only after first-time pass rate and review wait time look healthy. Otherwise you are just making a longer queue.

How we run it

This is the structure behind MigrateX, our migration toolkit for moving Angular, AngularJS, Backbone and Ember apps to React. Each plugin runs a read-only inventory agent first, writes the plan and unit map into a .migration/ folder in the repo, then ports unit by unit with a separate parity-reviewer agent checking each one against its original before the old code is removed.

The agents do the volume. Engineers own the plan, the conventions and the final call on anything the reviewer flags. That split, more than any single model, is where the multiplier comes from.

Key takeaways

  • One agent doing everything stalls on context, works in series and grades its own work.
  • Use an orchestrator, an inventory agent, parallel porters, a test writer and an independent reviewer.
  • The speed-up depends on the unit graph and on avoided rework, not on how many agents you run.
  • Keep project state in the repo, give shared files one owner, and lock tests once they're written.

Related reading: a migration testing strategy with AI agents, 10 legacy modernization mistakes to avoid and software migration lessons from Shopify's AI rewrite.