skip to the page

What it costs you

Every framework is a shape, and a shape is mostly refusals. The rest of this site is about what Loom lets you do. This page is the other column, and it is the one to read before you commit anything to it.

The bargain, said once more

Loom lets an AI change a page that is already running, and the reason that is not alarming is that it can only say a small number of things. The page is data. A change is data. The words a change may use are a list you wrote.

You give up the freedom to have the AI produce anything at all, and what you get back is a change you can read, measure, refuse and undo. The other half of the same trade: what a thing does lives in the component you registered, never in the tree — so a proposal can move your checkout, rename it and take it away, and it can never change what happens when somebody presses the button.

Everything below is that trade, itemized.

Eight things you can no longer do

Under each one is the ruling that made it so, and what that ruling turned down instead. Those lists are read out of the records as this page builds — they are not a summary of them, and they never say why. The why is in the record, one click away, written on the day. Where a ruling has since been replaced in part, the box says so, because part of it is somebody else's now.

Loom will not write your components

The thing most AI tools do — hand you a new component, freshly written — is the one thing Loom does not do. It rearranges and reconfigures the pieces you already built. If a page needs a seating plan and nobody has ever built a seating plan, no amount of asking will produce one.

What you do instead. You build it once, in the ordinary way, and register it. After that it is a word anybody can use, for ever. This is the trade the whole framework is: generated code is code nobody read, and what you get for giving it up is a change small enough to review in a few seconds.

The ruling

The tree and the delta are the unit of AI-authored change

Turned down with it

  • Generated component code.
  • The Hermes beta's flat warp.blocks IR.
  • A fragment node kind, and conditional/looping nodes.
  • Positional paths as the addressing scheme.

A change can only use words that are already yours

Every name a change is allowed to say comes off a list you wrote — your heading, your card, your checkout. Asking for something that is not on it does not produce a broken page later; it produces a change that could not be written down in the first place.

What you do instead. Add the word. Registering a primitive is a deploy rather than a conversation, so your vocabulary grows at the speed of your release process — which is the speed you already trust. Primitives and the registry shows it happening.

The ruling

The registry is what the model is told it may build

Turned down with it

  • Put the catalogue in the system prompt.
  • Generate a JSON Schema per primitive and constrain the reply to it. (not closed)
  • Send the Zod schemas as text.
  • Let the interpreter hold the registry directly instead of a projection.
  • Derive the catalogue from the tree instead (what types appear in it).

Your component cannot pass a change's settings straight through

A primitive is handed its settings as one object, and it has to read them by name. The familiar one-line shortcut — take everything you were given and spread it onto the element you return — is not available here, because the thing being spread was written by a model and the element it lands on is real HTML.

What you do instead. Read the props you declared, and pass on only what you meant to. It is a few more lines in a file you write once, and it is what stops a proposal reaching an attribute nobody designed for it.

The ruling

Primitives receive AI-authored props in a bag, never spread

Turned down with it

  • Spread props and blocklist the dangerous names.
  • Spread props and require primitives not to forward rest props.
  • Namespace the runtime's props instead (__loomNodeId) and spread the rest.
  • Validate props against the primitive's schema in the Gate instead. (not closed)

A word your registry has forgotten leaves a gap, and nothing crashes

Render a page that names a primitive you did not register and the page still renders. The unknown node is left out and a note is filed saying which one and where. Nothing throws, so nothing wakes anybody up — a page missing a whole section can look completely fine.

What you do instead. Read what a render hands back. Every render returns its notes beside the output, and a deployment that ignores them is choosing to find out from a reader instead. Rendering a tree shows it happening.

The ruling

The renderer is a total, pure projection of the tree

Turned down with it

  • Return Result<ReactNode, RenderError> and fail the whole render on an unknown primitive.
  • Render a visible placeholder for an unknown primitive.
  • Promote an unknown primitive's children into its parent.
  • Position paths as React keys instead of node ids.
  • Let the renderer load the tree itself (a default source, a fetch, a cache).
  • Trust the tree coming out of storage and skip parseTree.

Loom has no idea which parts of your page matter

Rewording a heading and changing a price are the same move: one setting, on one node. Nothing in the runtime has heard of your shop, so out of the box it cannot tell those apart, and nothing on your page is protected until you say so.

What you do instead. Write the policy. It is the second list you write after the registry, it is usually a few lines long, and it is what turns “an AI can change this page” into “an AI can change these parts of this page”. What AI may change shows it happening.

The ruling

The Gate is a pure function of two independent axes

Turned down with it

  • A weighted risk score with a threshold.
  • One combined "risk" axis.
  • Reversibility as a declared property of a primitive.
  • Snapshot-based undo.

A change is written against one version of the page, and the page will not wait

Somebody asks for a change at ten past nine. Between then and the moment it is applied, two other changes land. The first one does not quietly re-aim itself at the page as it now stands — it names the version it was written against, and when that version has moved on, it does not apply.

What you do instead. Ask again. That sounds like a cost and is mostly a refusal to guess: a change that re-targets itself is a change nobody reviewed, because the thing that was reviewed is not the thing that would happen. When something looks wrong shows it happening.

The ruling

AI drafts a change; the runtime names what it creates

Turned down with it

  • The model emits complete LoomNodes with ids.
  • The model emits placeholder handles ($0, $1) that the runtime resolves.
  • Accept model-supplied ids but rewrite them before applying.
  • Author the delta against the tree's current revision rather than the intent's.

There is no rewind

Undo does not wind the page back to how it was. It works out the change that would return things to how they were, and then that change goes through everything any other change goes through — including being refused, if it would throw away work somebody has done since.

What you do instead. Nothing, usually: an undo is a button like any other, and the difference only shows when it is refused. What you get is a history that only ever grows, so the page can always say who did what and when. The history of a page shows it happening.

The ruling

An undo is a proposal, not a rewind — partly superseded

Turned down with it

  • Store the inverse delta on the revision.
  • Rewind the log.
  • Apply the inverse straight to the store, skipping the Gate.
  • Let a contested revert proceed with a warning. (not closed)
  • A revert operation in the delta model.

You cannot fix a live page by editing the database

The page you can see is worked out from the list of changes that produced it. Reach past that and correct the stored page directly — one quick statement in a database console, the way anybody would — and the page will look right and stop matching its own history. Loom has a check that finds this, and finding it is all it can do.

What you do instead. Propose the correction, even from a script. There is one way in and it is the same one a person uses, so the fix arrives as a change with a name on it rather than as a mystery six weeks later. What your app has to do shows it happening.

The ruling

The log is the truth and the snapshot is a materialised view

Turned down with it

  • Pure event sourcing, no snapshot.
  • Snapshot only, no log.
  • Snapshot plus a log kept only for display.
  • Periodic snapshots every N revisions, replaying the remainder. (not closed)
  • Deriving the audit from inverse deltas

What is not settled

The eight above will read the same next year. Some of what Loom has turned down will not, because a record sometimes declines to close a question rather than answering it — deferred, rejected for now, worth revisiting once. Those are the constraints that might lift, and there is no reason to make you dig for them.

1023 alternatives, across 216 rulings. Every one of them is an approach somebody could reasonably have taken, written down on the day it was turned down. 40 of them are not closed:

A row is here because the record's own paragraph says so, in the sentence printed under it. Nothing is judged for it: if a ruling changes its mind, this list changes with it, and if it never does, the row stays.

The cost nobody records

There is one more, and it is not in any of the rulings because it is not a decision anybody made: Loom is worth its price only if the same page changes more than once. A page that ships and then sits there gets the whole bill — the registry, the policy, the store, the log — and none of the benefit, which only arrives the fourth time somebody asks for something and nobody has to open an editor.

That is a judgement about your situation rather than about the framework, and it is the one thing on this page that no test can hold true.

Where the arguments are

Decision records is every ruling Loom has made, in the order they were made, with what each one replaced. The alternatives named on this page are all in there with their reasoning attached, and so are the several hundred that no cost above points at.