Use it when choosing layout and components; use pipeline_run instead for the complete generation flow or code_generate when you already have a schema. Returns schema, a 30-minute process-local schemaRef and durable compositionId/version lineage. Prefer explicit object and context over keyword-based intent. preferences controls region/field order and sample seed; compositionId appends a version, while options.transient records none. Save schemas with schema_store to reuse across sessions. Selected nodes snapshot component mappings; composition does not generate or run an app. Reference: TOOL-REFERENCE.md#design_compose; full schema: oods://schemas/design_compose.input.json.

Inputs

Name Type Required Description
intent string no A short intent sentence (e.g., 'dashboard with metrics and sidebar', 'user registration form'), matched against fixed keyword and phrase tables, not understood; a sentence with no layout keyword becomes a low-confidence… See full schema for details.
object string no Object name from the OODS registry (e.g., 'Subscription', 'User'). When provided, composition uses trait-driven component placement via view_extensions.
context "detail" | "list" | "form" | "timeline" | "card" | "inline" | "workflow" no View context for object-aware composition. See full schema for details.
layout "dashboard" | "form" | "detail" | "list" | "card" | "timeline" | "landing" | "auto" no Layout template to use. 'landing' is a content/marketing page (hero + sections + CTA), not bound to a data object. 'auto' infers the best template from intent keywords.
preferences object no Layout and appearance preferences.
options object no Operation options.
compositionId string no Record this composition as the next version of an existing composition (operation "recompose") instead of creating a new one.
parentVersion integer no With compositionId: the version the new one derives from; default the latest.
presentation "stage1-inspection" no Named Stage1 inspection presentation: omit the accessibility score and prominently show measurement limits. Source records remain unchanged.

Outputs

Name Type Required Description
status "ok" | "error" yes Whether composition succeeded.
layout string yes The layout template that was used.
schema repl.ui.schema.json yes The generated UiSchema (with slot placeholders intact for agent customization).
schemaRef string no Server-managed reference to the generated schema for reuse in validate/render/code.generate.
schemaRefCreatedAt string no ISO timestamp when the schemaRef was created.
schemaRefExpiresAt string no ISO timestamp when the schemaRef expires.
compositionId string no The durable composition this result was recorded as; absent for transient compositions. Every version opens at /preview/<compositionId>/<version> on the preview host.
version integer no The recorded version number (1 for a new composition).
parentVersion integer | null no The version this one derives from; null for the first.
operation "compose" | "recompose" | "reorder-region" | "swap-slot" | "reorder-fields" | "seed" no How this version was produced.
head string | null no The OODS Foundry build head that produced it; null from a source checkout.
selections slotSelection[] yes Component selection results per slot.
validation object no
warnings issue[] yes Non-fatal issues during composition.
errors issue[] no Fatal issues that prevented composition.
objectUsed object no
meta object no

A real call

Recorded by this site's harbor run, step compose, with the published OODS Foundry 0.10.1.

Its input:

{
  "object": "Warehouse",
  "context": "detail",
  "preferences": {
    "brand": "Harbor",
    "theme": "light"
  }
}

Its result, first lines:

{
  "status": "ok",
  "layout": "detail",
  "schema": {
    "version": "2026.02",
    "theme": "light",
    "screens": [
      {
        "id": "screen-detail-13",
        "component": "Stack",
        "layout": {
          "type": "stack",
          "gapToken": "cluster-default"
        },
        "children": [
          {
            "id": "detail-header-1",
            "component": "Stack",
            "layout": {
              "type": "stack",
              "align": "space-between",
              "gapToken": "stack-default"
            },
            "children": [
              {
                "id": "detail-header-1-record-title",
                "component": "DetailHeader",
                "props": {
                  "titleField": "name",
                  "headingLevel": 1
                }
              },
              {
                "id": "screen-detail-13-record-summary",
                "component": "Stack",
                "layout": {
                  "type": "inline",
                  "gapToken": "cluster-tight"
                },
                "meta": {
                  "intent": "record-summary"
                },
                "children": [
                  {
                    "id": "screen-detail-13-record-summary-1",
                    "component": "StatusBadge",
                    "props": {
                      "tone": "lifecycle",
                      "statusField": "status",
                      "domain": "lifecycle"
                    }
                  }
                ]
              },
              {
                "id": "slot-header-2",
                "component": "StatusTimeline",
                "meta": {
                  "intent": "slot:header",
                  "label": "header"

The whole call, 27 KB of JSON