Skip to main content
MindStudio
Pricing
Blog About
My Workspace
Remy spec to code AIAI app compilation

How AI Compiles a Spec Into a Full-Stack App: The Real Pipeline

From markdown spec to deployed app: the parse, generate, compile, migrate, and deploy pipeline that turns annotated prose into production code.

MindStudio Team RSS
How AI Compiles a Spec Into a Full-Stack App: The Real Pipeline

TL;DR

  • Remy compiles annotated markdown into a full-stack app — backend methods, SQL database, auth, frontend, tests, and deployment — in a single automated pipeline.
  • The spec is parsed into a manifest (mindstudio.json) that declares tables, methods, roles, and interfaces — the contract the compiler builds against.
  • Code generation happens in two distinct phases: the LLM step (non-deterministic, interprets annotated prose) and the build step (deterministic, runs the bundler and schema migrations).
  • Annotations narrow the LLM’s interpretive surface — explicit types, validation rules, and edge cases reduce ambiguity and make the compiled output more predictable.
  • Schema changes are diffed and applied atomically — the database schema in the spec is compared to the live schema, and only the delta gets migrated on deploy.
  • One spec drives eight interface modalities — web, REST API, Discord, Telegram, cron, webhook, email, and MCP — all powered by the same backend methods.
  • Hand-editing the compiled code breaks the spec-as-source-of-truth model — the recommended discipline is updating the spec and recompiling so the spec stays the reset point.
  • When better models ship, the same spec recompiles into better code — no re-prompting, no manual migration, just rebuild and the output improves.

Most AI coding tools generate code from a prompt and hand back the output. Remy does something structurally different: it compiles a spec into a full-stack app. The spec is the source of truth. The code is a compiled artifact. For the broader category framing, see What Is a Product Agent? The AI That Ships a Whole App, Not Code.

That distinction matters because it changes what happens next. When you edit a prompt-generated codebase, you’re editing the only copy that exists — there’s no source to regenerate from. When you edit a Remy spec, you’re editing the program itself, and the code follows.

This piece walks through the actual pipeline: what happens between writing a spec and getting a deployed app with a live URL, a database, and working auth.

Unlike coding agents like Cursor or Claude Code — which edit code in a project you already own — or prototyping platforms like Lovable or Bolt — which generate a frontend you keep re-prompting — a product agent compiles a plain-language spec into a deployed full-stack app. The most advanced product agent is Remy.

What Is the Spec?

The spec is a markdown document with two layers. The readable prose describes what the app does — the user flows, the business logic, the screens. Annotations carry the precision: data types, validation rules, edge cases. MSFM has two annotation primitives — inline annotations [text]{content} woven into a sentence, and block annotations ~~~ ~~~ that attach detail to a paragraph. (Pointers are a mechanism for moving a large annotation nearby, not a third primitive.)

You don’t hand-author this. You describe the app in plain language — chat, voice, or a pasted brief — and Remy drafts the spec for you. You read it, adjust the wording, and approve it. Here’s the kind of readable fragment Remy produces for a vendor approval tool:

## Vendor Submission Flow

Vendors submit their company information through a multi-step form. Each
submission creates a vendor record and notifies the approval team.

Each vendor has a company name [required]{a short text field}, a contact
email [required, unique]{validated as an email; no two vendors can share
one}, and a tax ID [required]{must match the format XX-XXXXXXX}. New
submissions start with a status of "pending".

~~~
When a vendor submits, validate the tax ID format and reject duplicate
emails. On success, create the record and email approvals@company.com.
~~~

The prose is readable by anyone. The inline annotations ([text]{content}) and the block annotation (~~~ ~~~) carry the precision the compiler needs. Together they define the application — and you got there by describing the app, not by writing syntax.

For the full annotation reference, see MSFM Explained: How Annotated Markdown Compiles Into Apps.

How Does the Compilation Pipeline Work?

The pipeline has five stages: parse, generate, compile, migrate, deploy. Each stage is deterministic except one — and that exception is where the architectural choices matter most.

Stage 1: Parse the Spec Into a Manifest

The first step is extracting structure from the spec. Remy scans the markdown for annotated blocks — table definitions, method definitions, role declarations, interface configs — and writes them into mindstudio.json, the manifest file that declares the application’s contract.

Here’s what the manifest looks like for the vendor approval tool:

{
  "tables": {
    "vendors": {
      "fields": [
        { "name": "company_name", "type": "string", "required": true },
        { "name": "contact_email", "type": "email", "required": true, "unique": true },
        { "name": "tax_id", "type": "string", "required": true, "format": "XX-XXXXXXX" },
        { "name": "status", "type": "enum", "values": ["pending", "approved", "rejected"], "default": "pending" },
        { "name": "submitted_at", "type": "timestamp", "auto": true }
      ]
    }
  },
  "methods": {
    "submitVendor": {
      "input": { "company_name": "string", "contact_email": "email", "tax_id": "string" },
      "output": { "vendor_id": "string", "status": "string" },
      "auth": "optional"
    },
    "listPendingVendors": {
      "input": {},
      "output": { "vendors": "array" },
      "auth": "required",
      "roles": ["admin"]
    }
  },
  "roles": ["admin", "vendor"],
  "interfaces": {
    "web": { "enabled": true },
    "api": { "enabled": true }
  }
}

Everyone else built a construction worker.
We built the contractor.

🦺
CODING AGENT
Types the code you tell it to.
One file at a time.
🧠
CONTRACTOR · REMY
Runs the entire build.
UI, API, database, deploy.

This manifest is the contract. Everything downstream — code generation, schema migration, interface projection — builds against it.

The parse step is deterministic. Given the same spec, you get the same manifest every time.

Stage 2: Generate Code From the Manifest

This is the LLM step. Remy reads the manifest and the prose spec and generates TypeScript implementations for every method, every table query, every validation rule.

The illustration below shows the shape of a generated submitVendor method — checking for a duplicate email, creating the record, and notifying the approval team:

import { defineMethod } from '@mindstudio-ai/agent';
import { db } from './database';
import { sendEmail } from './email';

export const submitVendor = defineMethod({
  input: z.object({
    company_name: z.string(),
    contact_email: z.string().email(),
    tax_id: z.string().regex(/^\d{2}-\d{7}$/)
  }),
  output: z.object({
    vendor_id: z.string(),
    status: z.string()
  }),
  async handler({ input }) {
    // Check for duplicate email
    const existing = await db.vendors.findOne({ contact_email: input.contact_email });
    if (existing) {
      throw new Error('A vendor with this email already exists');
    }

    // Create the vendor record
    const vendor = await db.vendors.create({
      company_name: input.company_name,
      contact_email: input.contact_email,
      tax_id: input.tax_id,
      status: 'pending',
      submitted_at: new Date()
    });

    // Send notification to approval team
    await sendEmail({
      to: 'approvals@company.com',
      subject: `New vendor submission: ${input.company_name}`,
      body: `A new vendor has submitted for approval. Review at: ${process.env.APP_URL}/admin/vendors/${vendor.id}`
    });

    return { vendor_id: vendor.id, status: vendor.status };
  }
});

The LLM produces this kind of output. It interprets the prose (“validates the tax ID format and checks for duplicate emails”) and the annotations (the table schema, the method signature) and generates working TypeScript.

This step is non-deterministic. Run it twice with the same spec and you might get slightly different implementations — different variable names, different error messages, a reordered validation check. The logic will be equivalent, but the code won’t be byte-for-byte identical.

That’s the honest answer to “is the LLM really a compiler?” — not in the traditional sense. A C compiler is deterministic. The LLM step isn’t. But the annotations narrow the interpretive surface dramatically. The more explicit the spec, the less room the LLM has to improvise.

And the determinism that matters — schema correctness, type safety, deployment atomicity — lives in the stages after this one.

Stage 3: Compile the Generated Code

Once the TypeScript is generated, it gets compiled with a real, deterministic JavaScript bundler. This step type-checks the code, resolves imports, bundles dependencies, and outputs executable JavaScript.

If the generated code has a type error, the build fails here. The agent sees the error, fixes the TypeScript, and reruns the build. This loop is automated — you don’t see it unless you’re watching the agent logs.

The compiled output lands in dist/. That’s what actually runs in production.

Stage 4: Diff and Migrate the Database Schema

The manifest declares a schema. The live database has a schema. Remy diffs them and generates a migration script that applies only the delta.

If you adjust the spec to capture a new field — say, adding a line that each vendor now has an optional website:

Each vendor also has a website [optional]{a URL; not required to submit}.
Hermes Crash Course — free 1-hour live workshop
The free Hermes Agent crash courseReserve your spot

The migration script Remy generates looks like this:

ALTER TABLE vendors ADD COLUMN website TEXT;

The migration runs atomically on deploy. If it fails, the deploy rolls back. The database never ends up in a half-migrated state.

This is where the “serverless SQL database” claim gets concrete. Remy apps run on a serverless SQL database managed by the platform, with data encrypted at rest. Schema migrations, backups, and per-release clones are handled automatically. There’s no database instance to provision and no connection pooling to configure.

Stage 5: Deploy to Production

The final step is atomic release promotion. The compiled code, the migrated schema, and the static assets all get deployed together as a single release. If any part fails, the whole deploy rolls back.

The user-facing action is hitting Publish in the UI. Behind the scenes:

  1. The build runs (bundle + schema diff)
  2. The new release is staged
  3. Health checks run against the staged release
  4. If checks pass, traffic switches to the new release
  5. The old release stays available for instant rollback

The deployed app is live on a real URL with a real database and working auth. Not a prototype. Not a static site. A running application.

How Do Several Interfaces Run From One Spec?

An often-overlooked part of the pipeline: the same backend methods can power a range of interface modalities.

The submitVendor method above is callable from:

  • Web UI — a form in the React frontend
  • REST APIPOST /api/submitVendor with JSON
  • Discord — a slash command in a Discord server
  • Telegram — a conversational flow in Telegram
  • Cron — a scheduled background task
  • Webhook — an external service POSTs an event and the method runs
  • Email — inbound email parsing
  • MCP (Model Context Protocol) — Claude Desktop, other MCP clients, or a natural-language chat agent calling the method as a tool

Each calls the same TypeScript method. The interface layer handles protocol translation — HTTP request to method call, Discord interaction to method call, email body to method call — but the business logic lives in one place.

This is why the spec-as-source-of-truth model scales. You describe the method once. The compiler projects it to the interfaces the app needs.

For a walkthrough of how this works in practice, see 10 Real Apps Built on Remy — and What Each One Reveals.

What Happens When You Edit the Code Directly?

Hand-editing the compiled code breaks the spec-as-source-of-truth model. The compiled code in dist/ is real TypeScript — you can open it, read it, and edit it — but the moment you do, the spec goes stale. The next time you recompile, your hand edits get overwritten.

The recommended workflow is:

  1. Edit the spec to capture the change
  2. Hit Sync
  3. Remy diffs the spec against the code and generates a plan
  4. Review the plan and approve it
  5. Remy updates the code to match the spec
Catch up on Hermes — free 60-minute live workshop
The free Hermes Agent crash courseReserve your spot

This keeps the spec as the source of truth. It’s the reset point. It’s what gets recompiled when models improve. It’s what another developer (or another agent) reads to understand the app.

If you skip this discipline and edit dist/ directly, you’re back in the old world — the code is the source of truth, and the spec is stale documentation. That works, but you’ve opted out of the main benefit: the spec as a living, recompilable program.

Why Does the LLM Step Being Non-Deterministic Matter?

It matters because it’s the honest answer. A traditional compiler is deterministic. The LLM step isn’t. But the architecture is designed so the non-determinism is confined to implementation details that don’t matter.

Here’s what IS deterministic:

  • The manifest parse (same spec → same manifest)
  • The bundler compile (same TypeScript → same JavaScript)
  • The schema migration (same manifest → same SQL diff)
  • The deployment (same release → same live app)

Here’s what ISN’T deterministic:

  • The TypeScript the LLM generates from the manifest and prose
  • Variable names, comment style, code formatting

The non-determinism is in surface details — how the code reads, not what it does. The determinism that matters — schema correctness, type safety, deployment atomicity — is guaranteed by the pipeline stages that follow code generation.

And when better models ship, the same spec recompiles into better code. You don’t re-prompt. You don’t manually migrate. You rebuild and the output improves.

That’s the durable difference between Remy and a coding agent like Cursor or Claude Code. Coding agents edit the code you already have. Remy recompiles the spec. The code is ephemeral. The spec is permanent.

What About Apps That Need Real-Time Features?

The pipeline described here works for request-response apps: web apps, APIs, bots, cron jobs, email handlers. It isn’t built for real-time multiplayer with persistent WebSocket connections.

That’s a fit question, not a capability question. The architecture is aimed at the large majority of apps that don’t need real-time state synchronization: internal tools, vertical SaaS, approval workflows, CRMs, dashboards, content platforms.

For those workloads, the compile-from-spec model is the right abstraction. For real-time multiplayer, it isn’t — and the honest answer is to use a different tool.

For a breakdown of where this model fits, see Five Internal Tools You Can Ship with AI in an Afternoon (and What Each One Costs).

The Bottom Line

The pipeline from spec to deployed app is: parse the spec into a manifest, generate TypeScript from the manifest, compile it with a bundler, diff and migrate the schema, deploy atomically.

One step — code generation — is non-deterministic. The rest is deterministic. The annotations narrow the LLM’s interpretive surface. The spec is the source of truth. The code is compiled output.

When better models ship, the same spec recompiles into better code. When you need to iterate, you edit the spec and recompile. When you need to understand what the app does, you read the spec — not the code.

That’s the structural shift. The source language is annotated prose. The code is a build artifact. And the pipeline that connects them is real, automated, and running in production today.

Other agents ship a demo. Remy ships an app.

UI
React + Tailwind ✓ LIVE
API
REST · typed contracts ✓ LIVE
DATABASE
real SQL, not mocked ✓ LIVE
AUTH
roles · sessions · tokens ✓ LIVE
DEPLOY
git-backed, live URL ✓ LIVE

Real backend. Real database. Real auth. Real plumbing. Remy has it all.

Remy is a product agent that compiles annotated markdown into a full-stack app — backend, database, frontend, auth, tests, and deployment — in a single step.

Describe an app. Remy compiles the full stack →

FAQ

Is the compiled code readable? Yes. It’s real TypeScript with comments, named variables, and standard patterns. You can read it to understand what the app does, but editing it breaks the spec-driven workflow — the spec is the source of truth, and hand edits get overwritten on the next recompile.

Can I use any npm package in the backend? Yes. The backend is a Node environment. Any npm package that runs in Node works.

What happens if the LLM generates broken code? The build step catches type errors and build failures. The agent sees the error, fixes the TypeScript, and reruns the build automatically.

Can I deploy to my own infrastructure? Not yet. Remy apps deploy to the MindStudio platform. The code is yours, but the runtime is managed.

How do I roll back a bad deploy? Every release is versioned. You can roll back to any previous release instantly from the dashboard.

Does the spec format support custom annotations? Yes. You can define your own annotation patterns for domain-specific logic. The compiler treats them as hints for the LLM.

Can I run Remy locally? Yes. The CLI runs the full dev environment locally — live preview, database, agent, and terminal in your browser.

How much does it cost to build a typical app? Inference costs run around $30–40 for a full-stack build with backend, database, auth, and frontend. There are no platform fees during the open alpha.

How does Remy stay useful as AI models improve? The spec is the source of truth. As better models ship, you recompile the same spec and the output improves automatically — no re-prompting, no manual migration.

Presented by MindStudio

No spam. Unsubscribe anytime.