Rules, not code.
You say what is allowed and what follows from it. Mandala derives the rest: the state a record keeps, the screens to work on it, the API, the tables and the search. The rule is the program, and anyone on the team can read it.
Fry finds 120 crates of waffle irons bound for the Moon and decides to save everyone time by shipping them now.
He can’t. Neither can Mira, and neither can Hermes. The delivery contract says nothing goes to the Moon until a second person confirms it, and the contract is checked before anything happens.
Nobody wrote code to stop Fry. Hermes wrote one line about the Moon, months ago, and Leela approved it.
Nothing goes to the Moon until a second person confirms it. I’ve asked Leela.
state.status == Confirmed or state.destination != "Moon"
Say what is allowed.
A contract is a short text in DHL, a small language made for business rules. It names the state a record keeps, the actions that may change it, and what must hold for each one. That is all there is to write.
The check happens before anything is written, for people, the accomplice and outside apps alike. There is no admin screen that skips it.
Describe the rule in your own words. Your accomplice drafts the DHL, tries it on a scratch copy and shows what it would accept and refuse. A person signs it before it is installed.
A new version names the exact version it replaces and how existing records move across. The move is itself an action, checked and recorded.
# Nothing ships to the Moon, or over 200 units,# without a second person confirming (Leela).action Ship() authorize dhl validate state.paid or state.credit_terms state.crates_checked == state.crates state.status == Requested or state.status == Confirmed state.status == Confirmed or state.units <= 200 state.status == Confirmed or state.destination != "Moon" apply state.status = Shipped
The whole contract (65 lines)
aggregate Delivery state public customer: Text(len=200) public destination: Text(len=100) public units: Int = 0 public crates: Int = 0 public crates_checked: Int = 0 public paid: Bool = false public credit_terms: Bool = false public requested_by: Identity public confirmed_by: Identity public status: Enum(New, Requested, Confirmed, Shipped) = New action Request(customer: Text(len=200), destination: Text(len=100), units: Int, crates: Int, credit_terms: Bool) authorize dhl validate state.status == New units > 0 crates > 0 apply state.customer = customer state.destination = destination state.units = units state.crates = crates state.credit_terms = credit_terms state.requested_by = context.signer state.status = Requested action CheckCrate() authorize dhl validate state.status == Requested state.crates_checked < state.crates apply state.crates_checked = state.crates_checked + 1 action Confirm() authorize dhl validate state.status == Requested context.signer != state.requested_by apply state.confirmed_by = context.signer state.status = Confirmed action Pay() authorize dhl validate state.status != New state.paid == false apply state.paid = true # Nothing ships to the Moon, or over 200 units,# without a second person confirming (Leela).action Ship() authorize dhl validate state.paid or state.credit_terms state.crates_checked == state.crates state.status == Requested or state.status == Confirmed state.status == Confirmed or state.units <= 200 state.status == Confirmed or state.destination != "Moon" apply state.status = Shipped
Real DHL, exactly as it runs: this contract compiles. Every action is checked against it before it happens, for people and AI alike.
Everything else follows.
In an ordinary application the rule above would be spread over a database schema, validation code, an API layer, permission checks, an admin screen and an audit table, and they would drift apart. Here they are all read off the one contract.
What a record is now: its facts, added up.
todayNamed steps, and only the moves the actions allow.
todayLists you can filter and sort, a page per record, a button per action.
todayREST, GraphQL and gRPC descriptions generated from the contract.
todayQueries and projections declared next to the rules, kept current.
todayRanked search over the fields you name.
todayEach action and query becomes something it can ask for, under the same check.
todayDeclared in the contract like the rest.
coming- New
Requestanyone on the crew- Requested
Confirmnot the one who asked- Confirmed
Shippaid or on credit, every crate checked- Shipped
A small delivery may go straight from Requested to Shipped. Over 200 units, or anything bound for the Moon, has to pass Confirmed first.
projection PublishedPublications trigger action.* source state batch_window 0ms query std.commerce.storefront_publication | where published == true | select subject, seq, property, market, channel, product_subject, category_subject, slug, subtitle, description, image_path, featured, sort_order emit upsert published_publications
Real: a projection declared in a contract. Every action on a storefront publication updates the published list, with no delay.
Same history, same answer.
A rule is evaluated the same way everywhere: no clock it reads on its own, no network call, no randomness, no AI model inside a decision. Give the same contract the same facts in the same order and it reaches the same state, on your laptop, on your server, or on an auditor’s machine.
Compiling a contract gives it an id made from its exact content. A name alone never identifies what runs.
Throw every table and index away and the facts rebuild them, identically. Today a restart does exactly that.
When the new index kinds arrive, a decision may only use exact ones. Approximate search is for reading, never for deciding.
The real fingerprint of this contract. Change one character of a rule and it changes. Every record says which fingerprint decided it, so “which rules were in force?” has an exact answer.
What works today, and what’s coming.
DHL contracts with state, actions, validation, lifecycles, queries and projections; refusals that name the rule; a screen file per contract that gives tables, record pages and plain sentences for each rule; generated API descriptions; upgrades with migrations; a language server and the Workbench to write and try contracts, with diagnostics and completion.
Contracts that declare vector, graph and time-series indexes and query them together (built on a branch, not released). Installing a contract without a restart.
A rule is only as good as what its authors thought of. Mandala guarantees that the rule you wrote is the rule that ran. It can’t guarantee you wrote the right rule, which is why rules are short, readable and signed by a person.
Code says how. A rule says what must be true.
A small one, on purpose. It can say what a record holds, who may do what, and what must hold. It can’t open a socket or loop forever, and that is what makes it checkable.
Talking to the outside world is done by connectors, with their own declared access and approvals. The pages of a public website stay in a frontend framework, with Mandala as the backend behind it. How Dharma works