The Part of Your App You Can Hand to Something You Don't Trust
Sometime in the last year, "the agent will just edit the file" stopped being hypothetical and became a normal workflow. Point an agent at a config, a document, or a blob of state, and it reads, edits, and writes it back, with no UI in between.
That's useful. It's also a trust problem most formats were never built to handle.
Two Questions Most Formats Can't Answer
When something you don't fully control (an agent, a plugin, logic from another service) edits your app's state directly, two questions come up right away:
- Can it leave the data broken? Most formats are only structure. JSON doesn't know what a valid version of itself looks like. Validation lives somewhere else: a schema file, a Zod or Pydantic model, a check your app runs afterward. The data has no opinion.
- Can it reach further than it should? If the edit includes logic, like a new rule or a new function, what stops that logic from touching the file system, the network, or anything else once it runs?
Most systems built around "one portable file, edited by anything" answer both by trusting more, not less: bundle the whole app, sign the release, keep a rollback plan. That works. It's also a lot of machinery just to make an edit safe to accept.
A Narrower Answer
Stof goes the other way. Instead of trusting the whole bundle, it makes the data the part that can't misbehave.
A Stof document validates itself. Fields carry their types and rules, so there's no separate schema to drift:
#[type]
Person: {
#[schema((target_val: str): bool => target_val != null && target_val.len() > 1)]
str name: 'Ada'
#[schema((target_val: int): bool => target_val != null && target_val >= 0)]
int age: 30
fn greet() -> str { `Hello, ${self.name}!` }
}
#[main]
fn main() {
// an edit from an agent: checked before it's accepted
const edit = new { name: 'Grace', age: -4 };
pln(<Person>.schemafy(edit));
}And it's sandboxed by default. A document reaches only what your app gives it:
import { StofDoc } from '@formata/stof';
const doc = await StofDoc.new(state);
// nothing outside the document is reachable until you allow it
doc.allowHttp(['api.example.com']); // this host, and no other
doc.lib('App', 'notify', (user: string, message: string) => notify(user, message));
doc.setMaxExecutionTime(50); // and every call has a time limit
// logic from an agent goes in, and runs with exactly those limits
doc.parse(logicFromTheAgent);
await doc.run('on_update');
If network access was never granted, a function in that document can't reach the network. Not because a permission check ran, but because there's nothing to call. Logic from an agent, a tool result, or another service can be parsed into a running document and called right away, and the damage it could do is limited by what you gave it, not by how much you trust where it came from.
Not the Container, the Part Inside It You Can Trust
It's tempting to read "portable, sandboxed, single document" and reach for something bigger: what if the whole app lived in a Stof file, UI and all?
We don't think that's the right shape. The moment a document has to draw pixels or drive a UI, it needs broad, standing access to do its job, and you're back to trusting the whole bundle, the problem the sandbox was meant to avoid.
The useful version is narrower. The UI stays outside, doing what it's good at. The state, the rules, and what's allowed to happen live in a Stof document, because that's the part of the system that's safe to hand to something you don't fully trust. An agent can edit it. A plugin can extend it while it runs. Neither requires trusting the editor, only that the document can't be made invalid and can't reach further than you allowed.
More and more of an app's state is edited by something other than the app. The question isn't how to make the whole app safe to hand over. It's which part should be.
Run Rules a Model Writes walks through the full loop: a model writes logic, the app checks it, and only then does it run.
