App logic, shaped to each user at runtime.
One document per customer, holding rules, tools, and state: your agent can update it, you can reason about it, and your app can run it.
Stof is JSON with functions, run in a sandbox inside your app, in Rust, JavaScript, or Python.
npm i @formata/stofcargo add stofpip install stof
auto_approve_under: 50refunded: 0fn refund(order: str, amount: float) -> str {if (amount >= self.auto_approve_under)return 'escalated';Payments::refund(order, amount);self.refunded += amount;'refunded'}
One customer's document. The agent changed one line, and the app now behaves differently for that customer.
Why a document
Teams building agents end up hand-building each customer's rules out of prompts, JSON, and glue code. The usual options each break somewhere.
It can only use what your app hands it
Each customer's document gets its own tools, and nothing else. The sandbox isn't added on; it's how a document runs.
The tools you give it.
Your app registers functions for each document (Ex. acme.lib('Payments', 'refund', refund)). A call to anything else fails with an error that says so.
Nothing else is on.
No file system, network, or environment unless you turn them on, and network access can be limited to the hosts you list.
A time limit on every call.
Two minutes by default, set by your app. Errors give the line and a plain explanation, so a model can fix its own change.
Why it works: everything is data
Stof has functions, but it isn't a language for writing apps. It's a document, and every part of it is data, functions included.
root (acme.stof) ├── auto_approve_under: 50 field ├── refunded: 0 field, state the tool updates └── refund() function, data like a field
Anything you can do with data, you can do with logic.
Merge two documents, pull one object out with its functions, diff two versions, store it in a database row per customer, or send it over the wire as compact binary.
A document can change while it runs.
It can parse new fields and functions into itself, or drop them, with no build step. That's what lets an agent change one customer's behavior without a deploy.
It grows to fit your domain.
Your app adds its own functions, types and schemas live in the document, and in Rust you can add your own formats and kinds of data. Instead of designing a rules language or DSL for your product, describe your domain in Stof.
There's very little to learn.
If you can read JSON and a bit of JavaScript, you can read Stof, and so can a model.
It starts as JSON
Any JSON document is already valid Stof. Add types and functions where you need them, and export back to JSON, YAML, or TOML any time.
Animation showing that a JSON object is already a valid Stof document: the outer braces and key quotes are removed, types are added to each field, and a greet function is added alongside the data.
Valid JSON is already valid Stof.
Reach for Stof when
- Each customer, user, or tenant needs its own rules, tools, limits, or state, and an agent or a person needs to change them safely.
- A model, a user, or a customer gives you logic you need to run: rules, filters, transforms, scoring, tool behavior.
- You're about to invent a config format, rules engine, or DSL for your product.
- The same logic has to run in the browser, on a server, and in a worker, and give the same answer.
- You want to change behavior by sending or storing a new document, not by shipping a deploy.
Start with the data you have
A library inside your app. No server, container, or extra process.
- JavaScript and TypeScript
npm i @formata/stof- Rust
cargo add stof- Python
pip install stof- Command line
cargo install stof-cli
Editor support comes with the CLI: the VS Code extension gives you errors as you type, go to definition, completion, and rename. To teach an AI model Stof, give it the Stof skill.