The drafter loop
The shipped agent harness — sessions a host makes, services a host injects, drawing rounds an independent crit closes — and the measured failure behind every gate in it.
bimtex/drafter is the loop the studio page runs, packaged. It is not a
framework: it is one working loop whose every gate answers a failure that was
measured on a live run, and the fastest way to understand it is to read it as
a list of those failures.
The shape
brief ──→ scheme turn ──→ (your gate) ──→ round 1..N ──→ verdict
│ │
│ ├─ drawing turn write / edit · inspect · evaluate
│ ├─ independent crit — fresh eyes, fixed sheets
└─ state_scheme └─ findings carried into the next roundA job is: one turn that produces a scheme, an optional human gate, then drawing rounds. Each round is a drafting turn followed by an independent review, and only findings that survive the review re-enter as the next round's work order. The loop stops on counts — findings closed, likeness plateaued, ceiling reached — never on a score the drafter wrote itself.
Running it
import { createSession, runJob } from 'bimtex/drafter';
const session = createSession(); // the working drawing; one per operator
await runJob({
session,
hosts: { rasterize }, // what YOUR machine can do — see below
model: 'google/gemini-3.5-flash', // any OpenRouter route with vision
critModel: 'google/gemini-3.5-flash',
apiKey: process.env.OPENROUTER_API_KEY,
brief: 'A one-room garden studio, door to the south.',
references: [dataUrl], // photographs the drawing is held to
site: [[0, 0], [18, 0], [18, 12], [0, 12]], // a metre-coordinate lot ring
ceiling: 3, // most rounds you will pay for
patience: 2, // rounds with no closer likeness before it stops
emit: event => record.push(event), // the page IS a fold over this stream
});Install the peers first — they are deliberately not dependencies, so an engine-only install never pays for them:
npm i bimtex ai zod @openrouter/ai-sdk-providerSessions are made, not found
createSession() returns the working drawing: source, parsed entities,
message transcript, the scheme, and the bookkeeping the gates read. The
harness never reaches for a shared one. A browser tab makes one for its whole
life; a server makes one per request — two jobs handed the same session
are not two jobs, they are one drawing being written by two writers.
Hosts: what your machine can do
The loop needs two services it refuses to own, because they are the only parts that differ between a tab and a server:
| Service | Contract | Browser answer | Server answer |
|---|---|---|---|
rasterize | SVG string → base64 PNG | a canvas | @resvg/resvg-js, or resvg-wasm on an edge runtime |
renderShots | model source + shot list → rendered 3D perspectives | WebGL | omit it, or a headless renderer |
rasterize is required — runJob throws before spending a token without it,
because a loop that cannot look can never pass its own gates. renderShots
is optional the way WebGL always was: absent or failing, the two exterior
perspectives are lost and every flat sheet survives.
The tools, and what each gate prevents
The drafter gets seven tools. Five write or look; two are gates with teeth.
| Tool | What it is |
|---|---|
state_scheme | What the building is, its parti, what each view must show, the facts the givens fix, and the rubric its likeness is graded in |
getVocabulary | Every legal entity type with its fields; every room use, symbol, material, element |
browseElements | The appearance catalogue, as cards or one full body |
write_bimtex_model | The whole model, first pass or deliberate redraw |
apply_bimtex_ops | Atomic edits, checked, with a semantic diff and the checker's delta |
inspect | Compile once and report; with review: true, print the drawings and look |
evaluate | Hand in an assessment — which the harness may refuse |
The refusals are the design. Each one moved a rule that had been prose — and was therefore optimised away by the first live run — into a gate:
- No write without a scheme. A loop that goes straight from brief to entities produces a parts list, not a building.
- No verdict without a look.
evaluaterefuses while the last printed review trails the current revision. Measured twice: the model printed its sheets once, at the end, after deciding it was done. - No self-certification past the checker. Outstanding errors overrule
satisfied: true, always. - Every promise answered. Each
showsitem and eachfixedfact must be accounted for — visible, or departed from with a written reason. Dropping one silently is the failure; dropping one on purpose is allowed. - Oscillation is a brief problem. A finding fixed, reintroduced, and fixed again stops the loop and says the requirements conflict — instead of paying for the third reversal.
The independent crit
After each drawing turn, a second model call — with no drafting history at all — receives the brief, a measured area schedule, the reference photographs, and a fixed sheet set chosen by the harness: every storey's plan plus both exterior perspectives, whether the scheme named them or not. A drafter that picks its own sheets shows its good side; the fixed floor is what makes the review independent.
The crit returns at most five findings and, when the scheme named a rubric, a
scorecard graded 0–2 per dimension in words a reader can check ("would a
reader holding the photograph accept these as the same place"). The harness
sums the bands — likeness, 0–10, the one number two runs can be compared
by — and the crit never sees the pass bar either.
Findings carried into the next round are recheck-only: a finding the crit says still stands twice in a row is marked stuck and never retried, and a round that closes nothing ends the job with the honest sentence about why.
What it costs
Every event the loop emits carries per-step usage, and estimateCost prices
it against per-model rates that include the cache-write rate — which is,
measured, most of the bill. Two facts worth designing around: an image costs
a flat ~1,085 prompt tokens regardless of resolution, and the transcript is
append-only on purpose — editing history to save tokens invalidates the
prefix cache behind the edit and costs 12.5× what it saves.
The studio page is this exact loop with a browser host injected — its key stays in the reader's tab. A server host inverts one thing only: the key is yours, so meter your callers. Everything else, including every gate above, is the same code.
For agents
A building language a model can write, drawings it can look at, and a judgement loop it cannot flatter — the three moves that make an agent produce buildings instead of pictures of buildings.
Prompting a model
bimtex never fails loudly. Everything here is a way to see what the checker structurally cannot.