Page tree operations

3 operations named tree.*. Every one runs in a batch through apply_ops, dry_run_ops, the CLI or the admin.

Updated
OperationWhat it doesPermissionConfirmation
tree.readRead a draft page tree and its revision.site.readnone
tree.commitApply an invertible batch of splash.ops/2 ops to a page tree.content.editnone
tree.nodeRead one node of a page's draft tree with its props, styles, meta, variant and theme, and its children down to depth levels (1 by default, 0 for the node alone), without reading the whole tree.site.readnone

tree.read

Read a draft page tree and its revision.

permission: site.readreads onlyclass: read

Example input

{
  "pageId": "6f1d2c3b-4a59-4e8d-9c7b-1a2b3c4d5e6f"
}

Input

FieldTypeRequiredNotes
pageIdstringyesAt least 1 character.

Output

FieldTypeRequiredNotes
format"splash.tree"yes
v3yes
revisionintegeryesAt least 0.
rootobject | object | object | object | object | object | objectyes

Try it

yarn splash tree.read '{"pageId":"6f1d2c3b-4a59-4e8d-9c7b-1a2b3c4d5e6f"}' --dry-run

tree.commit

Apply an invertible batch of splash.ops/2 ops to a page tree. Each op names its node by id (insert names parentId and index): insert { parentId, index, node }, remove { id }, move { id, parentId, index }, set_props { id, patch } (a patch of props; null removes one), set_style { id, scope, patch }, set_meta { id, anchor?, name?, meta?, visibleTo?, locked? }, set_attrs { id, patch }, set_variant { id, variant }, set_theme { id, theme }, set_mixins { id, mixins }, set_visibility { id, visibility }, set_type { id, type }, set_override { id, target, patch }; only insert carries a whole node with its props. A node's section anchor is the node field anchor, not a prop or meta key. In a set_style patch and in the styles.sheet of an inserted node, each declaration value may be a raw CSS string ("clamp(22px, 2.3vw, 34px)", "{color.text}" for a token) or { kind: "raw", css }; the server tokenizes it with the inspector's parser and refuses a value the style catalogue does not allow, at its path. The class is content.edit, but only a content-prop edit (a set_props of a content field) needs no more: every other op of the batch needs site.edit.

permission: content.editwrites: tree:{pageId}class: transactionundo: yes

Example input

{
  "pageId": "6f1d2c3b-4a59-4e8d-9c7b-1a2b3c4d5e6f",
  "ops": [
    {
      "op": "insert",
      "parentId": "root0000",
      "index": 0,
      "node": {
        "id": "hero0001",
        "kind": "section",
        "type": "section",
        "anchor": "hero",
        "name": "Opening section",
        "styles": {
          "sheet": {
            "base": {
              "position": "sticky",
              "top": "0",
              "min-height": "100svh",
              "max-width": "none",
              "padding-inline": "0"
            }
          }
        },
        "children": [
          {
            "id": "claim001",
            "kind": "primitive",
            "type": "text",
            "props": {
              "text": {
                "en-US": "Architecture for the places we live in"
              }
            },
            "styles": {
              "sheet": {
                "base": {
                  "font-size": "clamp(22px, 2.3vw, 34px)",
                  "color": {
                    "kind": "raw",
                    "css": "{color.text.accent}"
                  }
                }
              }
            }
          }
        ]
      }
    },
    {
      "op": "set_props",
      "id": "claim001",
      "patch": {
        "text": {
          "en-US": "Architecture for the places we live and work in"
        }
      }
    },
    {
      "op": "set_style",
      "id": "claim001",
      "scope": "bp:md",
      "patch": {
        "margin-inline-start": "50%"
      }
    },
    {
      "op": "set_meta",
      "id": "hero0001",
      "anchor": "opening",
      "name": "Opening"
    },
    {
      "op": "set_attrs",
      "id": "claim001",
      "patch": {
        "data-tone": "quiet"
      }
    },
    {
      "op": "set_variant",
      "id": "button01",
      "variant": [
        "ghost"
      ]
    },
    {
      "op": "move",
      "id": "intro001",
      "parentId": "hero0001",
      "index": 1
    },
    {
      "op": "remove",
      "id": "old00001"
    }
  ]
}

Input

FieldTypeRequiredNotes
pageIdstringyesAt least 1 character.
opsarray of object | object | object | object | object | object | object | object | object | object | object | object | objectyesAt least 1 item.

Output

FieldTypeRequiredNotes
revisionintegeryesAt least 0.
inversearray of object | object | object | object | object | object | object | object | object | object | object | object | objectyes

Try it

yarn splash tree.commit '{"pageId":"6f1d2c3b-4a59-4e8d-9c7b-1a2b3c4d5e6f","ops":[{"op":"insert","parentId":"root0000","index":0,"node":{"id":"hero0001","kind":"section","type":"section","anchor":"hero","name":"Opening section","styles":{"sheet":{"base":{"position":"sticky","top":"0","min-height":"100svh","max-width":"none","padding-inline":"0"}}},"children":[{"id":"claim001","kind":"primitive","type":"text","props":{"text":{"en-US":"Architecture for the places we live in"}},"styles":{"sheet":{"base":{"font-size":"clamp(22px, 2.3vw, 34px)","color":{"kind":"raw","css":"{color.text.accent}"}}}}}]}},{"op":"set_props","id":"claim001","patch":{"text":{"en-US":"Architecture for the places we live and work in"}}},{"op":"set_style","id":"claim001","scope":"bp:md","patch":{"margin-inline-start":"50%"}},{"op":"set_meta","id":"hero0001","anchor":"opening","name":"Opening"},{"op":"set_attrs","id":"claim001","patch":{"data-tone":"quiet"}},{"op":"set_variant","id":"button01","variant":["ghost"]},{"op":"move","id":"intro001","parentId":"hero0001","index":1},{"op":"remove","id":"old00001"}]}' --dry-run

tree.node

Read one node of a page's draft tree with its props, styles, meta, variant and theme, and its children down to depth levels (1 by default, 0 for the node alone), without reading the whole tree. path names its ancestors from the root; cut lists the child ids left out at the depth limit. Find node ids in the page's outline resource; the answer's revision is the tree:<pageId> base revision of the batch that changes it.

permission: site.readreads onlyclass: read

Example input

{
  "pageId": "6f1d2c3b-4a59-4e8d-9c7b-1a2b3c4d5e6f",
  "nodeId": "claim001",
  "depth": 1
}

Input

FieldTypeRequiredNotes
pageIdstringyesAt least 1 character.
nodeIdstringyes
depthintegernoAt least 0. At most 4. Default 1.

Output

FieldTypeRequiredNotes
pageIdstringyes
revisionintegeryesAt least 0.
patharray of objectyes
path[].idstringyes
path[].kindstringyesOne of "root", "section", "repeater", "outlet", "primitive", "component", "instance".
path[].typestringyes
nodeobject | object | object | object | object | object | objectyes
cutrecord of array of stringyes

Try it

yarn splash tree.node '{"pageId":"6f1d2c3b-4a59-4e8d-9c7b-1a2b3c4d5e6f","nodeId":"claim001","depth":1}' --dry-run

Generated from the operation registry and the MCP tool catalogue (source bc1790f5703d2c89).

Something wrong on this page? Write to docs@librettocms.com.

Libretto docs

Colophon. These docs are a Libretto site: 68 pages in two languages, 20 guide pages imported from Markdown and 41 reference pages generated from the operation registry. Set in Softcore, with code in IBM Plex Mono. Its outline:

/ Libretto docs /start Get started /start/request-access Request access /start/workspace Your workspace /start/first-site Your first site /start/invite-a-client Invite a client /start/connect-claude Connect Claude to Libretto /build Build /build/first-page Build a page /build/layers-and-canvas Layers and canvas /build/site-components Site components /design-system Design system /design-system/tokens Colours, space and themes /design-system/components Components and variants /design-system/fonts Typography and fonts /motion Motion /motion/scenes Scenes and recipes /motion/image-sequences Image sequences /motion/reduced-motion Reduced motion /publish Publish /publish/languages Site languages /publish/versions Publish and versions /publish/members-and-forms Members and forms /publish/domains Domains /handover Hand a site to a client /glossary Glossary /agents Agents and API /agents/mcp MCP server /agents/cli CLI /agents/batches Batches /agents/errors Errors and findings /agents/operations Operations /search Search