You cannot optimise what you have not defined.
Right now “good” lives inside the model and inside your head. Coltrane puts it outside both — in typed, sealed pipelines you can change, resume and measure without holding your breath.
The same request takes a different path every time.
Prompts live in code. Nothing formal governs what happens next, so the route changes run to run and drift is the steady state rather than an incident. It stops partway and leaves you holding half an artifact. You sit and watch it work, because unattended is a risk with no bound on it.
The model is not the problem. The absence of a definition is.
“Good” exists inside the model and inside your head, and nowhere else — so there is nothing to check an output against, nothing to notice drift from, and no way to answer whether the cheaper model would have done just as well. The same model, handed a contract, produces something checkable instead. Structure is not the luxury tier here; it is the floor for getting anything dependable out of a model at all.
So write it down, outside the model. Four kinds of file.
- Types
- The data shapes. Everything else binds to these, so they come first.
- Agents
- Producers. Each declares its input types, its output types, its tool grant and its model tier.
- Skills
- Reusable capability, including executable code — which has to pass its own fixtures before it can be promoted.
- Standards
- A graph of phases. Each phase seats chairs, and a chair binds a producer to an input contract and an output contract, written in type slugs.
Between them, those four files are the definition of a good job: the shapes the work has to produce, the evidence each one has to carry, the criteria a judgment is made against, and the fixtures a skill still has to pass.
{
"phase": "assess",
"chairs": [
{
"role": "analyst",
"agent_slug": "impact-analyst",
"input_contract": ["incident-report"],
"output_contract": ["impact-assessment"]
}
]
}Phases connect by type. Not by name.
An edge exists exactly where an upstream output contract satisfies a downstream input contract. Which means compose time can tell you that a phase is asking for a shape nothing upstream produces — before you spend a run finding out at minute nine.
Seat the same agent twice in a phase and you get two runs that cannot see each other — two independent judgments on the same input, not one judgment quoted twice. Isolation is a property of the seating, so you get it by writing a second chair.
The floor holds no matter which model produced the output.
Six primitives, six core types, and each core type carries one substance field that has to be present when the output is sealed. Not a warning, not a lint, not a score you can override. The write is refused and the run stops.
{"type": "impact-assessment","primitive": "INTERPRET","claims": ["checkout latency exceeded 2s for 41 minutes","the retry loop in the payments client amplified load"],"confidence": 0.82}
The rule runs here, in your browser, against the object above — not a recorded outcome. When it seals, content_sha is sha256 of exactly the bytes shown, with no trailing newline, so you can reproduce it yourself.
{ "type": "impact-assessment", "primitive": "INTERPRET", "claims": [ "checkout latency exceeded 2s for 41 minutes", "the retry loop in the payments client amplified load" ], "confidence": 0.82 }Evidence and output are the same object, so there is no version of the artifact that exists without it. And because the floor sits outside the model, swapping the model out cannot quietly lower it — which is what makes a change safe to make.
Every sealed output carries the hash of its own bytes and the hashes of everything it consumed. There is no code path to a sealed output that skips it, so provenance is a property of the write rather than a logging habit somebody kept up.
Walk it upstream and you land on the signal that started it. Nothing in the middle can be quietly substituted, because substituting it changes a hash.
When it stops, that is a position — not a mess.
Work is a graph of discrete phases, and every completed phase seals a durable output. A run that halts partway leaves finished, content-addressed steps on disk rather than half an artifact and a guess about what got done. You resume from the last sealed phase and pay only for what has not run.
coltrane dispatch <standard> --resume <gig-id>
The part that matters is the refusal. If the definitions, the producers, the payload, the model or a consumed type changed while the run was stopped, the resume is refused and told you exactly what drifted — rather than splicing two different versions of the work together under one identity. You either resume the run you started, or you are told why you cannot.
Same idea one level down: a step that did not produce what its contract promised is reported, not waved through as complete. And when you set a per-run ceiling in dollars, the run stops rather than starting the step that would spend past it, so unattended does not mean unbounded.
Which is the point. The reason anyone sits and watches these runs is that an unattended stop costs them the whole thing. Durable phases and a resume that refuses are what make it safe to walk away.
You are not buying tokens. You are buying output you would sign.
The bill counts every attempt. The value counts only the ones that held up, and the gap between those two numbers is where most of an inference budget goes — re-run, re-prompt, discard, fix by hand. Coltrane does not make inference cheaper. It stops you buying the same thing twice, and stops you paying for output you were going to throw away.
And once you can see the conversion, you can change what produces it.
Cost and quality are recorded against the same unit of work, so a producer can be compared against the version it replaced, and a step can be moved onto a cheaper model and measured rather than argued about.
| reviewer | runs | cost | quality |
|---|---|---|---|
| v1 | 18 | $0.41 | 11.2 |
| v2 | 22 | $0.30 | 14.6 |
| model tier | runs | cost | quality |
| premium | 14 | $0.40 | 14.1 |
| economy | 12 | $0.05 | 13.7 |
Eight times cheaper for four tenths of a rubric point is a decision somebody can actually make. Spend expensive tokens once to find out where the cheap ones hold, then run cheap — and let the floors and the fixtures, not your nerve, be the thing holding the line.
What running it actually involves.
Including the awkward parts, which are the ones worth knowing before you start rather than after.
The engine spawns model subprocesses and holds live run state. It does not fit on serverless — which is the reason the execution layer is yours: your machine, your container, your key.
The loader reports what it cannot resolve instead of loading something adjacent and hoping. Expect that the first time. It is the same refusal that makes the rest of it worth anything.
A run you stop, stops. Not a flag checked at the top of the next loop, after the next model call has already been paid for.
npm install -g @eir-labs/coltrane, a Node process, and your own model key. It ships as an MCP server so an agent client can drive it, and as a CLI so CI can.
The definition is the asset. The model is an input you swap.
A model handed a contract — the shape it must produce, the evidence that shape has to carry, the criteria it will be judged against — does better work than the same model handed a paragraph of hopeful prose. Not a different model. The same one, improved, because it was finally told what the job is.
Which makes the definition an upgrade applied to every model that touches the work: the one you run now, the cheap one you are considering, and the one that ships next quarter that nobody has heard of yet. Improve the definition once and everything downstream of it improves with it. Prompt-tuning accrues to one model and evaporates the day you change it.
The model is rented. The definition is owned.
So adopting a cheaper or more specialised model stops being a re-tuning project you keep postponing. Point a step at it, look at whether it still clears the bar, keep it or don’t.
Types, contracts, criteria, fixtures and floors contain nothing model-specific — no standard names a provider, and a producer’s model is one field on the agent rather than something woven through the definition. The runner is an injectable interface (AgentInvoker), so the execution seam is pluggable by design. What ships today is a default invoker that runs the Claude CLI, with the tier map resolving to Claude models. That is a portable definition and a pluggable seam — not a claim that it runs on anything you like today.