Generating Code ​
In Carotene, you do not write business logic; you write architectural boundaries and generative intent. But how does the framework actually translate your intent into deterministic, production-ready code?
Carotene does not just blindly send your entire file to an LLM and cross its fingers. The generation engine is a highly structured compiler pipeline that treats the AI as a pure logic synthesizer, strictly bounded by the rules of your architecture.
Here is the exact lifecycle of how Carotene generates your code.
1. Context Extraction (Parsing the Blueprint) ​
When you run carrot build or carrot dev, the Carotene compiler first acts like a traditional language compiler. It parses your .carrot files into an Abstract Syntax Tree (AST).
During this phase, the compiler discovers a "Code Hole"—your @(...) Generative Operator. Before it talks to the AI, the compiler builds a rigid Context Matrix for that specific hole. It gathers:
- The exact types of the input arguments.
- The expected return type of the function.
- The database schemas (
models) the function is allowed toreadorupdate. - The external
integrationsit is allowed tocall. - The specific test
assertsstatements that apply to this function.
2. The Prompt Assembly ​
Carotene does not use generic "Write me a function" prompts. It uses the Context Matrix to construct a mathematically precise system prompt.
If you wrote:
discount = @("Calculate a tiered volume discount based on past orders")Carotene builds a prompt that looks like this under the hood:
System: You are a deterministic logic synthesizer. Your output will be executed in a zero-trust sandbox.
Language: TypeScript
Context:
Input:
userId: stringAllowed DB Access:
store.Order (fields: id, userId, total, date)Return Type Expected:
numberTask: Write the internal logic to satisfy the following intent: "Calculate a tiered volume discount based on past orders".
Constraints: Do not write network code. Do not write SQL connections. Return ONLY the raw mathematical logic to calculate the discount.
By hyper-focusing the context, Carotene completely eliminates the risk of the AI hallucinating external libraries, guessing incorrect database table names, or writing boilerplate you didn't ask for.
3. The Implementation Stub ​
Once the LLM returns the synthesized code, Carotene does not hide it in a proprietary binary. It injects the code directly into a standard, human-readable file inside your monorepo's src/ directory.
// apps/core-backend/src/commerce/ApplyDiscount.ts
import { store } from '../../.generated/carotene-runtime';
export async function ApplyDiscount(userId: string): Promise<number> {
// --- CAROTENE GENERATED: "Calculate a tiered volume discount based on past orders" ---
const pastOrders = await store.Order.find({ userId });
const totalVolume = pastOrders.reduce((sum, order) => sum + order.total, 0);
if (totalVolume > 5000) return 0.20;
if (totalVolume > 1000) return 0.10;
return 0.00;
// --------------------------------------------------------------------------------------
}Because the code is generated into standard src/ files, you maintain total ownership. If you want to manually optimize a reduce function the AI wrote, you can just open the file and edit it. Carotene respects human edits and will not overwrite them unless you explicitly alter the @(...) operator in the blueprint.
4. The Autonomic Correction Loop (TDG) ​
As soon as the AI writes the stub, Carotene feeds the generated file into the Vapor Sandbox.
If your test block asserts that a heavy buyer gets a 0.20 discount, and the AI accidentally wrote >= 50000 (an extra zero), the test fails.
- The Sandbox intercepts the failure:
Expected 0.20, Got 0.00. - It captures the exact stack trace and the inputs that caused the failure.
- It creates a Correction Prompt: "Your previous logic failed. For input X, the test expected Y but received Z. Fix the logic."
- The AI rewrites the stub.
This happens in milliseconds. By the time your terminal prints Build Successful, the AI has already been audited, tested, and corrected by the framework.
Best Practices for the @(...) Operator ​
Because the AI's output is directly tied to the quality of your prompt, treating the Generative Operator with care is essential.
- Keep it scoped: Do not ask an operator to "Build the whole checkout flow." Break it down. Use deterministic code to check the user's role, and use
@(...)just to calculate the complex tax math. - Be mathematically explicit: Instead of saying
@("Make the text sound nice"), say@("Format the string as Title Case and append the localized currency symbol"). - Let the architecture do the heavy lifting: You never need to tell the AI how to fetch data or save data. Carotene's variables already handle that. Use the operator strictly for data transformation.