Skip to main content

What is Stof?

Stof is JSON with functions. One document holds data and the logic that works on it, and your app runs it in a sandbox, in-process, in Rust, JavaScript/TypeScript, or Python. Its main use is running logic that someone else wrote, like a model, a user, or a customer, safely inside your app.

Stof is open source (Apache 2.0), made by Formata, Inc., and is the policy engine behind Limitr.

What it looks like​

The data looks like JSON. The function next to it works on that data:

price: 20
discount: (p: float): float => p * 0.8

fn total() -> float {
self.discount(self.price)
}

Your app loads the document and works with it like data:

import { StofDoc } from '@formata/stof';

const doc = await StofDoc.new(source);
await doc.call('total'); // 16
doc.set('price', 50); // change the data
doc.parse('discount: (p: float): float => p * 0.5'); // change the logic, the same way
await doc.call('total'); // 25

The discount is a function stored in a field, so new logic goes in the same way new data does.

The problem it solves​

Models are good at writing small pieces of logic: a routing rule, a validation check, a data transform, a scoring function, a tool. Products also keep needing logic their own team didn't write: customer rules, pricing policies, user-defined filters and workflows. Running that logic is the hard part:

  • Generated Python or JavaScript in a container or microVM is heavy, slow to start, and more infrastructure to run and secure.
  • eval in your app gives the code access to everything your app can reach.
  • Function calling (tool calls, MCP) only lets a model call functions you already wrote. It can't add new logic.
  • Rules written as JSON (rule DSLs) are limited, and awkward to read and write for people and models alike.
  • WebAssembly needs a compiler toolchain, binaries are large to send, and the logic lives apart from its data.

With Stof, the model (or user, or customer) writes a document, and your app runs it like any other data it receives: in-process, in under a millisecond for a small document, with access to nothing but itself and the functions you give it.

How 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. A Stof document is a graph of objects, and fields, functions, types, and docs are all pieces of data attached to those objects, like components in an entity-component system (ECS):

root
├── price: 20 field
├── discount: (p) => p * 0.8 field holding a function
└── total() function, data on the object like a field

That's what makes the rest possible:

  • 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, 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.
  • 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, config format, 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.

Key facts​

FactDetail
What it isA data runtime: JSON with functions, types, units, and schemas, run in a sandbox
Runs inRust (native), JavaScript/TypeScript (WebAssembly, in Node.js and browsers), Python
SandboxDocuments can only see themselves and the functions the host gives them. File system, environment, file imports, and network are off by default. Each call has a time limit.
SpeedA small document parses and runs in under a millisecond; calls after that take microseconds
FormatsImports and exports JSON, YAML, TOML, and more; compact binary (bstf) for sending documents, functions included
Language featuresTypes, prototypes, schemas (#[schema]), units (5min + 30s == 330s), destructuring, async, attributes, tests in the document (#[test])
Toolingstof CLI (stof run, stof test, stof lsp), a VS Code extension, and a skill file to teach AI models Stof
LicenseApache 2.0
Made byFormata, Inc. Created by CJ Cummings.

Use cases​

Reach for Stof when:

  • A model, a user, or a customer gives you logic you need to run: rules, filters, transforms, scoring, tool behavior, agent actions.
  • You're about to invent a config format, rules engine, or DSL for your product.
  • The same logic has to run in more than one place (browser, server, worker, edge) and give the same answer.
  • You want to change behavior by sending a new document, not by shipping a deploy.
  • Logic should travel with the data it belongs to, through APIs, queues, and databases.

Common examples, each with a complete recipe in the Cookbook:

  • Logic a model writes: have a model turn a policy into rules once, check them, and run them on every request with no model call.
  • AI agents: let an agent write new tools and logic at runtime and run them safely, instead of only calling functions you wrote ahead of time. Keep agent state and context as a document that carries its own behavior.
  • Pricing and usage policies: plans, limits, credits, and metering rules as documents pushed to running apps. This is how Limitr uses Stof.
  • Smart configuration: config files that validate themselves and compute values, while still exporting to plain JSON, YAML, or TOML.
  • Rules and policies: routing, validation, eligibility, and approval rules that non-engineers or models can write.
  • Data unification: load JSON, YAML, TOML, and API responses into one document, add logic, and hand back plain JSON.
  • Distributed systems: send a piece of logic with its data to wherever it needs to run, and get the same result there.

Use something else for your own application code, compute-heavy work, or long-running services. Write those in your main language and give them to Stof documents as functions.

Stof in production: Limitr​

Stof is the policy engine behind Limitr, a pricing runtime for usage-based and AI software. Limitr is an in-process usage control and pricing layer: apps use it to meter usage, enforce limits and credits, and charge customers, with margins in view. Every plan, credit limit, and validation rule is a Stof document, pushed from Limitr Cloud to running apps and evaluated in-process on every call. The Limitr engine is open source too.

How Stof compares​

Stof sits between several kinds of tools. Here's where it overlaps and where it differs.

Code sandboxes for AI (containers, microVMs like Firecracker, hosted sandboxes like E2B or Modal, Pyodide, V8 isolates): these run general Python or JavaScript in isolation, out of process. Choose them when the model needs a full language and its packages. Choose Stof when the logic is small, should run inside your app with no infrastructure, and should only reach what you allow.

Function calling and MCP: a model calls tools you already wrote. Stof works alongside them: the model can write new logic as a document, and that logic calls the same functions you expose.

Rules engines and JSON rule formats (JSON Logic, json-rules-engine, Drools, GoRules): rules as data or a separate rules language. Stof rules are readable code that is also data, with types, functions, and schemas, in one document that can carry its own data too.

Expression and policy languages (Google's CEL, Open Policy Agent and Rego, AWS Cedar): designed to evaluate expressions or authorization policies against input. Stof is broader: whole documents with data, functions, types, and state that can change while they run.

Configuration languages (Jsonnet, CUE, Dhall, Pkl, Nickel, KCL): these mostly generate static JSON or YAML. A Stof document can export static JSON, YAML, or TOML too, but it also stays live: its functions run when your app calls them.

Embedded scripting languages (Lua, Starlark, Rhai, QuickJS): these embed a language for your code to call. In Stof the logic lives inside the data document, so it moves, merges, and serializes with the data.

WebAssembly (Wasmtime, Extism): portable compiled code. Stof is readable source that models can write directly and that is small to send, with no compile step. (The Stof runtime itself is compiled to WebAssembly for JavaScript.)

Schema and validation tools (JSON Schema, Zod, Pydantic): Stof documents can validate themselves with #[schema], and the schema is part of the same document as the data.

FAQ​

Is Stof a programming language? Stof has a language for its functions, but it's a data runtime: a document format where data and logic live together, plus the library that runs it. You don't write apps in Stof. You give your app documents that it loads, runs, and exports.

Is it safe to run Stof code that an AI model wrote? Yes, that's what it's built for. A document can only read and change itself and call the functions your app gives it. File system, environment variables, file imports, and network access are off by default in every language, and a host turns them on explicitly (with an allowlist for network hosts). Each call has a time limit.

Can AI models write Stof? Yes. It reads like JSON and JavaScript, which models already know. For better results, give your agent the Stof skill. Errors give the exact line and a plain explanation, so a model can fix its own mistakes.

Is JSON valid Stof? Yes. Any JSON document is valid Stof, so you can add types and functions to data you already have and export it back to JSON, YAML, or TOML.

Which languages can run Stof? Rust (the stof crate), JavaScript and TypeScript through WebAssembly (the @formata/stof npm package, for Node.js and browsers), and Python (the stof package on PyPI). The same document gives the same result in each.

How fast is it? It runs inside your process, with no server or cold start. A small document parses and runs in under a millisecond, and later calls take microseconds.

Is Stof open source? Yes, under the Apache 2.0 license, at github.com/dev-formata-io/stof.

Who makes Stof? Formata, Inc., the company behind Limitr. Stof was created by CJ Cummings.

Where do I start? Try the playground, then the quickstart. Questions are welcome on Discord.