Skip to main content
Glama

Scaffold Workspace Structure

steps.apply

Apply a declarative 'Steps' document that scaffolds a whole workspace at once: a space (new, or an existing one you name), optional folders, and one or more sheets (each with attributes/views/peeks). Use this for multi-sheet apps (e.g. a CRM with Contacts + Deals) instead of creating sheets one by one.

  • Every node has a doc-local 'ref'; cross-references use {"$ref":""}; attributes are targeted by their author-assigned 'code'.

  • To LINK two sheets (a relation), use dataType "Relation" with options.relatedSheet:{"$ref":""}, or {"$existing":{"sheetId":}} to link to a sheet that already exists in this workspace (id from workspace.structure). Do NOT use "Link" — that is a plain URL field, not a cross-sheet relation.

  • A count or sum over linked rows: dataType "Rollup" with options {type:"RELATION", relatedAttr:{"$ref":""}, fn:{functionType:"COUNT"}, returnType:"Number"}. A linked row's field: dataType "Mirror" with options {relationAttr:{"$ref":""}, mirroredAttr:{"$ref":"<field of the related sheet, or Title>"}}. Name fields by ref or code, never by id; new sheets only.

  • Set isUnique: true on an attribute whose value identifies a row (an external id, an email): item.create then dedupes on it.

  • On a Status attribute give each option a bucket ("Todo" / "InProgress" / "Complete") so done choices read as done — give every option one. bucket is rejected on Select / Multi-Select.

  • A sheet with no 'folder' lands at the space root. Only set a sheet's folder to a ref you declared in 'folders' — never to a space ref.

  • dataType values must be canonical Atwork names (e.g. "Short Text", "Long Text", "Number", "Email", "Date", "Select", "Status", "Relation"); a file field is always "File List".

  • Do NOT include a version or capabilities in the doc — those are handled automatically.

  • Placement: pass spaceId (and optionally folderId) from workspace.structure to install into an EXISTING space. Omit both to create a new space.

  • Optional extras: top-level 'forms' ({ref,name,sheet:{$ref},fields:[{code,required?,label?}]}), 'dashboards' ({ref,name,sheet:{$ref},widgets}), 'pages' ({ref,name,markdown}), 'spaceHome' ({widgets}) and 'seedRows' ({"": [{"": value}]}) for starter rows. Pass a draft from steps.draft unchanged; any other top-level key is an error.

  • 'workflows' use the Steps workflow format from the build skill; a doc with only workflows on existing sheets ({"$existing":{"sheetId":}}) creates no space. Returns the created spaceId, a map of sheet ref -> new sheetId, each workflow's state or error, and the address of every sheet that now takes email.

Input Schema

NameRequiredDescriptionDefault
docYes
spaceIdNoInstall into this EXISTING space instead of creating a new one. From workspace.structure.
folderIdNoFolder inside that space; defaults to the space root.

Output Schema

NameRequiredDescriptionDefault
spaceIdNoThe space the document was applied to (new or existing)
sheetIdsNoSheet ref → new sheetId
workflowsNoOne per workflow: active = running; error = why it was not created or turned on — tell the user
inboundAddressesNoEmail to this sheet: give the user this address; each email sent to it creates an item

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed13 schema fields changed
    • addedInput schema / properties / doc / additionalProperties
      Added value: +false
    • addedInput schema / properties / doc / properties / dashboards
      Added value: +{
      +  "items": {
      +    "properties": {
      +      "description": {
      +        "type": "string"
      +      },
      +      "icon": {
      +        "type": "string"
      +      },
      +      "name": {
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "ref": {
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "sheet": {
      +        "anyOf": [
      +          {
      +            "properties": {
      +              "$ref": {
      +                "minLength": 1,
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "$ref"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "properties": {
      +              "$existing": {
      +                "properties": {
      +                  "sheetId": {
      +                    "description": "An existing sheet in this workspace (from workspace.structure)",
      +                    "exclusiveMinimum": 0,
      +                    "maximum": 9007199254740991,
      +                    "type": "integer"
      +                  }
      +                },
      +                "required": [
      +                  "sheetId"
      +                ],
      +                "type": "object"
      +              }
      +            },
      +            "required": [
      +              "$existing"
      +            ],
      +            "type": "object"
      +          }
      +        ]
      +      },
      +      "widgets": {
      +        "items": {
      +          "additionalProperties": {},
      +          "propertyNames": {
      +            "type": "string"
      +          },
      +          "type": "object"
      +        },
      +        "type": "array"
      +      }
      +    },
      +    "required": [
      +      "ref",
      +      "name",
      +      "sheet",
      +      "widgets"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedInput schema / properties / doc / properties / forms / items / properties / sheet / anyOf
      Added value: +[
      +  {
      +    "properties": {
      +      "$ref": {
      +        "minLength": 1,
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "$ref"
      +    ],
      +    "type": "object"
      +  },
      +  {
      +    "properties": {
      +      "$existing": {
      +        "properties": {
      +          "sheetId": {
      +            "description": "An existing sheet in this workspace (from workspace.structure)",
      +            "exclusiveMinimum": 0,
      +            "maximum": 9007199254740991,
      +            "type": "integer"
      +          }
      +        },
      +        "required": [
      +          "sheetId"
      +        ],
      +        "type": "object"
      +      }
      +    },
      +    "required": [
      +      "$existing"
      +    ],
      +    "type": "object"
      +  }
      +]
    • removedInput schema / properties / doc / properties / forms / items / properties / sheet / properties
      Removed value: -{
      -  "$ref": {
      -    "minLength": 1,
      -    "type": "string"
      -  }
      -}
    • removedInput schema / properties / doc / properties / forms / items / properties / sheet / required
      Removed value: -[
      -  "$ref"
      -]
    • removedInput schema / properties / doc / properties / forms / items / properties / sheet / type
      Removed value: -"object"
    • addedInput schema / properties / doc / properties / pages / items / properties / content
      Added value: +{
      +  "items": {
      +    "additionalProperties": {},
      +    "propertyNames": {
      +      "type": "string"
      +    },
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedInput schema / properties / doc / properties / sheets / items / properties / remove
      Added value: +{
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": "array"
      +}
    • addedInput schema / properties / doc / properties / sheets / items / properties / target
      Added value: +{
      +  "properties": {
      +    "sheetId": {
      +      "exclusiveMinimum": 0,
      +      "maximum": 9007199254740991,
      +      "type": "integer"
      +    }
      +  },
      +  "required": [
      +    "sheetId"
      +  ],
      +  "type": "object"
      +}
    • addedInput schema / properties / doc / properties / spaceHome
      Added value: +{
      +  "properties": {
      +    "widgets": {
      +      "items": {
      +        "additionalProperties": {},
      +        "propertyNames": {
      +          "type": "string"
      +        },
      +        "type": "object"
      +      },
      +      "type": "array"
      +    }
      +  },
      +  "required": [
      +    "widgets"
      +  ],
      +  "type": "object"
      +}
    • addedInput schema / properties / doc / properties / workflows
      Added value: +{
      +  "items": {
      +    "additionalProperties": {},
      +    "properties": {
      +      "actions": {
      +        "items": {
      +          "additionalProperties": {},
      +          "propertyNames": {
      +            "type": "string"
      +          },
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "active": {
      +        "description": "true = publish it so it runs now; omit to leave a draft",
      +        "type": "boolean"
      +      },
      +      "name": {
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "ref": {
      +        "minLength": 1,
      +        "type": "string"
      +      },
      +      "sheet": {
      +        "anyOf": [
      +          {
      +            "properties": {
      +              "$ref": {
      +                "minLength": 1,
      +                "type": "string"
      +              }
      +            },
      +            "required": [
      +              "$ref"
      +            ],
      +            "type": "object"
      +          },
      +          {
      +            "properties": {
      +              "$existing": {
      +                "properties": {
      +                  "sheetId": {
      +                    "description": "An existing sheet in this workspace (from workspace.structure)",
      +                    "exclusiveMinimum": 0,
      +                    "maximum": 9007199254740991,
      +                    "type": "integer"
      +                  }
      +                },
      +                "required": [
      +                  "sheetId"
      +                ],
      +                "type": "object"
      +              }
      +            },
      +            "required": [
      +              "$existing"
      +            ],
      +            "type": "object"
      +          }
      +        ]
      +      },
      +      "trigger": {
      +        "additionalProperties": {},
      +        "propertyNames": {
      +          "type": "string"
      +        },
      +        "type": "object"
      +      }
      +    },
      +    "required": [
      +      "ref",
      +      "name",
      +      "sheet",
      +      "trigger",
      +      "actions"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / inboundAddresses
      Added value: +{
      +  "description": "Email to this sheet: give the user this address; each email sent to it creates an item",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "active": {
      +        "type": "boolean"
      +      },
      +      "address": {
      +        "type": "string"
      +      },
      +      "sheetId": {
      +        "type": "number"
      +      }
      +    },
      +    "required": [
      +      "sheetId",
      +      "address",
      +      "active"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • addedOutput schema / properties / workflows
      Added value: +{
      +  "description": "One per workflow: active = running; error = why it was not created or turned on — tell the user",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "active": {
      +        "type": "boolean"
      +      },
      +      "error": {
      +        "type": "string"
      +      },
      +      "id": {
      +        "type": "string"
      +      },
      +      "name": {
      +        "type": "string"
      +      },
      +      "ref": {
      +        "type": "string"
      +      },
      +      "sheetId": {
      +        "type": "number"
      +      }
      +    },
      +    "required": [
      +      "ref",
      +      "name",
      +      "active"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
  2. First observed

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations already declaring readOnly=false, destructive=false and idempotent=false, the description still adds substantial behavioral rules: ref/code addressing, that unknown top-level keys are an error, that version/capabilities must be omitted, dedupe semantics via isUnique, and bucket rejection on Select. It stops short of saying what happens to pre-existing sheets on re-apply, what partial failure leaves behind, or why idempotency is false — the main behavioral gap for a mutating bulk tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core purpose is front-loaded in the first sentence and the rest is bulleted domain rules, so it scans well for a complex tool. Some bullets are dense and mix drafting guidance with schema constraints, and a few (e.g. the Rollup option object inline) read like spec text rather than routing guidance, but almost every sentence carries information an agent would otherwise get wrong.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with a large nested doc schema and an existing output schema, the description covers the traps that matter: relations, mirror/rollup wiring, folder refs, canonical dataTypes, extra keys being errors. Remaining gaps are the freeform sub-objects it never explains — views, peeks, widgets, page content — and the sheets 'target'/'remove' fields, plus the workflow format which is deferred to 'the build skill'.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is only 67% and the description more than compensates: it defines doc-local refs vs cross-references, that attributes are targeted by author-assigned code, canonical dataType names, the Relation/Mirror/Rollup option shapes, folder-vs-space-ref placement, and the allowed top-level extras (forms, dashboards, pages, spaceHome, seedRows, workflows). That is meaning well beyond the schema's type declarations.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource — 'Apply a declarative Steps document that scaffolds a whole workspace at once' — and enumerates exactly what it produces (space, optional folders, sheets with attributes/views/peeks). It also distinguishes itself from the one-by-one siblings (sheet.create, space.create, folder.create) with the CRM example.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It states the selecting condition clearly: 'Use this for multi-sheet apps ... instead of creating sheets one by one', and adds placement rules (pass spaceId/folderId from workspace.structure to install into an existing space; omit both to create a new one). What's missing is an explicit 'do not use this when…' case, e.g. for adding a single sheet or folder to an already-installed space, leaving the boundary partly to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources