For an agent

The operator is an agent in a terminal.

That is not a use case here, it is the premise. Every design decision in this project is judged by whether an agent gets it right on the first call without reading the implementation — and a feature that needs a GUI, a second round trip or a source read to use is a feature that has not landed.

What driving it looks like
a Claude Code session
# the agent has a drawing and a name, and no numbers at all

> polyweave accept mascot --from docs/design/art/ui/mascot.png
  wrote assets/mascot.accept.toml    3 predicates, 2 parameters to search

> polyweave search mascot
  job j_7f3a  stage=queued
  job j_7f3a  stage=rendering  rung=sphere   18/64  elapsed_s=54
  job j_7f3a  stage=rendering  rung=preview  61/64  elapsed_s=212
  done  score 0.94   light=2.8  form=1.9
        sheet  .polyweave/sheets/mascot-7f3a.png   (5 candidates)
        trace  .polyweave/traces/mascot-7f3a.json  (64 samples, 41 cached)

> polyweave bake mascot --rung final
  done  1024x1024  saturation_p99=0.87  delta_e=1.4  silhouette_iou=0.981
        accept: 3/3 predicates pass   rung=final

> polyweave bake shelf --rung final
  post.render-uniform  the render is a single colour, so nothing was lit
  -> the model 'shelf' carries no material. Set `material` on it, or pass
     `glaze: {roughness: 0.22}` to apply the default.

Four calls: turn a drawing into a spec, search for the parameters that satisfy it, take the verdict at the final rung, and — on the last one — get a failure that names the door instead of a traceback. The commands are the surface docs/specs/tool-surface.md fixes; the values are illustrative.

What follows from it

  • No GUI, ever. A surface that needs a person at a screen to operate is one the agent cannot use at all. That is the first non-goal, and it is the reason for most of the others.
  • A file beats a stream. Job state, traces, contact sheets, the budget ledger and every provenance record are files under .polyweave/ in the project, so a session that ends can be picked up by the next one and a colleague can reproduce what happened.
  • Names are the address. An asset, a predicate, a rung and a job all have names, and the trace addresses them by name. An anonymous thing cannot be discussed across a turn boundary.
  • Errors are instructions. A typed code, a message with no traceback in it, and a remedy that is the call which closes it.
  • Refusal over silence. An unknown field is refused, an unknown measure is refused, and a post-condition that fails is an error. Every one of those could have been a warning, and every one of them was a warning somewhere that cost a render.

The one thing it may not decide

A fetch from the generative service spends real money, and the plugin will not let an agent authorise that on its own judgement. What it does instead is make the spend bounded and visible: a ceiling in polyweave.toml that a person sets, a ledger of what has been spent against it, and a silhouette gate that refuses a request which plainly will not match the reference — because the cheapest credit is the one not spent. An agent can work continuously inside that ceiling without asking, and cannot move it.

Configuration, resolved per call

Explicit argument, then polyweave.toml, then the plugin default — in that order, evaluated on every call rather than cached at startup, so correcting a config file does not need a session restart. And nothing is written outside the project tree: a cache in a home directory is state a repository cannot review.

What it will not do for you

It will not tell you a render is good. It measures what it was given a measure for, and reports the margin. Where the criterion is real and no measure can compute it — “reads as cloth rather than paper” — the answer is the contact sheet: the search returns its best handful, you see that the winner is not the one you would have chosen, and you now know the spec is incomplete. Inventing a proxy for that criterion is how a spec ends up satisfied by a render a person rejects.

Deliberately not

What this will not be.

Five constraints bind the project, and they are governed alongside the backlog: a proposal is read against them before it becomes a line. The sharpest is the third.

A graphical editor

The caller here is an agent in a terminal, so a surface that needs a person at a screen to operate is one the agent cannot use at all.

Replacing Blender, Godot or the generative service

Those three already do the work; what is missing is the loop around them, so this orchestrates and measures and never re-implements a renderer, an engine or a mesh generator.

Spending money on the agent's own judgement

A fetch draws on a real balance, so the ceiling is a person's to set and the plugin's job is to make a spend bounded and visible, never to decide one is worth it.

One project's palette, rig or paths compiled in

Cottony is the first consumer and not the specification, so anything it needs that a second project would not is configuration, and a default that cannot be overridden is a defect.

A hosted service or an account to sign into

Everything runs on the developer's machine against files in their own repository, because a plugin that needs an account is one that fails on the day the account does.