← All ideas

Field note

One Root, Many Machines

You do not build a product per customer; you build one runtime and declare many machines on it, so a new machine is a configuration, not a codebase.

2026-10-08 · fronte.io

The reflexive way to serve a new job is to build a new app. One customer wants a planner, so you build a planner. Another wants a meter, so you build a meter. A third wants an agent that triages messy inbound reports, so you build a third app. Each has its own prompt, deploy, state, and dashboard. The work multiplies. You are no longer building a product. You are running a body shop, and every new vehicle is a fresh chassis.

There is a better shape. Build one runtime. Declare machines on it.

What a machine is

A machine is four things, every time:

Declare those four and the runtime becomes that machine. A planner is one declaration. A meter that fails closed at a spending ceiling is another. A triage machine that turns a messy report into a structured record is a third. Adding a machine is a config file, not a project.

The specificity is not in the tools. A cardiac surgeon and a neurosurgeon use near identical instruments. What differs is the protocol, what must be confirmed before the next cut, and what gets written down for the next person. Same hands, same tools, different machine. Two machines can share a skill list and still be different machines, because the difference lives in the gate and the memory shape.

That has a sharp consequence: tighten the gate and the memory shape first, and add skills last. A machine with the wrong gate is dangerous no matter how good its tools are. A machine with the right gate and a thin tool set is safe and improvable.

The dandelion

One root, many seeds.

The root is the runtime: the model loop, the gate engine, the memory store, the loader. The seeds are the machines. They share everything below the surface, and each seed carries only what is specific to it, which is the gate and the memory shape. You plant once. The garden grows by declaration.

The wrong lever here is fine tuning weights. It is slow and costly, and it does not give you a gate. It makes the model sound like the specialty, not behave to a process. The right lever is configuration: the skill surface, the gate rules, the memory schema, the tool policy. Same behavior, none of the training cost. The first machine we run reads its quality from its gate and runs with no weight changes at all.

So a machine shop is not a skill store. Skill libraries are a commodity; anyone can sell a set of tool calls. The quality lives in the gate, and the gate is hard to copy because it encodes a real process. The product is a gating engine plus a machine registry, not a shelf of tools.

The hard part: over-generalizing

The temptation is to build the runtime so general it does nothing well. You imagine every machine you might ever declare and add a hook for each. Now the root is a maze, and no seed is sharp.

Two rules keep this honest. First, the abstraction is pulled by the machines you have, not pushed by the machines you imagine. Build for two real machines. Let the second one, not the tenth hypothetical one, tell you where the seam belongs. Second, a factory that cannot express a sharp gate only mints broad assistants. If the spec format cannot say "every step must name the instrument, the site, and the timeout," that surgeon machine cannot exist yet, and the factory is a shop in name only. The spec's job is to make sharpness expressible, and cheap.

There is also a meta-gate worth keeping: a spec with no gate rules, and no defined behavior on failure, is refused. A machine that cannot refuse its own bad output is not a machine. Cheap to make a machine, but not free: the price of admission is a gate.

The hard part: shared runtime, cost and blast radius

One runtime for many machines means one fate for many machines: a defect in the loop is a defect in every machine, and a crash takes the whole set down.

The fix is to share the code, not the state. Machines share the root, the loop and the engine and the loader. They do not share memory. Each machine gets its own lane: its own state, session, model config, and tool policy. One gateway can host several lanes and hold them apart. Each customer's state stays in that customer's lane. The runtime is shared, the data is not. That distinction matters, because a shared runtime with shared state is one blast radius, and a shared runtime with isolated state is a set of small ones.

There is a run cost too. Many machines on one box contend for the same CPU, rate limits, and pool of model calls, and a burst in one can starve another. You manage it like any shared resource: bounds per lane, a queue, and the willingness to move a heavy machine to its own process when it leans on its neighbors.

The honest accounting: you trade a little isolation risk for a lot of maintenance savings. Keep the trade good by keeping the root small, gating every output, and versioning every spec, so a change to one machine cannot quietly change another.

The hard part: when a separate machine is right

Sometimes a declaration is the wrong call, and a separate machine is the honest one. Split when any of these breaks:

The rule of thumb: share the root while the gate fits the engine and the failure is survivable. Split when either one breaks. The split is not a failure of the idea. It is the idea working: now you know why the machine is separate.

The registry is the surface

A job names a machine. The registry maps the name to the declaration, and the machine brings its own model, skills, gate, and memory. Preselection is that match: a job request, a declared machine, a contract that says what it does and does not own.

This is the buyer experience as much as the builder one. The buyer describes a job, and the registry maps it to a machine. The gate guarantees proof instead of activity, and the meter makes the spend auditable. The buyer never runs on the broad assistant and hopes.

One root, many seeds. The thing worth building is the factory and the registry, not any single machine. When a new job arrives, it does not become a new project. It becomes a declaration. And declarations are cheap, so you can afford to be specific again. That is the only reason the general thing is worth having.