Language Syntax ​
The .carrot file is a strictly typed, declarative architectural blueprint. It is designed to be highly readable for humans, mathematically parsable by the Carotene compiler, and semantically perfect for the LLM generation engine.
This page serves as the complete syntax reference for the Carotene language.
1. Top-Level Declarations ​
Every .carrot file must contain at least one target architecture block (backend / frontend) or data primitive.
domain (Optional Namespace) ​
Acts as an organisational namespace for grouping related models, stores, and state machines.
- If omitted: All primitives are registered to the Global Namespace. Use this for small projects or simple prototypes.
- If used: All internal primitives are scoped to the domain name. Use this to prevent naming collisions in large monorepos.
Note: domain does not dictate your folder structure or deployment architecture; it is purely a compile-time naming convention.
// Global Namespace (No domain block)
model User { ... }
// Scoped Namespace
domain Commerce {
model Order { ... }
}backend / frontend ​
Defines a physical microservice or application target. The name you provide here dictates the folder name generated dynamically in your monorepo.
backend: Internal service mesh APIs.frontend: User-facing web or mobile applications.
backend CoreAPI {
// Functions go here
}
frontend AdminDashboard {
// Views go here
}2. Namespace Resolution & Referencing ​
Carotene uses strict lexical scoping to resolve references between frontends, backends, and data stores. You reference primitives using dot-notation paths.
To keep your code clean, Carotene supports Relative Pathing. You can omit parent names if you are referencing something within the same scope.
Absolute vs. Relative Paths ​
Imagine the following architecture:
domain Commerce {
backend OrderAPI {
store { model Order { id: UUID } }
function Process() { ... }
}
frontend Web { ... }
}- Absolute Path: If you are outside the domain entirely, you must use the full path:
Commerce.OrderAPI.store.Order. - Same Domain: If you are inside the
Webfrontend, you can drop the domain name:calls OrderAPI.Process. - Same Backend: If you are inside another function in
OrderAPI, you drop the backend name:reads store.Order.
Unnamed Blocks ​
If a block does not have a custom name, you simply use the keyword itself in the path.
// Unnamed backend and unnamed store
backend {
store { model User { id: UUID } }
}
frontend {
// Uses the literal keywords 'backend' and 'store'
view Profile(user: backend.store.User) { ... }
}Property Access ​
You can dot all the way down to specific model properties, which is highly recommended for function arguments to ensure perfect type alignment.
// Binds the argument directly to the UUID type of the Order's ID
function GetOrder(orderId: store.Order.id) {
reads store.Order
implements { ... }
}3. Decorators (Execution Ownership) ​
Decorators define who is responsible for implementing a block of code. They can be applied to any structural block (domain, backend, frontend, function, or loop).
@ai(Implicit Default): The Carotene compiler will actively manage thesrc/files for this block. It will invoke the LLM to synthesise the@("...")generative operators and overwrite the file if the contract description or signature changes.@manual: The compiler will generate the initial empty stub and strict native interfaces, but it will never invoke the AI or overwrite thesrc/file. Ownership is permanently yielded to the human developer.
Inheritance and Scoping ​
Decorators cascade downwards. The most specific decorator wins.
// 1. The entire backend is manual
@manual
backend PaymentAPI {
// Inherits @manual. Hand-written by a developer.
function ProcessRefund() {
implements {
tax = @("Calculate the 5% processing fee")
}
}
// 2. Specific Override: This single function delegates back to the AI
@ai
function FormatCurrency(amount: Float) {
implements {
formatted = @("Format as USD")
}
}
}4. Data & State Primitives ​
These blocks define the strict shapes and permitted lifecycles of your data. They can be declared globally or inside a domain.
model ​
Defines a data structure. Models are purely abstract and are not inherently connected to a database.
- Supported Primitives:
String,Int,Float,Boolean,UUID,Date,JSON. - Optional Fields: Suffix with
?.
model User {
id: UUID
email: String
age: Int?
}flow ​
Defines a deterministic finite state machine.
flow OrderState {
Pending -> Paid
Paid -> Shipped
Paid -> Refunded
}store ​
Binds a model to the physical database, exposing it to the Carotene runtime.
store Customer {
model: User
}5. Execution Primitives ​
These blocks define the actual executable APIs and autonomous workflows. Both are available in backend and frontend blocks; the compiler infers the runtime infrastructure (e.g., CRON vs. requestAnimationFrame) based on the context.
function (Event-Driven) ​
Defines an event-driven workflow. Arguments must be strictly typed, often referencing store or model fields directly.
function ProcessRefund(orderId: store.Order.id) {
reads store.Order
implements {
// Logic goes here
}
}The Fast-Path Shorthand (=>) ​
For simple, deterministic execution logic, you can use the expression-bodied shorthand => to eliminate boilerplate. Functions that use this shorthand are statically analyzed and do not require explicit Zero-Trust permission verbs.
// UI Component
view Button(label: String, onClick: Function) = @("Render a button.")
// Deterministic Function
function UpdateName(val: String) => state.User.name = valsocket (Real-Time Bidirectional) ​
Defines a continuous, bidirectional handler. The implements block runs once per received message, and returning a value automatically emits it back to the client's open stream.
socket HandleChat(msg: String) -> String {
reads store.Message
implements {
@("Process the message and return the response")
}
}loop (Continuous) ​
Defines a continuous, autonomous background workflow.
loop MatchmakingWorker {
config {
stream: { listensTo: state.PlayerQueue }
}
reads state.PlayerQueue
updates store.Match
implements {
@("Match players together")
}
}6. Security & Permission Primitives ​
These blocks define the Zero-Trust boundaries of your system.
gateway ​
Defines an ingress boundary for external traffic or programmable controls. Gateways must be defined inside a backend or frontend block. They act as routers, mapping external API URLs (and parameters) directly to functions defined in your architecture.
Gateways support protocol-specific routing blocks (such as rest { } for HTTP methods and paths, or rpc { }) to map incoming external endpoints explicitly to your internal functions.
backend CoreAPI {
function ProcessStripeWebhook(payload: JSON) { ... }
gateway ExternalAPI {
rest {
POST "/webhooks/stripe" -> ProcessStripeWebhook()
}
}
}integration ​
Defines an external software API, SDK, or hardware device.
- Scope: Must be defined inside a
backendorfrontendblock to prevent cross-boundary secret leakage. - Usage: Exposes external methods that can be triggered using the
callsverb.
requires (RBAC) ​
Immediately evaluates a condition. If it returns false, the function immediately terminates with an HTTP 401 or 403.
requires session.isAuthenticated == true
requires session.role == "Admin"The Zero-Trust Verbs ​
Explicitly declare what the function or loop is allowed to touch. If a verb is omitted, the Sandbox will physically block the action.
reads: Allows querying a specific store.updates: Allows mutating an existing record in a store.creates: Allows inserting a new record into a store.deletes: Allows removing a record from a store.calls: Allows outbound network requests to a defined integration.
reads store.Customer
updates store.Order
calls integration.Stripe7. Internal Logic & Variables ​
Inside a function or loop, you can write deterministic logic to handle fast-paths, assignments, and validation.
Variable Assignment ​
Standard assignment. Types are inferred automatically by the compiler.
customer = store.Customer.find(customerId)
fee = 5.0Conditionals (if / else) ​
Standard control flow.
if (customer.tier == "Gold") {
fee = 0.0
} else {
fee = 5.0
}error ​
Defines a strongly typed error primitive. Can be used for declarative error handling across boundaries.
error InsufficientFunds {
shortfall: Float
}throws ​
Immediately terminates the function and returns an error payload. Used for business logic validation.
if (order.ageInDays > 30) {
throws "Refund window has expired"
}
if (wallet.balance < cost) {
throws error.InsufficientFunds({ shortfall: cost - wallet.balance })
}catches ​
Used to catch strongly typed errors thrown by the backend or an integration.
backend.Process(id) catches InsufficientFunds (err) {
implements {
@("Handle the insufficient funds error by displaying a message")
}
}The Generative Operator (@) ​
The "Code Hole". Instructs the compiler to securely pass the bounded context to the configured LLM to synthesize the underlying implementation.
// Assignment generation
discount = @("Calculate the prorated volume discount")
// Fire-and-forget generation
@("Format the customer's address and map it to the Shipping target")triggers ​
Executes a state machine transition defined in a flow. If the transition is illegal, it throws an error.
triggers targetOrder.status.Refundedreturn ​
Outputs the final payload of the function to the client.
return discount8. Testing Primitives ​
The test block is a flat structure used to mathematically prove the AI's logic inside the Deterministic Sandbox. Tests can be placed anywhere in a .carrot file.
test ​
Defines the test scenario.
test "Calculates the correct discount" {
// Test code goes here
}config ​
Configures the Sandbox environment for the specific test block.
sandboxoptions:EmbeddedWASM(Default, ~2ms),DockerTransactional(Heavy, real-world DB features).time: Freezes the sandbox clock to a specific string.
config {
sandbox: EmbeddedWASM
time: "2026-01-01"
}given / mock ​
Seeds the isolated sandbox or intercepts external boundaries.
- Use
given... = mock store...to seed the database and bind a local variable simultaneously. - Use
mock integration... -> valueto intercept a network boundary and return a fakeFuture. - Use
throwsto simulate network errors.
// Database Mocking & Binding
given user = mock store.User { id: "1", role: "Admin" }
// Network Mocking (Success)
mock integration.Stripe.Charge -> "txn_123"
// Network Mocking (Failure)
mock integration.SendGrid.Send -> throws "Timeout"asserts ​
Evaluates a mathematical truth at the end of the test. If false, the AI is prompted to fix the code.
// Asserting variable output
asserts result == 100.0
// Asserting Sandbox database state
asserts store.User.find("1").status == Active
// Asserting network side-effects
asserts integration.Stripe.Charge.wasCalledWith(100.0)
asserts integration.Stripe.Refund.wasNotCalled()
// Asserting errors
asserts ProcessRefund(order.id) throws "Refund window has expired"