Cookbook
Each recipe here is a real problem, solved end to end: the Stof document, which you can run on the page, and the app code around it. Every one comes down to the same thing: logic that changes more often than your app, or comes from somewhere other than your codebase, as data your app can check and run safely.
Recipes
Logic from AI models
- Run Rules a Model Writes: turn a plain-English policy into code with a model, check it against tests and real examples, and run it on every request with no model call.
- Agent Tools at Runtime: tools as Stof functions, tool definitions generated from them, and an agent that writes new tools mid-conversation, all sandboxed.
Logic your customers and teams change
- Rules Your Customers Write: per-customer business rules instead of a homegrown rules language, with a preview of what a change would do.
- Usage Limits and Pricing Plans: plans, limits, and overage billing in one document every service asks, changed without a deploy.
- Feature Flags and Entitlements: targeting rules as functions, stable rollouts, and the same flags on the server and in the browser.
Data and logic that travel
- A Self-Validating Config: settings with their units, defaults, and rules, environments that list only what's different, and field-level errors in CI.
- One Shape for Data from Many Sources: a small mapping per webhook provider or feed, in any format, checked at the edge.
- The Same Logic in the Browser and on the Server: one checkout calculation for a TypeScript front end and a Python backend.
Patterns You'll See
The recipes share a handful of patterns. Once you know them, most new uses are a combination.
The attribute is the contract
Your app runs functions by attribute: #[route], #[approval], #[flag], #[tool]. Whoever writes the logic (a model, a customer, another team) can add as many functions as they need, with any names, and your app finds them with funcs(attributes = 'route') or doc.run('route'). See Attributes.
Your app owns a small harness
The part that runs the untrusted part is a few lines your app writes: take the input, call every tagged function, return the result. The recipes call it route, evaluate, normalize, and call_tool. It keeps the contract in one place, and the logic you accept never has to know how it's called.
Maps in, maps out
Your app passes plain objects (a JavaScript object or a Python dict), which arrive as maps. The harness turns one into an object with Obj.from_map, declares it with using so it's cleaned up afterward, and returns a map or JSON. Nothing piles up in a long-lived document.
Your functions are the only door
A document can't reach files, the network, or your app unless you give it a way. Give it specific functions with doc.lib(..), scoped to the current customer or request, and put your limits inside them (like "refunds over $100 need a person"), because new logic can call them too. See What a Document Can Reach.
Check before you trust
Logic from outside goes through checks before it's live: it parses, its own #[test] functions pass, it agrees with examples you know the answer to, and its output fits a #[schema]. Every failure is a plain message with a line number, which a model can fix and a person can read.
Logic ships as data
Binary Stof (bstf) holds logic and data together. Publish a new document, and every service and browser swaps it in: new plans, flags, rules, or mappings, with no release. Keep the source in version control with tests, and publish from CI.
Every call has a time limit
Set one with setMaxExecutionTime, sized to the job: tens of milliseconds for a check on every request, seconds for an agent's tool. A runaway loop fails that one call, and nothing else.