skip to the page

Proposing a change

Up to here a tree has been something you wrote. This is the part where somebody else asks for one to change, and the runtime decides what happens next.

The short version: nothing edits a page directly. An ask becomes a written proposal, the proposal is examined, and only then is anything applied. Every example on this site has that whole sequence behind it, and you can run it.

The smallest tree that renderslive · rendered through the runtime

Hello from a tree

Nothing here was written as markup.

Propose a change:

Every one of these goes through the same pipeline a model’s answer would: interpreted, analysed, weighed, judged, applied, appended. The log is real and it is in this tab — reload the page and the example is back as it was.

show the tree
{
  "kind": "element",
  "id": "n_firsttree5",
  "type": "loom.page",
  "props": {
    "fills": true,
    "width": "readable",
    "loom:theme": {
      "palette": "minimal",
      "fontPack": "minimal-sans",
      "stylePreset": "precise"
    }
  },
  "children": [
    {
      "kind": "element",
      "id": "n_firsttree2",
      "type": "loom.heading",
      "props": {
        "level": 1
      },
      "children": [
        {
          "kind": "text",
          "id": "n_firsttree1",
          "value": "Hello from a tree"
        }
      ]
    },
    {
      "kind": "element",
      "id": "n_firsttree4",
      "type": "loom.prose",
      "props": {},
      "children": [
        {
          "kind": "text",
          "id": "n_firsttree3",
          "value": "Nothing here was written as markup."
        }
      ]
    }
  ]
}
A page with a heading and a sentence. Every node names a registered primitive and carries props that primitive declared.

Click a chip. What appears underneath is not a description of what would happen — it is what happened, printed out of the same functions a production deployment calls.

The four steps, in the order they happen

1. Somebody asks for something. That ask is an intent: a sentence, plus who is asking and which page they are looking at. The sentence on the chips above is the intent's own words.

2. Something turns the sentence into a plan. The plan is a delta — a short list of operations against the page as it is right now. There are four verbs and no more:

VerbWhat it does
insertputs a new node under a parent, at a position
removetakes a node out, and everything under it goes too
moveputs an existing node somewhere else, unchanged
configuresets or clears props on one node

You can read the delta for yourself in the box: every operation names a node by its id, so a change is a list of small edits to specific things rather than a new version of the page to diff against the old one.

3. Something judges the plan. That is the Gate, and it is the next page.

4. If the Gate allows it, the delta is applied and the page has a new revision. If not, the tree is exactly as it was — a refusal changes nothing.

Who writes the plan

Step 2 is the only step in the sequence that has to guess, and it is the only one Loom lets you swap. The thing that does it is a change interpreter, and the runtime does not care what is behind it:

type ChangeInterpreter = {
  interpret: (intent: EditIntent, tree: LoomTree) => Promise<Result<ProposedChange, …>>
}

Two of them ship. modelInterpreter asks a language model, which is the case Loom exists for. The other computes its operations from the tree with no model at all — which is what every chip on this site uses, and why the examples work in a browser with no API key, no server and no network.

Connecting a model is the whole of the first one: the exact text a model is shown, what it is allowed to say back, and what a request costs.

Everything after step 2 is unable to tell the difference. The proposal records which one wrote it, and the Gate judges both by the same rules.

What a proposal carries

A delta is the plan. The proposal around it is the paperwork, and every field on it is there because someone downstream reads it:

  • rationale — why these operations answer that ask, in the interpreter's own words. It is what a human reviewer reads when the Gate holds the change.
  • provenance — who asked, what interpreted it, and how confident that interpreter is in its own answer. The chips on this site report a confidence of 1, and that is not a boast: their operations are computed rather than guessed, and the record says authoredBy: "runtime" so nobody counts them as a model's perfect score.
  • baseRevision — the revision of the page this plan was written against. A proposal written for revision 3 does not apply to revision 4 by accident; it is refused as inapplicable, with a reason.

Click the same chip twice in the box above and watch the revision number in the frame's header go up. The second proposal is planned against the page as it is after the first — not against the page the button was drawn on.

And then it is recorded

Step 4 has a second half. A change the Gate allowed is not only applied — it is appended to a log, which is what makes a page's history readable, attributable and undoable.

The box above has one. Press a chip and look underneath the verdict: there is a row there, and it says who asked, what planned it, and what it did. That is the next page.

What matters here is that everything above is true either way — the tree in this browser tab and a tree in Postgres go through the same four steps, in the same order, judged by the same rules.