Claude and Copilot on Legacy Cores
bankingAugust 26, 2026

Claude and Copilot on Legacy Cores

Prompting Patterns for COBOL/Java Bridges

Most of the engineers staffed onto a COBOL modernisation project don't read COBOL — they read Java, and they've been handed an AI assistant and told it closes the gap. It closes some of it. This one's for the Java engineer holding the bridge, who needs to know exactly which parts of that gap an LLM actually closes, and which parts it will confidently paper over if nobody stops it. 

Anthropic's announcement that Claude Code can analyse and document COBOL codebases — mapping dependencies, flagging risk, translating logic into modern languages, modernisation in "quarters rather than years" instead of the usual multi-year programme — moved IBM's stock down over 13% in a single day. That reaction tells you something true: the market believes AI-assisted legacy modernisation is now real enough to threaten the economics of staying on the mainframe. It doesn't tell you whether the code an LLM writes on your core banking ledger is safe to ship, and those are two different questions. The demo that impresses a room is a self-contained COBOL program with clean copybooks. The core your bank actually runs is forty years of paragraphs, GOTOs, and copybooks written by people who left before you were hired, none of it designed to be read out of context. 


Reading isn't understanding, and the failure mode is invisible until it isn't 

What LLMs are genuinely good at against real COBOL is close to what they're good at against any unfamiliar codebase: tracing program flow, mapping which paragraphs call which, pulling a plausible-sounding business rule out of an undocumented subroutine, and turning that into fluent documentation a Java team can actually read. What they're weak at is the thing that matters most on a core banking system — resolving a data structure's true shape when the answer lives somewhere the model didn't look. 

Here's the shape of the failure, as described in accounts from teams doing exactly this kind of migration: an AI system translated a COBOL financial module to Java. It compiled. It passed the unit tests the same AI had written for it. In production, it corrupted a database on the first live wire transfer. The root cause was a field — call it TRN-LIMIT — defined thousands of lines earlier in a copybook, carrying a REDEFINES clause that let the same memory reinterpret as a different data type depending on a runtime condition. The model read TRN-LIMIT where it was used, in the transaction paragraph, and treated it as a plain numeric field, because that's what it looked like locally. It never resolved the REDEFINES chain back to its actual definition — not because it couldn't, but because a RAG-style retrieval step finds text that's semantically similar to what you asked about, and a REDEFINES clause buried in an unrelated copybook doesn't read as similar to a payment paragraph. It reads as unrelated, right up until it's the thing that decides how the bytes get interpreted. 


That's the failure mode worth designing prompting patterns around: not the model being wrong about something it looked at, but the model being confidently right about something it never looked at, because nothing forced it to look. A COBOL codebase's real structure — copybook inheritance, REDEFINES, OCCURS DEPENDING ON, 88-level condition names — isn't always where the paragraph you're translating happens to be. Treating it like a self-contained unit of text, which is exactly what a chat-style prompt or an IDE-scoped Copilot completion implicitly does, is where these projects go wrong. 


Prompting patterns that assume the model can't see what you haven't shown it 


The fix isn't a smarter model. It's context discipline that doesn't rely on the model finding what it needs on its own. 

Enumerate the copybook chain before you ask for a translation, and paste all of it in. Before asking Claude or Copilot to translate a paragraph, walk every COPY statement it depends on and every REDEFINES on every field it touches, and put the full text of that chain in context — not a summary, not "here's the copybook it probably needs." If a field is redefined three copybooks away from where it's used, that redefinition has to be physically present in the prompt, because retrieval won't reliably surface it and the model has no way to ask you for it. 


Ask for a data dictionary before you ask for code. Two-step prompting beats one-step here: first, have the model enumerate every field the paragraph touches — its PICTURE clause, its REDEFINES if any, its 88-level condition names — as a table, before it writes a single line of Java. Reviewing that table against the copybook is fast for a human who doesn't read COBOL fluently; reviewing generated Java line-by-line for the same errors is not. If the model's data dictionary is wrong, you've caught the TRN-LIMIT-shaped bug before it became a bridge. 


Generate characterization tests before translation, not from the translation. A model asked to translate a paragraph and then write tests for its own output will write tests that confirm what it believes the paragraph does — which is exactly the confidence that missed the REDEFINES clause in the first place. Instead, ask it to generate golden-master tests from the existing COBOL behavior against representative input data, run against the current system, before any Java exists. The Java bridge then has to match a behavior captured independently of the model's own understanding, not a test suite the model wrote to agree with itself. 


Never let a model choose between double and BigDecimal. COBOL's COMP-3 packed decimal fields carry an exact scale and precision from the PICTURE clause — that's the entire reason COBOL is still running the general ledger. A model translating that field to a Java double or float isn't simplifying, it's silently introducing floating-point rounding into money math. The prompting pattern here is a standing instruction, not a per-task one: every numeric field maps to BigDecimal with scale and rounding mode taken explicitly from the source PICTURE clause, and the model has to state the PICTURE clause it read for each field so a reviewer can check the mapping against the copybook rather than trusting the narrative. 


Flag control flow instead of "cleaning" it. A GOTO or PERFORM ... THRU that looks dead in isolation can be what sequences an overnight batch job. Ask the model explicitly to flag every GOTO, ALTER, and PERFORM ... THRU it encounters and explain what it thinks controls it, rather than quietly restructuring the paragraph into cleaner-looking Java — a model instructed to simplify will simplify, including the parts it didn't understand were load-bearing. 


Use the bridge, not the rewrite, as the default prompting target 


The safest place to point an LLM on a legacy core isn't "rewrite this business logic in Java." It's the adapter layer around it. Java-calling-COBOL over JNI is a well-documented, mechanical pattern — a native method declared with the Java_classname_methodname convention, two hidden JNI arguments the COBOL side receives from the runtime, the compiled COBOL loaded as a shared library via System.loadLibrary(). That's exactly the kind of boilerplate-heavy, well-specified integration code LLMs are reliable at, because it's mechanical translation against a documented interface, not an inference about what forty-year-old business logic was supposed to mean. 


Prompt pattern (bridge generation, not logic translation): 

 

 1 "Generate a JNI adapter that calls COBOL program PYMT100 from 
 2 Java. Native method signature: calculateSettlement(BigDecimal 
 3 amount, String currencyCode) returning SettlementResult. Do not 
 4 reimplement PYMT100's internal logic — the COBOL program remains 
 5 the source of truth for the calculation. Map COMP-3 fields per 
 6 the attached copybook PYMT100-COPY.cpy exactly as specified; 
 7 flag any field where the copybook doesn't fully determine scale 
 8 or precision instead of guessing." 

That's the strangler-fig pattern applied to prompting: Java owns orchestration, the COBOL program stays authoritative for the calculation it was already trusted with, and the AI-generated surface area is the boring, verifiable adapter code rather than a reimplementation of business logic nobody's fully documented. It also changes what "AI-assisted modernisation" means as a phased programme — you can ship the bridge and start decommissioning around it long before anyone reimplements the underlying paragraph in Java, and the highest-risk translation work only happens once, deliberately, with a subject-matter expert in the loop, instead of as an implicit side effect of every prompt. 

Copilot and Claude earn different roles in this split. Copilot's inline, IDE-scoped suggestions are well suited to the adapter and boilerplate layer — small, well-specified completions reviewed in place, paragraph by paragraph. Claude's larger context window and agentic tooling are better matched to the analysis phase — ingesting a full copybook chain, producing the dependency map and data dictionary, flagging the REDEFINES and the GOTOs before a human decides what's safe to touch. Neither belongs unsupervised in the paragraph that calculates interest. 


Traceability is the part that makes this auditable, not just accurate 

Everything above produces a review burden, and the review burden is the point — but it only works if it's checkable after the fact, not just at merge time. Annotate every AI-generated line with where it came from: a source comment referencing the exact COBOL program and line range it was translated from, not just a commit message. Log the prompt, the context that was actually supplied, and the output together, so that eighteen months later, when an auditor or a regulator asks how a specific line of Java came to exist, the answer is a record instead of a reconstruction. We've written before about what DORA's operational resilience testing actually expects of an audit trail — evidence independent of the system it's describing, not a belief about what probably happened. AI-assisted migration on a regulated core needs exactly that same discipline, because "the model generated it and the tests passed" is not an answer a regulator, or a bank's own risk function, will accept for how a payment calculation changed. 

None of this makes COBOL-to-Java migration fast in the way the headlines promise. It makes the parts of it that are genuinely mechanical fast — and it keeps the parts that aren't mechanical in front of a human who can read a copybook, instead of letting an LLM's fluency stand in for understanding it never actually had. On a core that moves real money, that trade is the whole point.