Parity

An AI swarm migrates your codebase to a new language. Parity proves it works perfectly.

Our entry for Huawei's openJiuwen Multi-Agent Challenge and Warp's Best Developer Tool.

The problem

Code migrations are hard. Companies want them for speed, for safety, or to get onto one stack, but one AI agent can't do it alone since a big library codebase doesn't fit in its context. The AI forgets the delicate code structure and its own decisions halfway through, which is not acceptable because the result has to be right. Everything downstream depends on this code and a rewrite that just looks right isn't enough. You need strict proof that the code functions the same way.

What Parity does

Point Parity at a file and it tells you which functions it can migrate, and why it can't do the rest. You choose the ones you want, and a team of agents rewrites them. A checker then runs the old and new versions on the same inputs and compares every output. The checker is plain code and it keeps a function only when the two versions produce results that match exactly.

/check file      which functions can be migrated, and why not for the rest
/migrate file    build the tests, then let the team rewrite the functions you tick
/export          the new code, plus a report of what was checked

How a run works

  1. Scan. Before any AI runs, a plain-code scanner reads every function. It keeps the ones whose answer depends only on their inputs: no files, network, clock, randomness or shared state. In C it also turns away anything that writes through a pointer. Every function it turns away comes with the reason.
  2. Build the tests. Nobody writes them. Parity generates inputs for each function and gets the expected answers by running the original. A function that crashes, or answers the same input two different ways, is dropped here. Each function gets 40 visible tests and 100 hidden ones. The hidden ones are locked away and no agent ever sees them.
  3. Split. The library is cut into one task per function. Each task holds that function, the helpers it uses, and nothing else. The planner orders the tasks so a function comes after the ones it calls.
  4. Rewrite in isolation. Each worker gets one task and its own conversation. It never sees the rest of the library, the other workers, or the tests. Its code is built and run in a fresh folder with the original source removed, so it can't peek at the answers or lean on someone else's work.
  5. Run real code. The agents can't touch the machine, but they can ask Parity to run code for them. A worker sends its function to the real compiler and gets the real errors back. The expert runs the original on inputs it picks to see what it actually does. The tester runs the old and the new version side by side on inputs it makes up. So when an agent says what the code does, it has watched it happen.
  6. Escalate. A function gets three tries, and each failed try comes back with the input that broke it. When the tries run out, the function moves up to a stronger model with everything that failed so far. Cheap models do most of the work and the expensive one only sees the hard cases: one earlier run did nine functions on a small open model and one on Claude, $1.48 total. If the strongest model fails too, the function is marked as needing a human. Nothing is kept that didn't pass.
  7. Put it together. Functions are added one at a time and rechecked with everything already kept, so the library works as a whole. Then the hidden tests run, once.

Three migrations

We picked one real library for each migration

Mode What we ran Result
Python → Rust jellyfish, a real string matching library 12 of 12 functions, 1200 of 1200 hidden tests
C → Rust checksums and hashes from the Redis source 8 of 8 functions, 800 of 800 hidden tests
TypeScript → ArkTS telemetry logic, run on the HarmonyOS emulator 3 of 3 functions, 146 of 146 hidden tests

Python → Rust, for speed. jellyfish matches names that are spelled differently, the kind of code that runs millions of times when you clean a customer database. It stands for the slow Python loop everyone wants in Rust. The catch is that the two languages disagree in small ways: Python strings count characters and Rust strings count bytes, Python raises exceptions and Rust returns errors. The expert settled the string question once, by running the original, and all twelve workers followed it. 28 minutes, about $4.

C → Rust, for memory safety. Redis's checksums and hashes are the kind of old, fast, bit-level C that sits under everything and nobody dares touch. C is already fast. What it lacks is a compiler that stops you from reading past a buffer. The catch is arithmetic: C lets unsigned numbers wrap around silently and Rust panics. The expert ruled on wrapping before any worker started. Parity also turned away 13 of the 21 functions it scanned, the ones that write through pointers.

TypeScript → ArkTS, to reach HarmonyOS. This one stands for app logic a team already has and needs on a new platform. ArkTS is Huawei's language for HarmonyOS apps. It looks like TypeScript but is stricter: no any, no destructuring, no untyped object literals. The new code is built with DevEco, installed on the HarmonyOS emulator, and every test runs on the device itself. That matters because the device is not Node: its regex engine rejects patterns Node accepts. When the app crashes, the device's crash report goes back to the worker.

How we used SwarmFlow and openJiuwen

Built on WorkSwarm 0.2.6. We swapped out its stock worker because it can read files and would see the tests which would allow it to cheat on validation. openJiuwen gives us the agents and SwarmFlow decides who runs when.

openJiuwen: the agents. Every team member is an openJiuwen ReActAgent, an agent that thinks, calls a tool, reads the result and repeats until it hands in an answer. Each one stays alive for the whole run with its own conversation, so a worker on its second try remembers what it tried first and why it failed. Agents get no shell and no file access. Each role gets a few tools we wrote, and that's all it can touch: workers can compile and ask the expert, the expert can run the original code, the tester can run both versions on inputs it makes up. We also use openJiuwen's rails, hooks that fire around every tool call, to end an agent's turn the moment it submits and to bill every token to the run's budget.

SwarmFlow: the workflow. The whole migration is one SwarmFlow script with three phases: Plan, Migrate, Integrate. Functions that don't depend on each other go to workers through SwarmFlow's parallel, and a function that calls another waits for it. SwarmFlow also holds the token budget for the run and stops it cleanly when the budget runs out. What was already kept stays on disk, so a run that is cut off picks up where it stopped. We wrote a small backend that plugs our agents into SwarmFlow's engine: when the script asks for "the expert", that becomes one turn with that same long-lived agent.

No agent ever holds the whole library, which is how we get around the context problem.

  • Planner reads the code, orders the work by dependency, and flags where the two languages behave differently.
  • Workers rewrite one function each, in parallel. A worker can compile, and it can ask the expert.
  • Expert answers by running the original code on inputs it picks, then writes a rule every worker has to follow, for example "count text in characters, not bytes". That's how a decision made once reaches the whole library. If a rule changes, work done under the old one is thrown out and redone.
  • Tester runs on a different model from the workers. It invents inputs to break each function that passed. Anything it finds becomes a permanent test.

The agents never get to say done. Only the checker does.

How the agents work together

How the agents work together

Why a team and not one agent. The library doesn't fit in one context, so each worker holds one function. A decision about how the two languages differ has to be made once and reach everyone, which is the expert's job. And whoever tests the code can't be the one who wrote it, so the tester is a separate agent on a different model.

How the run adapts. Nothing is a fixed script. The planner names the language differences it is worried about and the expert settles them before any worker starts. When the checker finds a mismatch, the failing input goes to the worker and to the expert, who can turn it into a rule for everyone. When a rule changes, functions already kept are rechecked under it, and a worker is only called back if one fails. When code doesn't compile, the expert reads the error and tells the worker the fix.

When things go wrong. A function gets three tries. If it still fails, a stronger model takes over. If that fails too, Parity stops and flags it for a human. If a model hangs, Parity asks again. If a run gets cut off, it picks up where it left off and keeps everything it already proved. The agents never see the hidden tests, so they can't cheat them.

Adding a language. None of the core code is tied to a language. To add one, you give Parity a folder with the original code, a way to run it, and a way to build and run the new code. That's how a teammate added TypeScript to ArkTS during the hackathon.

Limits. Parity can't migrate everything. It only takes functions where the same input always gives the same output. Anything that reads a file, hits the network or changes something else is turned away. And it checks by testing, so it can't catch a bug on an input it never tried.

Built With

Share this project:

Updates

Submission history