Early product · starting with ERPNext
Data, logic, action and security — in one place.
Palantir does it for governments. Norn does it for the businesses Palantir will never serve, starting with ERPNext.
commerce.Order
Order #1042 confirmed
- 09:10WhatsAppMessage from Ahmed Mansour:
need 300 cartons by Thursday
- 09:10ruleClassified as new order for Customer · Ahmed Trading
- 09:11sales_agentDraft order created · 300 × carton 40×30 · requested Thu
- 09:11workflowStep confirm order started · needs stock and credit
- 09:11sales_agentChecked stock via
inventory.check_stock· 1,120 on hand, Alexandria WH - 09:12ruleCredit OK · exposure EGP 31,500 within limit
- 09:12Mona S.Confirmed delivery Thu 24 Sep
- 09:12ERPNextSales Order SAL-ORD-2026-00318 created
- 09:13sales_agentReplied on WhatsApp:
Confirmed, 300 cartons, Thursday 24 Sep
export const Order = Norn.type({
name: "commerce.Order",
properties: Schema.Struct({
number: Schema.String,
customer: Norn.link(Customer),
lines: Schema.Array(OrderLine),
delivery_date: Schema.NullOr(Norn.date),
status: Schema.Literals(["draft", "confirmed", "shipped", "invoiced"]),
}),
sources: [erpnext.SalesOrder, shopify.Order, whatsapp.Message],
lifecycles: [{
property: "status",
transitions: [
{ id: "confirm", from: ["draft"], to: "confirmed", gate: "human:sales" },
{ id: "ship", from: ["confirmed"], to: "shipped" },
{ id: "invoice", from: ["shipped"], to: "invoiced" },
],
}],
})
// tools/list · what the agent sees
{ "name": "inventory.check_stock",
"inputSchema": { "product": "string", "warehouse": "string" },
"annotations": { "reads": "inventory.Stock", "writes": [] } }
// tools/call · check_stock(carton-40x30, alex-wh)
{ "on_hand": 1120, "reserved": 180, "available": 940,
"as_of": "2026-09-21T09:11:04Z",
"ledger": "sha256:…", "why": "/v1/why/inventory.Stock/alex-wh:carton-40x30" }
Illustrative worked example. Delta Pack, Ahmed Trading and every number on this page are fictional sample data.
One model
One model across your systems.
Customers, orders, suppliers, invoices and products live in ERPNext, Shopify, WhatsApp and email. Norn resolves them into one typed model of how the business works, and every value remembers where it came from.
Workflows
Workflows that run on it.
A message becomes a draft, a draft becomes a confirmed order, and the order lands in ERPNext. The steps are declared, checked before they run, and where the rules say so, a person decides.
Agents
Agents that work through the same tools, with the same permissions as people.
An agent drafts the order, checks stock through an MCP tool and replies to the customer, with the same authorization, lifecycle checks and ledger as a person. What it can’t do, the model refuses with the reason, and a person picks it up.
Explainable
Every change explainable.
Ask why the delivery date is Thursday and Norn walks back from the field to the message, the stock check and the person who confirmed it. Same answer for a person, an auditor or an agent: it is one call.
Five things you can’t bolt on later.
Each needs data, logic, action and security in one model. Split them across tools and none of these exist. Today runs in the engine on norn dev; sample data runs against replayed sample data.
Agent permissions that know the state Today
What an agent may do depends on where the order is, not only on its role.
Workflows verified before they run Today
A workflow that confirms without the declared human gate is rejected before it ever runs.
Reality against intent Sample data
Process mining over your own history shows which steps were skipped, and who skipped them.
Changes backtested on the past Sample data
Change a rule and see which past orders it would have held, before you switch it on.
People in the loop, with the evidence Today
The confirmation goes to a person as a task with the message, the stock and the credit side by side.
Why not Palantir?
Palantir proved the model: data, logic, action and security in one ontology. It is among the most valuable software companies in the world, it works with governments and the largest enterprises, and it is priced and staffed for them. For nearly every other business it is out of reach.
Norn is the same idea for a different customer: the distributor in Alexandria, the factory in 10th of Ramadan, the ERPNext partner serving fifty of them. A product you install and can run yourself, starting from the ERPNext you already have, not a programme you buy.
Sovereign by design.
This technology is too important to rent from abroad. Norn is built so a business, or a country, can run it on its own terms. Built in Alexandria, for businesses like ours.
Your data in your own file Today
Each business’s state and ledger live in one database file it can export, verify and restore, with nothing held back.
Cloudflare or in-country Next
The same kernel runs hosted at the edge or self-hosted on your own servers inside the country. The self-hosted cell daemon is next.
Open, inspectable formats Today
A SQLite file, JSON definitions and a hash-chained ledger export you can read with ordinary tools.
Unabstracted primitives for agents.
An agent sees exactly four things. There is no hidden glue between them, so what the agent can do is what the model says it can do.
Data
Typed objects and the links between them, each value with its source.
Rules + workflows
Decision tables and declared steps that fire on events.
Permissions
Cedar policies evaluated against the state of the facts, not just the role.
Actions
Every admitted action, served as an MCP tool with a typed answer, or a typed refusal.
States and events
States and events are first-class.
Lifecycles are declared state machines: only a declared transition can move a state, and it is enforced at commit. Every commit appends events to a hash-chained ledger: created, transitioned, observed, deleted, timer, refused. Rules trigger on those events.
A write that isn’t a declared transition is refused, whoever asks. Hashes elided.
{ "kind": "observed", "actor": "sales_agent",
"tool": "inventory.check_stock",
"object": "inventory.Stock/alex-wh:carton-40x30",
"facts": { "on_hand": 1120, "available": 940 },
"prev": "sha256:…", "hash": "sha256:…" }
{ "kind": "transitioned", "actor": "mona.s",
"object": "commerce.Order/1042",
"transition": "confirm", "from": "draft", "to": "confirmed",
"gate": "human:sales", "cause": ["whatsapp.Message/9f2c", "observed/…"],
"prev": "sha256:…", "hash": "sha256:…" }
A constrained, pure-functional core.
Definitions are pure data. Rules are pure functions over a slice of state and an event, with budgeted expressions: no IO, no clock, no randomness. Side effects leave only as explicit commands, and their results come back as observations that are re-checked before they count.
observe
Results return as observations, re-checked against the rules before they count as facts.
pure core
decide(slice, event) → facts + commands + timersno IO · no clock · no randomness · budgeted expressions
perform
Commands leave as explicit effects: a stock check, a WhatsApp reply, a write to ERPNext. Named, authorized, ledgered.
const now = Date.now() // NORN-FLOW-AMBIENT 9:17
const coin = Math.random() // NORN-FLOW-AMBIENT 10:18
A very lean stack.
A pure Rust core, a sans-IO kernel compiled to native and to wasm, and one Durable Object per tenant holding that tenant’s data in its own SQLite file. There is no database cluster, queue cluster or fleet of microservices to run, because the cell is its tenant’s database, workflow engine and policy point in one process.
Pure Rust core Today
A sans-IO kernel that decides transitions. Same inputs, same result, native or wasm.
One SQLite file per tenant Today
State and ledger together in a single file the tenant can export, verify and restore.
Local host · norn dev Today
The whole cell on a laptop: scoped reads, ledger, OpenAPI and MCP.
Cloudflare Durable Object host Rolling out
One Durable Object per tenant at the edge, timers on the DO alarm. Being deployed now.
Definitions are data. Rules are pure functions. Effects leave only through perform. Small and inspectable pays three times: cheaper to run, easy to self-host in-country, and less surface for an agent to get wrong.
Agents never touch prod. Norn works like git.
An agent works on a fork of the business, a branch of the ledger, never on prod. Its changes merge back only through the same checks; conflicts are explicit, because every write is version-checked, and the agent has to resolve them. A bad merge is reverted by replaying the ledger. Mostly planned; the labels say which is which.
Hash-chained ledger Today
Every commit appends; the head is verified on read. Export and verified restore rebuild a cell.
Version-checked writes Today
Compare-and-set, so a stale write is refused, not merged. Backtesting a rule change on history runs on sample data.
Forks, rollback, simulation Next
Per-agent forks and merges; point-in-time rollback (an agent deletes every customer record; you roll back in one step); simulation against the fork or against history.
Leaner agents on a thinner substrate.
When the structure lives in the substrate, the model has less to get right. Typed objects, declared states, rules, permissions, and answers that say exactly what is true: the substrate catches what a smaller model would miss, so smaller and cheaper models can do work that otherwise needs the smartest one.
The model proposes; the rules decide. An agent drafts the order and checks the stock; whether the order confirms is the workflow’s call, with a person at the gate. A thesis we are building on, not a benchmark claim.
MCP
MCP as the universal tool surface.
Point an agent at /mcp. It gets your actions, not your database. Calls go through the same authorization, lifecycle checks and ledger as a person’s, and the answer is typed, so the agent knows exactly what it learned.
Today Every Norn action is an MCP tool, with authorization, lifecycle checks and typed answers, plus norn.why.
Next External HTTP, GraphQL, SDK and other MCP services wrapped as Norn tools, agentgateway-style, under the same permissions.
{
"mcpServers": {
"norn": {
"type": "http",
"url": "http://127.0.0.1:8787/mcp",
"headers": { "x-norn-org-id": "org_demo", "x-norn-actor": "sales_agent" }
}
}
}
commerce.order.draftinventory.check_stockwhatsapp.replynorn.why
Early product. Here is exactly where it is.
- Runs today
norn dev: a local cell with scoped reads, ledger and OpenAPI- MCP: admitted actions as tools, plus
norn.why - Cedar PDP: actions and reads authorized by compiled policy
- Rules: decision tables in the dev loop
- why: lineage with matched rows
- ERPNext: signed webhooks and mapping into Norn types
- Exact decimals in the IR and runtime values
- Restore from a verified ledger export
- Version-checked writes: a stale write is refused
- Next
- Hosted cells on Cloudflare Durable Objects, rolling out now
- Admin UI for definitions, ledger and reviews
- External services as tools under the same permissions
- More connectors beyond ERPNext, Shopify, WhatsApp and email
- Installing definitions into a running cell
- Per-agent forks, rollback, simulation
- Self-hosted cells in-country, on your own servers
Early product. If you run a business on ERPNext, or implement it for others, I want to talk.
A walkthrough on your own order flow, no slides. Operators and ERPNext implementation partners first.
Youssef Tarek Ali, founder