← Receivers

blocks:list

blocks family

mcp

Discover the page blocks that exist — name, category, surface, description and variant list, filterable and paged

Effect
ask
Awaits an outcome — the call returns the response below.
Cost
free
What one call costs, so you can budget before acting.
Reversible
yes
The effect can be undone by a later call.
Idempotent
yes
Safe to retry as-is.

Send it with your agent

One click hands your coding agent a prompt that registers the substrate, reads this contract, and makes the call. Launch opens the app; the others copy the prompt.

Claude Code
Codex
Cursor
Gemini CLI
Claude Desktop
ChatGPT
curl -X POST https://one.ie/api/ask/blocks:list \
  -H "Authorization: Bearer $ONE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"data": { "category": "marketing", "limit": 20 }}'

The key is never in a link. npx -y @oneie/cli login writes it to ~/.config/oneie/key on your machine.

Request

Validated before dispatch — an invalid payload is refused with the fix, never half-applied.

  • category string optional Exact category filter: ai · app · auth · content · data · ecommerce · email · learning · marketing · social · wallet. Read `facets.categories` for the live list.
  • surface string optional Exact surface filter: section · container · atomic · app · social-preview — how much chrome the block may carry.
  • search string optional Case-insensitive substring over name + description + category.
  • limit number optional Rows per page. Default 50, max 200.
  • cursor string optional Opaque offset from a previous response's `nextCursor`. The order is by name, so a cursor is stable.

Response

What comes back from the call.

  • ok true
  • workspace string | null The attested caller's slug, or null when anonymous. Never echoed from the request.
  • blocks object[]
  • total number Rows matching the filters BEFORE paging — exact. Tenant rows are counted in it and sort first.
  • returned number Rows in this response.
  • registryTotal number Every block in the registry, ignoring filters.
  • tenantTotal number The caller's own declared blocks matching the filters. 0 for an anonymous caller — this axis is read off the attested slug, never a body field.
  • measuredAt string When the manifest this projects was generated.
  • nextCursor string Present ⟺ more rows match. Absent means you have them all.
  • truncated object Present ⟺ rows were cut. ABSENT IS NOT FALSE — an uncut answer carries no `truncated` key.
  • stale object Present ⟺ the manifest's own header count disagrees with its contents. Regenerate with `node .claude/scripts/blocks-manifest.mjs`.
  • facets object Every value the filters accept, read off the registry — never hand-listed.

Traffic

Every call to blocks:list, counted where it is dispatched — over HTTP or in-process alike. Aggregate only — no actor, no payload, no workspace.

Counting…

Wiring

Every place in the open source that names blocks:list, and the file that answers it. Read from the tree at build time — a receiver is reached by NAME through one door, so there is no import edge to follow and a grep is the honest shape of the question. Structure, not volume — the count is in Traffic above.

Called from

API route 1
  • one.ie/web/src/lib/resolvers/blocks.ts:273

Answered by

blocks:list one.ie/web/src/lib/resolvers/blocks.ts:326 Dispatched through POST /api/ask/blocks:list, after the envelope validates the payload.

blocks family · 2 more

JSON Schema
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "category": {
      "description": "Exact category filter: ai · app · auth · content · data · ecommerce · email · learning · marketing · social · wallet. Read `facets.categories` for the live list.",
      "type": "string"
    },
    "surface": {
      "description": "Exact surface filter: section · container · atomic · app · social-preview — how much chrome the block may carry.",
      "type": "string"
    },
    "search": {
      "description": "Case-insensitive substring over name + description + category.",
      "type": "string"
    },
    "limit": {
      "description": "Rows per page. Default 50, max 200.",
      "type": "number"
    },
    "cursor": {
      "description": "Opaque offset from a previous response's `nextCursor`. The order is by name, so a cursor is stable.",
      "type": "string"
    }
  }
}
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "ok": {
      "type": "boolean",
      "const": true
    },
    "workspace": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "description": "The attested caller's slug, or null when anonymous. Never echoed from the request."
    },
    "blocks": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "enum": [
              "registry",
              "tenant"
            ],
            "description": "`registry` is ONE's first-party Puck registry; `tenant` is a composition THIS workspace declared with `blocks:declare`. A tenant key can never shadow a registry name — the declare door refuses one that does."
          },
          "category": {
            "type": "string"
          },
          "surface": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "icon": {
            "type": "string"
          },
          "chatFit": {
            "type": "string"
          },
          "pagesUsing": {
            "type": "number",
            "description": "How many stored pages hold an instance, at the manifest's `measuredAt`. A popularity signal, not a live count — always 0 for a tenant block."
          },
          "canonicalVariant": {
            "description": "The variant that renders when none is sent. Absent on a block that is not a collapsed family, and on a tenant block.",
            "type": "string"
          },
          "variants": {
            "description": "The variant values this family accepts. Absent on a non-family block.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "composedOf": {
            "description": "TENANT ONLY — the registry components this composition expands into, in render order.",
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "name",
          "source",
          "category",
          "surface",
          "description",
          "icon",
          "chatFit",
          "pagesUsing"
        ]
      }
    },
    "total": {
      "type": "number",
      "description": "Rows matching the filters BEFORE paging — exact. Tenant rows are counted in it and sort first."
    },
    "returned": {
      "type": "number",
      "description": "Rows in this response."
    },
    "registryTotal": {
      "type": "number",
      "description": "Every block in the registry, ignoring filters."
    },
    "tenantTotal": {
      "type": "number",
      "description": "The caller's own declared blocks matching the filters. 0 for an anonymous caller — this axis is read off the attested slug, never a body field."
    },
    "measuredAt": {
      "type": "string",
      "description": "When the manifest this projects was generated."
    },
    "nextCursor": {
      "description": "Present ⟺ more rows match. Absent means you have them all.",
      "type": "string"
    },
    "truncated": {
      "description": "Present ⟺ rows were cut. ABSENT IS NOT FALSE — an uncut answer carries no `truncated` key.",
      "type": "object",
      "properties": {
        "rows": {
          "type": "number",
          "description": "How many matching rows are NOT in this response."
        },
        "limit": {
          "type": "number",
          "description": "The budget that bit."
        },
        "reason": {
          "type": "string",
          "const": "page"
        }
      },
      "required": [
        "rows",
        "limit",
        "reason"
      ]
    },
    "stale": {
      "description": "Present ⟺ the manifest's own header count disagrees with its contents. Regenerate with `node .claude/scripts/blocks-manifest.mjs`.",
      "type": "object",
      "properties": {
        "declared": {
          "type": "number"
        },
        "actual": {
          "type": "number"
        }
      },
      "required": [
        "declared",
        "actual"
      ]
    },
    "facets": {
      "type": "object",
      "properties": {
        "categories": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "surfaces": {
          "type": "array",
          "items": {
            "type": "string"
          }
        }
      },
      "required": [
        "categories",
        "surfaces"
      ],
      "description": "Every value the filters accept, read off the registry — never hand-listed."
    }
  },
  "required": [
    "ok",
    "workspace",
    "blocks",
    "total",
    "returned",
    "registryTotal",
    "tenantTotal",
    "measuredAt",
    "facets"
  ]
}