Cookbook: Legacy Codebase Migration ​
Migrating an enterprise application to a new framework is usually a multi-year nightmare. You have to rewrite the entire application from the ground up, run it in parallel, and pray you didn't miss any edge cases.
Carotene flips this model upside down using Reverse Blueprint Extraction. You can ingest your legacy codebase, generate the architectural guardrails, and selectively hand over ownership to the AI function by function, file by file.
Here is how you onboard a legacy API into the Carotene ecosystem.
1. Introspect the Codebase ​
Let's say you have an aging Express.js/Sequelize codebase governing your company's billing system. You start by pointing the Carotene CLI at your source folder.
$ carrot introspect ./legacy-billing-api/srcCarotene's AI engine analyzes your routes, your database models, and your middleware. In a few minutes, it generates a billing.carrot file that maps your exact physical architecture into Carotene's strict DSL.
2. Review the Generated Blueprint ​
When you open the generated billing.carrot file, you will notice two things:
- Carotene successfully mapped your data shapes and Zero-Trust boundaries.
- Every execution block is protected by the
@manualdecorator.
domain Billing {
backend BillingAPI {
store {
model Invoice {
id: UUID
amount: Float
status: String
}
}
// Carotene flagged this as manual. It recognizes the inputs, outputs,
// and database interactions, but will NOT attempt to overwrite your legacy code.
@manual
function ProcessInvoice(invoiceId: store.Invoice.id) -> Boolean {
reads store.Invoice
updates store.Invoice
implements {
// Points to your existing legacy file
file: "./legacy-billing-api/src/controllers/processInvoice.js"
}
}
}
}At this stage, you are actively using Carotene. Running carrot dev will strictly lint your legacy architecture to ensure your existing Express code isn't violating its own boundaries, but the AI will not write a single line of code.
3. The Surgical Takeover ​
You decide that the ProcessInvoice logic is buggy, full of technical debt, and needs a rewrite. You want the Carotene compiler to take over.
You do this in three steps:
- Change
@manualto@ai. - Add strict mathematical bounds (
ensures). - Replace the legacy file reference with a Generative Operator (
@).
domain Billing {
backend BillingAPI {
// 1. Transfer ownership to the AI Compiler
@ai
function ProcessInvoice(invoiceId: store.Invoice.id) -> Boolean {
reads store.Invoice
updates store.Invoice
// 2. Enforce absolute mathematical safety before the rewrite
ensures rule.ValidTransaction(result)
implements {
// 3. Drop the code hole. The AI will now synthesize the new logic.
return @("Fetch the invoice, calculate late fees (if any), and mark as paid.")
}
}
}
}4. Compile and Verify ​
When you run carrot generate:
- Carotene ignores all the remaining
@manualfunctions, leaving your legacy code untouched. - It zeroes in on
ProcessInvoice. - It provisions the Vapor Sandbox, writes the new logic in clean, highly-optimized TypeScript, and runs it against the fuzzed
ensuresbounds to guarantee safety.
You have successfully replaced a piece of legacy tech debt with mathematically verified, AI-generated code without taking your application offline or executing a massive rewrite.