The Spec Is the Program. The Code Is What Gets Compiled.
When the spec is the source of truth and code is compiled output, what happens when you edit the code? How reconciliation works in spec-driven development.
TL;DR
- The spec is the source of truth — in spec-driven development, the annotated markdown document (
src/app.md) is the program, and the TypeScript/React code indist/is compiled output. - Code drift is real but manageable — if you hand-edit the compiled code, it can drift from the spec, just like editing
.jsfiles can drift from.tsin a TypeScript project. - Bidirectional sync exists — Remy provides a sync button that reconciles changes in either direction: update the spec to match code edits, or recompile the code to match spec changes.
- The recommended discipline is “fix the spec, recompile” — treating the spec as the reset point means better models automatically improve your app on recompile, and the spec stays readable as the project’s documentation.
- This isn’t a bug, it’s a design choice — the same tradeoff exists in every compiled language. The source file is the source of truth because that’s what you version, review, and reason about.
- Recompilation is where the gains compound — when a stronger model ships, you recompile the same spec and get better output. If the code were the source of truth, you’d have to re-prompt your way back.
Most software has a source file and a compiled artifact. In C, you write .c files and the compiler produces machine code. In TypeScript, you write .ts and the compiler produces .js. The source file is what you edit, version, and treat as the program. The compiled output is what runs.
Remy doesn't write the code. It manages the agents who do.
Remy runs the project. The specialists do the work. You work with the PM, not the implementers.
Spec-driven development applies the same idea one level up. The source file is an annotated markdown document — a plain-language description of what the app does, with precision added through structured annotations. The compiled artifact is the TypeScript backend, the React frontend, the database schema, the auth flows. You describe the app. The compiler builds it.
This raises an obvious question: what happens when you edit the compiled code?
What Does “The Spec Is the Source of Truth” Actually Mean?
In a spec-driven project, the spec lives in src/app.md. It’s a markdown file that describes the application in readable prose, with annotations that carry the precision: data types, validation rules, edge cases, UI hints. When you hit build, Remy compiles this spec into a full-stack application — backend methods in TypeScript, a React frontend, a serverless SQL database with typed schemas, auth flows with verification codes and sessions, tests, deployment config.
The code lives in dist/. It’s real TypeScript. You can read it, run it, deploy it. But it’s not the source of truth. The spec is.
This is the same relationship .ts has to .js in a TypeScript project. The .ts file is the source. The .js file is what runs. You don’t hand-edit the .js and expect the .ts to stay in sync. You edit the .ts and recompile.
The difference: in spec-driven development, the source language is annotated prose instead of TypeScript syntax. The compiled output is still TypeScript — it’s just one more level down the abstraction ladder.
Why the Spec, Not the Code?
Three reasons the spec is the better source of truth:
1. Readability. The spec is readable by anyone — PMs, designers, operators, engineers, AI agents. The code is readable by engineers and AI agents who understand TypeScript and React. When the project needs to be understood six months from now, or by someone who wasn’t there when it was built, the spec is the artifact that explains what the app does and why.
2. Recompilation gains. When a stronger AI model ships, you recompile the same spec and get better code. Cleaner architecture, faster queries, better error handling, modern framework patterns. The spec doesn’t change. The compiled output improves. If the code were the source of truth, you’d have to re-prompt your way back through every feature to get the same upgrade.
3. The spec is the contract. The spec defines what the app does: the methods, the tables, the roles, the interfaces. The code is one implementation of that contract. As long as the contract stays stable, the implementation can change — better models, different frameworks, performance optimizations — without breaking anything that depends on it.
This is the same reason API specs (OpenAPI, GraphQL schemas) are treated as source of truth in backend development. The spec is the contract. The implementation is derived.
What Happens When You Edit the Code?
You can edit the code. It’s real TypeScript, sitting right there in the project. Open it in Cursor, make changes, save them. Nothing stops you.
But now the code and the spec are out of sync. The spec says the app does X. The code does Y. This is drift.
Remy is new. The platform isn't.
Remy is the latest expression of years of platform work. Not a hastily wrapped LLM.
Drift isn’t a failure. It’s a natural consequence of having two representations of the same program. The question is how you reconcile them.
How Reconciliation Works
Remy provides a sync button that reconciles changes in either direction:
Sync spec → code: You edited the spec (added a new table, changed a method signature, rewrote a user flow). Click sync, and Remy updates the code to match. This is the primary workflow. You describe what you want in the spec, and the code follows.
Sync code → spec: You edited the code (fixed a bug, optimized a query, added a feature by hand). Click sync, and Remy updates the spec to reflect what the code now does. This is the escape hatch. If you made changes directly in dist/, you can pull them back into the source of truth.
Both directions work. The sync is bidirectional.
But the recommended discipline is always sync spec → code. Treat the spec as the reset point. If something’s broken, fix it in the spec and recompile. If you need a new feature, describe it in the spec and recompile. If you hand-edited the code and now the spec is stale, sync code → spec once to get back in sync, then go back to editing the spec.
Why? Because the spec is what compounds. The spec is what gets better when models improve. The spec is what another person (or another AI agent) can read and understand. The code is ephemeral. The spec is the program.
The TypeScript Analogy
This is the same tradeoff TypeScript developers navigate every day.
In a TypeScript project, you write .ts files. The compiler produces .js files. The .js is what runs. Technically, you could hand-edit the .js files. They’re just JavaScript. But nobody does, because:
- The
.tsfile is the source of truth. That’s the file you maintain and reason about. - The
.jsfile gets overwritten on the next compile. - If you edit the
.jsand want to keep the change, you have to manually port it back to the.ts— and at that point, why not just edit the.tsin the first place?
Same logic applies here. The spec is the .ts. The code is the .js. You can edit the code. But the discipline that keeps the project maintainable is: edit the source, recompile.
The difference: TypeScript’s compile step is deterministic. The same .ts always produces the same .js. Remy’s compile step uses an LLM, so the same spec can produce slightly different code on each compile. That’s a real tradeoff (see the non-determinism discussion in product agents). But the source-of-truth principle holds either way. The spec is what you version and reason about. The code is what runs.
When Hand-Editing the Code Makes Sense
There are legitimate cases where editing the code directly is the right move:
Debugging in production. Something’s broken, users are blocked, and you need a fix now. You don’t have time to update the spec, recompile, test, and deploy. You edit the code, hit Publish, and the fix is live. Then later, when the fire’s out, you sync the spec to match what you changed.
Performance optimization. The compiled code works but it’s slow. You profile it, find the bottleneck, rewrite the query by hand. The spec doesn’t need to change — the contract is the same, the implementation is just faster. You can leave it as a code-level optimization, or sync it back to the spec if you want the optimization to survive future recompiles.
Learning. You’re new to spec-driven development and you want to see what the compiled output looks like. You edit the code, see what breaks, learn how the pieces fit together. That’s fine. Just remember to sync back to the spec before you move on.
The point isn’t “never touch the code.” The point is: the spec is the source of truth, so any change you want to keep needs to end up in the spec eventually.
Why This Isn’t a Flaw
Every compiled language has this tradeoff. You could hand-edit the assembly output of a C compiler. You could hand-edit the JavaScript output of a TypeScript compiler. You could hand-edit the bytecode output of a Java compiler. Technically, it’s all possible.
But nobody does, because the source file is the source of truth. That’s the file you version, review, and reason about. The compiled output is ephemeral. It gets regenerated.
Spec-driven development applies the same principle one level higher. The spec is the source. The code is the output. You can edit the output. But the discipline that keeps the project maintainable is: edit the source, recompile.
The gains come from the fact that the source is readable, versionable, and improvable. When models get better, the same spec compiles into better code. When a new developer joins the team, they read the spec to understand what the app does. When you need to explain the project to a stakeholder, you show them the spec, not the TypeScript.
The code is what runs. The spec is the program.
How This Compares to Coding Agents
Coding agents like Cursor or Claude Code work at the code level. You point them at a codebase, describe what you want, and they edit the files. The code is the source of truth. There’s no higher-level spec. The chat log is the only record of intent.
This works well for editing an existing codebase. If you already have a project and you need to add a feature or fix a bug, a coding agent is the right tool. It reads the code, understands the context, makes the change.
But it doesn’t work well for building a new project from scratch, because there’s no source of truth above the code. The code is the program. If you want to change the architecture, you re-prompt the agent and hope it edits the right files. If a better model ships, you don’t get an automatic upgrade — you have to re-describe what you want and let the new model rewrite it.
Other agents start typing. Remy starts asking.
Scoping, trade-offs, edge cases — the real work. Before a line of code.
Spec-driven development inverts this. The spec is the source of truth. The code is compiled output. When you want to change the architecture, you edit the spec and recompile. When a better model ships, you recompile the same spec and get better code.
Different tools, different layers. Coding agents edit code. Product agents compile specs. Both are useful. The question is which layer you want to work at. What Is a Product Agent? The AI That Ships a Whole App, Not Code explains the structural difference in detail.
The Discipline That Makes It Work
The spec-as-source-of-truth model works when the team follows one rule: edit the spec, recompile.
If you need a new feature, describe it in the spec and recompile. If something’s broken, fix it in the spec and recompile. If you hand-edited the code, sync the spec to match, then go back to editing the spec.
This discipline is the same discipline that makes TypeScript work. You don’t hand-edit the .js files. You edit the .ts files and let the compiler handle the rest.
The payoff: the spec stays readable, the project stays maintainable, and when better models ship, you get better code for free.
FAQ
Can I use a coding agent on a Remy-built app?
You can edit the code by hand, so yes, you could point Cursor or Claude Code at the dist/ folder and let them make changes. But the way Remy stays useful is updating the spec. The spec is what gets recompiled when models improve. The spec is what reproduces the build. The spec is the source of truth. If you hand-edit the code (or let a coding agent edit it), sync the spec afterward so the two stay aligned.
What if I don’t want to recompile? Can I just keep the code?
Yes. The code is real TypeScript and it’s yours. You can take it, run it anywhere, keep maintaining it by hand. But if you stop syncing the spec, you’ve left the spec-driven workflow. You’re back to maintaining code by hand. That’s fine — it’s your project. But you lose the recompilation gains (better models → better code) and the readability gains (the spec as documentation).
How often should I recompile?
Whenever the spec changes. If you edited the spec to add a feature, recompile. If you edited the spec to fix a bug, recompile. The compile step is fast (usually under a minute for incremental changes). Treat it like running tsc in a TypeScript project — you do it every time the source changes.
What if the recompiled code breaks something that was working?
That’s a real risk with LLM-based compilation. The same spec can produce slightly different code on each compile. If a recompile introduces a regression, you have two options: (1) fix the spec to be more precise about what you want, then recompile again, or (2) hand-edit the code to fix the regression, then sync the spec to match. Either way, the spec ends up as the source of truth.
Is this actually spec-driven development, or is it just “AI writes code”?
Other agents ship a demo. Remy ships an app.
Real backend. Real database. Real auth. Real plumbing. Remy has it all.
The difference is where the source of truth lives. In “AI writes code” workflows (coding agents, vibe coding), the code is the source of truth and the AI is a tool that edits it. In spec-driven development, the spec is the source of truth and the code is compiled output. The AI is the compiler. Same way tsc is the compiler for TypeScript. The abstraction layer is different.
What happens when I deploy? Does the spec get deployed too?
No. When you hit Publish, Remy compiles the spec into code and deploys the compiled artifact — TypeScript backend, React frontend, database schema, auth flows — to a live URL. The spec stays in the project as the source of truth. When you need to change the deployed app, you edit the spec, recompile, and hit Publish again.
How does Remy stay useful as AI models improve?
The spec is the source of truth; recompile and the app upgrades. When a stronger model ships, you recompile the same spec and get cleaner architecture, faster queries, modern patterns — without re-prompting, without rewriting. The spec doesn’t change. The compiled output improves. That’s the recompilation advantage.
The Bottom Line
The spec is the program. The code is what gets compiled.
This isn’t a metaphor. It’s the actual architecture. The spec lives in src/app.md. The code lives in dist/. The spec is what you version, edit, and treat as the source of truth. The code is what runs.
You can hand-edit the code. Remy provides a sync button to reconcile changes in either direction. But the discipline that makes spec-driven development work is: edit the spec, recompile.
When you follow that discipline, three things happen:
- The spec stays readable. It’s the documentation, the contract, the artifact that explains what the app does.
- The project stays maintainable. New developers read the spec. Stakeholders read the spec. AI agents read the spec.
- Better models produce better code. When a stronger model ships, you recompile the same spec and get cleaner architecture, faster queries, modern patterns — without re-prompting, without rewriting.
The code is ephemeral. The spec is the program.
That’s what it means when the spec is the source of truth.
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.
