Inspiration
Banks, insurers and governments still run on COBOL. The engineers who wrote it are retiring, and rewrites are risky for one reason: nobody can prove the new code does the same thing as the old code. A single cent rounded differently in a payroll or invoice system becomes a real problem at scale. We wanted AI to do the migration, but with a referee it can't argue with: the original program itself.
What it does
You drop a legacy COBOL codebase into NorthBound. A team of NVIDIA Nemotron agents migrates it to Python, one module at a time, through six phases:
- Understand: maps
CALLandCOPYdependencies and orders modules so callees migrate first. - Spec: Nemotron writes a plain-English spec of each program and flags legacy quirks (truncation, overflow, implied decimals).
- Record: we compile and run the real COBOL with GnuCOBOL on generated edge-case inputs and save exactly what it prints. That is the answer key.
- Rewrite: Nemotron writes idiomatic Python using
Decimal, runs it in a sandbox, and fixes its own mistakes before handing it over. - Verify: every recorded case is replayed against the Python.
- Accept: a module is accepted only when every output matches, character for character:
$$\text{accept}(P) \iff \forall x \in G:\ P(x) = \text{COBOL}(x)$$
If a rewrite still fails after three attempts, an explainer agent says in one plain-English sentence whether it's a bug in the new code or a quirk of the old system, for example "the old system cuts off fractions of a cent instead of rounding." A person can then send a hint that guides the next attempt.
Everything plays out in a cinematic "galaxy" frontend: each program is a star travelling through seven stations, and you can click any station to see what that step really produced: the spec, the test inputs, the COBOL answer key, each rewrite attempt, and the verification result.
How we built it
- Models: NVIDIA Nemotron 3.5 Super for rewriting, test writing and explanations; Nemotron 3.5 Lightning for specs, via
langchain-nvidia-ai-endpoints. - Orchestration: a LangGraph state machine with a verify → rewrite retry loop, writing live state after every step.
- Ground truth: GnuCOBOL compiles and runs the original programs; their recorded outputs become pytest equivalence tests.
- Multi-file codebases: subprograms expose a
call()convention, callersimportalready-verified dependencies instead of re-implementing them, and copybooks are expanded into the prompt. - Safety: generated code runs in a separate sandboxed process, and an anti-cheat gate rejects any rewrite that touches files or the OS (so it can't just read the answer key).
- Frontend: a canvas "galaxy" in plain JavaScript that replays recorded real runs, plus a quick live mode that runs one program through Nemotron in about 25 seconds.
- Team workflow: four people built in parallel against one frozen contract of function signatures, with stubs so the pipeline ran end to end from the first hour.
Challenges we ran into
- COBOL is full of traps. Values are silently truncated, not rounded;
ON SIZE ERRORoverrides overflow; input fields have implied decimal points; edited pictures likeZ,ZZ9.99pad with spaces. Every one of these broke a first attempt, so we encoded them into the prompts and gave the model tested helpers. - Our model IDs died mid-hackathon. Live testing showed one Nemotron model had been retired (
410 Gone) and another wasn't enabled for our accounts (404). We added automatic fallback across Nemotron models. - Reasoning ate the answer. With reasoning on, Nemotron sometimes spent its entire token budget thinking and returned nothing, and we were caching those empty replies. We made reasoning a per-agent choice and retried empty answers without it.
- Invisible context. A program that does
COPY INVRECnever shows the model its record layout, and Python's isolated mode blocked our sandbox from importing verified dependencies. Both silently broke multi-file rewrites until we found them. - A rewrite that cheats can look perfect. Code that reads the recorded outputs from disk would pass every test, so we built a gate that forbids it.
Accomplishments that we're proud of
- All 3 programs in each of our recorded real runs were verified byte for byte, and they passed 926/926 and 600/600 held-out inputs they had never seen.
- A dependency chain (INVOICE calls DISCOUNT) migrates with the caller importing the verified callee, never copying its logic.
- When we planted a one-cent rounding bug, the system caught it and explained it in plain English.
- The legacy quirks are preserved, not "fixed", because the real COBOL output is the test.
What we learned
- Generating code is the easy part. Verifying it is what makes AI migration trustworthy, and the original program is the best possible oracle.
- Give LLMs exact rules and tested helpers for fiddly semantics instead of hoping they infer them.
- Test against the live API early: model catalogs change, and reasoning models need room in the token budget.
- A frozen contract between teammates is what let four people merge without conflicts.
What's next for NorthBound
- Programs that read and write files and databases, plus CICS screens and batch JCL.
- Coverage-guided input generation, so the answer key provably hits every branch.
- Producing a ready-to-review pull request per module, with its spec, tests and proof attached.
- More source languages (PL/I, RPG) and target languages (Java, Go).
Built With
- cobol
- css
- html
- javascript
- langgraph
- nemotron
- pytest
- python
- streamlit