WootBuild.

Studio/Doctrine/The charter

docs/00-CHARTER.md

00 — Charter

WootBuild is a private art studio that lives inside Claude Code. It generates images on demand for other Claude projects, holds the institutional memory of how each project is supposed to look, and gets better at each project's house style every time a human says yes or no.

It is not a wrapper around an image API. The wrapper is the cheapest part.

The thesis

Anyone can call an image model. What nobody has is the thing between the model and the deliverable:

OpenArt gives model access. WootBuild gives model access plus the four things above, and it is scriptable, so an agent can run it unattended.

Vernacular (fixed — used verbatim in code, docs, and DB)

TermMeaning
ClientA Claude project that consumes images. docade, salon-structure. WootBuild is its own client, for one purpose only — the incubator, below. It held the opposite rule until 2026-08-25, when the incubator needed a shape and this was the honest one.
LaneA distinct visual track inside one client. salon-structure has a diagram lane and a human lane. Lanes do not share style sheets, but may inherit a client's house style — see 13-WORKFLOW.md §2.
Style SheetThe versioned visual contract for a lane. Prompt scaffolding, palette, model binding, references, negative constraints, accumulated lessons. The unit of consistency.
House StyleAn optional parent style sheet carrying what is common across all of one client's lanes. Lanes inherit it and override with thin deltas that may narrow but never contradict. Optional: salon-structure has none.
SpecThe mechanical requirements of an output: dimensions, aspect, format, DPI, safe areas, transparency, filename pattern, destination path. Orthogonal to style.
RequestWhat a client asks for, filed through the bridge before WootBuild has costed or specced it. Free text + lane + count + deadline. Not yet a brief, and never executed directly.
BriefWootBuild's compiled, specced, priced version of a request. Free text + client + lane + spec + count. The thing a run executes.
RunOne execution of a brief. Produces N candidates, has a cost, has a status.
CandidateOne generated image inside a run, pre-verdict.
Verdictapprove / revise / reject on a candidate, with a critique. The learning signal.
AssetAn approved candidate, normalized, named, and registered in the library with full provenance.
MandateHow much creative latitude the studio has for a client: greenfield · advisory · conforming · locked. Narrows over time, never widens without an explicit reset. Distinct from autonomy, which governs delivery.
CorpusThe retrievable knowledge base: lessons, exemplars, model behavior notes, rejected patterns. Per-style and global.
DeliveryCopying an asset into a client repo at its destination path.
IncubatorThe studio's own lab, held as a client record whose mandate is absent: client wootbuild, serving itself. Visual creation, experimentation, process and tooling done for WootBuild's own advancement and entertainment. Segmented into categories that share nothing with each other. Named and specified by Justin, 2026-08-25.

Incubator — WootBuild is the client we serve ourselves

Justin, 2026-08-25, deciding the shape after naming it:

I think the incubator is actually a client-shaped record with a mandate absence. Or if we wanted to look at the Incubator at Large as a client record with no mandate, perhaps WootBuild is the client we serve ourselves. There's really no mandate around that other than our natural documentation parameters, so we can still document things appropriately on WootBuild and have our reviews and persistence. Because the Incubator has no mandate, the categories have no mandate either, and no interconnectivity.

It is client-shaped on purpose. Not a new top-level thing in the data model, not a special case in art status, the queue, the site or the SessionStart hook. A client record with one field absent, so every surface already knows how to render it and nothing has to learn a second shape.

What "no mandate" removes, and what it does not

A client's mandate is creative latitude that narrows over time — greenfield → advisory → conforming → locked. The incubator has none, and that absence is the whole definition.

RemovedKept
Any client requirement: a manifest row that must exist, a spec that must be satisfiable, a palette, a house style, an advisory owed to anyoneThe studio's own documentation parameters — Justin's phrase, and the line that matters. Docs, review, verdicts, persistence, cost lines.

The incubator escapes client constraint, not studio discipline. Work here still gets a board, still gets a human verdict, still writes its lessons into the corpus, still shows its spend. That is not an obligation imposed on it — it is the only reason to put speculative work inside the studio rather than in a brainstorm folder, which is where all of this lived until now.

Categories share nothing

Because the incubator has no mandate, no category inherits one either. There is no house style and no interconnectivity. A category is free to contradict every other category in register, palette, medium and method — and normally, for a client, that would be a defect.

That is a real departure from the client model, where lanes may inherit a house style (docs/13-WORKFLOW.md §2), and it is deliberate: coherence is something a client buys. Nobody bought this.

It produces two kinds of thing, and only one of them is images

Visual workAssets. May later be retrofitted to a client. Behaves like any lane — brief, run, board, verdict.
CapabilityProcess and tooling. Learning a tool, proving a method, building an integration. Produces no candidates and may have no spec at all. docs/14-CAPABILITY-RADAR.md lists what the studio cannot do yet; the incubator is where it goes and learns to.

A category may be either. Not every incubator category is a lane, and forcing one to be would be the same error as calling this a lane in the first place.

Two ways work leaves, and neither is automatic

RetrofitA specific piece made freely is later adapted to a client's requirements. The likely path, and it is not a copy — the piece re-enters the normal pipeline: specced against that client's lane, re-judged under that client's contract, delivered only through art deliver. Made-here does not mean approved-there.
GraduateThe work itself acquires a repo, a manifest and a mandate, and stops being an incubator category. It becomes a client.

It cannot displace an engagement, structurally

art deliver implements only deliver_to: from-manifest and refuses everything else, so incubator work cannot reach a client repo by accident — retrofit is the only door and it is a deliberate one. There is likewise no deadline to breach and no promise to miss, because nobody is waiting. Visible without being urgent.

docs/20-PILOT-ARCADE.md spent a day arguing this had to be held outside the studio to avoid competing with client work, and kept that priority by hand. The incubator makes it a property instead, which is this repo's own doctrine: if the fix is a sentence someone promises to remember, it is not a fix.

Non-negotiables

  1. Records are local; pixels are addressed. Every record — sidecar, brief, verdict, lesson, style contract, canon — is a file in this repo, and art reindex rebuilds the index from files alone with no network call. Media bytes live in R2, addressed by asset id, and the repo holds the record that points at them. Nothing Claude reasons from requires a network call; nothing a person looks at requires a checkout.

Amended 2026-08-19. It previously read "Cloud is for backup and sharing, never for the read path", which collapsed two different read paths into one sentence. Claude's — corpus, canon, sidecars — is local permanently, for the original reason: behind an API call it stops being the thing that makes this worth building inside Claude Code. A person's read path is looking at pictures, and it never needed to be local.

The forcing function was arithmetic. The site could only display files committed to git, so every normalized PNG was committed: one lane of one client is 145 images and 27MB, docade projects to 332, ten clients to ~1.05GB in version control, and 200 short animation loops adds another 0.59GB. Binaries do not diff, do not compress, and never leave history.

This is not new machinery — library/**/*.png has been gitignored with its provenance sidecars tracked since the beginning, for the reason written there: bytes can be pruned, the record cannot. The amendment applies the rule the studio already had to the one place it exempted.

  1. Every image carries provenance. Model, prompt, seed, style version, cost, verdict, and parent run are recoverable for any asset, forever.
  2. No silent spending. Every run estimates cost before it spends, and a hook blocks runs over the ceiling without explicit approval.
  3. Nothing writes to a client repo without a human verdict. Generation is autonomous; delivery is not, until a lane is explicitly marked trusted.
  4. Style sheets are versioned and immutable once used. A change forks a new version so old assets remain reproducible.
  5. Env isolation. WootBuild reads only WOOT_* variables. The shell's global SUPABASE_* points at salon production; WootBuild must never see it.

What "done" looks like for v1

art opens Claude Code in the studio. I say "I need twelve chore-card illustrations for docade, the existing kid-facing style, 512×512 transparent PNG." Ten minutes later a contact sheet appears in my terminal. I press 1 1 3 2 1 …. The approved ones land in ~/Projects/docade/public/assets/chores/ with the right names, the rejections are explained back to the corpus, and the next batch is measurably better without me editing a prompt.

What the product actually is — and the honest alternative

The alternative is real and worth naming, because it is what Justin would do without this: go to a generation site, build a standing style or character profile, and batch out what is needed. That works, and for a one-off set it is the right tool. It fails on three things, and all three are the job.

1. It cannot hold a spec. Filenames that are database foreign keys. Transparency. A collectible judged at 80px, not at 512. A prize that has to survive a committed two-stop gradient. A standing profile has no idea any of that exists, so the spec quietly bends to whatever came out.

2. It cannot survive time. A standing profile is a prompt, not a contract. Models get retired, endpoints get renamed, defaults shift underneath it — this repo has already caught six phantom model ids and a 3× price error in one pass. Six months later the same profile produces something subtly different and there is nothing to compare against, because nothing was ever fixed. That is what the canary set exists to catch.

3. It cannot learn. It will not remember that the last four times Lyle was drawn with an open mouth, Justin rejected it.

So the product is not a batch of images. It is this:

Consistency, once established, is ongoing. A client's buckets can be refilled — next month, next year, after the model has been replaced — to the same specification, by something that still holds the contract and still remembers every verdict.

Volume is what makes that worth building. docade needs 204 pieces and then ~150 a year, forever. Anyone can produce the first thirty.

At volume, the spec flows from what can actually be produced

The naive order is spec → art. At scale the real order runs the other way: what can be produced consistently is what the spec can honestly promise. A spec written before anyone knows what the pipeline reliably yields is a wish, and the gap gets discovered at asset forty.

So the reference-sheet probe is not only style validation — it is spec discovery, and probe results are allowed to amend the spec and the visual mission. Amending them from evidence is the process working. Quietly shipping art that misses the spec, and calling it done, is the failure.

The studio advises; it does not take dictation

A client's manifest is a request, not a specification. WootBuild is the visual advisor, and the job includes saying "this is the wrong work" — not only "here is the work you asked for, rendered well."

Three questions belong to the studio and are asked on every engagement:

  1. Is this the right art to make at all? A list of assets is a set of assumptions about what the product needs. Some of them are wrong, and the client is usually too close to see which.
  2. Is it sequenced by value? Art budget spent on the part of a product that isn't its wager is the most common and least visible waste there is.
  3. Does the plan contradict itself? Clients document decisions months apart. The contradictions are real findings and are cheap for an outsider to spot.

Deference is the failure mode, not the safe option. A studio that renders a bad list beautifully has done harm that looks like service, and the invoice is identical. Say it plainly, say it early, and say it with the client's own evidence — then build whatever they decide.

A fourth question belongs to the studio and is the one most often skipped:

  1. What does each constraint cost to change? A client's design tokens arrive looking like fixed ground. Most of them are not. A background colour is one line and a few minutes; a font swap is scarcely more. Art is hundreds of pieces, is produced at a rate, and every future piece pays whatever tax the token imposes.

When a cheap constraint is making an expensive one harder, propose changing the cheap one. Deferring to a token because it was already written is how a studio takes a five-minute problem and pays for it in every asset it will ever make. The asymmetry is usually enormous and usually invisible: nobody re-opens a colour that already shipped, so the art quietly absorbs the cost forever.

This is not licence to redesign the client's product. It is a duty to price the alternative and say so. The client still decides — but they decide knowing that the thing they assumed was fixed costs minutes, and the thing they assumed was flexible costs the rest of the engagement.

Mandate — how much latitude the studio actually has

Advisory latitude is not constant. It scales inversely with how much the client has already committed, and it is declared per client, not assumed.

MandateClient stateWhat WootBuild may do
greenfieldNo prior art. Specs provisional.Propose the art direction outright. Challenge spec, sequencing and economics.
advisorySpecs committed, nothing produced yet.Propose changes where economics demand; price the alternative. Client decides.
conformingPrior art exists and must be matched.Consistency with what exists outranks our preferences. Advise sparingly.
lockedStyle sheet approved and in production.Refill to exact spec. No latitude; a change forks a version.

Mandate narrows over time and never widens without an explicit reset. That direction is the whole point: latitude is highest before anything exists and approaches zero once consistency has been earned, because after that, exercising latitude is drift. The moment to argue about art direction is therefore the moment before any art exists — and that moment does not come back.

Mandate is not autonomy. Autonomy governs what may be delivered without a human verdict; mandate governs how much may be decided about what the work should look like. A lane can be trusted to deliver unattended (autonomy: 3) while having no latitude at all (mandate: locked) — in fact that is the mature steady state for a volume lane.

Advisory findings are written down (clients/<id>/advisory-<n>.md), because advice given in conversation is advice that gets rediscovered.

The agency contract

WootBuild is the estate's image agency. Every other Claude project under Wootface is a potential client, and the studio's relationship to all of them is the same shape: they ask, we cost and spec, a human judges, we deliver into their repo. This section is that relationship stated once, so a client project does not have to reverse-engineer it from our code and a new client is an onboarding, not a negotiation.

Four parts: how a client asks, what we promise, how much we may do unattended, and how work crosses the boundary.

1. One-directional, always

The bridge has a direction and it does not have two.

WootBuild reads a client's repodeclared paths, each with a role, hashed and diffed. art intake
WootBuild writes into a client's repoonly on delivery, only on a human verdict, only to paths the client declared
A client reads WootBuild's reponever. There is nothing for them to read and no path they may depend on
A client writes into WootBuild's reponever. Requests arrive in their drop-box, which we read

The asymmetry is deliberate and it is not a limitation of the current transport. A client that could read our internals would couple its work to our style versions, run ids and directory layout, and every one of those is ours to change. What they get instead is a generated contract page — clients/<id>/bridge.md — and files delivered at paths they named. No package, no dependency, no shared schema. See 18-CLIENT-BRIDGE.md §2.

2. How a client asks — the request

A client files a request into the drop-box declared with the requests role in their client.yaml. Append-only, agreed before the first request is filed, because a request dropped at a path nobody watches is worse than no request.

A request carries five things, and nothing else is required:

FieldWhy
What, in proseThe client knows their product. Prose is the right shape for intent
Where it goes — a manifest key, or an explicit "no key yet"Filenames are foreign keys. The key may exist long before the art does; "no key yet" is a valid and useful answer, and it tells us this needs a lane decision
How manyCount drives the estimate and the set contract
By when, if it mattersMost requests have no deadline. Saying so is information
Why nowThe one field that lets the studio sequence by value, and the one a client is most tempted to skip

A request may not name a model, a style version, a prompt, or a price. Those are the studio's to decide and the client's to be told. A client that names a model has made a routing decision without the corpus in front of them, and the router exists precisely because that decision is not obvious — see 03-MODEL-ROUTER.md. A request that names one is not refused; the name is recorded as a preference and the router still decides.

A request is not a brief and is never executed. art brief turns it into a costed, specced brief, and that step is free and prompts for nothing. The gap between the two is where the studio does its actual thinking: whether this is the right art at all, whether it belongs to an existing lane, what it will cost, and what the client assumed was fixed that is not.

3. What we promise

Two kinds of promise, and only one of them is about time.

The standing promises — true for every client, every lane, unconditionally:

  1. Consistency outlives the model. Piece four hundred matches piece one, and it still will after the model that made piece one has been retired. This is the product; everything else is delivery.
  2. Provenance, forever. Model, prompt, seed, style version, cost, verdict and parent run are recoverable for any asset we have ever delivered.
  3. No silent spend. Every generating command estimates first. Ceilings are enforced in code, not in a habit.
  4. Nothing ships on a machine's say-so. A grader verdict is recorded as a grader verdict and never delivers on its own below autonomy 3.
  5. We say when the work is wrong. Including when it is the work the client asked for. Deference is the failure mode — see The studio advises, above.
  6. A category never quietly ships short. If we cannot yet make it, the client is told it is outstanding rather than sent the nearest thing we can make.

Service levels are measured, never declared. A lane's turnaround is whatever the ledger says it has been — computed from real runs, not promised in a config file. This is deliberate and it is the opposite of how an agency usually writes an SLA:

A number nobody derived is not a commitment, it is a wish with a deadline attached. It gets missed silently, because nothing was ever measuring it.

So the studio publishes observed service levels per lane — lead time from request to first board, from board to verdict, from verdict to delivery — and a declared target may not be tighter than what has actually been observed. The mechanism is designed in 19-AGENCY-HARNESS.md §3.

The honest consequence: a new lane has no service level at all, and says so. It gets one after it has run. That is strictly more useful than a confident number invented on day one.

4. Autonomy — how much the studio may do unattended

Autonomy governs what the studio may do without a person in the room, and it runs along two risk axes that the old four-value ladder quietly conflated:

  1. Spending money unattended.
  2. Writing into other people's repositories.

Mandate governs creative latitude and is independent of both — see Mandate is not autonomy, above.

Each rung adds exactly one capability bit, and never removes one.

LevelAddsWhat it means
0—Human-triggered. A person starts every run and records every verdict
1runs_unattendedProduction may run on a schedule. Every verdict is still human, and nothing is delivered
2grader_verdictsThe grader may record machine-approved. A human still decides what ships
3deliversGrader verdicts stand, and delivery is unattended

Reading the bits rather than the number is the point: delivers is the bit that crosses into someone else's repository, and it is the last one granted.

What earns rung 1 its place — and it is a budget consequence, not a convenience. An unattended run cannot answer an interactive question. The spend guard's ask decision assumes a person is watching a terminal, and at level 1 nobody is. So level 1 declares its own budget behaviour rather than inheriting a prompt that cannot be answered:

This is why level 1 is a genuine rung and not a synonym for 0: it is the first level at which the studio spends money with nobody watching, and it needs a declared answer to "what happens when the price is over the line?" that levels 0 and 2 do not.

Promotion is a human act. laneStats() computes eligibility — at least 50 recorded verdicts and an approval rate at or above 90% — and eligibility is not promotion. Only Justin moves a lane, and only upward. Confusing the computed half with the authored half here would mean a lane promoting itself into unattended writes to someone else's repository.

Declared in lib/autonomy.mjs since 2026-08-20 (ATL-55). The table above is generated from that module's meaning, not maintained alongside it: every gate asks can(level, capability), and npm run check fails if any code outside that module compares autonomy to a number. It landed inert — no lane changed level, and the new gate is behaviour-identical to the autonomy < 3 threshold it replaced.

And the ladder now guards the capability, not just the function. Asking can(lane, 'delivers') inside art deliver protects the delivery function; it does nothing about a raw file write aimed at a client repo, because until this landed the only PreToolUse matcher in the studio was Bash. So the gate lived in exactly one code path, inside the mechanism that writes into other people's repositories — the same defect the ladder itself was built to fix, one layer out. .claude/hooks/guard-write.sh closes it: writes outside the studio tree are refused, and a client repo is reachable only through the function that asks the ladder. 19-AGENCY-HARNESS.md §4 carries the shape, the traversal rule, and the checks.

5. How work crosses the boundary — delivery

Scope — determined by the client, not by the roster

The question is never "is this in scope?" It is: what is the best possible asset for this requirement? — and then: what do we need to build up and staff up to make it? (Set 2026-08-17.)

Scope lists invert the logic. They start from what the studio currently owns and narrow the client's need to fit it, which produces a deliverable that looks complete and is not. An agency that only sells what it already knows how to make is a vendor. WootBuild is the client's art department, so the requirement leads and the capability follows.

The stack is the studio's roster, and it is staffed to the work. A capability WootBuild lacks — animation, vector at icon scale, geospatially grounded reference, a format nobody here has produced — is a hiring decision: named, scoped, priced, acquired. Until it is acquired the client is told plainly that it is outstanding, because the one unacceptable outcome is a category that quietly ships short.

docade's crane category is the worked example: 14 pieces of Rive animation. The right answer is not "animation is out of scope for v1" and it is not "send it to a diffusion model and deliver stills." It is to establish what those 14 pieces need to do in the product, determine the best artifact for that, and staff up to produce it.

Determining the best answer, then costing the gap to reach it, is therefore a required onboarding stage — before art direction and long before production. 13-WORKFLOW.md §3, Stage 2.

Still out of scope — but these are studio shape, not client capability

Deferred, not declined