Adopt an existing app
Bring a Lovable, Bolt, v0 or Cursor app onto MainSDK with mainsdk check and mainsdk adopt, one module and one pull request at a time, no rewrite.
Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.
Stability The promise an interface ships with.
- Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
- Beta Usable in production; may change before it becomes stable.
- Experimental May change or go away; needs an explicit opt-in in main.yaml.
The quickstart started from an empty folder. Most apps already exist, and you don't rewrite yours to use MainSDK: you check it, see the gaps, lock what works, and close the gaps one pull request at a time. Your coding agent can do the work through the migration skill, or you can run mainsdk adopt yourself.
Phase 1 covers Next.js and Node apps, including those generated by Lovable, Bolt and v0. Other stacks are reported as unsupported, never half-migrated. MainSDK is pre-release; these commands are the planned design and do not run yet. init, check and the framework adapters are planned for 0.2; mainsdk adopt and the migration skill are planned for 0.5.
Start with a check
Run it in the app's root. No account, nothing sent anywhere.
npx mainsdk checkOn a typical generated app, the first run finds things like a payment key in client code or a raw database client:
$ npx mainsdk check
mainsdk check · my-lovable-app · env dev · Main 27
secrets 1 finding
MAIN-SECRET-0002 critical src/lib/stripe.ts:4
fix: Move the key to secrets and use secret:STRIPE_SECRET_KEY
data 1 finding
MAIN-DATA-0001 high src/lib/db.ts:12
fix: Route queries through MainSDK (withPrisma, withDrizzle or db.<model>.for(user))
config network
2 gates failed · exit 1Adopt, step by step
Plain npx mainsdk adopt runs the next step each time and is safe to re-run. The steps below run each one by name. Progress is kept in .mainsdk/adopt.json (git-ignored); main.yaml stays the source of truth.
1. Scan
npx mainsdk adopt scanA deterministic scan maps sign-in, data access, secrets and outbound calls, and writes a main.yaml describing the app as it is. It changes no code; the same repo always gives the same file.
It keeps what you already run. An app on Clerk and OpenFGA stays on them:
schema: 1
project: prj_01JC8Q4W7ZK3M5N8P2R6T9V0XY
baseline: main27
auth: { driver: clerk } # byo-identity: users, sessions and MFA stay in Clerk
access: { driver: openfga } # byo-policy: your model and tuples stay in place
pay: { driver: stripe }
overlays: { order: [market, segment, env] }
exceptions: []2. Report
npx mainsdk adopt reportA plain-language gap report against Main 27, ordered by risk: secrets first, then access, then data, then the rest. Each item names the rule and the fix. Add --json for tools.
3. Lock key flows
npx mainsdk adopt lockRecords the app's key flows, such as sign-in and checkout, as locked flows before anything changes. adopt next refuses to run until they exist (MAIN-ADOPT-0001 lock flows first), so migration can't silently change what your users see.
4. Migrate one module per pull request
npx mainsdk adopt next --module secretsEach step is one branch and one pull request, limited to one module, that must pass mainsdk check and every locked flow. If a step breaks a locked flow it's marked failed, the branch is kept for review, and your main branch is untouched.
A secrets step, before and after:
import Stripe from "stripe";
export const stripe = new Stripe("sk_live_…");import { pay } from "mainsdk";
export function checkout(orderId: string, amountInCents: number) {
return pay.checkout({ order: orderId, amount: amountInCents, currency: "USD",
successUrl: "/orders/done", cancelUrl: "/cart" });
}Code that can't move to an interface yet stays behind that interface's escape hatch, raw(), and check lists every use.
5. Finish
npx mainsdk adopt finishProduces the launch report: the app meets Main 27, or the report lists exactly what remains, with file and line.
Hono, Express and Node
If your app is a Hono or Express server rather than Next.js, three commands put it under the check:
npx mainsdk initimport express from "express";
import { mainsdk } from "mainsdk/express"; // Hono: import { mainsdk } from "mainsdk/hono"; app.use("*", mainsdk())
const app = express();
app.use(mainsdk());
// … your routes
app.use(mainsdk.errors()); // lastnpx mainsdk checkThe adapters give every request a trace, its user and market context, and errors as problem details (see installation). What is and isn't specified for adopting these apps:
- The adapters for Hono, Express and Node workers, and
withPrismaandwithDrizzlefor the database, are specified for 0.2. - The adopt steps are scoped to "Next.js and Node apps". Hono and Express servers are Node apps, but the migration spec doesn't name them or say that
adopt scanrecognises their routes:. - Until that is settled, wire the adapter and run
checkyourself, and useadoptfor Next.js apps.
Let your agent do it
The migration skill runs the same five steps through the MainSDK MCP server (adopt.scan, adopt.report, adopt.lock, adopt.plan_module, adopt.verify_module, adopt.finish). It works in Claude Code, Cursor and any MCP-capable agent, and intent checks run on your own agent and keys.
Bring this app onto MainSDK with the mainsdk-adopt skill. Start with secrets.See Use MainSDK with your coding agent.
Next
Open questions
Was this page helpful?