# OODS Foundry: the full text > OODS Foundry is an object-oriented design system that extends the one you already have. Your AI assistant drives it over MCP: your objects, traits and brand become React and Vue apps of governed components and tokens, with charts it certifies. This file holds, whole, the Markdown twin of each page /llms.txt lists under Start here, Guides, Tools: the front door, the guides and the tool reference, at OODS Foundry 0.11.3. Every other page has its own twin, at its path with .md added; https://oods-foundry.com/llms.txt lists the main ones. --- Source: https://oods-foundry.com/agents # For agents OODS Foundry, the object-oriented design system, is driven by your AI assistant over MCP. This page is for the assistant: how to install it, what to ask first, every tool with its schemas, and the files on this site an agent can read. You can try the hosted tools before installing. ## Use it in Claude Connect OODS Foundry to Claude to explore its objects and components, find recorded React and Vue screens, and draw charts from data you provide. The hosted tools are free and read-only. You don't need an OODS Foundry account, an API key or a local installation. ### Add the connector 1. In claude.ai, open **Customize → Connectors**, choose **+ Add**, then **Add custom connector**. 2. Name it **OODS Foundry** and enter `https://oods-foundry.com/mcp` as the remote MCP server URL. Choose **Continue**. 3. Review the connection settings and choose **Continue**. If Claude asks for an authentication method, choose **No sign in**. OODS Foundry needs no credentials or request headers. Finish with **Add**. 4. In a chat, open **+ → Connectors** and enable **OODS Foundry**. Try a prompt below. On a Team or Enterprise plan, an owner or authorized administrator must first add the connector for the organization. See [Claude's custom connector instructions](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp) for the steps for your plan. ### Try these prompts #### Explore components `Use OODS Foundry to show the first 10 components in the core category, with a short summary of each. Tell me whether there are more.` You get a page of components from the current registry and whether another page follows. #### Read an object `Use OODS Foundry to show the Subscription object's fields and traits. Explain what each trait contributes.` You get the object's definition, including its fields, traits and relationships. #### Find a screen `Use OODS Foundry to find the recorded Subscription detail screen in Vue. Give me its link and content hash.` You get a link to a screen already generated by the site's pinned release, with the hash identifying that recorded app. #### Draw and check a chart `Use OODS Foundry to draw a bar chart of subscriptions by plan: Starter 12, Team 28, Business 9. Use brand A in the light theme. Include the data table, narrative and certification results.` You get the chart as SVG, its data table and narrative, and the results of the chart's checks. Certification reports what passed or failed; read the results alongside the chart. ### What the hosted tools can do The connector reads OODS Foundry's published objects, components and tokens, looks up recorded screens, and draws and checks charts from up to 500 rows. Importing your schema files, composing new screens, creating brands and writing files are available through the [local package](#install). ### If something doesn't work - **The tools aren't available in your chat:** check that OODS Foundry is enabled under **+ → Connectors**. On a work account, check that your organization has added it. - **The connection fails:** check that the URL is exactly `https://oods-foundry.com/mcp`, including `/mcp`. No OODS Foundry sign-in or key is needed. - **The service is busy:** a `429` or `503` response gives a retry delay. Wait for that delay, then try the same request again. Anthropic's hosted MCP clients, including Claude's custom connectors, share a budget of 600 requests and 30 new charts a minute. That budget is shared across users. - **A reply is too large:** ask for fewer components per page, shorter component summaries or fewer chart rows. Read the [privacy policy](https://oods-foundry.com/privacy). For help, [contact us](https://oods-foundry.com/about) at . Report bugs in [GitHub Issues](https://github.com/kneelinghorse/OODS-Foundry/issues). ### Hosted endpoint details `https://oods-foundry.com/mcp` Connect an MCP client over Streamable HTTP. No account or key is needed. The tools read the pinned package's catalog and registry. They draw and certify charts. They also look up the screens already recorded on this site. - `health_check`, `catalog_list` and `object_registry` list and show read the running package, and `registry_snapshot` returns the package's summary of every object and trait in it. - `structured_data_fetch` reads the tokens and manifest datasets, and their available versions. Read components a page at a time with `catalog_list`. - `tool_schema` returns a tool's shipped schema, source URL and file hash. `tools/list` describes the narrower hosted inputs. - `design_preview` returns a recorded screen's URL and content hash, by object, context and React or Vue. This site's lookup is separate from the local package's preview writer and `design_versions` history reader. - `viz_render` draws from inline data in brand A or B, in light, dark or high contrast, through the same route as the [chart playground](https://oods-foundry.com/charts/playground). - `artifact_certify` takes that chart input in `chart`, then draws and certifies its normalized spec in the same scope. ``` { "name": "design_preview", "arguments": { "object": "Subscription", "context": "detail", "framework": "react", "reproduce": true } } ``` Set `reproduce: true` to include the pinned local command and calls or files to check. It is off by default. Repeat those locally and compare the recorded content hash. For a screen, create the recorded brand, compose, then use your own composition's `schemaRef` to generate. `health_check`'s process measurements and registry snapshot timestamps vary; host folder paths are omitted. Chart replies contain hashes and certification by default. Set `output.svg` for the drawing, `output.includeA11y` for the data table and narrative, or `output.includeNormalizedSpec` for its specification. For `artifact_certify`, these options go inside `chart.output`. Reproduction details use `specFrom`, `rowsFrom` or `dataFrom` to name data already in the reply or preceding call, instead of repeating it. Replies are bounded so that every Claude client accepts them. A reply that would be larger is refused with its size and a narrower call to make instead, and `catalog_list` limits the page size at full detail and reports any adjustment. The `sparkline-grid` pattern is not offered here. The package over local stdio returns the full outputs. Local stdio is the authoritative path for the full toolset: generation, your objects and brands, file inputs and certification of your own specs. Hosted tools share the chart route's request budget and cache. Each address has a budget of its own, except that MCP clients hosted by Anthropic, such as claude.ai custom connectors, call from Anthropic's published addresses and share one larger budget between them. Past a budget, the reply is `429` with `Retry-After`. A retryable refusal says when to retry; repeated chart input can use the cached reply. ## Install `npx -y @oods/foundry` It runs on your machine as a local MCP server over stdio, registered as `oods-foundry`. It needs Node.js 22.0.0 or newer, as the `node` the client starts, on macOS or Linux (Windows is untested), with `npx` and `tar` on the PATH. Nothing to sign up for: it needs no account or key. The package documents Claude Desktop, Claude Code and Cursor. Each starts the same command. ### Claude Code ``` claude mcp add oods-foundry -- npx -y @oods/foundry claude mcp get oods-foundry ``` The second command prints `Status: ✓ Connected`. `-e MCP_TOOLSET=all` after the name adds the on-demand tool, 27 tools in all. ### Claude Desktop Add this under `mcpServers` in `~/Library/Application Support/Claude/claude_desktop_config.json`, then restart Claude Desktop: ``` { "mcpServers": { "oods-foundry": { "command": "npx", "args": [ "-y", "@oods/foundry" ] } } } ``` ### Cursor Add this to `.cursor/mcp.json` in the project, or `~/.cursor/mcp.json` for every project, then reload the window: ``` { "mcpServers": { "oods-foundry": { "type": "stdio", "command": "npx", "args": [ "-y", "@oods/foundry" ] } } } ``` How to check each one worked, and what to do when one doesn't: [Get started](https://oods-foundry.com/start). ## The Claude Code plugin The plugin bundles the server with the `oods-foundry` skill, which walks your assistant through the calls and tells it to report what wasn't checked. In Claude Code the skill is `/oods-foundry:oods-foundry`. ``` claude plugin marketplace add https://github.com/kneelinghorse/oods-foundry-claude-plugin.git claude plugin install oods-foundry@oods-foundry ``` Another agent can read the skill as it ships: [SKILL.md](https://cdn.jsdelivr.net/npm/@oods/foundry@0.11.3/skills/oods-foundry/SKILL.md), in `@oods/foundry` 0.11.3. ## In the MCP Registry OODS Foundry is listed in the official MCP Registry as `com.oods-foundry/foundry`. The `server.json` the package ships names the npm package and that entry: [the package's original server.json](https://cdn.jsdelivr.net/npm/@oods/foundry@0.11.3/server.json). That entry already lists this site's hosted endpoint, and [this site's server card](https://oods-foundry.com/.well-known/mcp/server-card.json) preserves that entry, including its title and icon. ## Source OODS Foundry is open source under Apache-2.0. [The public source repository](https://github.com/kneelinghorse/OODS-Foundry) mirrors each release. ## Your first prompt with the local package Each reply shown here is the real one, recorded by this site from the published OODS Foundry 0.11.3. This example needs the local package connected to your assistant. The hosted connector can look up recorded screens, but it cannot compose a new one. `Use oods-foundry to compose the Subscription detail screen and preview it.` **What comes back:** OODS Foundry composes the screen by rule and names the component it chose for each slot, and why. The preview answers with a link to the screen running in React and another in Vue, with the Subscription's sample records, on your machine. What `design_compose` answered for Subscription detail: ``` { "status": "ok", "layout": "detail", "schema": { "version": "2026.02", "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": "plan_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": "subscription" } }, { "id": "screen-detail-13-record-summary-2", "component": "BillingSummaryBadge", "props": { "amountField": "amount", "currencyField": "currency", "intervalField": "billing_interval", "minorUnitsParameter": "minorUnits", "minorUnits": 100 } } ] }, { "id": "slot-header-2", "component": "Stack", "meta": { "intent": "slot:header", "label": "header" }, "children": [ { "id": "ve-header-26", "component": "VizMarkPreview", "props": { "title": "Payment amounts", "description": "Payments recorded for this subscription, in its currency." }, "chart": { "chartType": "bar", "source": "payment-events", "dateFields": [ "last_payment_at", "next_payment_due_at" ], "amountField": "amount", "minorUnits": 100, "currencyField": "currency" } }, { "id": "ve-header-27", "component": "StatusTimeline", "props": { "field": "status", "historyField": "state_history", "statesParameter": "states", "showActorId": true, "showReason": true } }, { "id": "ve-header-28", "component": "CancellationSummary", "props": { "hideWhenDefault": true, "cancelAtPeriodEndField": "cancel_at_period_end", "reasonField": "cancellation_reason", "codeField": "cancellation_reason_code", "requestedAtField": "cancellation_requested_at" } }, { "id": "ve-header-29", "component": "ArchiveSummary", "props": { "hideWhenDefault": true, "archivedField": "is_archived", "archivedAtField": "archived_at", "restoredAtField": "restored_at", "reasonField": "archive_reason", "archivedByField": "archived_by", "metadataField": "archive_metadata", "retainHistoryParameter": "retainHistory", "restoreWindowParameter": "restoreWindowDays", "allowPartialRestoreParameter": "allowPartialRestore" } } ], "layout": { "type": "stack", "gapToken": "cluster-default" } } ] }, { "id": "detail-body-10", "component": "Card", "layout": { "type": "stack", "gapToken": "cluster-default" }, "children": [ { "id": "detail-tabs-9", "component": "Tabs", "children": [ { "id": "detail-tab-panel-3", "component": "Stack", "layout": { "type": "stack", "gapToken": "cluster-default" }, "props": { "label": "Billing" }, "children": [ { "id": "slot-tab-0-4", "component": "CycleProgressCard", "meta": { "intent": "slot:tab-0", "label": "tab-0" }, "props": { "progressField": "current_period_progress", "periodStartField": "current_period_start", "periodEndField": "current_period_end", "intervalField": "billing_interval" } }, { "id": "slot-tab-1-6", "component": "PaymentTimeline", "meta": { "intent": "slot:tab-1", "label": "tab-1" }, "props": { "lastPaymentField": "last_payment_at", "nextPaymentField": "next_payment_due_at", "paymentStatusField": "payment_status", "paymentMethodField": "payment_method_type", "amountField": "amount", "currencyField": "currency" } } ] }, { "id": "detail-tabs-9-read-fields", "component": "Stack", "props": { "label": "Details" }, "children": [ { "id": "detail-tabs-9-subscription_id-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-subscription_id-label", "component": "Text", "props": { "as": "strong", "content": "Subscription" } }, { "id": "detail-tabs-9-subscription_id-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "subscription_id" } } ] }, { "id": "detail-tabs-9-plan_code-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-plan_code-label", "component": "Text", "props": { "as": "strong", "content": "Plan code" } }, { "id": "detail-tabs-9-plan_code-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "plan_code" } } ] }, { "id": "detail-tabs-9-plan_interval-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-plan_interval-label", "component": "Text", "props": { "as": "strong", "content": "Plan interval" } }, { "id": "detail-tabs-9-plan_interval-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "plan_interval" } } ] }, { "id": "detail-tabs-9-customer_name-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-customer_name-label", "component": "Text", "props": { "as": "strong", "content": "Customer name" } }, { "id": "detail-tabs-9-customer_name-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "customer_name" } } ] }, { "id": "detail-tabs-9-customer_email-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-customer_email-label", "component": "Text", "props": { "as": "strong", "content": "Customer email" } }, { "id": "detail-tabs-9-customer_email-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "customer_email" } } ] }, { "id": "detail-tabs-9-created_at-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-created_at-label", "component": "Text", "props": { "as": "strong", "content": "Created at" } }, { "id": "detail-tabs-9-created_at-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "created_at" } } ] }, { "id": "detail-tabs-9-updated_at-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-updated_at-label", "component": "Text", "props": { "as": "strong", "content": "Updated at" } }, { "id": "detail-tabs-9-updated_at-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "updated_at" } } ] }, { "id": "detail-tabs-9-last_event-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-last_event-label", "component": "Text", "props": { "as": "strong", "content": "Last event" } }, { "id": "detail-tabs-9-last_event-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "last_event" } } ] }, { "id": "detail-tabs-9-last_event_at-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-last_event_at-label", "component": "Text", "props": { "as": "strong", "content": "Last event at" } }, { "id": "detail-tabs-9-last_event_at-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "last_event_at" } } ] } ] } ], "props": { "ariaLabel": "Record details" } } ] } ], "bindings": { "onEdit": "handleEdit", "onDelete": "handleDelete", "onCancel": "handleCancel", "onViewTimeline": "handleViewTimeline" }, "meta": { "label": "Subscription" } } ], "objectSchema": { "status": { "type": "string", "required": true, "default": "future", "description": "Current lifecycle status of the subscription.", "enum": [ "future", "trialing", "active", "paused", "pending_cancellation", "past_due", "unpaid", "terminated" ], "semanticType": "billing.subscription.status", "examples": [ "active", "paused", "active", "trialing", "past_due", "active", "terminated", "pending_cancellation" ] }, "state_history": { "type": "StateTransition[]", "required": false, "default": [], "description": "Chronological log of state transitions. Each entry records the before/after states,\ntimestamp, and (when governance is enabled) the actor, reason, and transition metadata.\nRendered by StatusTimeline in the detail and timeline views.\n\nEntry structure:\n - from: string (previous state)\n - to: string (new state)\n - timestamp: ISO 8601 datetime\n - actor_id: string (user/system who triggered the transition, optional)\n - reason: string (human-readable justification, required when requireTransitionReason is true)\n - transition_metadata: Record (arbitrary context, optional)\n", "semanticType": "timeline.state_transition", "examples": [ [ { "title": "Trial started", "from": "future", "to": "trialing", "at": "2026-02-16T15:00:00Z", "reason": "Started a 14-day Team trial" }, { "title": "Trial converted", "from": "trialing", "to": "active", "at": "2026-03-02T15:00:00Z", "reason": "First Team payment collected" } ], [ { "title": "Started", "from": "future", "to": "active", "at": "2026-04-10T15:00:00Z", "reason": "Analytics add-on purchased" }, { "title": "Paused", "from": "active", "to": "paused", "at": "2026-08-20T14:00:00Z", "reason": "Paused during the ERP migration" } ], [ { "title": "Started", "from": "future", "to": "active", "at": "2026-01-15T08:00:00Z", "reason": "Subscribed to the Starter plan" }, { "title": "Payment failed", "from": "active", "to": "past_due", "at": "2026-05-15T08:00:00Z", "reason": "Card expired; retrying" }, { "title": "Recovered", "from": "past_due", "to": "active", "at": "2026-05-17T08:00:00Z", "reason": "New card charged" } ], [ { "title": "Scheduled", "from": null, "to": "future", "at": "2026-09-19T10:00:00Z", "reason": "Trial starts once a card is verified" }, { "title": "Trial started", "from": "future", "to": "trialing", "at": "2026-09-21T09:00:00Z", "reason": "Card verified; 14-day trial started" } ], [ { "title": "Trial started", "from": "future", "to": "trialing", "at": "2026-01-20T10:30:00Z", "reason": "Started a 14-day Team trial" }, { "title": "Trial converted", "from": "trialing", "to": "active", "at": "2026-02-03T10:00:00Z", "reason": "First payment collected" }, { "title": "Payment failed", "from": "active", "to": "past_due", "at": "2026-09-03T10:00:00Z", "reason": "Card declined; retrying" } ], [ { "title": "Started", "from": "future", "to": "active", "at": "2024-10-30T14:00:00Z", "reason": "Annual Enterprise agreement signed" }, { "title": "Invoice overdue", "from": "active", "to": "past_due", "at": "2025-11-14T14:00:00Z", "reason": "Renewal invoice unpaid after 15 days" }, { "title": "Recovered", "from": "past_due", "to": "active", "at": "2025-11-20T02:00:00Z", "reason": "Paid by bank transfer" } ], [ { "title": "Started", "from": "future", "to": "active", "at": "2026-01-09T10:15:00Z", "reason": "Subscribed to the Starter plan" }, { "title": "Cancellation requested", "from": "active", "to": "pending_cancellation", "at": "2026-06-20T09:00:00Z", "reason": "Closing the studio in July" }, { "title": "Ended", "from": "pending_cancellation", "to": "terminated", "at": "2026-07-09T10:15:00Z", "reason": "Cancelled at the end of the billing period" } ], [ { "title": "Trial started", "from": "future", "to": "trialing", "at": "2026-04-23T12:30:00Z", "reason": "Started a 14-day Business trial" }, { "title": "Trial converted", "from": "trialing", "to": "active", "at": "2026-05-07T12:00:00Z", "reason": "First payment collected" }, { "title": "Cancellation requested", "from": "active", "to": "pending_cancellation", "at": "2026-09-21T16:40:00Z", "reason": "Moving to an annual contract elsewhere" } ] ] }, "allowed_transitions": { "type": "string[]", "required": false, "default": [], "description": "Materialized list of valid next states from the current status, computed from the\ntransitionRules parameter. When transitionRules is null (open model), this contains\nall states except the current one. Used by StatusSelector to disable invalid options\nand by StatusBadge to indicate available paths.\n", "semanticType": "status.navigation" }, "cancel_at_period_end": { "type": "boolean", "required": true, "description": "Whether the subscription will cancel at the natural billing period end.", "semanticType": "billing.subscription.cancel_at_period_end", "examples": [ false, false, false, false, false, false, true, true ] }, "cancellation_reason": { "type": "string", "required": false, "description": "Free-form explanation captured during cancellation workflows.", "semanticType": "billing.subscription.cancellation_reason", "examples": [ null, null, null, null, null, null, "Closing the studio in July", "Moving to an annual contract elsewhere" ] }, "cancellation_reason_code": { "type": "string", "required": false, "description": "Structured reason code chosen from the allowedReasons parameter.", "semanticType": "status.cancel.reason_code" }, "cancellation_requested_at": { "type": "datetime", "required": false, "description": "Timestamp when cancellation was initiated.", "semanticType": "billing.subscription.cancellation_requested_at", "examples": [ null, null, null, null, null, null, "2026-06-20T09:00:00Z", "2026-09-21T16:40:00Z" ] }, "created_at": { "type": "datetime", "required": true, "description": "Timestamp recording when the entity was first created.", "semanticType": "audit.created_at", "examples": [ "2026-02-16T15:00:00Z", "2026-04-10T15:00:00Z", "2026-01-15T08:00:00Z", "2026-09-19T10:00:00Z", "2026-01-20T10:30:00Z", "2024-10-30T14:00:00Z", "2026-01-09T10:15:00Z", "2026-04-23T12:30:00Z" ] }, "updated_at": { "type": "datetime", "required": false, "description": "Timestamp for the most recent modification, when available.", "semanticType": "audit.updated_at", "examples": [ "2026-09-02T15:00:00Z", "2026-09-10T15:00:00Z", "2026-09-15T08:00:00Z", "2026-09-21T09:00:00Z", "2026-09-03T10:00:00Z", "2025-11-20T02:00:00Z", "2026-07-09T10:15:00Z", "2026-09-21T16:40:00Z" ] }, "last_event": { "type": "string", "required": true, "description": "Lifecycle event associated with the most recent timestamp mutation.", "enum": [ "billing_cycle_started", "billing_cycle_completed", "payment_received", "cancellation_requested" ], "semanticType": "audit.event.type", "examples": [ "payment_received", "billing_cycle_completed", "payment_received", "billing_cycle_started", "billing_cycle_started", "payment_received", "billing_cycle_completed", "cancellation_requested" ] }, "last_event_at": { "type": "datetime", "required": false, "description": "Timestamp for the lifecycle event captured in last_event.", "semanticType": "audit.event.timestamp", "examples": [ "2026-09-02T15:00:00Z", "2026-09-10T15:00:00Z", "2026-09-15T08:00:00Z", "2026-09-21T09:00:00Z", "2026-09-03T10:00:00Z", "2025-11-20T02:00:00Z", "2026-07-09T10:15:00Z", "2026-09-21T16:40:00Z" ] }, "amount": { "type": "integer", "required": true, "description": "Recurring price expressed in minor units (e.g., cents).", "semanticType": "billing.plan.amount", "money": { "currencyField": "currency", "minorUnits": 100 }, "examples": [ 14900, 3900, 1900, 4900, 4900, 1200000, 1900, 14900 ] }, "currency": { "type": "string", "required": true, "description": "ISO 4217 currency code used for billing.", "semanticType": "billing.plan.currency", "examples": [ "USD", "USD", "EUR", "USD", "GBP", "USD", "USD", "USD" ] }, "billing_interval": { "type": "string", "required": false, "description": "Recurrence cadence (monthly, yearly, quarterly, etc.).", "semanticType": "billing.subscription.interval", "examples": [ "monthly", "monthly", "monthly", "monthly", "monthly", "yearly", "monthly", "monthly" ] }, "payment_status": { "type": "string", "required": false, "default": "pending", "description": "Outcome of the most recent collection attempt. Distinct from subscription\nlifecycle status — a subscription can be \"active\" with payment_status \"retrying\".\n", "enum": [ "pending", "succeeded", "failed", "retrying", "refunded" ], "semanticType": "billing.cycle.payment_status", "examples": [ "succeeded", "succeeded", "succeeded", "pending", "retrying", "succeeded", "succeeded", "succeeded" ] }, "payment_method_type": { "type": "string", "required": false, "description": "Payment instrument category used for collection.", "enum": [ "card", "ach", "wire", "invoice", "other" ], "semanticType": "billing.cycle.payment_method", "examples": [ "card", "card", "card", "card", "card", "wire", "card", "card" ] }, "proration_amount": { "type": "integer", "required": false, "default": 0, "description": "Prorated credit or charge in minor currency units generated by a mid-cycle\nplan change. Positive values are charges; negative values are credits.\nOnly populated when the supportProration parameter is true.\n", "semanticType": "billing.cycle.proration", "money": { "currencyField": "currency", "minorUnits": 100 }, "examples": [ 5333, 0, 0, 0, 0, 0, 0, 0 ] }, "proration_date": { "type": "integer", "required": false, "description": "Unix timestamp (epoch SECONDS) at which proration is calculated. Pinned when an\nupcoming-invoice PREVIEW is requested and MUST be passed identically on commit so the\ncommitted charge equals the previewed amount. The preview is read-only and does NOT\nmutate the subscription. Stored as an integer (not a datetime) so the value round-trips\nbyte-identically between preview and commit — an ISO string normalization could shift it\nand desync the previewed vs charged amount. Only populated when supportProration is true.\nSource: docs.stripe.com/billing/subscriptions/prorations.\n", "semanticType": "billing.cycle.proration_timestamp" }, "last_payment_at": { "type": "datetime", "required": false, "description": "Timestamp of the most recent successful payment.", "semanticType": "billing.subscription.last_payment_at", "examples": [ "2026-09-02T15:00:00Z", "2026-08-10T15:00:00Z", "2026-09-15T08:00:00Z", null, "2026-08-03T10:00:00Z", "2025-11-20T02:00:00Z", "2026-06-09T10:15:00Z", "2026-09-07T12:00:00Z" ] }, "next_payment_due_at": { "type": "datetime", "required": false, "description": "Timestamp when the next payment attempt should occur.", "semanticType": "billing.subscription.next_payment_due_at", "examples": [ "2026-10-02T15:00:00Z", null, "2026-10-15T08:00:00Z", "2026-10-05T09:00:00Z", "2026-10-01T10:00:00Z", "2026-10-30T14:00:00Z", null, null ] }, "current_period_start": { "type": "datetime", "required": true, "description": "Start timestamp of the current billing cycle.", "semanticType": "billing.subscription.current_period_start", "examples": [ "2026-09-02T15:00:00Z", "2026-08-10T15:00:00Z", "2026-09-15T08:00:00Z", "2026-09-21T09:00:00Z", "2026-09-03T10:00:00Z", "2025-10-30T14:00:00Z", "2026-06-09T10:15:00Z", "2026-09-07T12:00:00Z" ] }, "current_period_end": { "type": "datetime", "required": true, "description": "End timestamp of the current billing cycle.", "semanticType": "billing.subscription.current_period_end", "examples": [ "2026-10-02T15:00:00Z", "2026-09-10T15:00:00Z", "2026-10-15T08:00:00Z", "2026-10-05T09:00:00Z", "2026-10-03T10:00:00Z", "2026-10-30T14:00:00Z", "2026-07-09T10:15:00Z", "2026-10-07T12:00:00Z" ] }, "current_period_progress": { "type": "number", "required": false, "description": "Decimal progress (0-1) through the active billing cycle.", "semanticType": "billing.subscription.current_period_progress", "examples": [ 0.93, 1, 0.5, 0.64, 0.9, 0.92, 1, 0.77 ] }, "is_archived": { "type": "boolean", "required": true, "default": false, "description": "Flag indicating whether the entity is currently archived (soft-deleted).", "semanticType": "status.archive.state" }, "archived_at": { "type": "datetime?", "required": false, "description": "Timestamp for when the entity entered the archived state.", "semanticType": "status.archive.timestamp" }, "restored_at": { "type": "datetime?", "required": false, "description": "Timestamp for when the entity was most recently restored from an archived state.", "semanticType": "status.archive.restore_timestamp" }, "archive_reason": { "type": "string", "required": false, "description": "Human-readable narrative describing why the entity was archived.", "semanticType": "status.archive.reason" }, "archived_by": { "type": "string", "required": false, "description": "User ID or system identifier of the actor who archived this entity.\nSet to \"system\" for automated/policy-driven archival. Supports audit trail queries\nlike \"show all entities archived by user X\" or \"show all auto-archived entities\".\n", "semanticType": "status.archive.actor" }, "archive_metadata": { "type": "object", "required": false, "description": "Structured metadata about the archival action for compliance and audit purposes.\n\nProperties:\n - method: \"manual\" | \"automated\" | \"policy\" — how the archive was triggered\n - compliance_tags: string[] — regulatory labels (e.g., [\"GDPR\", \"SOX\", \"HIPAA\"])\n - retention_policy_id: string — reference to the retention policy that triggered archival\n - original_status: string — the Stateful status before archival\n - related_entity_count: number — count of related entities also archived (cascade)\n", "semanticType": "status.archive.compliance" }, "restoration_metadata": { "type": "object", "required": false, "description": "Metadata about the most recent restoration action.\n\nProperties:\n - restored_by: string — user ID or \"system\"\n - restored_fields: string[] — when partial restore, which fields were restored\n - restoration_reason: string — why the entity was restored\n - restored_from_snapshot: boolean — whether restored from a point-in-time snapshot\n", "semanticType": "status.archive.restoration" }, "subscription_id": { "type": "string", "required": true, "description": "Primary identifier used across billing and lifecycle systems.", "semanticType": "billing.subscription.id", "examples": [ "sub_northwind_business", "sub_northwind_analytics", "sub_lindqvist_starter", "sub_blueharbor_team", "sub_kestrel_team", "sub_tidewater_enterprise", "sub_marlow_starter", "sub_summit_business" ] }, "plan_name": { "type": "string", "required": true, "description": "Human-readable plan label shown in headers.", "semanticType": "billing.plan.name", "examples": [ "Business", "Analytics add-on", "Starter", "Team", "Team", "Enterprise", "Starter", "Business" ] }, "plan_code": { "type": "string", "required": false, "description": "Internal plan code or price identifier.", "semanticType": "billing.plan.code", "examples": [ "business-monthly", "analytics-addon-monthly", "starter-monthly", "team-monthly", "team-monthly", "enterprise-annual", "starter-monthly", "business-monthly" ], "displayLabel": "Plan code", "referenceLabels": { "plan_starter_monthly": "plan_starter_monthly", "plan_team_monthly": "plan_team_monthly", "plan_business_monthly": "plan_business_monthly", "plan_team_annual": "plan_team_annual", "plan_enterprise_annual": "plan_enterprise_annual", "plan_analytics_addon_monthly": "plan_analytics_addon_monthly", "plan_pro_monthly_2025": "plan_pro_monthly_2025", "plan_business_plus_monthly": "plan_business_plus_monthly" } }, "plan_interval": { "type": "string", "required": false, "description": "Billing interval descriptor (monthly, yearly, etc.).", "semanticType": "billing.plan.interval", "examples": [ "monthly", "monthly", "monthly", "monthly", "monthly", "yearly", "monthly", "monthly" ] }, "customer_name": { "type": "string", "required": false, "description": "Customer or account name associated with the subscription.", "semanticType": "text.summary", "examples": [ "Northwind Traders", "Northwind Traders", "Lindqvist Bakery", "Blue Harbor Studio", "Kestrel Print Co.", "Tidewater Co-op", "Marlow Yoga", "Summit Outfitters" ] }, "customer_email": { "type": "email", "required": false, "description": "Billing contact email address.", "semanticType": "customer.account.email", "examples": [ "billing@northwind.example", "billing@northwind.example", "finance@lindqvist.example", "accounts@blueharbor.example", "hello@kestrelprint.example", "treasurer@tidewater.example", "studio@marlowyoga.example", "ap@summit.example" ] }, "payment_history": { "type": "PaymentRecord[]", "required": false, "description": "Recorded payments, oldest first, each with its time and amount in minor units. Drawn by the payment chart.", "examples": [ [ { "at": "2026-03-02T15:00:00Z", "amount": 4900 }, { "at": "2026-04-02T15:00:00Z", "amount": 4900 }, { "at": "2026-05-02T15:00:00Z", "amount": 4900 }, { "at": "2026-06-02T15:00:00Z", "amount": 4900 }, { "at": "2026-06-16T15:00:00Z", "amount": 5333 }, { "at": "2026-07-02T15:00:00Z", "amount": 14900 }, { "at": "2026-08-02T15:00:00Z", "amount": 14900 }, { "at": "2026-09-02T15:00:00Z", "amount": 14900 } ], [ { "at": "2026-04-10T15:00:00Z", "amount": 3900 }, { "at": "2026-05-10T15:00:00Z", "amount": 3900 }, { "at": "2026-06-10T15:00:00Z", "amount": 3900 }, { "at": "2026-07-10T15:00:00Z", "amount": 3900 }, { "at": "2026-08-10T15:00:00Z", "amount": 3900 } ], [ { "at": "2026-01-15T08:00:00Z", "amount": 1900 }, { "at": "2026-02-15T08:00:00Z", "amount": 1900 }, { "at": "2026-03-15T08:00:00Z", "amount": 1900 }, { "at": "2026-04-15T08:00:00Z", "amount": 1900 }, { "at": "2026-05-17T08:00:00Z", "amount": 1900 }, { "at": "2026-06-15T08:00:00Z", "amount": 1900 }, { "at": "2026-07-15T08:00:00Z", "amount": 1900 }, { "at": "2026-08-15T08:00:00Z", "amount": 1900 }, { "at": "2026-08-16T08:00:00Z", "amount": 1900 }, { "at": "2026-08-19T11:30:00Z", "amount": -1900 }, { "at": "2026-09-15T08:00:00Z", "amount": 1900 } ], [], [ { "at": "2026-02-03T10:00:00Z", "amount": 4900 }, { "at": "2026-03-03T10:00:00Z", "amount": 4900 }, { "at": "2026-04-03T10:00:00Z", "amount": 4900 }, { "at": "2026-05-03T10:00:00Z", "amount": 4900 }, { "at": "2026-06-03T10:00:00Z", "amount": 4900 }, { "at": "2026-07-03T10:00:00Z", "amount": 4900 }, { "at": "2026-08-03T10:00:00Z", "amount": 4900 } ], [ { "at": "2024-10-30T14:00:00Z", "amount": 1200000 }, { "at": "2025-11-20T02:00:00Z", "amount": 1200000 } ], [ { "at": "2026-01-09T10:15:00Z", "amount": 1900 }, { "at": "2026-02-09T10:15:00Z", "amount": 1900 }, { "at": "2026-03-09T10:15:00Z", "amount": 1900 }, { "at": "2026-04-09T10:15:00Z", "amount": 1900 }, { "at": "2026-05-09T10:15:00Z", "amount": 1900 }, { "at": "2026-06-09T10:15:00Z", "amount": 1900 } ], [ { "at": "2026-05-07T12:00:00Z", "amount": 14900 }, { "at": "2026-06-07T12:00:00Z", "amount": 14900 }, { "at": "2026-07-07T12:00:00Z", "amount": 14900 }, { "at": "2026-08-07T12:00:00Z", "amount": 14900 }, { "at": "2026-09-07T12:00:00Z", "amount": 14900 } ] ] } } }, "schemaRef": "compose-779f5455", "schemaRefCreatedAt": "2026-11-02T05:29:53.587Z", "schemaRefExpiresAt": "2026-11-02T05:59:53.587Z", "compositionId": "cmp-0cb678c9e88d", "version": 1, "parentVersion": null, "operation": "compose", "head": "e2bb227041596b62187099b4d174b238cdfe0e6f", "selections": [ { "slotName": "tab-0", "intent": "data-display", "selectedComponent": "CycleProgressCard", "explanation": "CycleProgressCard leads slot \"tab-0\" because view_extension placement.", "candidates": [ { "name": "CycleProgressCard", "reason": "view_extension placement" } ], "placedComponents": [ "CycleProgressCard" ] }, { "slotName": "tab-1", "intent": "status-indicator", "selectedComponent": "PaymentTimeline", "explanation": "PaymentTimeline leads slot \"tab-1\" because view_extension placement.", "candidates": [ { "name": "PaymentTimeline", "reason": "view_extension placement" } ], "placedComponents": [ "PaymentTimeline" ] }, { "slotName": "header", "intent": "page-header", "selectedComponent": "DetailHeader", "explanation": "DetailHeader leads slot \"header\" because record title placed by the layout from the object's label field. The slot also renders VizMarkPreview, StatusTimeline, CancellationSummary, ArchiveSummary after it, in that order.", "candidates": [ { "name": "DetailHeader", "reason": "record title placed by the layout from the object's label field" }, { "name": "VizMarkPreview", "reason": "view_extension placement" } ], "placedComponents": [ "DetailHeader", "VizMarkPreview", "StatusTimeline", "CancellationSummary", "ArchiveSummary" ] } ], "validation": { "status": "ok", "errors": [], "warnings": [] }, "warnings": [ { "code": "OODS-V121", "message": "Object 'Subscription' has maturity 'beta' — composed output may change.", "hint": "Consider using stable objects for production compositions." }, { "code": "OODS-V117", "message": "Subscription refines 11 fields its traits define, and its own definitions are used: lifecycle/Stateful (status); lifecycle/Cancellable (cancel_at_period_end, cancellation_reason, cancellation_requested_at); financial/Billable (amount, currency, billing_interval, current_period_start, current_period_end, current_period_progress, next_payment_due_at)." } ], "objectUsed": { "name": "Subscription", "version": "2.0.0", "traits": [ "lifecycle/Stateful", "lifecycle/Cancellable", "lifecycle/Timestampable", "financial/Billable", "lifecycle/Archivable", "viz/MarkBar" ], "fieldsComposed": 37, "viewExtensionsApplied": { "list": 4, "detail": 7, "form": 4, "card": 4, "timeline": 1, "dashboard": 1 } }, "meta": { "intentParsed": "Subscription detail view", "layoutDetected": "context-inferred: detail (from context=\"detail\")", "slotCount": 3, "nodeCount": 44, "intentSynthetic": true, "warnings": [ "Object 'Subscription' has maturity 'beta' — composed output may change.", "Subscription refines 11 fields its traits define, and its own definitions are used: lifecycle/Stateful (status); lifecycle/Cancellable (cancel_at_period_end, cancellation_reason, cancellation_requested_at); financial/Billable (amount, currency, billing_interval, current_period_start, current_period_end, current_period_progress, next_payment_due_at)." ], "intelligence": { "fieldsExpanded": true, "slotsExpanded": 5, "expansionReason": "Expanded from 3 to 8 tabs for 37 fields", "patternGroups": [ { "slotName": "tab-0", "patternId": "status-timeline", "compositeComponent": "StatusTimeline", "matchedFields": [ "status", "updated_at" ], "confidence": 1 } ], "fieldAffinityUsed": true } } } ``` What `health_check` answers next, and what each part of it means: [Get started](https://oods-foundry.com/start#first-prompt). ## Tools 27 tools. Your assistant sees 26 by default, and `MCP_TOOLSET=all` turns on the rest. Each tool's input and output schemas are here as JSON, as the package ships them, beside a real call this site recorded. | Tool | Listed | Input schema | Output schema | A real call | | - | - | - | - | - | | [`a11y_scan`](https://oods-foundry.com/tools/a11y-scan) | with MCP_TOOLSET=all | [JSON: the input schema of a11y_scan](https://oods-foundry.com/registry/0.11.3/tools/a11y_scan.input.json) | none ships | [JSON: a recorded call of a11y_scan](https://oods-foundry.com/tools/a11y-scan/call.json) | | [`artifact_certify`](https://oods-foundry.com/tools/artifact-certify) | by default | [JSON: the input schema of artifact_certify](https://oods-foundry.com/registry/0.11.3/tools/artifact_certify.input.json) | [JSON: the output schema of artifact_certify](https://oods-foundry.com/registry/0.11.3/tools/artifact_certify.output.json) | [JSON: a recorded call of artifact_certify](https://oods-foundry.com/tools/artifact-certify/call.json) | | [`brand_apply`](https://oods-foundry.com/tools/brand-apply) | by default | [JSON: the input schema of brand_apply](https://oods-foundry.com/registry/0.11.3/tools/brand_apply.input.json) | [JSON: the output schema of brand_apply](https://oods-foundry.com/registry/0.11.3/tools/brand_apply.output.json) | [JSON: a recorded call of brand_apply](https://oods-foundry.com/tools/brand-apply/call.json) | | [`brand_create`](https://oods-foundry.com/tools/brand-create) | by default | [JSON: the input schema of brand_create](https://oods-foundry.com/registry/0.11.3/tools/brand_create.input.json) | [JSON: the output schema of brand_create](https://oods-foundry.com/registry/0.11.3/tools/brand_create.output.json) | [JSON: a recorded call of brand_create](https://oods-foundry.com/tools/brand-create/call.json) | | [`brand_read`](https://oods-foundry.com/tools/brand-read) | by default | [JSON: the input schema of brand_read](https://oods-foundry.com/registry/0.11.3/tools/brand_read.input.json) | [JSON: the output schema of brand_read](https://oods-foundry.com/registry/0.11.3/tools/brand_read.output.json) | [JSON: a recorded call of brand_read](https://oods-foundry.com/tools/brand-read/call.json) | | [`catalog_list`](https://oods-foundry.com/tools/catalog-list) | by default | [JSON: the input schema of catalog_list](https://oods-foundry.com/registry/0.11.3/tools/catalog_list.input.json) | [JSON: the output schema of catalog_list](https://oods-foundry.com/registry/0.11.3/tools/catalog_list.output.json) | [JSON: a recorded call of catalog_list](https://oods-foundry.com/tools/catalog-list/call.json) | | [`code_generate`](https://oods-foundry.com/tools/code-generate) | by default | [JSON: the input schema of code_generate](https://oods-foundry.com/registry/0.11.3/tools/code_generate.input.json) | [JSON: the output schema of code_generate](https://oods-foundry.com/registry/0.11.3/tools/code_generate.output.json) | [JSON: a recorded call of code_generate](https://oods-foundry.com/tools/code-generate/call.json) | | [`component_map`](https://oods-foundry.com/tools/component-map) | by default | [JSON: the input schema of component_map](https://oods-foundry.com/registry/0.11.3/tools/component_map.input.json) | [JSON: the output schema of component_map](https://oods-foundry.com/registry/0.11.3/tools/component_map.output.json) | [JSON: a recorded call of component_map](https://oods-foundry.com/tools/component-map/call.json) | | [`component_map_read`](https://oods-foundry.com/tools/component-map-read) | by default | [JSON: the input schema of component_map_read](https://oods-foundry.com/registry/0.11.3/tools/component_map_read.input.json) | [JSON: the output schema of component_map_read](https://oods-foundry.com/registry/0.11.3/tools/component_map_read.output.json) | [JSON: a recorded call of component_map_read](https://oods-foundry.com/tools/component-map-read/call.json) | | [`dashboard_render`](https://oods-foundry.com/tools/dashboard-render) | by default | [JSON: the input schema of dashboard_render](https://oods-foundry.com/registry/0.11.3/tools/dashboard_render.input.json) | [JSON: the output schema of dashboard_render](https://oods-foundry.com/registry/0.11.3/tools/dashboard_render.output.json) | [JSON: a recorded call of dashboard_render](https://oods-foundry.com/tools/dashboard-render/call.json) | | [`design_compose`](https://oods-foundry.com/tools/design-compose) | by default | [JSON: the input schema of design_compose](https://oods-foundry.com/registry/0.11.3/tools/design_compose.input.json) | [JSON: the output schema of design_compose](https://oods-foundry.com/registry/0.11.3/tools/design_compose.output.json) | [JSON: a recorded call of design_compose](https://oods-foundry.com/tools/design-compose/call.json) | | [`design_preview`](https://oods-foundry.com/tools/design-preview) | by default | [JSON: the input schema of design_preview](https://oods-foundry.com/registry/0.11.3/tools/design_preview.input.json) | [JSON: the output schema of design_preview](https://oods-foundry.com/registry/0.11.3/tools/design_preview.output.json) | [JSON: a recorded call of design_preview](https://oods-foundry.com/tools/design-preview/call.json) | | [`design_versions`](https://oods-foundry.com/tools/design-versions) | by default | [JSON: the input schema of design_versions](https://oods-foundry.com/registry/0.11.3/tools/design_versions.input.json) | [JSON: the output schema of design_versions](https://oods-foundry.com/registry/0.11.3/tools/design_versions.output.json) | [JSON: a recorded call of design_versions](https://oods-foundry.com/tools/design-versions/call.json) | | [`fidelity_preview`](https://oods-foundry.com/tools/fidelity-preview) | by default | [JSON: the input schema of fidelity_preview](https://oods-foundry.com/registry/0.11.3/tools/fidelity_preview.input.json) | [JSON: the output schema of fidelity_preview](https://oods-foundry.com/registry/0.11.3/tools/fidelity_preview.output.json) | [JSON: a recorded call of fidelity_preview](https://oods-foundry.com/tools/fidelity-preview/call.json) | | [`health_check`](https://oods-foundry.com/tools/health-check) | by default | [JSON: the input schema of health_check](https://oods-foundry.com/registry/0.11.3/tools/health_check.input.json) | [JSON: the output schema of health_check](https://oods-foundry.com/registry/0.11.3/tools/health_check.output.json) | [JSON: a recorded call of health_check](https://oods-foundry.com/tools/health-check/call.json) | | [`object_import`](https://oods-foundry.com/tools/object-import) | by default | [JSON: the input schema of object_import](https://oods-foundry.com/registry/0.11.3/tools/object_import.input.json) | [JSON: the output schema of object_import](https://oods-foundry.com/registry/0.11.3/tools/object_import.output.json) | [JSON: a recorded call of object_import](https://oods-foundry.com/tools/object-import/call.json) | | [`object_import_read`](https://oods-foundry.com/tools/object-import-read) | by default | [JSON: the input schema of object_import_read](https://oods-foundry.com/registry/0.11.3/tools/object_import_read.input.json) | [JSON: the output schema of object_import_read](https://oods-foundry.com/registry/0.11.3/tools/object_import_read.output.json) | [JSON: a recorded call of object_import_read](https://oods-foundry.com/tools/object-import-read/call.json) | | [`object_register`](https://oods-foundry.com/tools/object-register) | by default | [JSON: the input schema of object_register](https://oods-foundry.com/registry/0.11.3/tools/object_register.input.json) | [JSON: the output schema of object_register](https://oods-foundry.com/registry/0.11.3/tools/object_register.output.json) | [JSON: a recorded call of object_register](https://oods-foundry.com/tools/object-register/call.json) | | [`object_registry`](https://oods-foundry.com/tools/object-registry) | by default | [JSON: the input schema of object_registry](https://oods-foundry.com/registry/0.11.3/tools/object_registry.input.json) | [JSON: the output schema of object_registry](https://oods-foundry.com/registry/0.11.3/tools/object_registry.output.json) | [JSON: a recorded call of object_registry](https://oods-foundry.com/tools/object-registry/call.json) | | [`pipeline_run`](https://oods-foundry.com/tools/pipeline-run) | by default | [JSON: the input schema of pipeline_run](https://oods-foundry.com/registry/0.11.3/tools/pipeline_run.input.json) | [JSON: the output schema of pipeline_run](https://oods-foundry.com/registry/0.11.3/tools/pipeline_run.output.json) | [JSON: a recorded call of pipeline_run](https://oods-foundry.com/tools/pipeline-run/call.json) | | [`registry_snapshot`](https://oods-foundry.com/tools/registry-snapshot) | by default | [JSON: the input schema of registry_snapshot](https://oods-foundry.com/registry/0.11.3/tools/registry_snapshot.input.json) | [JSON: the output schema of registry_snapshot](https://oods-foundry.com/registry/0.11.3/tools/registry_snapshot.output.json) | [JSON: a recorded call of registry_snapshot](https://oods-foundry.com/tools/registry-snapshot/call.json) | | [`schema_read`](https://oods-foundry.com/tools/schema-read) | by default | [JSON: the input schema of schema_read](https://oods-foundry.com/registry/0.11.3/tools/schema_read.input.json) | [JSON: the output schema of schema_read](https://oods-foundry.com/registry/0.11.3/tools/schema_read.output.json) | [JSON: a recorded call of schema_read](https://oods-foundry.com/tools/schema-read/call.json) | | [`schema_render`](https://oods-foundry.com/tools/schema-render) | by default | [JSON: the input schema of schema_render](https://oods-foundry.com/registry/0.11.3/tools/schema_render.input.json) | [JSON: the output schema of schema_render](https://oods-foundry.com/registry/0.11.3/tools/schema_render.output.json) | [JSON: a recorded call of schema_render](https://oods-foundry.com/tools/schema-render/call.json) | | [`schema_store`](https://oods-foundry.com/tools/schema-store) | by default | [JSON: the input schema of schema_store](https://oods-foundry.com/registry/0.11.3/tools/schema_store.input.json) | [JSON: the output schema of schema_store](https://oods-foundry.com/registry/0.11.3/tools/schema_store.output.json) | [JSON: a recorded call of schema_store](https://oods-foundry.com/tools/schema-store/call.json) | | [`structured_data_fetch`](https://oods-foundry.com/tools/structured-data-fetch) | by default | [JSON: the input schema of structured_data_fetch](https://oods-foundry.com/registry/0.11.3/tools/structured_data_fetch.input.json) | [JSON: the output schema of structured_data_fetch](https://oods-foundry.com/registry/0.11.3/tools/structured_data_fetch.output.json) | [JSON: a recorded call of structured_data_fetch](https://oods-foundry.com/tools/structured-data-fetch/call.json) | | [`tokens_build`](https://oods-foundry.com/tools/tokens-build) | by default | [JSON: the input schema of tokens_build](https://oods-foundry.com/registry/0.11.3/tools/tokens_build.input.json) | none ships | [JSON: a recorded call of tokens_build](https://oods-foundry.com/tools/tokens-build/call.json) | | [`viz_render`](https://oods-foundry.com/tools/viz-render) | by default | [JSON: the input schema of viz_render](https://oods-foundry.com/registry/0.11.3/tools/viz_render.input.json) | [JSON: the output schema of viz_render](https://oods-foundry.com/registry/0.11.3/tools/viz_render.output.json) | [JSON: a recorded call of viz_render](https://oods-foundry.com/tools/viz-render/call.json) | ## Rate limits The README that ships with OODS Foundry 0.11.3 gives them, from the server's own policy: Each tool accepts 60 calls a minute, except `design_preview` and `design_versions` (10); `brand_apply` and `a11y_scan` (12); `object_import` and `object_import_read` (20); `tokens_build`, `brand_create`, `brand_read`, `fidelity_preview`, `component_map`, `component_map_read`, `schema_store` and `schema_read` (30); and `pipeline_run` (40). A call past its tool's limit is refused with a rate-limit error; wait a few seconds and call again. ## Files for agents - [/llms.txt](https://oods-foundry.com/llms.txt): this site's map for language models, with the pages to read first and these files. - [/llms-full.txt](https://oods-foundry.com/llms-full.txt): the front door, the guides and the tool reference, whole, in one file. - Every page as Markdown, at its path with `.md` added, such as [/agents.md](https://oods-foundry.com/agents.md); the home page's is `/index.md`. A request for the page's own URL with `Accept: text/markdown` gets the same text, and Copy as Markdown at the top of each page copies it. - [/registry/0.11.3/index.json](https://oods-foundry.com/registry/0.11.3/index.json): every file below with its source and SHA-256 hash, and where each tool's schemas are. - [/registry/0.11.3/tools.json](https://oods-foundry.com/registry/0.11.3/tools.json): every tool as a client lists it with MCP_TOOLSET=all: its name, description and input schema. - [/registry/0.11.3/objects.json](https://oods-foundry.com/registry/0.11.3/objects.json): the 11 business objects, as object show returns them. - [/registry/0.11.3/traits.json](https://oods-foundry.com/registry/0.11.3/traits.json): the 49 traits, as registry_snapshot with detail full returns them. - [/registry/0.11.3/components.json](https://oods-foundry.com/registry/0.11.3/components.json): the 114 components, as catalog_list returns them. - [/registry/0.11.3/tokens.json](https://oods-foundry.com/registry/0.11.3/tokens.json): every CSS variable by brand and theme, as @oods/tokens ships it. - The same files for the version this site is built from, without the version in the path, such as `/registry/tools.json`. - [/.well-known/mcp/server-card.json](https://oods-foundry.com/.well-known/mcp/server-card.json): the package's registry entry, which lists this site's Streamable HTTP endpoint. It's also at `/.well-known/mcp-server-card` and `/.well-known/mcp.json`, the paths earlier proposals named. --- Source: https://oods-foundry.com/start # Get started OODS Foundry, the object-oriented design system, runs on your machine as a local MCP server. Install it once, and your AI assistant can call it. ## What you need - Node.js 22.0.0 or newer, as the `node` your assistant starts. On an older Node it stops before it unpacks anything, with a sentence that says what it needs. - macOS or Linux. Windows is untested. - `npx` and `tar` on your PATH. - Claude Desktop, Claude Code or Cursor. - Nothing to sign up for. It needs no account or key. ## Install `npx -y @oods/foundry` Every client starts this same command and registers it as `oods-foundry`. On its first start it downloads the package and unpacks its runtime into `~/.oods-foundry`, so that start takes longer than the ones after it. Apache-2.0: free for any use, including at work. What it generates for you is yours. **Claude Code** ``` claude mcp add oods-foundry -- npx -y @oods/foundry claude mcp get oods-foundry ``` - **Check it worked:** the second command prints `Status: ✓ Connected`. - **Options** go after the name: `-s user` registers it for every project, and `-e MCP_TOOLSET=all` adds the on-demand tool, 27 tools in all. - **Remove it:** `claude mcp remove oods-foundry` **Claude Desktop** **Step 1:** Open `~/Library/Application Support/Claude/claude_desktop_config.json` (create it if it doesn't exist), add this under `mcpServers`, then restart Claude Desktop: ``` { "mcpServers": { "oods-foundry": { "command": "npx", "args": [ "-y", "@oods/foundry" ] } } } ``` **Check it worked:** the tools appear under the `oods-foundry` server. **If they don't:** the server's log says why: `~/Library/Logs/Claude/mcp-server-oods-foundry.log`. If it says `spawn npx ENOENT`, which can happen when Node comes from a version manager, put the full path of `npx` (what `which npx` prints) in `command`, and add an `env` block whose `PATH` includes the folder `node` is in. **Cursor** **Step 1:** Add this to `.cursor/mcp.json` in your project, or `~/.cursor/mcp.json` for every project, then reload the window: ``` { "mcpServers": { "oods-foundry": { "type": "stdio", "command": "npx", "args": [ "-y", "@oods/foundry" ] } } } ``` **Check it worked:** the server shows up in Cursor's MCP settings with its tools. ## Or install the Claude Code plugin The plugin bundles the server with the `oods-foundry` skill, which walks your assistant through the calls and tells it to report what wasn't checked. ``` claude plugin marketplace add https://github.com/kneelinghorse/oods-foundry-claude-plugin.git claude plugin install oods-foundry@oods-foundry ``` In Claude Code the skill is `/oods-foundry:oods-foundry`. **Updating:** the plugin runs an exact version of the server and moves when its repository does. Update it with `claude plugin marketplace update oods-foundry`, then `claude plugin update oods-foundry@oods-foundry`. ## In the MCP Registry OODS Foundry is listed in the official MCP Registry as `com.oods-foundry/foundry`. ## Your first prompt Each reply shown here is the real one, recorded by this site from the published OODS Foundry 0.11.3. `Use oods-foundry to compose the Subscription detail screen and preview it.` **What comes back:** OODS Foundry composes the screen by rule and names the component it chose for each slot, and why. The preview answers with a link to the screen running in React and another in Vue, with the Subscription's sample records, on your machine. Open one in your browser. What `design_compose` answered for Subscription detail: ``` { "status": "ok", "layout": "detail", "schema": { "version": "2026.02", "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": "plan_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": "subscription" } }, { "id": "screen-detail-13-record-summary-2", "component": "BillingSummaryBadge", "props": { "amountField": "amount", "currencyField": "currency", "intervalField": "billing_interval", "minorUnitsParameter": "minorUnits", "minorUnits": 100 } } ] }, { "id": "slot-header-2", "component": "Stack", "meta": { "intent": "slot:header", "label": "header" }, "children": [ { "id": "ve-header-26", "component": "VizMarkPreview", "props": { "title": "Payment amounts", "description": "Payments recorded for this subscription, in its currency." }, "chart": { "chartType": "bar", "source": "payment-events", "dateFields": [ "last_payment_at", "next_payment_due_at" ], "amountField": "amount", "minorUnits": 100, "currencyField": "currency" } }, { "id": "ve-header-27", "component": "StatusTimeline", "props": { "field": "status", "historyField": "state_history", "statesParameter": "states", "showActorId": true, "showReason": true } }, { "id": "ve-header-28", "component": "CancellationSummary", "props": { "hideWhenDefault": true, "cancelAtPeriodEndField": "cancel_at_period_end", "reasonField": "cancellation_reason", "codeField": "cancellation_reason_code", "requestedAtField": "cancellation_requested_at" } }, { "id": "ve-header-29", "component": "ArchiveSummary", "props": { "hideWhenDefault": true, "archivedField": "is_archived", "archivedAtField": "archived_at", "restoredAtField": "restored_at", "reasonField": "archive_reason", "archivedByField": "archived_by", "metadataField": "archive_metadata", "retainHistoryParameter": "retainHistory", "restoreWindowParameter": "restoreWindowDays", "allowPartialRestoreParameter": "allowPartialRestore" } } ], "layout": { "type": "stack", "gapToken": "cluster-default" } } ] }, { "id": "detail-body-10", "component": "Card", "layout": { "type": "stack", "gapToken": "cluster-default" }, "children": [ { "id": "detail-tabs-9", "component": "Tabs", "children": [ { "id": "detail-tab-panel-3", "component": "Stack", "layout": { "type": "stack", "gapToken": "cluster-default" }, "props": { "label": "Billing" }, "children": [ { "id": "slot-tab-0-4", "component": "CycleProgressCard", "meta": { "intent": "slot:tab-0", "label": "tab-0" }, "props": { "progressField": "current_period_progress", "periodStartField": "current_period_start", "periodEndField": "current_period_end", "intervalField": "billing_interval" } }, { "id": "slot-tab-1-6", "component": "PaymentTimeline", "meta": { "intent": "slot:tab-1", "label": "tab-1" }, "props": { "lastPaymentField": "last_payment_at", "nextPaymentField": "next_payment_due_at", "paymentStatusField": "payment_status", "paymentMethodField": "payment_method_type", "amountField": "amount", "currencyField": "currency" } } ] }, { "id": "detail-tabs-9-read-fields", "component": "Stack", "props": { "label": "Details" }, "children": [ { "id": "detail-tabs-9-subscription_id-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-subscription_id-label", "component": "Text", "props": { "as": "strong", "content": "Subscription" } }, { "id": "detail-tabs-9-subscription_id-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "subscription_id" } } ] }, { "id": "detail-tabs-9-plan_code-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-plan_code-label", "component": "Text", "props": { "as": "strong", "content": "Plan code" } }, { "id": "detail-tabs-9-plan_code-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "plan_code" } } ] }, { "id": "detail-tabs-9-plan_interval-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-plan_interval-label", "component": "Text", "props": { "as": "strong", "content": "Plan interval" } }, { "id": "detail-tabs-9-plan_interval-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "plan_interval" } } ] }, { "id": "detail-tabs-9-customer_name-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-customer_name-label", "component": "Text", "props": { "as": "strong", "content": "Customer name" } }, { "id": "detail-tabs-9-customer_name-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "customer_name" } } ] }, { "id": "detail-tabs-9-customer_email-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-customer_email-label", "component": "Text", "props": { "as": "strong", "content": "Customer email" } }, { "id": "detail-tabs-9-customer_email-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "customer_email" } } ] }, { "id": "detail-tabs-9-created_at-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-created_at-label", "component": "Text", "props": { "as": "strong", "content": "Created at" } }, { "id": "detail-tabs-9-created_at-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "created_at" } } ] }, { "id": "detail-tabs-9-updated_at-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-updated_at-label", "component": "Text", "props": { "as": "strong", "content": "Updated at" } }, { "id": "detail-tabs-9-updated_at-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "updated_at" } } ] }, { "id": "detail-tabs-9-last_event-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-last_event-label", "component": "Text", "props": { "as": "strong", "content": "Last event" } }, { "id": "detail-tabs-9-last_event-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "last_event" } } ] }, { "id": "detail-tabs-9-last_event_at-read-field", "component": "Stack", "children": [ { "id": "detail-tabs-9-last_event_at-label", "component": "Text", "props": { "as": "strong", "content": "Last event at" } }, { "id": "detail-tabs-9-last_event_at-value", "meta": { "intent": "read-only-field" }, "component": "Text", "props": { "field": "last_event_at" } } ] } ] } ], "props": { "ariaLabel": "Record details" } } ] } ], "bindings": { "onEdit": "handleEdit", "onDelete": "handleDelete", "onCancel": "handleCancel", "onViewTimeline": "handleViewTimeline" }, "meta": { "label": "Subscription" } } ], "objectSchema": { "status": { "type": "string", "required": true, "default": "future", "description": "Current lifecycle status of the subscription.", "enum": [ "future", "trialing", "active", "paused", "pending_cancellation", "past_due", "unpaid", "terminated" ], "semanticType": "billing.subscription.status", "examples": [ "active", "paused", "active", "trialing", "past_due", "active", "terminated", "pending_cancellation" ] }, "state_history": { "type": "StateTransition[]", "required": false, "default": [], "description": "Chronological log of state transitions. Each entry records the before/after states,\ntimestamp, and (when governance is enabled) the actor, reason, and transition metadata.\nRendered by StatusTimeline in the detail and timeline views.\n\nEntry structure:\n - from: string (previous state)\n - to: string (new state)\n - timestamp: ISO 8601 datetime\n - actor_id: string (user/system who triggered the transition, optional)\n - reason: string (human-readable justification, required when requireTransitionReason is true)\n - transition_metadata: Record (arbitrary context, optional)\n", "semanticType": "timeline.state_transition", "examples": [ [ { "title": "Trial started", "from": "future", "to": "trialing", "at": "2026-02-16T15:00:00Z", "reason": "Started a 14-day Team trial" }, { "title": "Trial converted", "from": "trialing", "to": "active", "at": "2026-03-02T15:00:00Z", "reason": "First Team payment collected" } ], [ { "title": "Started", "from": "future", "to": "active", "at": "2026-04-10T15:00:00Z", "reason": "Analytics add-on purchased" }, { "title": "Paused", "from": "active", "to": "paused", "at": "2026-08-20T14:00:00Z", "reason": "Paused during the ERP migration" } ], [ { "title": "Started", "from": "future", "to": "active", "at": "2026-01-15T08:00:00Z", "reason": "Subscribed to the Starter plan" }, { "title": "Payment failed", "from": "active", "to": "past_due", "at": "2026-05-15T08:00:00Z", "reason": "Card expired; retrying" }, { "title": "Recovered", "from": "past_due", "to": "active", "at": "2026-05-17T08:00:00Z", "reason": "New card charged" } ], [ { "title": "Scheduled", "from": null, "to": "future", "at": "2026-09-19T10:00:00Z", "reason": "Trial starts once a card is verified" }, { "title": "Trial started", "from": "future", "to": "trialing", "at": "2026-09-21T09:00:00Z", "reason": "Card verified; 14-day trial started" } ], [ { "title": "Trial started", "from": "future", "to": "trialing", "at": "2026-01-20T10:30:00Z", "reason": "Started a 14-day Team trial" }, { "title": "Trial converted", "from": "trialing", "to": "active", "at": "2026-02-03T10:00:00Z", "reason": "First payment collected" }, { "title": "Payment failed", "from": "active", "to": "past_due", "at": "2026-09-03T10:00:00Z", "reason": "Card declined; retrying" } ], [ { "title": "Started", "from": "future", "to": "active", "at": "2024-10-30T14:00:00Z", "reason": "Annual Enterprise agreement signed" }, { "title": "Invoice overdue", "from": "active", "to": "past_due", "at": "2025-11-14T14:00:00Z", "reason": "Renewal invoice unpaid after 15 days" }, { "title": "Recovered", "from": "past_due", "to": "active", "at": "2025-11-20T02:00:00Z", "reason": "Paid by bank transfer" } ], [ { "title": "Started", "from": "future", "to": "active", "at": "2026-01-09T10:15:00Z", "reason": "Subscribed to the Starter plan" }, { "title": "Cancellation requested", "from": "active", "to": "pending_cancellation", "at": "2026-06-20T09:00:00Z", "reason": "Closing the studio in July" }, { "title": "Ended", "from": "pending_cancellation", "to": "terminated", "at": "2026-07-09T10:15:00Z", "reason": "Cancelled at the end of the billing period" } ], [ { "title": "Trial started", "from": "future", "to": "trialing", "at": "2026-04-23T12:30:00Z", "reason": "Started a 14-day Business trial" }, { "title": "Trial converted", "from": "trialing", "to": "active", "at": "2026-05-07T12:00:00Z", "reason": "First payment collected" }, { "title": "Cancellation requested", "from": "active", "to": "pending_cancellation", "at": "2026-09-21T16:40:00Z", "reason": "Moving to an annual contract elsewhere" } ] ] }, "allowed_transitions": { "type": "string[]", "required": false, "default": [], "description": "Materialized list of valid next states from the current status, computed from the\ntransitionRules parameter. When transitionRules is null (open model), this contains\nall states except the current one. Used by StatusSelector to disable invalid options\nand by StatusBadge to indicate available paths.\n", "semanticType": "status.navigation" }, "cancel_at_period_end": { "type": "boolean", "required": true, "description": "Whether the subscription will cancel at the natural billing period end.", "semanticType": "billing.subscription.cancel_at_period_end", "examples": [ false, false, false, false, false, false, true, true ] }, "cancellation_reason": { "type": "string", "required": false, "description": "Free-form explanation captured during cancellation workflows.", "semanticType": "billing.subscription.cancellation_reason", "examples": [ null, null, null, null, null, null, "Closing the studio in July", "Moving to an annual contract elsewhere" ] }, "cancellation_reason_code": { "type": "string", "required": false, "description": "Structured reason code chosen from the allowedReasons parameter.", "semanticType": "status.cancel.reason_code" }, "cancellation_requested_at": { "type": "datetime", "required": false, "description": "Timestamp when cancellation was initiated.", "semanticType": "billing.subscription.cancellation_requested_at", "examples": [ null, null, null, null, null, null, "2026-06-20T09:00:00Z", "2026-09-21T16:40:00Z" ] }, "created_at": { "type": "datetime", "required": true, "description": "Timestamp recording when the entity was first created.", "semanticType": "audit.created_at", "examples": [ "2026-02-16T15:00:00Z", "2026-04-10T15:00:00Z", "2026-01-15T08:00:00Z", "2026-09-19T10:00:00Z", "2026-01-20T10:30:00Z", "2024-10-30T14:00:00Z", "2026-01-09T10:15:00Z", "2026-04-23T12:30:00Z" ] }, "updated_at": { "type": "datetime", "required": false, "description": "Timestamp for the most recent modification, when available.", "semanticType": "audit.updated_at", "examples": [ "2026-09-02T15:00:00Z", "2026-09-10T15:00:00Z", "2026-09-15T08:00:00Z", "2026-09-21T09:00:00Z", "2026-09-03T10:00:00Z", "2025-11-20T02:00:00Z", "2026-07-09T10:15:00Z", "2026-09-21T16:40:00Z" ] }, "last_event": { "type": "string", "required": true, "description": "Lifecycle event associated with the most recent timestamp mutation.", "enum": [ "billing_cycle_started", "billing_cycle_completed", "payment_received", "cancellation_requested" ], "semanticType": "audit.event.type", "examples": [ "payment_received", "billing_cycle_completed", "payment_received", "billing_cycle_started", "billing_cycle_started", "payment_received", "billing_cycle_completed", "cancellation_requested" ] }, "last_event_at": { "type": "datetime", "required": false, "description": "Timestamp for the lifecycle event captured in last_event.", "semanticType": "audit.event.timestamp", "examples": [ "2026-09-02T15:00:00Z", "2026-09-10T15:00:00Z", "2026-09-15T08:00:00Z", "2026-09-21T09:00:00Z", "2026-09-03T10:00:00Z", "2025-11-20T02:00:00Z", "2026-07-09T10:15:00Z", "2026-09-21T16:40:00Z" ] }, "amount": { "type": "integer", "required": true, "description": "Recurring price expressed in minor units (e.g., cents).", "semanticType": "billing.plan.amount", "money": { "currencyField": "currency", "minorUnits": 100 }, "examples": [ 14900, 3900, 1900, 4900, 4900, 1200000, 1900, 14900 ] }, "currency": { "type": "string", "required": true, "description": "ISO 4217 currency code used for billing.", "semanticType": "billing.plan.currency", "examples": [ "USD", "USD", "EUR", "USD", "GBP", "USD", "USD", "USD" ] }, "billing_interval": { "type": "string", "required": false, "description": "Recurrence cadence (monthly, yearly, quarterly, etc.).", "semanticType": "billing.subscription.interval", "examples": [ "monthly", "monthly", "monthly", "monthly", "monthly", "yearly", "monthly", "monthly" ] }, "payment_status": { "type": "string", "required": false, "default": "pending", "description": "Outcome of the most recent collection attempt. Distinct from subscription\nlifecycle status — a subscription can be \"active\" with payment_status \"retrying\".\n", "enum": [ "pending", "succeeded", "failed", "retrying", "refunded" ], "semanticType": "billing.cycle.payment_status", "examples": [ "succeeded", "succeeded", "succeeded", "pending", "retrying", "succeeded", "succeeded", "succeeded" ] }, "payment_method_type": { "type": "string", "required": false, "description": "Payment instrument category used for collection.", "enum": [ "card", "ach", "wire", "invoice", "other" ], "semanticType": "billing.cycle.payment_method", "examples": [ "card", "card", "card", "card", "card", "wire", "card", "card" ] }, "proration_amount": { "type": "integer", "required": false, "default": 0, "description": "Prorated credit or charge in minor currency units generated by a mid-cycle\nplan change. Positive values are charges; negative values are credits.\nOnly populated when the supportProration parameter is true.\n", "semanticType": "billing.cycle.proration", "money": { "currencyField": "currency", "minorUnits": 100 }, "examples": [ 5333, 0, 0, 0, 0, 0, 0, 0 ] }, "proration_date": { "type": "integer", "required": false, "description": "Unix timestamp (epoch SECONDS) at which proration is calculated. Pinned when an\nupcoming-invoice PREVIEW is requested and MUST be passed identically on commit so the\ncommitted charge equals the previewed amount. The preview is read-only and does NOT\nmutate the subscription. Stored as an integer (not a datetime) so the value round-trips\nbyte-identically between preview and commit — an ISO string normalization could shift it\nand desync the previewed vs charged amount. Only populated when supportProration is true.\nSource: docs.stripe.com/billing/subscriptions/prorations.\n", "semanticType": "billing.cycle.proration_timestamp" }, "last_payment_at": { "type": "datetime", "required": false, "description": "Timestamp of the most recent successful payment.", "semanticType": "billing.subscription.last_payment_at", "examples": [ "2026-09-02T15:00:00Z", "2026-08-10T15:00:00Z", "2026-09-15T08:00:00Z", null, "2026-08-03T10:00:00Z", "2025-11-20T02:00:00Z", "2026-06-09T10:15:00Z", "2026-09-07T12:00:00Z" ] }, "next_payment_due_at": { "type": "datetime", "required": false, "description": "Timestamp when the next payment attempt should occur.", "semanticType": "billing.subscription.next_payment_due_at", "examples": [ "2026-10-02T15:00:00Z", null, "2026-10-15T08:00:00Z", "2026-10-05T09:00:00Z", "2026-10-01T10:00:00Z", "2026-10-30T14:00:00Z", null, null ] }, "current_period_start": { "type": "datetime", "required": true, "description": "Start timestamp of the current billing cycle.", "semanticType": "billing.subscription.current_period_start", "examples": [ "2026-09-02T15:00:00Z", "2026-08-10T15:00:00Z", "2026-09-15T08:00:00Z", "2026-09-21T09:00:00Z", "2026-09-03T10:00:00Z", "2025-10-30T14:00:00Z", "2026-06-09T10:15:00Z", "2026-09-07T12:00:00Z" ] }, "current_period_end": { "type": "datetime", "required": true, "description": "End timestamp of the current billing cycle.", "semanticType": "billing.subscription.current_period_end", "examples": [ "2026-10-02T15:00:00Z", "2026-09-10T15:00:00Z", "2026-10-15T08:00:00Z", "2026-10-05T09:00:00Z", "2026-10-03T10:00:00Z", "2026-10-30T14:00:00Z", "2026-07-09T10:15:00Z", "2026-10-07T12:00:00Z" ] }, "current_period_progress": { "type": "number", "required": false, "description": "Decimal progress (0-1) through the active billing cycle.", "semanticType": "billing.subscription.current_period_progress", "examples": [ 0.93, 1, 0.5, 0.64, 0.9, 0.92, 1, 0.77 ] }, "is_archived": { "type": "boolean", "required": true, "default": false, "description": "Flag indicating whether the entity is currently archived (soft-deleted).", "semanticType": "status.archive.state" }, "archived_at": { "type": "datetime?", "required": false, "description": "Timestamp for when the entity entered the archived state.", "semanticType": "status.archive.timestamp" }, "restored_at": { "type": "datetime?", "required": false, "description": "Timestamp for when the entity was most recently restored from an archived state.", "semanticType": "status.archive.restore_timestamp" }, "archive_reason": { "type": "string", "required": false, "description": "Human-readable narrative describing why the entity was archived.", "semanticType": "status.archive.reason" }, "archived_by": { "type": "string", "required": false, "description": "User ID or system identifier of the actor who archived this entity.\nSet to \"system\" for automated/policy-driven archival. Supports audit trail queries\nlike \"show all entities archived by user X\" or \"show all auto-archived entities\".\n", "semanticType": "status.archive.actor" }, "archive_metadata": { "type": "object", "required": false, "description": "Structured metadata about the archival action for compliance and audit purposes.\n\nProperties:\n - method: \"manual\" | \"automated\" | \"policy\" — how the archive was triggered\n - compliance_tags: string[] — regulatory labels (e.g., [\"GDPR\", \"SOX\", \"HIPAA\"])\n - retention_policy_id: string — reference to the retention policy that triggered archival\n - original_status: string — the Stateful status before archival\n - related_entity_count: number — count of related entities also archived (cascade)\n", "semanticType": "status.archive.compliance" }, "restoration_metadata": { "type": "object", "required": false, "description": "Metadata about the most recent restoration action.\n\nProperties:\n - restored_by: string — user ID or \"system\"\n - restored_fields: string[] — when partial restore, which fields were restored\n - restoration_reason: string — why the entity was restored\n - restored_from_snapshot: boolean — whether restored from a point-in-time snapshot\n", "semanticType": "status.archive.restoration" }, "subscription_id": { "type": "string", "required": true, "description": "Primary identifier used across billing and lifecycle systems.", "semanticType": "billing.subscription.id", "examples": [ "sub_northwind_business", "sub_northwind_analytics", "sub_lindqvist_starter", "sub_blueharbor_team", "sub_kestrel_team", "sub_tidewater_enterprise", "sub_marlow_starter", "sub_summit_business" ] }, "plan_name": { "type": "string", "required": true, "description": "Human-readable plan label shown in headers.", "semanticType": "billing.plan.name", "examples": [ "Business", "Analytics add-on", "Starter", "Team", "Team", "Enterprise", "Starter", "Business" ] }, "plan_code": { "type": "string", "required": false, "description": "Internal plan code or price identifier.", "semanticType": "billing.plan.code", "examples": [ "business-monthly", "analytics-addon-monthly", "starter-monthly", "team-monthly", "team-monthly", "enterprise-annual", "starter-monthly", "business-monthly" ], "displayLabel": "Plan code", "referenceLabels": { "plan_starter_monthly": "plan_starter_monthly", "plan_team_monthly": "plan_team_monthly", "plan_business_monthly": "plan_business_monthly", "plan_team_annual": "plan_team_annual", "plan_enterprise_annual": "plan_enterprise_annual", "plan_analytics_addon_monthly": "plan_analytics_addon_monthly", "plan_pro_monthly_2025": "plan_pro_monthly_2025", "plan_business_plus_monthly": "plan_business_plus_monthly" } }, "plan_interval": { "type": "string", "required": false, "description": "Billing interval descriptor (monthly, yearly, etc.).", "semanticType": "billing.plan.interval", "examples": [ "monthly", "monthly", "monthly", "monthly", "monthly", "yearly", "monthly", "monthly" ] }, "customer_name": { "type": "string", "required": false, "description": "Customer or account name associated with the subscription.", "semanticType": "text.summary", "examples": [ "Northwind Traders", "Northwind Traders", "Lindqvist Bakery", "Blue Harbor Studio", "Kestrel Print Co.", "Tidewater Co-op", "Marlow Yoga", "Summit Outfitters" ] }, "customer_email": { "type": "email", "required": false, "description": "Billing contact email address.", "semanticType": "customer.account.email", "examples": [ "billing@northwind.example", "billing@northwind.example", "finance@lindqvist.example", "accounts@blueharbor.example", "hello@kestrelprint.example", "treasurer@tidewater.example", "studio@marlowyoga.example", "ap@summit.example" ] }, "payment_history": { "type": "PaymentRecord[]", "required": false, "description": "Recorded payments, oldest first, each with its time and amount in minor units. Drawn by the payment chart.", "examples": [ [ { "at": "2026-03-02T15:00:00Z", "amount": 4900 }, { "at": "2026-04-02T15:00:00Z", "amount": 4900 }, { "at": "2026-05-02T15:00:00Z", "amount": 4900 }, { "at": "2026-06-02T15:00:00Z", "amount": 4900 }, { "at": "2026-06-16T15:00:00Z", "amount": 5333 }, { "at": "2026-07-02T15:00:00Z", "amount": 14900 }, { "at": "2026-08-02T15:00:00Z", "amount": 14900 }, { "at": "2026-09-02T15:00:00Z", "amount": 14900 } ], [ { "at": "2026-04-10T15:00:00Z", "amount": 3900 }, { "at": "2026-05-10T15:00:00Z", "amount": 3900 }, { "at": "2026-06-10T15:00:00Z", "amount": 3900 }, { "at": "2026-07-10T15:00:00Z", "amount": 3900 }, { "at": "2026-08-10T15:00:00Z", "amount": 3900 } ], [ { "at": "2026-01-15T08:00:00Z", "amount": 1900 }, { "at": "2026-02-15T08:00:00Z", "amount": 1900 }, { "at": "2026-03-15T08:00:00Z", "amount": 1900 }, { "at": "2026-04-15T08:00:00Z", "amount": 1900 }, { "at": "2026-05-17T08:00:00Z", "amount": 1900 }, { "at": "2026-06-15T08:00:00Z", "amount": 1900 }, { "at": "2026-07-15T08:00:00Z", "amount": 1900 }, { "at": "2026-08-15T08:00:00Z", "amount": 1900 }, { "at": "2026-08-16T08:00:00Z", "amount": 1900 }, { "at": "2026-08-19T11:30:00Z", "amount": -1900 }, { "at": "2026-09-15T08:00:00Z", "amount": 1900 } ], [], [ { "at": "2026-02-03T10:00:00Z", "amount": 4900 }, { "at": "2026-03-03T10:00:00Z", "amount": 4900 }, { "at": "2026-04-03T10:00:00Z", "amount": 4900 }, { "at": "2026-05-03T10:00:00Z", "amount": 4900 }, { "at": "2026-06-03T10:00:00Z", "amount": 4900 }, { "at": "2026-07-03T10:00:00Z", "amount": 4900 }, { "at": "2026-08-03T10:00:00Z", "amount": 4900 } ], [ { "at": "2024-10-30T14:00:00Z", "amount": 1200000 }, { "at": "2025-11-20T02:00:00Z", "amount": 1200000 } ], [ { "at": "2026-01-09T10:15:00Z", "amount": 1900 }, { "at": "2026-02-09T10:15:00Z", "amount": 1900 }, { "at": "2026-03-09T10:15:00Z", "amount": 1900 }, { "at": "2026-04-09T10:15:00Z", "amount": 1900 }, { "at": "2026-05-09T10:15:00Z", "amount": 1900 }, { "at": "2026-06-09T10:15:00Z", "amount": 1900 } ], [ { "at": "2026-05-07T12:00:00Z", "amount": 14900 }, { "at": "2026-06-07T12:00:00Z", "amount": 14900 }, { "at": "2026-07-07T12:00:00Z", "amount": 14900 }, { "at": "2026-08-07T12:00:00Z", "amount": 14900 }, { "at": "2026-09-07T12:00:00Z", "amount": 14900 } ] ] } } }, "schemaRef": "compose-779f5455", "schemaRefCreatedAt": "2026-11-02T05:29:53.587Z", "schemaRefExpiresAt": "2026-11-02T05:59:53.587Z", "compositionId": "cmp-0cb678c9e88d", "version": 1, "parentVersion": null, "operation": "compose", "head": "e2bb227041596b62187099b4d174b238cdfe0e6f", "selections": [ { "slotName": "tab-0", "intent": "data-display", "selectedComponent": "CycleProgressCard", "explanation": "CycleProgressCard leads slot \"tab-0\" because view_extension placement.", "candidates": [ { "name": "CycleProgressCard", "reason": "view_extension placement" } ], "placedComponents": [ "CycleProgressCard" ] }, { "slotName": "tab-1", "intent": "status-indicator", "selectedComponent": "PaymentTimeline", "explanation": "PaymentTimeline leads slot \"tab-1\" because view_extension placement.", "candidates": [ { "name": "PaymentTimeline", "reason": "view_extension placement" } ], "placedComponents": [ "PaymentTimeline" ] }, { "slotName": "header", "intent": "page-header", "selectedComponent": "DetailHeader", "explanation": "DetailHeader leads slot \"header\" because record title placed by the layout from the object's label field. The slot also renders VizMarkPreview, StatusTimeline, CancellationSummary, ArchiveSummary after it, in that order.", "candidates": [ { "name": "DetailHeader", "reason": "record title placed by the layout from the object's label field" }, { "name": "VizMarkPreview", "reason": "view_extension placement" } ], "placedComponents": [ "DetailHeader", "VizMarkPreview", "StatusTimeline", "CancellationSummary", "ArchiveSummary" ] } ], "validation": { "status": "ok", "errors": [], "warnings": [] }, "warnings": [ { "code": "OODS-V121", "message": "Object 'Subscription' has maturity 'beta' — composed output may change.", "hint": "Consider using stable objects for production compositions." }, { "code": "OODS-V117", "message": "Subscription refines 11 fields its traits define, and its own definitions are used: lifecycle/Stateful (status); lifecycle/Cancellable (cancel_at_period_end, cancellation_reason, cancellation_requested_at); financial/Billable (amount, currency, billing_interval, current_period_start, current_period_end, current_period_progress, next_payment_due_at)." } ], "objectUsed": { "name": "Subscription", "version": "2.0.0", "traits": [ "lifecycle/Stateful", "lifecycle/Cancellable", "lifecycle/Timestampable", "financial/Billable", "lifecycle/Archivable", "viz/MarkBar" ], "fieldsComposed": 37, "viewExtensionsApplied": { "list": 4, "detail": 7, "form": 4, "card": 4, "timeline": 1, "dashboard": 1 } }, "meta": { "intentParsed": "Subscription detail view", "layoutDetected": "context-inferred: detail (from context=\"detail\")", "slotCount": 3, "nodeCount": 44, "intentSynthetic": true, "warnings": [ "Object 'Subscription' has maturity 'beta' — composed output may change.", "Subscription refines 11 fields its traits define, and its own definitions are used: lifecycle/Stateful (status); lifecycle/Cancellable (cancel_at_period_end, cancellation_reason, cancellation_requested_at); financial/Billable (amount, currency, billing_interval, current_period_start, current_period_end, current_period_progress, next_payment_due_at)." ], "intelligence": { "fieldsExpanded": true, "slotsExpanded": 5, "expansionReason": "Expanded from 3 to 8 tabs for 37 fields", "patternGroups": [ { "slotName": "tab-0", "patternId": "status-timeline", "compositeComponent": "StatusTimeline", "matchedFields": [ "status", "updated_at" ], "confidence": 1 } ], "fieldAffinityUsed": true } } } ``` Then, to see what it knows: `Use oods-foundry to check its health.` **What comes back:** a status of ok, the version, and how many objects, traits and components it knows. The object count includes internal objects that its listings leave out. Each measurement it keeps names the version it was measured on. What `health_check` answered: ``` { "status": "ok", "server": { "version": "0.11.3", "uptime": 796 }, "registry": { "components": 114, "traits": 49, "objects": 16, "lastSync": "2026-10-10T03:40:00Z", "countsFrom": { "components": "live", "objects": "live", "traits": "live" }, "definitions": { "folders": { "objects": "~/.oods-foundry/objects", "traits": "~/.oods-foundry/traits" }, "objects": { "total": 16, "shipped": 16, "user": 0, "replacingShipped": [] }, "traits": { "total": 49, "shipped": 49, "user": 0 }, "issues": [] } }, "tokens": { "built": true, "brands": [ "A", "B" ], "themes": [ "dark", "hc", "light" ], "scopes": { "A": [ "dark", "hc", "light" ], "B": [ "dark", "hc", "light" ] }, "defaultScope": { "brand": "A", "theme": "light", "source": "default" }, "registry": { "brands": [ "A", "B" ], "default": "A", "folder": "~/.oods-foundry/runtime/0.11.3-510074895fa1/packages/tokens/src/tokens/brands", "teamFolder": "~/.oods-foundry/brands", "issues": [] } }, "schemas": { "savedCount": 0, "storeDir": "~/.oods-foundry/schemas" }, "latency": 9, "productReality": { "runtime": { "cells": 200, "pass": 200, "typedGap": 0, "fail": 0, "head": "debfc52e74881829b2d79726262fe955dc96cb7f", "archiveSha256": "6ebf8a9caaaaed13b0b865bd7d101daa0e6cb273d7ecb9deeafc0753523fb19f", "thisBuild": false, "measuredOn": { "version": "0.4.1", "sourceHead": "debfc52e74881829b2d79726262fe955dc96cb7f", "archiveSha256": "6ebf8a9caaaaed13b0b865bd7d101daa0e6cb273d7ecb9deeafc0753523fb19f" } }, "release": { "bundleHead": "93c5224a48c1a2e87aed3dbd24c49d8a62009327", "archiveSha256": "cd1f7f71b52e7e5a33297bcec7e74aa186a8cc370558a2aa6f588ceb80117ad7", "apps": [ "Organization", "Subscription", "User" ], "frameworks": [ "react", "vue" ], "cells": 42, "pass": 42, "typedGap": 0, "fail": 0, "head": "93c5224a48c1a2e87aed3dbd24c49d8a62009327", "thisBuild": false, "measuredOn": { "version": "0.2.0", "sourceHead": "93c5224a48c1a2e87aed3dbd24c49d8a62009327", "archiveSha256": "cd1f7f71b52e7e5a33297bcec7e74aa186a8cc370558a2aa6f588ceb80117ad7" } }, "tools": { "entries": 27, "byTestImportLocation": { "test/product-reality": 26, "test/contracts": 1, "other-spec": 0, "none": 0 }, "head": "101fb413c804769aaab9430423d1cb34fbdcb65a", "sourceHead": "7c1127f35fd6577ce43ff79edd12231e48714e09", "portable": { "path": "build record (not shipped): e2e-npm-node24-b.json", "sha256": "sha256:9b741abecdea5dab91873d35a77155837bbcd9f6dff8ae57fc0f212e2c82dbca", "bundleHead": "101fb413c804769aaab9430423d1cb34fbdcb65a", "dirty": false, "tools": 26, "pass": 26, "typed": 0 }, "thisBuild": false, "measuredOn": { "version": "0.11.0", "sourceHead": "101fb413c804769aaab9430423d1cb34fbdcb65a", "archiveSha256": null } }, "html": { "head": null, "heads": [ "36a3220f18a6743c4c7a75216cd1cfcddcd9b157", "c49317088d7e83690d1de709b2e43d39debf5eb9" ], "cells": 300, "pass": 300, "fail": 0, "receipt": "packages/mcp-server/registry/html-cells.v1.json", "sha256": "sha256:b61105d596aa58dd488ce2e236013110ca6767cd3aa7d5b202cb6a9383ce4453", "thisBuild": false, "measuredOn": { "version": "0.2.1", "sourceHead": "36a3220f18a6743c4c7a75216cd1cfcddcd9b157", "archiveSha256": null } }, "fidelity": { "head": null, "heads": [ "4187360314532c2f8ba5ee150fdc163d99c3e43d" ], "cells": 18, "pass": 18, "fail": 0, "receipt": "build record (not shipped): fidelity-proof.json", "sha256": "sha256:f37ea21d51e3bc28dd0d90f2b0db7bb82e9f29d96d8922a7deb4b1f87486ffbe", "files": 138, "thisBuild": false, "measuredOn": { "version": "0.10.2", "sourceHead": "4187360314532c2f8ba5ee150fdc163d99c3e43d", "archiveSha256": null } }, "viz": { "types": 13, "patterns": 22, "retiredPatterns": 1, "families": 8, "classified": 36, "coreCells": 17, "coreSurfaceComplete": 17, "typedGaps": 0, "retiredCells": 3, "certifiedChartTypes": 13, "certifiedScopes": 78, "measuredOn": { "version": "0.11.1", "sourceHead": "5257da5427e6ecfe0d371199a989367d02722905", "archiveSha256": null } } }, "dslVersion": "1.0" } ``` ## Next - [Make your first change](https://oods-foundry.com/guides/quickstart): the quickstart edits a trait on its examples, then walks Harbor to a running app in your brand - [Bring your own objects](https://oods-foundry.com/guides/importing-objects): draft objects from a schema your team already has, and accept the ones you want - [See the quickstart's Harbor run, start to finish](https://oods-foundry.com/demos/harbor) - [Look around the system first](https://oods-foundry.com/system) - [For agents](https://oods-foundry.com/agents): every tool with its schemas, the rate limits, and this site's files for agents Report bugs in [GitHub Issues](https://github.com/kneelinghorse/OODS-Foundry/issues). For everything else: --- Source: https://oods-foundry.com/ [**0.11.3** · Apache-2.0 · for Claude Desktop, Claude Code and Cursor](https://oods-foundry.com/start) **One object. Every screen. On the record.** # Your product is made of objects. Your UI should be too. You've already defined them in your database, your API or your GraphQL schema. Bring in their schema files, keep what's right, and map the components you already own, [starting with shadcn/ui on Radix or Base UI](https://oods-foundry.com/shadcn). Your assistant builds their list, detail, form and timeline screens in React or Vue, in your brand. [Get started](https://oods-foundry.com/start) [See one change across screens](https://oods-foundry.com/demos/trait-change) Every app comes with a receipt: what was built, what was checked, and what wasn't. `npx -y @oods/foundry` Registered as `oods-foundry` · Node.js 22.0.0 or newer · macOS or Linux · Apache-2.0: free for any use, including at work. What it generates for you is yours. [Subscription detail screen generated by OODS Foundry in React](https://oods-foundry.com/objects/subscription/screens/detail-react) **Subscription** detail React `sha256:9967f5eaf7…` [Open](https://oods-foundry.com/objects/subscription) [Transaction list screen generated by OODS Foundry in Vue](https://oods-foundry.com/objects/transaction/screens/list-vue) **Transaction** list Vue `sha256:5e4d2ece96…` [Open](https://oods-foundry.com/objects/transaction) [Usage detail screen generated by OODS Foundry in React](https://oods-foundry.com/objects/usage/screens/detail-react) **Usage** detail React `sha256:40de422aa3…` [Open](https://oods-foundry.com/objects/usage) [User list screen generated by OODS Foundry in Vue](https://oods-foundry.com/objects/user/screens/list-vue) **User** list Vue `sha256:1595b2a3fc…` [Open](https://oods-foundry.com/objects/user) [Relationship detail screen generated by OODS Foundry in React](https://oods-foundry.com/objects/relationship/screens/detail-react) **Relationship** detail React `sha256:a5b2bdb3f5…` [Open](https://oods-foundry.com/objects/relationship) [Plan form screen generated by OODS Foundry in Vue](https://oods-foundry.com/objects/plan/screens/form-vue) **Plan** form Vue `sha256:4037ee0d62…` [Open](https://oods-foundry.com/objects/plan) [Invoice detail screen generated by OODS Foundry in React](https://oods-foundry.com/objects/invoice/screens/detail-react) **Invoice** detail React `sha256:96d7071513…` [Open](https://oods-foundry.com/objects/invoice) Every screen here runs live. OODS Foundry 0.11.3 generated each one from a shipped object and the sample records in its file, in this site's brand; the hash is the app's content hash as generated. Charts are drawn when a screen is generated, and they follow the theme you choose. Design systems settled into the same set of components, and that was the right bet while the industry was scaling. It's how we kept up. It's also why you can't tell one company's system from another's past the colours. What makes a product its own, the things it's made of and the rules they follow, lives everywhere except the system. OODS Foundry starts there. An object is a thing your product is made of, like a subscription. A trait is a capability objects share, like a lifecycle that runs from active to cancelled. A context is where the object shows up, like a detail page or a list. Put a rule on the trait once, and every screen that shows the object is built from it. Change the trait, and the screens it reaches change on the next build. Agents can build screens faster than a team can review them. Screens built from the objects can be checked against them, and the receipt says what was checked and what wasn't. It runs the same for one person with an assistant and for a design-system team with many products, and it works with the components and brand you already have. How it works ## From one object file to every screen ### Bring in the object An object is a thing your product is made of, like a Subscription or a Warehouse. Point OODS Foundry at a local schema file you already have, from Postgres, Prisma, dbt, OpenAPI, GraphQL or OData, and it drafts the objects and proposes the traits it found evidence for. Nothing is registered until you accept it. Each object is one YAML file you can read and edit, and a trait defined once reaches every object that has it. ``` object: name: Subscription version: 2.0.0 domain: core.billing description: Canonical subscription record composing lifecycle, billing, and cancellation semantics. tags: - billing - lifecycle - monetization traits: - name: lifecycle/Stateful alias: SubscriptionLifecycle parameters: ``` ### Pick a context OODS Foundry composes the object by rule for each context and generates a running React or Vue app. - [detail](https://oods-foundry.com/contexts/detail) - [list](https://oods-foundry.com/contexts/list) - [form](https://oods-foundry.com/contexts/form) - [timeline](https://oods-foundry.com/contexts/timeline) - [card](https://oods-foundry.com/contexts/card) - [inline](https://oods-foundry.com/contexts/inline) - [workflow](https://oods-foundry.com/contexts/workflow) The same call gives the same bytes, and every app comes back with its content hash and a receipt of the checks that ran and the ones that didn't. ### Describe it once. Every screen follows. Change a trait, rebuild, and the screens that edit reaches change, on every object that has the trait. One edit to the Stockable trait reaches the Warehouse and the cold room; the before and after, with their receipts and hashes, are in the demo. [See one change across screens](https://oods-foundry.com/demos/trait-change) [See a schema become a Membership workspace](https://oods-foundry.com/demos/membership) ## Try it on your own schema Point it at one local schema file your product already has. Keep the objects that are right, build their screens, and read the receipt. Install it, then follow the guide to importing objects. `npx -y @oods/foundry` [Read the importing guide](https://oods-foundry.com/guides/importing-objects) --- Source: https://oods-foundry.com/faq # FAQ Questions about OODS Foundry, the object-oriented design system, answered for version 0.11.3. ## What's a trait? A capability that several objects share, like being stocked, having a price or moving through states. You define it once, and every object that lists it gets its fields and what it adds to each screen. ## Will it use my design system? Yes: your objects and traits, written in short YAML files; your brand, made from a recipe or from your own colour values; and your own React or Vue components, mapped in place of the ones it ships. It keeps choosing components by rule, so a screen stays governed while it uses yours. ## Can I add my own components? You can replace any of the 114 components it ships with your own React or Vue component, and the generated code imports yours. Adding components beyond those 114 isn't part of 0.11.3. ## Isn't this another design-system MCP server? It is an MCP server, and most design systems ship one now. The difference is what it works from and what comes back. A design-system server usually gives your assistant documentation to follow. OODS Foundry works from your objects and hands back the generated app, with its receipt and its hash. ## Is there AI inside it? Will it make things up? There's no language model inside OODS Foundry. Your assistant is the AI, and it decides what to ask for. OODS Foundry builds by rule, so the same call gives the same bytes. The sample records on its shipped objects' screens come from their object files; it invents none of their values. An object it drafts from your schema gets illustrative sample values, including names, email addresses and record codes, where your schema gives no example. Some fields still use numbered labels. ## What does certification cover? Charts. Certify a chart and you get 4 results with their findings: accessibility equivalence, determinism, contrast and accuracy. A generated app comes with a receipt instead, and the preview records accessibility results from the running page. Each lists what it didn't check. ## Can I use it at work? What does it cost? Yes, and nothing. OODS Foundry is licensed under Apache-2.0: free for any use, including at work. What it generates for you is yours. ## Is it open source? Yes. OODS Foundry is open source under Apache-2.0. [The source repository](https://github.com/kneelinghorse/OODS-Foundry) mirrors each release, and the package is on npm. ## Which assistants and computers does it work with? Claude Desktop, Claude Code and Cursor. The package documents the setup for each, and [Get started](https://oods-foundry.com/start) gives it. It runs on macOS or Linux, with Node.js 22.0.0 or newer. Windows is untested. ## Is it ready for production? After 0.4.1 was published, the OODS Foundry team generated an app for every context each object supports, in React and Vue, from the published package, and every one installed, type-checked, built and mounted. It wasn't repeated for 0.11.3. A generated app labels its sample data and the actions you still need to wire up. Each object's page shows its maturity, and only User is marked stable. ## How do I know the demos are real? Every demo shows the calls and the package version that produced it. The package states the quickstart's hashes itself, in `quickstart/expected.json`. Run the same calls with @oods/foundry 0.11.3 and compare your content hash with the one on the page. ## How is this different from Claude Design? Claude Design is Anthropic's tool for designing with Claude. It turns a described visual into a first version on brand, which you refine and hand off, and it works with your own design system. OODS Foundry is a tool your assistant calls to build screens from your objects, by rule, and it hands you the list of what it checked. They do different jobs, and you can use both. ## Why "object-oriented"? OODS stands for object-oriented design system. A screen starts from the object it's about, like a Warehouse or a Quote, rather than from a pile of components. If you know Object-Oriented UX, the idea is familiar: start from the objects, not the screens. OODS Foundry builds the screens from them. ## Who makes it? OODS Foundry is an aquex.ai product. ## What 0.11.3 covers - Your components replace shipped ones. Adding components beyond the 114 isn't part of 0.11.3. - Objects compose in 7 fixed contexts: detail, list, form, timeline, card, inline and workflow. - Rules live inside one object, like which states it can move between. Rules that span objects aren't part of 0.11.3. - Certification covers charts. Apps get a receipt instead. - A brand comes from a recipe, from OODS Foundry's own slots filled by you, or from your team's DTCG token file, which keeps the names, aliases and modes it supports once you accept the draft. - It runs in Claude Desktop, Claude Code and Cursor on macOS and Linux. Windows is untested. - Each object's page shows its maturity, and only User is marked stable. - There's no Figma or canvas integration. --- Source: https://oods-foundry.com/license # License Apache-2.0: free for any use, including at work. What OODS Foundry generates for you is yours. ## Typefaces and colours OODS Foundry's typefaces, Geist, Geist Mono and DM Sans, ship with its design tokens under the SIL Open Font License 1.1, and its colour scales are calibrated on Radix Colors (MIT License). ## Notice The NOTICE opens with these lines: ``` OODS Foundry Copyright 2026 System Systems LLC (https://aquex.ai) ``` It goes on with the notices for the typefaces and for Radix Colors, each with its license text. [The NOTICE in the published package](https://cdn.jsdelivr.net/npm/@oods/foundry@0.11.3/NOTICE) ## Third-party packages The third-party packages inside keep their own licenses. The package lists them, with their license texts, in [THIRD-PARTY-NOTICES.md](https://cdn.jsdelivr.net/npm/@oods/foundry@0.11.3/THIRD-PARTY-NOTICES.md). ## The license text [The Apache-2.0 LICENSE in the published package](https://cdn.jsdelivr.net/npm/@oods/foundry@0.11.3/LICENSE) [The Apache-2.0 LICENSE in the public source repository](https://github.com/kneelinghorse/OODS-Foundry/blob/v0.11.3/LICENSE) --- Source: https://oods-foundry.com/privacy # Privacy What oods-foundry.com, its hosted MCP endpoint, `https://oods-foundry.com/mcp`, the npm package and the Claude Code plugin collect, keep and pass on. The site and hosted endpoint were checked on 2026-10-08; the package checks below were made separately. ## What the site collects You don't need an account for this site or its [hosted endpoint](https://oods-foundry.com/agents), and neither asks who you are. Requests to oods-foundry.com come through Cloudflare, which gives the site's server your IP address. The server reads it only on the chart route and the hosted endpoint, to count your requests. The server also receives what you send it: - in the [chart playground](https://oods-foundry.com/charts/playground), the chart you make, which it draws; - on the hosted endpoint, the tool calls your assistant makes and their arguments, which it answers. Nothing else you type or choose in the site's controls leaves your browser. Cloudflare's Web Analytics script, which Cloudflare adds to the site's pages, reports each page you open to Cloudflare. ## How it is used and kept The server counts each visitor's recent requests in its memory, under the visitor's IP address, so that no one visitor can use up everyone's share of the chart route and the hosted endpoint. For an IPv6 address it keeps only the network part, not the part that names your device. Calls from claude.ai's connectors come from Anthropic's addresses, not yours, and the server counts them all as one visitor. The server keeps the charts it draws and the hosted endpoint's replies in memory, each under the request that asked for it, not under who sent it, so the same request gets the same reply without being worked out again. A kept chart includes the rows that were sent. OODS Foundry, which draws the charts on the server, keeps its own copy of each chart in memory too. The server's own log records when it starts, when OODS Foundry starts or stops, and the error when a call fails unexpectedly. It does not record requests. If you choose a theme, your browser keeps the choice in its local storage as `oods-site-theme`, and the site reads it there to show that theme. Neither the site nor Cloudflare's script sets a cookie or stores anything else in your browser. ## Who else receives it The site's pages load everything from this site, except Cloudflare's Web Analytics script, which comes from Cloudflare. ### Cloudflare Cloudflare carries every request and reply between your browser and the site's server at oods-foundry.com, and adds its Web Analytics script to every page your browser asks for. For each page you open, the script reports to Cloudflare when you opened it, the page's address, the page you came from, whether you followed a link, went back or reloaded, your browser's engine and version, your operating system's version, how quickly the page loaded and drew, and how much memory it used. It reports each page load under an id of its own. Its reports go to Cloudflare at `oods-foundry.com/cdn-cgi/rum` and don't reach the site's server. [Cloudflare's privacy policy](https://www.cloudflare.com/privacypolicy/) says what Cloudflare does with what it receives. ### Railway Railway runs the site's server. For every request that reaches it, Railway logs when it came, its method, host and path without the query, the reply's status, size and timing, your IP address, your browser's user agent and which of Railway's edge locations handled it. [Railway's privacy policy](https://railway.com/legal/privacy) says what Railway does with what it receives. ### No one else The site's server passes on nothing it receives. OODS Foundry runs on the same server, and Railway's network logs show the server opening no connection of its own. ## How long it is kept - What the server keeps in memory is gone, at the latest, when the server restarts, as it does at every deploy. None of it is written to disk. - Railway keeps its logs for 30 days, the period [its documentation](https://docs.railway.com/observability/logs#log-retention) gives for the plan this site is on. - Your theme choice stays in your browser until you clear its storage for this site. - Cloudflare keeps its reports as its privacy policy describes. ## The npm package and Claude Code plugin We checked OODS Foundry 0.11.3 using the command in Claude Code plugin v0.11.3 on 2026-11-02, from a fresh home and empty npm cache. The plugin starts the pinned `@oods/foundry` package through `npx`, with tool calls and replies on standard input and output. Starting with an empty cache, npm downloaded that version from its registry and also made package metadata, version and security advisory requests. The saved composition and its preview data stayed under `~/.oods-foundry/compositions` after the server stopped; the unpacked runtime stayed under `~/.oods-foundry/runtime`. npm also kept its cache and logs under `~/.npm`, and Node wrote a compile cache in the system's temporary directory. The generated React preview used a server listening on `127.0.0.1`. The traffic capture covered first start plus health, component, object, chart, composition and preview calls with default settings. Apart from npm's registry requests, it found only traffic to the same machine. Trace export was off when `OODS_OTLP_ENDPOINT` was absent or blank. Setting it sent tool names, timings and request identifiers to that address. These measurements cover the package process, not the assistant's own data handling or every tool and configuration. ## Contact Questions about this page, or about what the site keeps, go to . --- Source: https://oods-foundry.com/terms # Terms These terms cover oods-foundry.com and its hosted MCP endpoint, `https://oods-foundry.com/mcp`. By using either, you agree to them. They last changed on 2026-11-02. ## Using the site and the hosted endpoint Both are free to use. You don't need an account for either, and neither asks who you are. The hosted endpoint is read-only. It reads OODS Foundry's published objects, components and tokens, looks up recorded screens, and draws and checks charts. Importing your schema files, composing new screens, creating brands and writing files need the [local package](https://oods-foundry.com/agents#install). ## Rate limits The chart route and the hosted endpoint limit how many requests and new charts each visitor can send, so that no one visitor can use up everyone's share. A refused request gives a retry delay: wait for it, then send the same request again. [For agents](https://oods-foundry.com/agents#rate-limits) describes the limits. Don't try to get around the limits, for example by sending requests from many addresses, and don't use the site or the endpoint in a way that stops others from using them. ## Provided as is The site, the hosted endpoint and everything they return are provided as is, without warranty of any kind. A reply or a chart can be wrong, and the service can change, slow down or stop at any time. As far as the law allows, we are not liable for any loss or damage that comes from using them. ## The software OODS Foundry is licensed under Apache-2.0: free for any use, including at work. What OODS Foundry generates for you is yours. The [license](https://oods-foundry.com/license), not these terms, covers the software, including the npm package you run yourself. ## Privacy [Privacy](https://oods-foundry.com/privacy) says what the site and its hosted endpoint collect, keep and pass on. ## Contact Questions about these terms go to . --- Source: https://oods-foundry.com/about # About OODS Foundry OODS stands for object-oriented design system. A screen starts from the object it's about, like a Warehouse or a Quote, rather than from a pile of components. In version 0.11.3, OODS Foundry ships 11 business objects, 49 traits, 114 governed components in React and Vue, 13 chart types, and 26 tools your assistant sees by default. You can add your own objects and traits, make your own brand from a recipe or your colour values, and map your own components in place of shipped ones. It builds by rule, with no language model inside. OODS Foundry is an aquex.ai product. OODS Foundry is open source under Apache-2.0. [View the source](https://github.com/kneelinghorse/OODS-Foundry). Report bugs in [GitHub Issues](https://github.com/kneelinghorse/OODS-Foundry/issues). For everything else: --- Source: https://oods-foundry.com/guides # Guides The guides that ship with OODS Foundry 0.11.3, shown as written. Each tool's inputs and outputs are on its page under [Tools](https://oods-foundry.com/tools), from the schemas it ships. Generated from @oods/foundry 0.11.3 - [Quickstart](https://oods-foundry.com/guides/quickstart) From one object file to a running app in your brand. `QUICKSTART.md` - [Your own objects and traits](https://oods-foundry.com/guides/objects-and-traits) Write objects and traits in YAML, check them, and register them without a restart. `OBJECTS-AND-TRAITS.md` - [Bring your own objects](https://oods-foundry.com/guides/importing-objects) Draft objects from a schema your team already has, review the drafts, and accept the ones you want. `IMPORTING-OBJECTS.md` - [Your own brand](https://oods-foundry.com/guides/brands) Make a brand from a recipe, your colour values or your team's DTCG tokens, checked for contrast before it's written. `BRANDS.md` - [Your own components](https://oods-foundry.com/guides/components) Map a shipped component to your own React or Vue component, and read its contract report. `COMPONENTS.md` - [Maintaining generated apps](https://oods-foundry.com/guides/generated-apps) What a new generation gives you, which files are yours, and what it never merges into your app. `GENERATED-APPS.md` - [Settings and where files go](https://oods-foundry.com/guides/settings) The settings OODS Foundry reads, and the folders your work lives in. `README.md: Settings, Where things go` --- Source: https://oods-foundry.com/guides/quickstart [Guides](https://oods-foundry.com/guides) / Quickstart # Quickstart From one object file to a running app in your brand. Generated from @oods/foundry 0.11.3 The guide below is the one the package ships, `QUICKSTART.md` in `@oods/foundry@0.11.3`, shown as written. ## Make your first change, then bring your design system Change one trait and predict which screens follow it. The first run uses the shipped Warehouse and ColdRoom examples; the Harbor walkthrough that follows adds your colour tokens and component, generates an app, and renders and certifies a separate chart. Chart certification does not certify the surrounding application. Use Node.js 22.0.0 or newer on macOS or Linux and connect your MCP client as the package README describes. The calls below use the underscore names your client lists. Start with a fresh user-data folder if you already registered any of these example names; creation does not silently overwrite existing work. Keep each walkthrough in one server session because schema references expire. ### Get the editable inputs In your project, install this version of OODS Foundry and copy its examples outside the installed runtime: ```sh npm install @oods/foundry@0.11.3 cp -R node_modules/@oods/foundry/quickstart ./harbor-design-system ``` The input folder contains `harbor.tokens.json`, `Stockable.trait.yaml`, `Warehouse.object.yaml`, `ColdRoom.object.yaml` and `team-components/`. Replace their example values with your design system's values as you go. The brand document maps colour values into OODS Foundry's named roles; it is not an automatic importer for every design-token format. Keep the base, dark and high-contrast documents and their role names. Ask your assistant to make each named call. Replace file placeholders with the files' complete text and composition placeholders with the returned ids; placeholders are values to substitute, not literal tool arguments. ### The first change This run makes **23 tool calls**, including **six `design_preview` calls**. Leave at least seven seconds between preview calls to stay below their rate limit. Save an untouched copy of `Stockable.trait.yaml` before editing it. #### Register the examples Register Stockable, Warehouse and then ColdRoom. ColdRoom belongs to a Warehouse, so that object must exist first. ```json {"action":"register","yaml":""} ``` ```json {"action":"register","yaml":""} ``` ```json {"action":"register","yaml":""} ``` #### Compose four screens Retain the `compositionId` for each screen. These calls create version 1. ```json {"object":"Warehouse","context":"detail"} ``` ```json {"object":"ColdRoom","context":"detail"} ``` ```json {"object":"Warehouse","context":"list"} ``` ```json {"object":"Subscription","context":"detail"} ``` Open Warehouse detail with `design_preview`; keep the returned browser link. ```json {"compositionId":"","version":1} ``` #### Make a prediction, then edit Before looking, say which of Warehouse detail, ColdRoom detail, Warehouse list and Subscription detail you expect to change. A trait places a field on a screen through `view_extensions`, and this edit names `detail`. In your copied `Stockable.trait.yaml`, change the version under `trait` from `1.0.0` to: ```yaml version: 1.1.0 ``` Add this field inside `schema`, beside the existing fields: ```yaml last_counted_at: type: datetime required: false description: When the stock in this location was last counted. examples: - '2026-09-20T07:30:00Z' ``` Append this placement to the existing list under `view_extensions.detail`: ```yaml - component: Text position: main priority: 67 props: field: last_counted_at ``` Register your complete edited file with `overwrite: true`: ```json {"action":"register","yaml":"","overwrite":true} ``` Compose the same screens again, passing each saved id. These calls create version 2. ```json {"object":"Warehouse","context":"detail","compositionId":""} ``` ```json {"object":"ColdRoom","context":"detail","compositionId":""} ``` ```json {"object":"Warehouse","context":"list","compositionId":""} ``` ```json {"object":"Subscription","context":"detail","compositionId":""} ``` #### Compare your prediction Compare version 1 with version 2 for each screen, then open the returned compare links. ```json {"action":"compare","compositionId":"","version":1,"against":{"version":2}} ``` ```json {"action":"compare","compositionId":"","version":1,"against":{"version":2}} ``` ```json {"action":"compare","compositionId":"","version":1,"against":{"version":2}} ``` ```json {"action":"compare","compositionId":"","version":1,"against":{"version":2}} ``` | Screen | What happens | | - | - | | Warehouse detail | Changes. “Last counted at” appears. | | ColdRoom detail | Changes the same way: a different object with the same trait. | | Warehouse list | The screen is the same. Its definition gained a field placed on detail only, so compare names `objectSchema.last_counted_at` under Definition. | | Subscription detail | Untouched, with the same hash. Subscription does not have Stockable. | Compare also lists the generated files whose hashes changed: the Warehouse list's generated type includes the new field even though its screen stays the same. #### Put the trait back Replace the edited file with your saved, untouched Stockable file and register it again: ```json {"action":"register","yaml":"","overwrite":true} ``` Compose each screen once more, using its same id, to create version 3. All four return to their version 1 schema hash. ```json {"object":"Warehouse","context":"detail","compositionId":""} ``` ```json {"object":"ColdRoom","context":"detail","compositionId":""} ``` ```json {"object":"Warehouse","context":"list","compositionId":""} ``` ```json {"object":"Subscription","context":"detail","compositionId":""} ``` Compare Warehouse detail version 1 against version 3: it is identical. ```json {"action":"compare","compositionId":"","version":1,"against":{"version":3}} ``` ### The Harbor walkthrough If you did the first run and put the trait back, Stockable and Warehouse are already registered: skip only the two `register` calls for those definitions below. The remaining walkthrough uses the same input folder. Prepare its editable example component package: ```sh cd harbor-design-system/team-components npm install --ignore-scripts npm pack --ignore-scripts ``` The last command creates `harbor-example-components-1.0.0.tgz`, used when installing the generated apps. The team package is an editable example, not a published library. A new OODS Foundry process draws its first chart more slowly than the next. Replace `` with the parsed JSON document, `` and `` with those files' complete text, and `` with the copied package's absolute directory. Replace ``, `` and `` with values returned earlier in this walkthrough. #### Register your brand Ask your assistant to make each named call. Start with `health_check`: ```json {} ``` Then `brand_read` with `template` to inspect the roles and descriptions: ```json {"action":"template"} ``` The supplied Harbor document has a complete set of values. Change values, then call `brand_read` with `validate`. Fix each reported issue before creating the brand; a failed contrast check includes the pair, measured ratio and required floor. ```json {"action":"validate","brand_id":"Harbor","documents":""} ``` When `valid` is true, create it: ```json {"action":"create","brand_id":"Harbor","documents":""} ``` The result names the written files and token build. Your brand lives outside the unpacked runtime and generated apps carry its stylesheet. Reusing an existing brand id is refused; use `brand_apply` for an intentional change. #### Register your trait and object `Stockable` supplies stock fields and views; `Warehouse` combines it with shipped lifecycle traits and authors ten sample warehouses. Their authored values keep each site's operating status, status history, stock, last restock, manager and operating organization coherent, so the detail screen shows no placeholders. Start with `object_registry` to validate the trait: ```json {"action":"validate","yaml":""} ``` Register it only after `valid: true`: ```json {"action":"register","yaml":""} ``` Validate and register the object after its trait exists: ```json {"action":"validate","yaml":""} ``` ```json {"action":"register","yaml":""} ``` Read the returned context checks. A missing trait or invalid definition is reported with its cause and registration is refused. See `OBJECTS-AND-TRAITS.md` for field types, money semantics, number formats, form controls and name-collision rules. #### Substitute your component The example Button expects `caption` and `appearance`, so this mapping translates OODS Foundry's `content` and `intent`. Call `component_map`: ```json { "action":"create","apply":true,"externalSystem":"harbor", "externalComponent":"TeamButton","oodsTraits":["Stateful"], "substitution":{ "component":"Button", "react":{ "package":"@harbor/example-components/react","version":"1.0.0","export":"TeamButton","localPath":"", "props":{"content":{"name":"caption"},"intent":{"name":"appearance","values":{"neutral":"quiet","primary":"prominent","danger":"danger"}}} }, "vue":{ "package":"@harbor/example-components/vue","version":"1.0.0","export":"TeamButton","localPath":"", "props":{"content":{"name":"caption"},"intent":{"name":"appearance","values":{"neutral":"quiet","primary":"prominent","danger":"danger"}}} } } } ``` This replaces a shipped identity; it does not add a new catalog identity. The package's name, version and exports must match. Local paths help the preview find the package and are not emitted as consumer dependencies. Component reports distinguish met, unmet and not-checked obligations; a mapped name is not proof of semantic compatibility. #### Compose the Warehouse screen Call `design_compose` and retain its `schemaRef`, `compositionId` and version: ```json {"object":"Warehouse","context":"detail","preferences":{"brand":"Harbor","theme":"light"}} ``` The result contains the composed schema, object and trait provenance, selections and validation findings. Check `status` and warnings. Composition uses declared objects and keyword rules; missing selection confidence is not inferred. #### Render and certify a chart Call `viz_render` with explicit rows from the example stock records: ```json {"chartType":"bar","brand":"Harbor","theme":"light","rows":[{"warehouse":"Lakeside Distribution","pallets":640},{"warehouse":"North Yard","pallets":760},{"warehouse":"Harbor Cold Store","pallets":2400}],"encodings":{"x":{"field":"warehouse","type":"nominal"},"y":{"field":"pallets","type":"quantitative"}},"output":{"includeNormalizedSpec":true,"includeA11y":true}} ``` Then call `artifact_certify` with that returned normalized specification and the same brand/theme: ```json {"spec":"","brand":"Harbor","theme":"light"} ``` Read `conformant`, each pillar, and its findings. For this Cartesian chart, certification reads the specification's data. ECharts-primary charts also need the same data operand used for rendering. High contrast has a forced-colour exemption, not a numeric contrast pass. This chart is a separate artifact; this walkthrough does not insert it into the Warehouse screen. #### Preview and generate Call `design_preview` for the saved composition: ```json {"compositionId":"","version":1} ``` Open the returned React or Vue `appUrl`. Inspect the Warehouse name, stock status and team Button. The app is served locally by default. Inline presentation depends on the MCP host; the browser link is the portable route. An absent contract browser leaves browser obligations not checked, with reasons. Call `code_generate` to receive a complete single-screen app rather than only a component: ```json {"schemaRef":"","framework":"react","profile":"build","options":{"output":"application","brand":"Harbor","theme":"light","payloadMode":"file"}} ``` ```json {"schemaRef":"","framework":"vue","profile":"build","options":{"output":"application","brand":"Harbor","theme":"light","payloadMode":"file"}} ``` Each result names its payload directory, artifact content hash, dependencies and `validationReceipt`. The content hashes a clean run of this walkthrough produces are in the package's `quickstart/expected.json`. The build profile checks source statically; read `notChecked` for compilation and browser work that has not run. Copy each artifact's files into a separate app folder. Its package.json pins, at exact versions, the OODS packages its code imports, which install from npm, and the example team package. The example package is on no registry, so first install the local `harbor-example-components-1.0.0.tgz` by its path, then follow the install block (`npm install`, then `npm run build`) and run `npm run dev`. The screen labels its sample data. Connect actions to your application before shipping: the preview's integration notice means that no domain record was changed. Request `context: "workflow"` when you want multiple screens with a local sample store; that store does not supply production persistence. OODS Foundry's code is under the Apache License 2.0. The fonts it bundles (Geist, Geist Mono and DM Sans) are under the SIL Open Font License 1.1, and its colour scales adapt Radix Colors (MIT); the NOTICE file in `@oods/foundry` carries both licenses. Generated output belongs to you; installed dependencies keep their licenses. Retain the returned hashes and receipts when reviewing what you built. See [GENERATED-APPS.md](https://oods-foundry.com/guides/generated-apps) for what to keep and replace when you generate again after a definition changes. --- Source: https://oods-foundry.com/guides/objects-and-traits [Guides](https://oods-foundry.com/guides) / Your own objects and traits # Your own objects and traits Write objects and traits in YAML, check them, and register them without a restart. Generated from @oods/foundry 0.11.3 The guide below is the one the package ships, `OBJECTS-AND-TRAITS.md` in `@oods/foundry@0.11.3`, shown as written. ## Your own objects and traits OODS Foundry composes screens from **objects** (the things your product is about: a warehouse, an invoice, a user) and **traits** (capabilities an object composes: a lifecycle, prices, stock levels). It ships objects such as `Subscription` and `User` and traits such as `lifecycle/Stateful`; `object_registry` `list` names them, leaving out the five internal capture objects (Run, Finding, CapturedArtifact, Comparison and ComparisonSignal) unless you ask with `"includeInternal": true`. This guide is for adding your own, so `design_compose`, `code_generate` and `design_preview` work with them as they do with the shipped ones. ### Where they live | Folder | Holds | Setting | | - | - | - | | `~/.oods-foundry/objects` | `*.object.yaml` files | `OODS_OBJECTS_DIR` | | `~/.oods-foundry/traits` | `*.trait.yaml` files | `OODS_TRAITS_DIR` | Your folders are read after the shipped ones, including subfolders. They are outside the unpacked runtime, so they survive upgrades. Set either variable in your client's `env` block to keep your definitions somewhere else, such as your product's repository. From the runtime archive the variables have no default: set them to register anything. ### An object ```yaml object: name: Warehouse # letters and digits; it names files, types and components in generated code version: 1.0.0 domain: acme.logistics description: A storage site the team ships orders from. traits: # shipped traits by name (lifecycle/Stateful) or yours (Stockable) - name: lifecycle/Stateful parameters: states: [planned, active, closed] initialState: planned - name: Stockable parameters: capacityUnit: pallets schema: # the object's own fields, beside the ones its traits add warehouse_id: { type: uuid, required: true, description: Unique identifier. } name: type: string required: true description: The warehouse's name. examples: [Lakeside Distribution, North Yard] # sample records cycle through these monthly_rent: { type: number, required: true, description: Monthly cost in major units. } currency: type: string required: true description: Currency the rent is paid in. validation: { enum: [USD, EUR, GBP] } semantics: monthly_rent: semantic_type: logistics.warehouse.rent token_mapping: tokenMap(commerce.price.primary) ui_hints: component: CurrencyAmount # this field is money... currencyField: currency # ...in the currency this field holds samples: # optional: whole sample records, by field name, shown in this order - { name: Lakeside Distribution, monthly_rent: 12500.5, currency: USD, status: active } - { name: North Yard, monthly_rent: 9800, currency: EUR, status: planned } metadata: maturity: beta # supportedContexts: [list, detail, card] # optional; without it the object composes every context ``` Field types are `string`, `number`, `integer`, `boolean`, `date`, `datetime`, `uuid`, `email`, `url`, arrays such as `string[]`, and structured types. The sample records the preview and generated apps show are the object's `samples:`, in order, as the shipped business objects show their eight. A sample names values for any of the object's fields, its traits' included (`status` above comes from `lifecycle/Stateful`). A field a sample leaves out shows that field's own example at the same position, or else an empty value of its type (empty text, 0 or false): never another sample's value or a default, which would state a fact the sample did not record. `validate` refuses a sample that names a field the object does not have or an enum value the field does not allow. An object with no `samples:` cycles through each field's `examples`, so give one per distinct row you want to see: a preview list shows ten. #### Money A field is money only when its semantics say so, as above: `ui_hints.component: CurrencyAmount` and the `currencyField` that holds its currency. Without anything more the amount is in **major units**: `12500.5` is 12,500.50. If the amount is stored in minor units, say how many make one major unit: ```yaml ui_hints: component: CurrencyAmount currencyField: currency minorUnits: 100 # 1999 is 19.99 ``` A field's name never decides this: a field called `amount` or `total_minor` is not money unless its semantics declare it. `PriceSummary` and the billing badges read amounts stored in minor units; a field in major units shows through `PriceBadge`. `validate` refuses a trait view that would show a major-unit amount 100 times too small. #### Numbers and form controls A number field's semantics can say how its value reads with `ui_hints.format`: ```yaml ui_hints: format: percent # 12.5 reads 12.5%; with quantity, 86420 reads 86,420 ``` React, Vue and HTML print the same text. A number that declares nothing keeps the digits it was stored with, so a year or a score is not grouped. `format: integer` is accepted and changes nothing; any other value is an error when the object is composed. A generated form edits a boolean with a Checkbox and an enum with a Select. A field's semantics can ask for another control with `ui_hints.component`: `Switch` for a boolean, `SegmentedControl` for an enum of two to five options, or `Combobox` for an enum picked from a list you filter by typing. A control that cannot edit the field, such as a Switch on a text field or a SegmentedControl over six options, leaves the default in place. Date fields can use either a DatePicker or a native date Input. The composer budgets ten suggested form slots, then adds any missing required scalar fields with plain editors. In the shipped Plan form, `period_start` gets a DatePicker in the suggested slots; `period_end` is added as a required date Input. Both come from `SaaSBillingMetered`, are required `date` fields, and declare no different control hint or trait placement. The different controls reflect this slot selection limit, not different date semantics. Substitution preserves each selected identity, so mapping DatePicker does not turn the other Input into a calendar picker. ### A trait ```yaml trait: name: Stockable # must not be a shipped trait's name version: 1.0.0 description: How full a storage location is. category: inventory parameters: - name: capacityUnit type: string required: false description: The unit stock is counted in. default: pallets schema: stock_level: type: string required: true description: Whether the location has room, is nearly full, or is full. validation: { enum: [room_available, nearly_full, full] } units_on_hand: { type: integer, required: true, description: Units stored now. } view_extensions: # what the trait places on each screen: list, card, detail, form, timeline, inline, dashboard list: - component: StatusBadge position: after props: { statusField: stock_level } detail: - component: StatusBadge position: main priority: 70 props: { statusField: stock_level } - component: Text # a field placed explicitly is always shown position: main priority: 69 props: { field: units_on_hand } ``` A trait of yours can place only the components OODS Foundry ships; `catalog_list` names them. Your own components can replace those ids through substitution; see [COMPONENTS.md](https://cdn.jsdelivr.net/npm/@oods/foundry@0.11.3/COMPONENTS.md). ### Checking and registering Ask your assistant to use `object_registry` to validate or reload, and `object_register` to save, with the whole file as `yaml`: 1. `{"action": "validate", "yaml": ""}` parses it, checks the header and fields, resolves every trait, checks the contexts, and composes the object with its traits. It answers `valid`, the `errors` with where each is, the composer's `warnings`, and the contexts the object composes. Nothing is written. 2. `object_register` with `{"action": "register", "yaml": ""}` validates, writes `.object.yaml` (or `.trait.yaml`) into your folder, reads the folders again and composes the object in every context it declares. If anything fails, your folder is left exactly as it was and the answer says why (`OODS-V215`). A name you already registered is replaced only with `"overwrite": true` (`OODS-C004`). 3. `{"action": "reload"}` reads the folders again without a restart, after you edit a file by hand. Register a trait before an object that uses it. `{"action": "list"}` shows each object's `source` (`shipped` or `user`), and `health_check` reports your folders and counts under `registry.definitions`. ### Rules - **Your object with a shipped object's name is used in its place**, everywhere, and `list`, `health_check` and `validate` say so. You can model your own `User`, `Product` or `Invoice`. Remove the file and `reload`, and the shipped one returns. - **Your trait cannot reuse a shipped trait's name.** Shipped objects compose shipped traits by name, so yours would change screens you never touched. It is reported and not used; give it a name of its own. - **Two of your files with one name are ambiguous**: neither is used until only one declares it. - **Nothing is skipped silently.** A file that is not valid YAML, declares no name, or uses a trait that no folder defines is reported by `list`, `health_check` and `validate` with the file and the reason. ### What composition does with them Your objects compose, generate, preview and run like the shipped ones: `design_compose` in each context, `code_generate` for React and Vue, `design_preview` in the browser, and a generated workflow app whose form saves. Two limits of the composer apply to every object, yours and shipped: - the composer budgets ten suggested form slots, then adds any missing required scalar editors; trait editors retain ownership of their structured fields; - a detail screen shows the fields a trait places explicitly (as `Text` above) and the object's own fields. ### HTML, relationships and wireframes A run of the npm package, measured on 0.10.0, verified HTML, a relationship diagram and a composed wireframe from the same registered Warehouse on Node 24.6.0 and on Node 22.0.0, the floor. Its brand, objects, traits and mappings stay outside the unpacked runtime; generation leaves the shipped readiness attestation unchanged. These are builder measurements, not independent certification. For static sample HTML, compose your object, then call `code_generate`: ```json {"schemaRef":"","framework":"html","profile":"build","options":{"output":"application","brand":"Harbor","theme":"dark","payloadMode":"file"}} ``` Open the returned `index.html` from its payload directory. The document carries styles and sample record data. Tabs, local list controls and native edits work locally; domain actions explain where to connect your application and never persist a record. HTML renders OODS Foundry's controls; a React/Vue team-component mapping does not execute that package in HTML. Static HTML has separate browser measurements; it is not covered by the React/Vue runtime sweep. Read the HTML measurement summary and its evidence identity from `health_check` before treating it as proof for your object and theme. Build validation is static; browser measurements are separate. There is no universal form-parity claim. Declare an association in an object's YAML only when its target contract is known: ```yaml relationships: - target: Organization via: organization_id cardinality: many-to-one label: Operated by ``` The via field must exist on the source object or one of its traits. The target must be registered first (self-links are allowed). Cardinality is source-relative: one-to-one, one-to-many, many-to-one or many-to-many. Validate/register return typed errors for an unknown target/field or malformed declaration. Identifiers alone never create an association. ```json {"fidelityKind":"boxes-arrows","object":"Warehouse","options":{"depth":1,"brandOverlay":"Harbor","theme":"dark"}} ``` `fidelity_preview` returns HTML and an accessible standalone SVG. Arrows show declared type associations with label, cardinality and via field, plus each object's traits and key fields. They do not join live records or check referential integrity. Depth is 0–3; an `objects` array draws only the declared edges within that set. Large diagrams scroll inside the page. ```json {"fidelityKind":"wireframe","object":"Warehouse","context":"detail"} ``` Alternatively pass `schemaRef` from composition or an inline `schema`, with exactly one source. Composed wireframes draw the component tree and regions using the selected brand and theme tokens, label field bindings, and stack at phone widths. Alternate states and tab panels appear together for inspection. `review` adds recorded node confidence; absent confidence says Not recorded. `branded-mockup` renders the static sample HTML. `boxes-arrows` with a composition draws a clearly labelled component-containment graph, not object associations. Legacy `manifest` input and the nine named registry fixtures remain available; legacy views retain their entity/slot projection and branded manifests use light tokens. --- Source: https://oods-foundry.com/guides/importing-objects [Guides](https://oods-foundry.com/guides) / Bring your own objects # Bring your own objects Draft objects from a schema your team already has, review the drafts, and accept the ones you want. Generated from @oods/foundry 0.11.3 The guide below is the one the package ships, `IMPORTING-OBJECTS.md` in `@oods/foundry@0.11.3`, shown as written. ## Bring your own objects `object_import` reads a schema your team already has and drafts OODS Foundry objects. Review the drafts and accept the objects and trait proposals you want. `object_registry` validates hand-written object or trait YAML; `object_register` saves it. ### Files in Supported inputs are OpenAPI/Swagger 2.0, OpenAPI 3.0–3.2, JSON Schema draft-07 or 2020-12, Postgres DDL and migrations, Prisma schemas, dbt manifests/projects, OData CSDL XML/JSON, GraphQL SDL/introspection, or the [OODS hub](https://cdn.jsdelivr.net/npm/@oods/foundry@0.11.3/object-hub.schema.json). Pass one local file, a schema folder, or inline content up to 1 MiB. `source.format` can select `openapi`, `json-schema`, `sql`, `prisma`, `dbt`, `odata` or `graphql`; otherwise the document and extension select the reader. Files have a combined limit of 128 MiB, checked before reading. Folder entries are processed in deterministic order. OODS Foundry does not fetch a URL, connect to an API/database, import a module, or run your code. Local JSON Pointer `$ref`s and relative file references are supported within the source folder. References that escape it, including through symlinks, are refused with the source file and pointer. Unreachable network and absolute references, missing local files and named anchors are reported at their file/pointer and skipped; nothing is fetched. Download remote specs yourself before importing them. ```json {"action":"draft","source":{"path":"/path/to/openapi.json"}} ``` The response gives an `importId`, counts, object names in dependency order, shipped-name clashes, proposal grades, and a diff-file path. Large listings are explicitly truncated in the response; `order.json` has the complete order and cycles. Nothing is registered at this step. The complete bundle is in `~/.oods-foundry/imports//`, beside your objects and traits, outside the package install. A portable installation may set `OODS_FOUNDRY_HOME` before starting the server. `objects/` holds the draft YAML, `hub.json` the normalized schemas, `report.json` every outcome, and `diff.json` the comparison with currently registered definitions. `import.json` is content-addressed and binds the hashes of its separately streamed hub and report; editing any of them invalidates the import. To hand-edit a draft, use `object_registry` to validate and `object_register` to save that YAML. ### Review and accept Call `object_import_read`: ```json {"action":"show","importId":"","object":"YourObject"} ``` `show` returns one draft's YAML, proposals with evidence and grades, unmapped elements, and the re-import comparison. A re-import reports added, removed and changed fields, trait and relationship changes, and potentially affected list/detail/form/timeline screens. It compares the unaccepted base draft with your effective registered definition, with previously accepted trait contributions listed separately as `traitFields`, rather than false removals; review those differences before overwriting. A name alone is weak evidence and never raises a proposal's grade. Types, enums, formats and read-only declarations provide structural evidence. Trait parameter schemas validate every proposal; an invalid proposal is shown with errors and cannot be accepted. Proposals add a trait's canonical fields and views, so check that its fields express your model. Nothing is silently applied. ```json {"action":"apply","importId":"","objects":[{"name":"YourObject","proposals":[""]}]} ``` Omit `proposals` to accept an object with no traits. Accept dependencies in the same call unless they are already registered. The batch validates all definitions, writes them in dependency order, and composes each supported context transiently, including timeline where declared or contributed by an accepted lifecycle/history trait. Read-only sources omit form. Cyclic relationships are retained: all files exist before composition. A write or composition failure restores previous files byte for byte and removes newly created files. A filesystem lock excludes concurrent registration/import writes; this is rollback on operation failure, not a crash-recovery database transaction. `overwrite: true` permits replacing your existing objects. A shipped-name replacement additionally requires that exact name in `confirmShipped`, for example `"confirmShipped":["User"]`. Reviewing one shipped replacement does not authorize another. ### What is preserved Primitive fields, supported formats, nullability, examples, defaults and constraints become object fields. Compatible `allOf` declarations merge; conflicting intersections are reported. `oneOf`/`anyOf` alternatives remain distinct, including discriminators; a null-plus-one-type union can become a nullable field. Named object references become relationship identifier fields. Source names and every normalized value retain file/pointer provenance. Read-only fields are omitted from editable forms. Write-only fields and their samples are omitted from read screens. Maps, nested documents, unconstrained values, unsupported unions and unsupported metadata remain in the hub with explicit unmapped outcomes. API operations do not become executable actions. Samples without supplied examples are illustrative, not customer records. The report's mapped, proposed and unmapped counts sum to its total. ### The hub vocabulary The hub is JSON Schema 2020-12 plus `x-oods` annotations, with its own Ajv vocabulary instance. Its [schema](https://cdn.jsdelivr.net/npm/@oods/foundry@0.11.3/object-hub.schema.json) ships beside this guide. `$defs` contains named schemas. `x-oods.version` is `1`; `sources`, `sourceNames` and `provenance` record the input identity. A provenance key is a hub JSON Pointer, and its value is `{ "file": "source.json", "pointer": "/components/schemas/Widget" }`. Schema annotations can carry `relationships` (target, via, cardinality, label), `enumLabels`, `localeLabels`, `currency` (field, optional positive minorUnits divisor), `unit` (field or symbol), `lifecycle` (field, states, initialState), `history` (field, timestampField), and `traitProposals` (name, parameters, grade, evidence). These annotations are preserved even when the current object projection cannot use them. Explicit currency annotations become money semantics; field names never imply money. Each proposal's evidence has file, pointer, reason, and kind (`name`, `structure`, `declaration`). Name-only evidence stays weak even if a producer labels it strong. ### Export from your own tools Run the export in your own trusted project, save the resulting JSON, then give only that file to OODS Foundry. These are export expressions/commands, not programs OODS Foundry runs: | Source | One-line export | | - | - | | [Zod 4](https://zod.dev/json-schema) | `console.log(JSON.stringify(z.toJSONSchema(YourSchema)))` | | [Valibot](https://valibot.dev/guides/json-schema/) | `console.log(JSON.stringify(toJsonSchema(YourSchema)))` using `toJsonSchema` from `@valibot/to-json-schema` | | [TypeBox](https://github.com/sinclairzx81/typebox) | `console.log(JSON.stringify(YourTypeBoxSchema))` | | [Effect 3](https://effect.website/docs/v3/schema/json-schema) | `console.log(JSON.stringify(JSONSchema.make(YourSchema)))` using `JSONSchema` from `effect` | | [Pydantic](https://docs.pydantic.dev/latest/concepts/json_schema/) | `print(json.dumps(YourModel.model_json_schema()))` with Python's `json` module | | [TypeScript types](https://github.com/vega/ts-json-schema-generator) | `npx ts-json-schema-generator --path 'src/model.ts' --type 'YourType' > schema.json` | Converters cannot represent every transformation, refinement or runtime behavior as JSON Schema. Review their export diagnostics and the import report. OODS Foundry's accepted YAML stays the canonical object definition; another discovery tool can produce the documented hub without access to OODS Foundry internals. Broken local JSON Pointers are preserved as `x-oods-unresolved-ref` with an unmapped link and source location; they never become invented relationships. Network and named-anchor references are reported and skipped. Outside-folder and escaping-symlink references refuse the whole import before an outside read. Traversal is bounded to 160 nesting levels and ten million values, including YAML alias expansion. Imported records use declared titles or natural keys, then identifiers. Samples are deterministic and checked against enum, pattern, format and bounds; unsatisfiable sample constraints are reported. Field help comes only from source descriptions. Date-only values display without a time. Declared relationships use related sample records in form pickers; applications supply their live choices. ### Postgres DDL and migrations Pass a `.sql` file or migration folder, or `source.format: "sql"` with inline SQL. The reader parses schema declarations and replays them in memory; it never connects to a database or executes SQL. It reads columns/types, NOT NULL, literal defaults, enum types, primary/unique keys, scalar foreign keys, comments, literal CHECK comparisons/IN lists, and direct-column view projections. `now()` supplies timestamp evidence without evaluation. Views are read-only. Composite foreign keys, complex view expressions, procedural SQL and unsupported syntax are individually reported. Prisma migration timestamp folders, Flyway numeric versions, golang-migrate `.up.sql` files and Rails `structure.sql` work as files. Drizzle follows `meta/_journal.json`; unlisted SQL and down/undo migrations are reported and skipped. ALTER, DROP and RENAME update the replayed schema. Postgres is the supported dialect; MySQL and SQL Server dialect support remains later work, with unsupported statements reported rather than guessed. ### Prisma and dbt Pass `format: "prisma"` with a `.prisma` file or a schema folder. Models, enums, native types, keys, literal defaults and documentation are projected. Relation navigation uses its declared foreign key when available. Generated defaults and `@updatedAt` are read-only; source table/column mappings remain in the hub. Generators and datasource declarations are never executed. Pass `format: "dbt"` with a manifest or a project properties folder. A compiled manifest is authoritative when supplied. YAML models, sources, snapshots, column tests, constraints and semantic declarations provide fields and relationships; both standalone semantic models and embedded column entities/dimensions with simple metrics are supported. All dbt objects are read-only. Snapshots include history and offer Supersedable. Jinja, SQL expressions, custom tests and dynamic descriptions are reported without execution. Missing types stay unmapped; a familiar column name does not supply a type. ### OData and GraphQL OData accepts CSDL JSON or XML/EDMX (`format: "odata"`). Entity/complex types, enums, keys, inheritance and navigation references become hub schemas. Draft names use local type names with deterministic collision suffixes; full service names stay in provenance. Scalar navigation uses its declared foreign key in one editor, including v2 association constraints. HeaderInfo names records, LineItem supplies `metadata.listColumns`, FieldGroup/Facets group details, Common labels/text/value lists shape fields and pickers, ISO currency pairs supply money semantics, literal units label values, and capability restrictions remove forms when inserts and updates are prohibited. Nullable display text is supported. Dynamic units, unresolved translation tokens and unsupported vocabulary expressions stay preserved and reported. XML refuses DTD/entity declarations; vocabulary URLs are never fetched. XML and JSON retain their respective nullability defaults. GraphQL accepts SDL (`.graphql`/`.gql`) or introspection JSON (`format: "graphql"`). Object types draft as records; mutation input types remain explicitly reported and are not drafted as records. Enums, nullability, lists, descriptions and deprecation metadata are retained; interfaces and unions remain alternatives, not merged records. Object fields become relationships. Operation roots and resolvers are not run. Custom scalar names do not supply types: only explicitly supported `@specifiedBy` URLs provide format evidence. Duplicate field declarations are reported and the first stays in effect. Hand-written objects can use `metadata.listColumns: [{field: name, label: Name}, {field: total}]` to select and order fields in list rows. Every column must name a composed field. Source annotation support uses the same object contract. ### Accepted trait field bindings A proposal carries one configuration per trait and all of its evidence. Accepting a Timestampable or Stateful proposal records `fieldBindings` on the trait reference, so screens and generated React and Vue apps use the original source fields. An alternative configuration stays in the report with its reason; review the selected binding before accepting. Hand-written object definitions can use the same declaration: ```yaml traits: - name: Stateful parameters: states: [open, closed] initialState: open fieldBindings: status: state - name: Timestampable fieldBindings: created_at: placedAt updated_at: updatedAt last_event: null last_event_at: null ``` Binding targets must be fields declared in the object's schema with a matching type. `null` explicitly omits a canonical field the source does not provide, including its view bindings. Without `fieldBindings`, a trait keeps its existing fields and behavior. Imported proposals explicitly omit every canonical record field the source does not supply. A proposal with no supported field bindings says that it contributes no record views. A single supplied creation time also serves the list timestamp. Timestamped objects can show that fact on their timeline without invented lifecycle events. Detail screens resolve related records from the same sample lookup used by form pickers. OData `Common.Text` supports a local label field or one navigation hop through a declared foreign-key constraint, such as `Agency/Name`. Generated lookup labels contain imported samples only: connect your application's relationship data for real records. Declared list-column labels take precedence over field semantics labels, then the human-readable field name. ### Declare money when accepting A numeric field remains a number until its currency is declared in the source or explicitly accepted. Use `object_import_read` with `action: "show"` to review a draft, then add `currencies` to its accepted object: ```json {"action":"apply","importId":"","objects":[{"name":"Order","proposals":[""],"currencies":{"total":{"field":"currency"}}}]} ``` The currency field must be a declared string field. Add `minorUnits: 100` for amounts stored as cents; omit it for major units. The whole batch is validated before any definition changes. --- Source: https://oods-foundry.com/guides/brands [Guides](https://oods-foundry.com/guides) / Your own brand # Your own brand Make a brand from a recipe, your colour values or your team's DTCG tokens, checked for contrast before it's written. Generated from @oods/foundry 0.11.3 The guide below is the one the package ships, `BRANDS.md` in `@oods/foundry@0.11.3`, shown as written. ## Your own brands OODS Foundry styles every screen through design tokens. A **brand** is one colour value for each role the design system paints (surfaces, text, actions, borders, focus, status and charts) in a light, a dark and a high-contrast theme, and its corner radii and fonts. It ships brands A and B; this guide is for adding yours, so `design_compose`, `design_preview`, `viz_render`, `artifact_certify`, `code_generate` and the apps it generates all use it. ### Where they live | Folder | Holds | Setting | | - | - | - | | `~/.oods-foundry/brands//` | your brand's `base.json` (light), `dark.json` and `hc.json` | `OODS_BRANDS_DIR` | | `~/.oods-foundry/brands/.build/` | the token build made from your brands and the shipped ones | | Your brands are built there, outside the unpacked runtime, so they survive upgrades; the first start of a new version rebuilds them for it. Set `OODS_BRANDS_DIR` in your client's `env` block to keep them somewhere else. From the runtime archive the variable has no default: set it to create a brand. ### From your own tokens `brand_read` accepts your team's DTCG document without renaming its groups or tokens: ```json {"action":"derive","tokens":{"color":{"brand":{"500":{"$type":"color","$value":"#387d47"}}}}} ``` It returns a partial `recipe`, `provenance` for each value (source path, raw and resolved value, and rule), `gaps` with candidate paths, and `warnings`. It writes nothing. Review the result, fill every required gap, then call `brand_create` with `{"action":"create","brand_id":"Meadow","recipe":{...}}`. Creation grades the complete brand before writing it. | Value | Derivation rule | | - | - | | Neutral hue and chroma | Circular median OKLCH hue and median chroma of colours with chroma ≤ 0.03 whose path contains gray, grey, neutral, slate, zinc or stone | | Accent hue | Colour nearest OKLCH lightness 0.5 whose path contains primary, accent or brand; prefer a 500 or 600 step | | Primary action | Accent when an accent was found, neutral otherwise; a missing accent hue remains a gap | | Radius | Median dimension whose path contains radius, converting rem to px at 16px; clamp to 0–16 and warn | | Font and mono font | First fontFamily in document order containing sans, body or base; mono for the mono family. Use the first family of a list | | Status hues | Mid-lightness colours containing success, warning, info, error, danger or critical; the last three become critical | Paths match without case sensitivity; ties follow document order. Group `$type` is inherited and `{group.token}` aliases resolve within the document. Colours may be CSS strings or DTCG color objects. Transparent or unreadable colours are reported; an achromatic colour with no hue cannot supply a hue. Optional `hints` selects exact paths for `accent`, `neutral`, `radius`, `font` or `fontMono`, for example `"hints":{"accent":"color.selected"}`. A bad hint is reported instead of silently falling back to inference. Recipe font names allow letters, digits, spaces and hyphens (64 characters). Dark and high contrast are generated from the recipe. The same contrast rules apply: 84 pairs in light and dark, 83 graded pairs and one stated exemption in high contrast, plus 7 chart pairs per theme. This recipe flow supplies values for OODS roles. Use the reviewed file intake below to preserve your token names in generated apps. Optional status families and mono font not found in the document remain absent from the recipe; the recipe generator's documented defaults apply at creation. #### From a shadcn/ui theme Pass the project's CSS entry as `css`, or its absolute path as `cssPath`, in place of `tokens`: ```json {"action":"derive","cssPath":"/absolute/path/to/app/src/index.css"} ``` The light `:root` declarations and `@theme inline` fonts supply the recipe. CSS imports and project scripts are not run. | Value | CSS source | | - | - | | Neutral | Circular median hue and median chroma of `--background`, `--foreground`, `--card`, `--muted`, `--border`, `--input`, with chroma ≤ 0.03 | | Accent | Chromatic `--primary`, otherwise chromatic `--ring`, otherwise a gap | | Primary | Accent when `--primary` is chromatic, neutral otherwise | | Radius | `--radius`, converting rem to px at 16px | | Fonts | First family in `--font-sans` and `--font-mono`, following one `var()` reference | | Critical status | Hue of `--destructive` | The default neutral shadcn theme leaves an accent gap. Nothing fills it for you. Each value's provenance names its custom property and raw value; `hints` can name a different custom property. Other properties, including `--accent` (the hover colour), `--secondary`, chart and sidebar colours, are ignored and named in a warning. Missing fonts are reported as gaps; the optional mono font may remain absent. This derives OODS brand values; it does not write them back to the project's CSS or copy the project's dark theme into OODS. ### Making one from a recipe The quickest way is a recipe: six values from which every colour, the radius set and the font stacks follow. | Value | What it sets | | - | - | | `neutralHue` (0 to 360) and `neutralChroma` (0 to 0.03) | the greys of surfaces, text and borders: their hue, and how much of it they carry | | `accentHue` (0 to 360) | the accent for links, focus and selection; the brand's charts take their palette from it | | `primary` | `"neutral"` for a near-black primary action in light (near-white in dark), or `"accent"` for one in the accent | | `radius` (0 to 16) | the control radius in px; the other radii follow from it | | `font` | the sans family; `fontMono` sets the monospace one too | `status` can also set the hue, and optionally the chroma, of `info`, `success`, `warning`, `critical` and `archive`. Ask your assistant to use `brand_read` for template and validate, then `brand_create` for create: 1. `{"action": "template", "from": {"recipe": {"neutralHue": 286, "neutralChroma": 0, "accentHue": 267, "primary": "neutral", "radius": 6, "font": "Geist"}}}` returns the complete brand the recipe gives: one document per theme, graded with the rules below (`report`), and every colour a rule moved off its step (`adjustments`). 2. `{"action": "validate", "brand_id": "Harbor", "recipe": {...}}` checks it under your brand's id and names the files `create` will write with their sha256. Nothing is written. 3. `{"action": "create", "brand_id": "Harbor", "recipe": {...}}` writes the files into your brands folder and builds them, in a few seconds. The brand is then in use everywhere, without a restart; `health_check` lists it. ### Making one slot by slot To choose every value yourself: 1. `{"action": "template"}` returns one document per theme with every slot (103 in light, 96 in dark and in high contrast), each with what it paints as `$description` and a starting value: brand A's, another brand's with `"from": {"brand": "B"}`, or a preset's with `"from": {"preset": "corporate-blue"}` (the answer lists the presets). 2. Replace the `$value`s with yours. Keep the documents as they are: `surface.canvas`, not `color.brand..surface.canvas`. 3. `{"action": "validate", "brand_id": "Harbor", "documents": {...}}` reports every problem by rule, with the contrast ratio of each pair that misses its floor, and names the files `create` will write with their sha256. Nothing is written. 4. `{"action": "create", "brand_id": "Harbor", "documents": {...}}` writes the files into your brands folder and builds them, as a recipe's are. `create` never replaces a brand (`OODS-C005`); it refuses a brand that does not validate, with the report (`OODS-V216`), and if the build fails the brand is removed again (`OODS-S022`). ### The rules - **Id**: capitals then digits (`ACME`, `A1`) or a letter then lower-case letters and digits (`Harbor`, `acme2`), at most 32 characters, and no existing brand's id in any case. - **Colours**: any opaque CSS colour (hex, `rgb()`, `hsl()`, `oklch()`, `lab()`, a named colour), not a reference to another token. System colours (`Canvas`, `CanvasText`, `Highlight` and the rest) follow the user's high-contrast settings, so only `hc` may use them. - **Radii and fonts**: the light document carries `radius.control`, `small`, `large`, `card` and `pill` (0 to 999px) and `font.sans` and `font.mono` (family lists); every theme of a brand shares them. - **Contrast**: light and dark are graded on 84 pairs each. Text is graded at 4.5:1 on the surfaces it sits on (53 pairs, among them the text on the primary action at rest, hovered and pressed, and status text on its own fill and on the canvas, raised and subtle panels). Status icons, control borders at rest and hovered, and the focus ring on the canvas, on a raised panel and on the primary action are graded at 3:1 (31 pairs). In `hc`, a pair of two system colours is graded as Chromium resolves them without forced colours, on macOS and Linux under a light and a dark colour scheme, and must pass in all four; a pair of two colours is graded like light and dark, and a pair of one of each is refused. - **Chart colours**: every theme has 27 chart slots (six series, the one-series colour, nine sequential steps and eleven diverging ones), and they are your brand's own in every theme. A brand made from a recipe gets its accent's palette, and a preset carries its own recipe's. In every theme the one-series colour and the six series are graded at 3:1 on the canvas (7 pairs; in `hc`, as its system colours resolve). A series that misses says whether its value is brand A's, which a template starts from, so you know to set it for your canvas. ### Changing one `brand_apply` changes your brand: `{"brand": "Harbor", "delta": {"dark": {"color": {"brand": {"Harbor": {"text": {"primary": {"$value": "#f5f5f0"}}}}}}}, "apply": true}`. The brand as the change would leave it is checked first, exactly as `validate` checks a new one, and nothing is written unless it passes. The receipt lists each slot that changed, and its `variables.css` holds the CSS variables the build emitted differently. The brands OODS Foundry ships cannot be changed from the npm package: for them `brand_apply` writes only a review kit. The next composition, preview or generated app shows a change. A preview you made before it keeps the chart it drew; make a new one to see the chart in the new colours. ### In the apps you generate `code_generate` for your brand adds `src/oods-brand-.css`, your brand's variables and its light, dark and high-contrast scopes, and imports it from the screen (or, for a workflow app, from `App`). The app's `@oods/tokens` carries the shipped brands; this file carries yours, so the app needs nothing else to show it. The file is part of the artifact and of its content hash. ### Keep your token names Use `brand_create` to draft from a local DTCG file. It reads data only, follows aliases within that file, and never fetches or runs project code. Group `$type` is inherited. Supported colors, dimensions, durations, numeric values, font families and cubic-bezier values become scoped custom properties; unsupported values, alias cycles, CSS-name collisions and reserved OODS names are reported individually. Dots become hyphens: `team.color.primary` becomes `--team-color-primary`. ```json {"action":"draft","brand_id":"Team","source":{"path":"/absolute/team/tokens.json","modes":{"base":"light","dark":"dark"}},"bindings":{"base":{"surface.canvas":"light.team.canvas","text.primary":"light.team.ink"},"dark":{"surface.canvas":"dark.team.canvas","text.primary":"dark.team.ink"}}} ``` `modes` selects dot-separated groups in the document. Top-level `light` and `dark` groups are recognized when both are present. Without declared modes the same tokens are available in each theme; the reader does not invent a dark palette. Mode prefixes are omitted from custom property names so the same variable takes the declared theme's value. Shared tokens remain available in both modes. Explicit `bindings` name OODS slots and exact source token paths. A token may also declare `$extensions: {"org.oods.intake": {"slot": "surface.canvas"}}`. Otherwise only a unique matching type and value can bind a template slot; token names alone do not decide. Every unbound slot is identified as a template fallback. `from.brand` or `from.preset` chooses the starting template, default A. High contrast keeps the checked template. Review all fallbacks and unmatched tokens before acceptance. Call `show` with the returned `draftId`: ```json {"action":"show","draftId":"brand-"} ``` Then call `apply` to accept it: ```json {"action":"apply","draftId":"brand-","accept":true} ``` Acceptance covers the whole reviewed brand, its retained token values and the listed template fallbacks. Apply uses the existing contrast/type checks, refuses replacement and rolls back a failed token build. An invalid draft cannot apply; adjust bindings/source and draft again. CSS emits the team's names and aliases bound `--theme-*` slots to them. Generated React and Vue apps carry that stylesheet. Existing brands and the recipe flow keep their previous behavior. The files retain this mapping in `org.oods.intake` metadata. The named variable must equal the slot literal used for contrast grading. When editing a bound slot through `brand_apply`, update that variable as well (or deliberately remove its slot binding); mismatches are refused rather than bypassing contrast checks. --- Source: https://oods-foundry.com/guides/components [Guides](https://oods-foundry.com/guides) / Your own components # Your own components Map a shipped component to your own React or Vue component, and read its contract report. Generated from @oods/foundry 0.11.3 The guide below is the one the package ships, `COMPONENTS.md` in `@oods/foundry@0.11.3`, shown as written. ## Your own components OODS Foundry supports your own components by **substitution** in React and Vue. A mapping says which implementation replaces one shipped OODS Foundry component. Composition keeps using OODS Foundry's component ids and traits; generation imports your implementation, and the preview bundles it. New components beyond the shipped catalog are not supported. ### Map an implementation Install or unpack your component package outside the runtime. Give `component_map` a shipped component id (from `catalog_list`), its exact package version and export, and translations for any props whose names or values differ. For example: ```json { "action": "create", "apply": true, "externalSystem": "my-team", "externalComponent": "TeamButton", "oodsTraits": ["Stateful"], "substitution": { "component": "Button", "react": { "package": "@my-team/components/react", "version": "1.0.0", "export": "TeamButton", "localPath": "/absolute/path/to/my-team-components", "props": { "content": { "name": "caption" }, "intent": { "name": "appearance", "values": { "neutral": "quiet", "primary": "prominent", "danger": "danger" } } } } } } ``` Add a `vue` entry with the same shape for Vue. Untranslated props, children/slots and event handlers pass through. Set `passthrough: false` to drop unlisted optional props; every required OODS Foundry prop then needs a translation. An unknown OODS Foundry component or prop, or an uncovered required OODS Foundry prop, is reported before a mapping is saved. The team's component still has to implement the expected semantics; translating a name does not establish compatibility. The launcher defaults mappings to `~/.oods-foundry/mappings/component-mappings.json`. `OODS_MAPPINGS_DIR` selects another folder; the existing `MCP_MAPPINGS_PATH` selects a file and takes precedence. Team traits resolve from your trait folder. Mappings and local packages belong outside the unpacked runtime so upgrades and readiness checks leave them intact. `localPath` must be absolute and point at the package root. Without it the preview looks for an installed package. The package manifest's name/version must match, and its export must resolve. Local paths are not emitted into consumers. #### Map several at once A checked mapping file contains a `mappings` array. Each entry has the same fields as the single call above, without `action` or `apply`: ```json { "mappings": [ { "externalSystem": "my-team", "externalComponent": "TeamButton", "oodsTraits": ["Stateful"], "substitution": { "component": "Button", "react": { "package": "@my-team/components/react", "version": "1.0.0", "export": "TeamButton", "localPath": "/absolute/path/to/my-team-components", "props": { "content": { "name": "caption" } } } } } ] } ``` Call `component_map` once for the file: ```json {"action":"create","mappingsPath":"/absolute/path/to/mappings.json","apply":true} ``` You can instead pass the array as `mappings` in that call. Omit `apply` to check every entry without saving it. The response lists each entry's zero-based `index`, generated `id`, validation `status` and whether it was `applied`. All entries must pass before anything is written: mapping ids must be distinct; each shipped component can be substituted only once across the list and the existing store; all component and prop checks still apply. With `localPath`, the package manifest must match the package name and exact version, and its entry file must statically export the named identifier. OODS Foundry reads these files without running package scripts. An invalid entry is named with `OODS-V219`; no entry is saved. A valid list is saved in one atomic write. The package ships `quickstart/team-components/mappings.json`, the Harbor walkthrough's Button mapping in this file shape. Copy the example set to your workspace and replace both `` values with that folder's absolute path before calling `component_map`. The placeholder is documentation, not a path that the tool expands. Your own file uses your package names, exact versions, exports and prop translations. ### Compose, preview and generate Use `design_compose` or `design_preview` with your object as usual. Only components present in the screen are replaced. A preview records package content hashes and freezes compiled output per version; reopening an explicit version retains its original bytes. Opening the latest version after package bytes change creates a new version. Missing or unbundleable packages produce `OODS-V217`. Package CSS can be inlined, but external CSS assets, unsafe paths and symlinks are refused. `code_generate` imports the mapped package and declares its exact dependency version. Set `options.output` to `"application"` for a single screen with a package manifest, entry, HTML and Vite configuration. The default remains a component. Follow the response's install block: the `@oods` libraries install from npm at exact versions, and a team package from your registry, or from its own tarball or folder when it is not on one. Then run `npm run build` and `npm run dev`. No package is published by generation. Sample data is labelled, and actions needing your application show an integration notice; wire your data, navigation and persistence handlers before shipping. ### Draft adapters from a project `component_map` with `action: "draft"` and `source: {project: "", format: "shadcn"}` stores proposals for the copied components it can support. Inspect the draft with `component_map_read` `action: "show"`, then accept the reviewed proposal IDs with `component_map` `action: "apply"`. Drafting and applying both write; no `apply: true` parameter is needed for those actions. Before applying adapters, install the OODS libraries in the team project as well as its own dependencies. For React: ```bash npm install @oods/components-react@0.11.3 @oods/component-contracts@0.11.3 @oods/component-styles@0.11.3 @oods/tokens@0.11.3 ``` For Vue, replace `@oods/components-react` with `@oods/components-vue` at the same version. Connecting the MCP server alone does not install these project dependencies. A missing dependency is reported before any adapter is written. If the manifest changes after drafting, draft again before applying. ### shadcn/ui A React project using shadcn/ui's **Radix or Base UI base and Tailwind 4** can map its own copied components. Keep `components.json`, the TypeScript path aliases, the CSS entry, and the installed dependencies in the project. The base is read from `components.json`: supported bases are Radix (`radix-*`, legacy `new-york` and `default`) and Base UI (`base-*`). React Aria (`aria-*`) and unknown styles are refused at map creation with OODS-V219 naming the style found and these supported bases. Vue projects on shadcn-vue / Reka UI use the Vue adapters below. Start in an existing shadcn project. For a fresh trial, create the project first, in an empty working folder. This selects Vite with Radix: ```bash npx shadcn@4.21.1 init --template vite --base radix --preset nova --name team-app --no-monorepo --no-rtl -y cd team-app ``` Or use the CLI's defaults, Next.js with Base UI: ```bash npx shadcn@4.21.1 init --defaults --name team-app --no-monorepo -y cd team-app ``` From the shadcn project, install OODS Foundry locally. Connecting the MCP server with `npx` does not install a package into that project, and the next command needs its registry files: ```bash npm install @oods/foundry@0.11.3 ``` Install the sixteen adapters from that package in one call: ```bash npx shadcn@4.21.1 add ./node_modules/@oods/foundry/shadcn/oods-button.json ./node_modules/@oods/foundry/shadcn/oods-card.json ./node_modules/@oods/foundry/shadcn/oods-status-badge.json ./node_modules/@oods/foundry/shadcn/oods-tabs.json ./node_modules/@oods/foundry/shadcn/oods-select.json ./node_modules/@oods/foundry/shadcn/oods-search-input.json ./node_modules/@oods/foundry/shadcn/oods-pagination-bar.json ./node_modules/@oods/foundry/shadcn/oods-banner.json ./node_modules/@oods/foundry/shadcn/oods-input.json ./node_modules/@oods/foundry/shadcn/oods-textarea.json ./node_modules/@oods/foundry/shadcn/oods-checkbox.json ./node_modules/@oods/foundry/shadcn/oods-date-picker.json ./node_modules/@oods/foundry/shadcn/oods-tag-input.json ./node_modules/@oods/foundry/shadcn/oods-status-selector.json ./node_modules/@oods/foundry/shadcn/oods-card-header.json ./node_modules/@oods/foundry/shadcn/oods-price-badge.json -y ``` Copy `shadcn/mappings.json` from that package into your workspace: ```bash cp node_modules/@oods/foundry/shadcn/mappings.json ./oods-mappings.json ``` Replace every `` in the copied file with your project's absolute path. If the project's component alias differs from `@/components`, edit the sixteen `module` values to match the paths the CLI wrote. Apply the file in one call, substituting the copied file's absolute path: ```json {"action":"create","mappingsPath":"/absolute/path/to/team-app/oods-mappings.json","apply":true} ``` Each React implementation uses this source form instead of `package`, `version` and `localPath`: ```json {"shadcn":{"project":"/absolute/path/to/team-app","module":"@/components/oods/button"},"export":"OodsButton"} ``` Create and substitution-changing updates check the named export, local imports, aliases, CSS entry, Tailwind version and installed bare dependencies without executing the component. Dependencies resolve from the importing file, through the project’s installed package layout. Tailwind 4 accepts either @tailwindcss/vite or @tailwindcss/postcss. Updating only notes, confidence or oodsTraits does not need the source project. Use `design_compose`, `design_preview` and `code_generate` as above. Preview compiles the project's Tailwind and theme; changes to mapped source files, their imports, configuration or CSS create a new latest version. Unrelated project files do not. Explicit old versions retain their compiled output. Component output imports the project's module. React output begins with `'use client'`, so Next.js App Router can mount it. Place its files in the project, supply its declared props and action callbacks, and set the surrounding container's `data-brand` and `data-theme` for the chosen OODS brand and theme. For dark, that ancestor needs both `data-theme="dark"` and `class="dark"`. In hc the team's parts keep their light palette because shadcn has no hc theme. Application output remains a Vite application, including when the source project uses Next.js. It copies the needed source files, local assets and CSS, configures aliases and Tailwind, and pins dependencies to their installed versions. The emitted metadata records the base and style, project-relative paths and closure hashes, with no absolute project path. React and Vue mappings apply to their own framework. Single-screen and routed workflow applications both copy the checked source closure. HTML keeps OODS components; a mapping missing the requested framework reports `OODS-V218`. See [BRANDS.md](https://cdn.jsdelivr.net/npm/@oods/foundry@0.11.3/./BRANDS.md) to derive an OODS brand from the same CSS theme. The proven project layouts are npm + Vite, pnpm's isolated linker + Vite, a hoisted npm workspace, and npm + Next.js App Router, measured on 0.6.0. The two committed fixtures use shadcn CLI 4.21.1: Vite with Radix and Next.js with Base UI. Their generated screens pass each project's own production build, measured on 0.7.0. Yarn PnP, Bun and a Turbopack-only development server are not proven. CSS derivation reports font gaps when Next.js supplies the font variables through `next/font`. Fill those recipe fields from your project's declared font families before creating the brand. Generated Vite apps copy CSS-referenced local assets; they do not copy font assets generated by the Next.js build. #### From the mapped project to a running screen Keep these calls in the same MCP session. The CSS entry is `tailwind.css` in your project's `components.json` (the Vite example uses `src/index.css`; the Next.js example uses `app/globals.css`). Call `brand_read` with its absolute path: ```json {"action":"derive","cssPath":"/absolute/path/to/team-app/src/index.css"} ``` Read `gaps` and complete the returned `recipe` with your team's choices before `brand_read` `validate` and `brand_create` `create`, as [BRANDS.md](https://cdn.jsdelivr.net/npm/@oods/foundry@0.11.3/./BRANDS.md) describes. A neutral shadcn theme has no accent hue to derive: choose one explicitly. For a trial, `accentHue: 262` is an example choice, not a colour inferred from that theme. A default Next.js project declares Geist and Geist Mono in `app/layout.tsx`; those family names can fill its font gaps. Replace `` below with the complete JSON object, not a string, and choose an unused brand id: ```json {"action":"validate","brand_id":"Teambrand","recipe":""} ``` After `valid: true`, call `brand_create` to create it: ```json {"action":"create","brand_id":"Teambrand","recipe":""} ``` Call `design_compose` for a shipped object, for example the Plan form, and retain its `compositionId`, `version` and `schemaRef`: ```json {"object":"Plan","context":"form","preferences":{"brand":"Teambrand","theme":"light"}} ``` Call `design_preview`, substituting that id and version, then open its React `appUrl`: ```json {"compositionId":"","version":1,"framework":"react"} ``` Call `code_generate` with the returned schema reference: ```json {"schemaRef":"","framework":"react","profile":"build","options":{"output":"application","brand":"Teambrand","theme":"light","payloadMode":"file"}} ``` Copy the files from `payload.directory` into a fresh app folder. They include the mapped source, CSS, assets and exact dependency versions. From that folder, run: ```bash npm install npm run build npm run dev ``` Open the local URL Vite prints and compare it with the preview. This is a Vite app even when the mapped source project is Next.js. To integrate a component into the original project instead, use component output and the props and action contract described above. The adapters preserve the data-driven OODS props. They use `data-oods-adapter` markers so OODS component CSS does not override the team's shadcn styles. The contract report still lists each obligation as met, unmet or not checked, with a reason; the adapter is not a claim of complete component equivalence. These differences are also named in each registry item's description: | Adapter | Explicit limits | | - | - | | Button | Danger/destructive uses solid `bg-destructive text-background`, including hover and dark, from the team's own tokens. Primary preserves the team's `primary`/`primary-foreground` token pair. Success and warning intents use the secondary variant; there are no separate success/warning palettes. | | Card | A semantic `as` element wraps the shadcn Card. | | StatusBadge | OODS supplies status labels and icons. Critical/danger uses destructive with solid `bg-destructive text-background` in light and dark; other tones use default or secondary, without separate status colours. `compact` and `readOnly` retain OODS's no-op behavior. | | Tabs | The list scrolls horizontally; `overflowLabel` and the OODS overflow menu are not implemented. | | Select | The visible control is a shadcn combobox. A hidden native select keeps form values and native change events. Use `options`; native option children, `multiple`, native `size` and native-select keyboard behavior are unsupported. | | SearchInput | Value, debounce, minimum query length and clear events retain their meanings. | | PaginationBar | Page links are anchors; disabled links prevent navigation and leave the tab order. | | Banner | Critical/danger uses solid `bg-destructive text-background`; its description inherits the foreground. Other tones use the team's default Alert palette; separate success/warning/info colours and solid emphasis are unsupported. | | Input | Native input props, datetime-local normalization, label, help, validation and value callbacks keep their meanings; density uses team spacing rather than OODS pixel dimensions. | | Textarea | Native textarea props, the four-row default, label, help, validation and value callbacks keep their meanings; density uses team spacing rather than OODS pixel dimensions. | | Checkbox | The team checkbox is visible. A visually hidden native checkbox preserves the input ref, native onChange and form values. Other native input event handlers apply to that hidden input; density is metadata only. | | DatePicker | A native date input plus the team's Calendar, Popover and Button keeps min, max, step, disabled and readOnly. pickerClassName and pickerStyle apply to the native input; density is metadata only. | | TagInput | Keeps text-value callbacks and the displayed tag list, including record labels and authored children. The OODS contract does not create or remove tags, so the adapter adds no tag mutation API. | | StatusSelector | Keeps status/value, normalized options/states, authored children, help and native change callbacks. Keyboard interaction follows the team's combobox instead of a native select. | | CardHeader | Keeps the semantic header, heading level/as, title aliases, scalar/authored children and supporting copy without duplication. The team CardTitle and CardDescription supply the visual parts. | | PriceBadge | Keeps amount/currency precedence, currency minor units, label/children/value fallback and emphasis. Binding metadata props field, amountField, currencyField, intervalField and minorUnitsParameter retain OODS's no-op behavior. | The sixteen adapters cover every generated-screen primitive with a direct shadcn counterpart in the 0.5.0 census of 60 screens: the 11 shipped business objects and the Warehouse example object, each in detail, list, form, timeline and card. Stack, Text, DetailHeader, RelativeTimestamp, StatusTimeline, LabelCell and TimelineEntryLabel stay OODS because they have no direct shadcn counterpart. Trait panels and editors also stay OODS: substitution replaces a component imported by the generated screen, not the components used inside an OODS panel. ### What the report means Mapped components carry `component-contracts.json` in the generated artifact and reports in the preview's Measurements. OODS Foundry runs its shared scenarios through the actual generated prop adapter when a browser is available to the preview host. It uses an installed Chromium browser, `OODS_CONTRACT_BROWSER_EXECUTABLE`, or `OODS_PLAYWRIGHT_WS_ENDPOINT`; it does not download a browser. Every declared obligation is **met**, **unmet** or **not checked**, with a reason. Unsupported probes and unavailable browsers remain not checked. Warnings (`OODS-V218`) are advisory and do not refuse generation. A passing subset is not full compatibility, accessibility certification or a claim about every state of a component. A run of the npm package, measured on 0.10.0, covers the bundled test team's Button and StatusBadge in Warehouse screens in both frameworks and three themes. Separate browser checks, measured on 0.2.1, cover its Input and deliberately broken Button. Material UI, Ant Design and Chakra UI are not proven by these fixtures; a library needs its own adapter and its own proof. ### Draft mappings from local files `component_map` can inventory a shadcn project or a built Storybook without running its code, resolving installed dependencies, or fetching anything. Supply an absolute project folder; every source path must stay inside it. JSONC TypeScript paths and project-relative config inheritance are read statically. A Nuxt layout needs its generated paths present inside the supplied folder. Symbolic links in source files are refused. ```json {"action":"draft","source":{"format":"shadcn","project":"/absolute/team-app"},"externalSystem":"team"} ``` The reply gives a `draftId`, source content hash, mapping proposals, counts and warnings. Call `show` with that id to review every component, prop and story, each either proposed or unmatched with a reason. Matching uses typed props, native elements, primitive imports and variant sets. A name alone never selects a contract. Imported/generic prop types that cannot be expanded from the defining file are retained as unmatched prop groups; individual members are not invented. Shadcn proposals stage the shipped adapter needed to translate the team's primitive into the OODS contract; `show` includes its exact contents and limitations. No team file or active mapping changes during drafting. Call `show`: ```json {"action":"show","draftId":"components-"} ``` Then call `apply` with the proposal ids you accept: ```json {"action":"apply","draftId":"components-","accept":["mapping-"]} ``` Accept exact proposal ids after review. Apply checks the source hashes again, writes only reviewed new adapter files, and runs the existing mapping validator against the installed project. Missing dependencies or any invalid mapping roll back the adapter files and leave the mapping store unchanged. Existing adapters with different contents are reported for manual review and never overwritten. A component keeps one mapping owner: a complementary React or Vue implementation can join that owner; an existing implementation requires an intentional `update` to replace it. For a built Storybook, use `{"format":"storybook","project":"/absolute/library","storybook":"storybook-static"}`. The reader inventories `index.json` and, when present, `manifests/components.json`, including React docgen source paths and props. Defining source files must be within the supplied project; absolute paths from another build machine, missing definitions and unsupported manifest shapes are reported. Names and docgen declarations without defining source remain inventory evidence. A structural match drafts a package substitution using the project's package name and version; apply verifies its built export. Storybook's manifest format is still in preview, so unmatched entries remain visible rather than being guessed. A draft is evidence for review, not behavioral conformance. Generate and preview the accepted mappings and read their existing contract reports. Component substitutions need no trait annotation; an empty `oodsTraits` list is accepted only when the mapping supplies a substitution. #### shadcn-vue / Reka UI Use `component_map` draft/apply and `component_map_read` show on the installed project as described above. The reader recognizes `https://shadcn-vue.com/schema.json` and the `typescript` flag, including `reka-*`, legacy `new-york` and `default` styles. Vue proposals use `.vue` modules with `export: "default"`; an accepted Vue proposal joins the same mapping that owns the React implementation. Review the full draft before accepting its proposal ids. The package ships the same sixteen adapters under `shadcn/vue/`. To install an item manually from your project: ```bash npx shadcn-vue@2.8.2 add ./node_modules/@oods/foundry/shadcn/vue/oods-button.json -y ``` Other item names match the React list. The Vue mapping template is `shadcn/vue/mappings.json`; replace `` and adjust aliases if needed. Do not create a second mapping for an OODS component already owned by a React mapping: the reviewed intake flow merges the complementary framework for you. Vue adapters preserve the shipped Vue model updates and emitted events. Their item descriptions state limits: Tabs scrolls instead of showing an overflow menu; Select/StatusSelector use Reka combobox interaction and preserve empty reset options, including their labels and empty submitted values; DatePicker uses the team's native date Input, matching the Vue contract; Checkbox uses Reka's checkbox button and boolean model events; TagInput does not create or remove tags. Vue text fields update their model on input and emit native change on commit/blur. Shared probes that require a native select/checkbox target or React's per-keystroke change semantics can report unmet obligations; inspect the report rather than treating mounting as full contract conformance. The team palette supplies noncritical status colours. Danger uses solid destructive/background tokens in both themes. The Vue layout proof covers npm + Vite, installed TypeScript, project-relative TypeScript aliases, and inline SFC scripts/templates with styles in `tailwind.css`. SFC `

Relationships: Article

Declared object associations · 2 edges · * required field. These are object types, not joined records.

Relationships: Article3 object types and 2 declared associations. Arrows point from source to target. Labels state source-relative cardinality and the via field; they do not assert live referential integrity. Article to Media: Hero media, many-to-one, via hero_media_id. Article to User: Author, many-to-one, via author_id.Hero mediamany-to-onevia hero_media_idAuthormany-to-onevia author_idCanonical editorial article with hybrid taxonomy + tag classification for CMS surfaces.ArticleTraits: Labelled, Stateful,Timestampable, ClassifiableKey fields (6 of 28)article_id: uuid *label: string *author_id: uuid *hero_media_id: stringbody_markdown: string *content_type: string *Canonical digital asset metadata powering media library, DAM, and CMS integrations.MediaTraits: Labelled, Stateful,Timestampable, ClassifiableKey fields (6 of 29)media_id: uuid *label: string *asset_type: string *file_size_bytes: number *mime_type: string *object_key: string *Canonical identity record representing a platform user across lifecycle contexts.UserTraits: Stateful, Timestampable,Taggable, Addressable, Preferenceable,Authable, CommunicableKey fields (6 of 37)user_id: uuid *name: string *primary_email: email *role: string *description: stringpreferred_name: string
", "svg": "Relationships: Article3 object types and 2 declared associations. Arrows point from source to target. Labels state source-relative cardinality and the via field; they do not assert live referential integrity. Article to Media: Hero media, many-to-one, via hero_media_id. Article to User: Author, many-to-one, via author_id.Hero mediamany-to-onevia hero_media_idAuthormany-to-onevia author_idCanonical editorial article with hybrid taxonomy + tag classification for CMS surfaces.ArticleTraits: Labelled, Stateful,Timestampable, ClassifiableKey fields (6 of 28)article_id: uuid *label: string *author_id: uuid *hero_media_id: stringbody_markdown: string *content_type: string *Canonical digital asset metadata powering media library, DAM, and CMS integrations.MediaTraits: Labelled, Stateful,Timestampable, ClassifiableKey fields (6 of 29)media_id: uuid *label: string *asset_type: string *file_size_bytes: number *mime_type: string *object_key: string *Canonical identity record representing a platform user across lifecycle contexts.UserTraits: Stateful, Timestampable,Taggable, Addressable, Preferenceable,Authable, CommunicableKey fields (6 of 37)user_id: uuid *name: string *primary_email: email *role: string *description: stringpreferred_name: string", "meta": { "entityCount": 3, "edgeCount": 2, "appliedBrandOverlay": "A", "theme": "light", "width": 788, "height": 697 }, "warnings": [], "errors": [] } ``` [The whole call, 12 KB of JSON](https://oods-foundry.com/tools/fidelity-preview/call.json) --- Source: https://oods-foundry.com/tools/health-check [Tools](https://oods-foundry.com/tools) / health_check # `health_check` Read server readiness, live registry/store counts and retained proof summaries. Generated from @oods/foundry 0.11.3 One of the 26 tools your assistant sees by default. Use it when checking availability and built brand/theme scopes; use object_registry for definitions or registry_snapshot for mappings. Returns status, server uptime, registry counts, token scopes and productReality evidence. status:ok means sources were readable; retained proofs identify their measured build and do not automatically certify this one. includeChangelog and sinceVersion filter the reported DSL changelog. tokens.defaultScope is configured metadata rather than an observed consumer scope; missing scope data is unavailable. Full schema: oods\://schemas/health_check.input.json. ## Inputs | Name | Type | Required | Description | | - | - | - | - | | `includeChangelog` | `boolean` | no | When true, include DSL version changelog in the response. | | `sinceVersion` | `string` | no | When provided with includeChangelog, only return changelog entries since this version. | ## Outputs | Name | Type | Required | Description | | - | - | - | - | | `productReality` | `object` | yes | Runtime, portable release, tool and visualization evidence summaries. Release identifies the measured bundle archive and 42 reference-application cells with artifact parity to the host; unavailable ledgers are null. | | `status` | `"ok" \| "degraded"` | yes | | | `server` | `object` | yes | | | `registry` | `object` | yes | | | `tokens` | `object` | yes | | | `schemas` | `object` | yes | | | `latency` | `integer` | yes | | | `warnings` | `string[]` | no | | | `dslVersion` | `string` | no | Current DSL version of this server. | | `changelog` | `object[]` | no | DSL version changelog entries, included when requested via includeChangelog input. | ## A real call Recorded by this site's `harbor` run, step `health`, with the published OODS Foundry 0.11.3. Its input: ``` {} ``` Its result, first lines: ``` { "status": "ok", "server": { "version": "0.11.3", "uptime": 775 }, "registry": { "components": 114, "traits": 49, "objects": 16, "lastSync": "2026-10-10T03:40:00Z", "countsFrom": { "components": "live", "objects": "live", "traits": "live" }, "definitions": { "folders": { "objects": "~/.oods-foundry/objects", "traits": "~/.oods-foundry/traits" }, "objects": { "total": 16, "shipped": 16, "user": 0, "replacingShipped": [] }, "traits": { "total": 49, "shipped": 49, "user": 0 }, "issues": [] } }, "tokens": { "built": true, "brands": [ "A", "B" ], "themes": [ "dark", "hc", "light" ], "scopes": { "A": [ "dark", "hc", "light" ], "B": [ "dark", "hc", "light" ] }, "defaultScope": { "brand": "A", ``` [The whole call, 5 KB of JSON](https://oods-foundry.com/tools/health-check/call.json) --- Source: https://oods-foundry.com/tools/object-import [Tools](https://oods-foundry.com/tools) / object_import # `object_import` Draft objects from local OpenAPI, JSON Schema, Postgres SQL, Prisma, dbt, OData or GraphQL files, then apply accepted proposals. Generated from @oods/foundry 0.11.3 One of the 26 tools your assistant sees by default. Use it when importing a schema; use object_import_read to review a staged object. Returns importId, staged files, proposal counts and re-import differences, or batch registration results. draft takes source.path or source.content; apply requires explicit objects and proposal ids. overwrite replaces team objects; confirmShipped names approved shipped replacements. No network fetch or code execution. Full schema: oods\://schemas/object_import.input.json. ## Inputs | Name | Type | Required | Description | | - | - | - | - | | `action` | `"draft" \| "apply"` | yes | Choose draft, apply. | | `source` | `object` | no | Local file/folder or inline schema. Used only by draft. | | `importId` | `string` | no | Content-addressed import id from draft. Required by show and apply. | | `objects` | `object[]` | no | Explicit accepted object names and optional proposal ids for apply. | | `overwrite` | `boolean` | no | Allow replacing existing team objects. | | `confirmShipped` | `string[]` | no | Each shipped object name whose replacement is explicitly confirmed. | ## Outputs: draft | Name | Type | Required | Description | | - | - | - | - | | `action` | `"draft"` | yes | | | `importId` | `string` | yes | | | `directory` | `string` | yes | | | `contentHash` | `string` | yes | | | `counts` | `object` | yes | | | `objectCount` | `integer` | yes | | | `objects` | `string[]` | yes | | | `objectsTruncated` | `boolean` | yes | | | `shippedClashes` | `string[]` | yes | | | `diff` | `object` | yes | | | `proposalGrades` | `object` | yes | | | `cycleCount` | `integer` | yes | | | `files` | `object` | yes | | | `proposalTraits` | `object` | no | | ## Outputs: show | Name | Type | Required | Description | | - | - | - | - | | `action` | `"show"` | yes | | | `importId` | `string` | yes | | | `name` | `string` | yes | | | `yaml` | `string` | yes | | | `proposals` | `object[]` | yes | | | `unmapped` | `object[]` | yes | | | `diff` | `object` | yes | | ## Outputs: apply | Name | Type | Required | Description | | - | - | - | - | | `action` | `"apply"` | yes | | | `importId` | `string` | yes | | | `count` | `integer` | yes | | | `applied` | `object[]` | yes | | ## A real call Recorded by this site's `tools` run, step `object-import-draft`, with the published OODS Foundry 0.11.3. Its input: ``` { "action": "draft", "source": { "path": "/object-import/petstore.yaml" } } ``` Its result: ``` { "action": "draft", "importId": "import-9b81d91c8453593c6acffa0af9d2d7ac36590eeb9230fe43200055cf1cc1628c", "directory": "~/.oods-foundry/imports/import-9b81d91c8453593c6acffa0af9d2d7ac36590eeb9230fe43200055cf1cc1628c", "contentHash": "sha256:380789f6757c66ca7a800f731767211ec663da702a3e851aef3980557bbef246", "counts": { "total": 55, "mapped": 32, "proposed": 0, "unmapped": 23, "fields": 5, "mappedFields": 5 }, "objectCount": 7, "objects": [ "Error", "Operation27023d0e7d", "Operation4d740bf4c2", "Operation4deff75316", "Operation68547e2036", "Operationc343d75736", "Pet" ], "objectsTruncated": false, "shippedClashes": [], "diff": { "new": 7, "changed": 0, "unchanged": 0, "file": "~/.oods-foundry/imports/import-9b81d91c8453593c6acffa0af9d2d7ac36590eeb9230fe43200055cf1cc1628c/diff.json" }, "proposalTraits": {}, "proposalGrades": { "strong": 0, "medium": 0, "weak": 0 }, "cycleCount": 0, "files": { "hub": "hub.json", "report": "report.json", "order": "order.json", "objects": "objects/" } } ``` [The whole call, 1 KB of JSON](https://oods-foundry.com/tools/object-import/call.json) --- Source: https://oods-foundry.com/tools/object-import-read [Tools](https://oods-foundry.com/tools) / object_import_read # `object_import_read` Read one staged object import. Generated from @oods/foundry 0.11.3 One of the 26 tools your assistant sees by default. Use it when reviewing YAML, graded proposals and unmapped elements before acceptance; use object_import to draft or apply. Returns the named object, proposals and differences from its registered definition. Supply importId and the exact object name. Reading never rewrites the staged report. Full schema: oods\://schemas/object_import_read.input.json. ## Inputs | Name | Type | Required | Description | | - | - | - | - | | `action` | `"show"` | yes | Choose show. | | `importId` | `string` | no | Content-addressed import id from draft. Required by show and apply. | | `object` | `string` | no | Exact draft object name for show. | ## Outputs: draft | Name | Type | Required | Description | | - | - | - | - | | `action` | `"draft"` | yes | | | `importId` | `string` | yes | | | `directory` | `string` | yes | | | `contentHash` | `string` | yes | | | `counts` | `object` | yes | | | `objectCount` | `integer` | yes | | | `objects` | `string[]` | yes | | | `objectsTruncated` | `boolean` | yes | | | `shippedClashes` | `string[]` | yes | | | `diff` | `object` | yes | | | `proposalGrades` | `object` | yes | | | `cycleCount` | `integer` | yes | | | `files` | `object` | yes | | | `proposalTraits` | `object` | no | | ## Outputs: show | Name | Type | Required | Description | | - | - | - | - | | `action` | `"show"` | yes | | | `importId` | `string` | yes | | | `name` | `string` | yes | | | `yaml` | `string` | yes | | | `proposals` | `object[]` | yes | | | `unmapped` | `object[]` | yes | | | `diff` | `object` | yes | | ## Outputs: apply | Name | Type | Required | Description | | - | - | - | - | | `action` | `"apply"` | yes | | | `importId` | `string` | yes | | | `count` | `integer` | yes | | | `applied` | `object[]` | yes | | ## A real call Recorded by this site's `tools` run, step `object-import-show`, with the published OODS Foundry 0.11.3. Its input: ``` { "action": "show", "importId": "import-9b81d91c8453593c6acffa0af9d2d7ac36590eeb9230fe43200055cf1cc1628c", "object": "Error" } ``` Its result: ``` { "action": "show", "importId": "import-9b81d91c8453593c6acffa0af9d2d7ac36590eeb9230fe43200055cf1cc1628c", "name": "Error", "yaml": "metadata:\n references:\n - petstore.yaml#/components/schemas/Error\n supportedContexts:\n - list\n - detail\n - form\nobject:\n description: Imported Error schema. Samples without source examples are illustrative.\n domain: imported\n name: Error\n version: 1.0.0\nrelationships: []\nsamples:\n - code: 1\n message: Message 1\n - code: 2\n message: Message 2\n - code: 3\n message: Message 3\n - code: 4\n message: Message 4\n - code: 5\n message: Message 5\nschema:\n code:\n description: ''\n required: true\n type: integer\n validation:\n format: int32\n message:\n description: ''\n required: true\n type: string\nsemantics:\n message:\n semantic_type: text.label\n token_mapping: tokenMap(text.primary)\ntokens: {}\ntraits: []\n", "proposals": [], "unmapped": [], "diff": { "name": "Error", "status": "new", "fields": { "added": [ "code", "message" ], "removed": [], "changed": [] }, "screens": [ "list", "detail", "form" ], "traitsChanged": false, "relationshipsChanged": false } } ``` [The whole call, 2 KB of JSON](https://oods-foundry.com/tools/object-import-read/call.json) --- Source: https://oods-foundry.com/tools/object-register [Tools](https://oods-foundry.com/tools) / object_register # `object_register` Register an object or trait from reviewed YAML. Generated from @oods/foundry 0.11.3 One of the 26 tools your assistant sees by default. Use it when saving a definition; use object_registry to list, inspect or validate without writing. Returns the saved definition and registry result. overwrite replaces your own definition. Team objects may shadow shipped objects; traits cannot reuse shipped names. Relationships must name valid targets and fields. Full schema: oods\://schemas/object_register.input.json. ## Inputs | Name | Type | Required | Description | | - | - | - | - | | `action` | `"register"` | yes | Choose register. | | `yaml` | `string` | no | The whole definition as YAML: an object file starts with "object:", a trait file with "trait:" (the same format as OODS Foundry's own objects/ and traits/). Actions: register (required). See full schema for details. | | `overwrite` | `boolean` | no | Replace a definition of yours with this name; without it a name you already registered is refused (OODS-C004). Actions: register. | ## Outputs The package ships no output schema for this tool. ## A real call Recorded by this site's `harbor` run, step `trait-register`, with the published OODS Foundry 0.11.3. Its input: ``` { "action": "register", "yaml": "trait:\n name: Stockable\n version: 1.0.0\n description: How full a storage location is, counted in the unit the team stores goods in.\n category: inventory\n tags:\n - inventory\n - capacity\n\nparameters:\n - name: capacityUnit\n type: string\n required: false\n description: The unit capacity and stock are counted in.\n default: pallets\n\nschema:\n stock_level:\n type: string\n required: true\n description: Whether the location has room, is nearly full, or is full.\n validation:\n enum:\n - room_available\n - nearly_full\n - full\n capacity_units:\n type: integer\n required: true\n description: How many units the location holds when it is full.\n examples:\n - 1200\n - 800\n - 2400\n units_on_hand:\n type: integer\n required: true\n description: How many units are stored there now.\n examples:\n - 640\n - 760\n - 2400\n\nsemantics:\n stock_level:\n semantic_type: inventory.stock.level\n token_mapping: tokenMap(inventory.stock.*)\n ui_hints:\n component: StatusBadge\n\nview_extensions:\n list:\n - component: StatusBadge\n position: after\n props:\n statusField: stock_level\n emphasis: subtle\n showIcon: false\n card:\n - component: StatusBadge\n position: after\n props:\n statusField: stock_level\n emphasis: subtle\n showIcon: false\n detail:\n - component: StatusBadge\n position: main\n priority: 70\n props:\n statusField: stock_level\n emphasis: subtle\n showIcon: false\n # Like the shipped Supersedable trait: the fields the trait is about are placed explicitly, so the detail\n # composer's field budget never leaves them out.\n - component: Text\n position: main\n priority: 69\n props:\n field: units_on_hand\n - component: Text\n position: main\n priority: 68\n props:\n field: capacity_units\n\ntokens:\n inventory.stock.tone: neutral\n\ndependencies: []\n" } ``` Its result: ``` { "kind": "trait", "name": "Stockable", "file": "~/.oods-foundry/traits/Stockable.trait.yaml", "status": "created", "contexts": [], "warnings": [], "registry": { "folders": { "objects": "~/.oods-foundry/objects", "traits": "~/.oods-foundry/traits" }, "objects": { "total": 16, "shipped": 16, "user": 0, "replacingShipped": [] }, "traits": { "total": 50, "shipped": 49, "user": 1 }, "issues": [] } } ``` [The whole call, 3 KB of JSON](https://oods-foundry.com/tools/object-register/call.json) --- Source: https://oods-foundry.com/tools/object-registry [Tools](https://oods-foundry.com/tools) / object_registry # `object_registry` Read object and trait definitions or validate YAML without saving. Generated from @oods/foundry 0.11.3 One of the 26 tools your assistant sees by default. Use it when exploring shapes or checking a definition; use object_register to save one or object_import to draft from a schema file. Returns definitions, composed traits, validation findings or cache reload status. includeInternal reveals hidden objects; reload clears only process caches. Full schema: oods\://schemas/object_registry.input.json. ## Inputs | Name | Type | Required | Description | | - | - | - | - | | `action` | `"list" \| "show" \| "validate" \| "reload"` | yes | Choose list, show, validate, reload. | | `domain` | `string` | no | Filter to objects in a specific domain (e.g. 'core.identity', 'saas.billing'). Actions: list. | | `maturity` | `"draft" \| "alpha" \| "beta" \| "stable"` | no | Filter by metadata maturity level. Actions: list. | | `trait` | `string` | no | Filter to objects composing a given trait (e.g. 'Priceable', 'lifecycle/Stateful'). Actions: list. | | `includeInternal` | `boolean` | no | Also list OODS Foundry's internal (non-business) objects, after the business objects. Without it they are left out and hiddenInternal counts them. Actions: list. | | `name` | `string` | no | Object name to look up (e.g. 'User', 'Product', 'Invoice'). Actions: show (required). | | `context` | `string` | no | Optional: filter view_extensions to a single context (e.g. 'detail', 'list', 'form', 'timeline', 'card', 'inline'). Actions: show. | | `yaml` | `string` | no | The whole definition as YAML: an object file starts with "object:", a trait file with "trait:" (the same format as OODS Foundry's own objects/ and traits/). Actions: validate (required). See full schema for details. | ## Outputs The package ships no output schema for this tool. ## A real call Recorded by this site's `harbor` run, step `trait-validate`, with the published OODS Foundry 0.11.3. Its input: ``` { "action": "validate", "yaml": "trait:\n name: Stockable\n version: 1.0.0\n description: How full a storage location is, counted in the unit the team stores goods in.\n category: inventory\n tags:\n - inventory\n - capacity\n\nparameters:\n - name: capacityUnit\n type: string\n required: false\n description: The unit capacity and stock are counted in.\n default: pallets\n\nschema:\n stock_level:\n type: string\n required: true\n description: Whether the location has room, is nearly full, or is full.\n validation:\n enum:\n - room_available\n - nearly_full\n - full\n capacity_units:\n type: integer\n required: true\n description: How many units the location holds when it is full.\n examples:\n - 1200\n - 800\n - 2400\n units_on_hand:\n type: integer\n required: true\n description: How many units are stored there now.\n examples:\n - 640\n - 760\n - 2400\n\nsemantics:\n stock_level:\n semantic_type: inventory.stock.level\n token_mapping: tokenMap(inventory.stock.*)\n ui_hints:\n component: StatusBadge\n\nview_extensions:\n list:\n - component: StatusBadge\n position: after\n props:\n statusField: stock_level\n emphasis: subtle\n showIcon: false\n card:\n - component: StatusBadge\n position: after\n props:\n statusField: stock_level\n emphasis: subtle\n showIcon: false\n detail:\n - component: StatusBadge\n position: main\n priority: 70\n props:\n statusField: stock_level\n emphasis: subtle\n showIcon: false\n # Like the shipped Supersedable trait: the fields the trait is about are placed explicitly, so the detail\n # composer's field budget never leaves them out.\n - component: Text\n position: main\n priority: 69\n props:\n field: units_on_hand\n - component: Text\n position: main\n priority: 68\n props:\n field: capacity_units\n\ntokens:\n inventory.stock.tone: neutral\n\ndependencies: []\n" } ``` Its result: ``` { "kind": "trait", "name": "Stockable", "valid": true, "errors": [], "warnings": [], "contexts": [ "list", "card", "detail" ], "folder": "~/.oods-foundry/traits" } ``` [The whole call, 2 KB of JSON](https://oods-foundry.com/tools/object-registry/call.json) --- Source: https://oods-foundry.com/tools/pipeline-run [Tools](https://oods-foundry.com/tools) / pipeline_run # `pipeline_run` Run composition, validation, rendering and code generation in one call. Generated from @oods/foundry 0.11.3 One of the 26 tools your assistant sees by default. Use it when starting from an object/context or intent and needing generated output; use design_compose instead to inspect layout first or code_generate for an existing schema. Returns step results, schemaRef with expiry, versioned artifacts, dependencies and validationReceipt. options controls validation/render skipping and optional static accessibility checks; save persists the schema beyond its process-local 30-minute reference. Generation validation forwards draft/build/release without downgrade. Release verifies supplied evidence without rerunning it; unresolved accessibility pairs stay unmeasured. Oversized output goes to files unless options.payloadMode is inline. Calls may write composition and saved-schema records. Full schema: oods\://schemas/pipeline_run.input.json. ## Inputs | Name | Type | Required | Description | | - | - | - | - | | `object` | `string` | no | Object name from the OODS registry (e.g., Subscription, User). | | `intent` | `string` | no | A short intent sentence, matched against fixed keyword and phrase tables (a sentence that matches no layout keyword becomes a low-confidence dashboard). Prefer object and context. | | `context` | `"detail" \| "list" \| "form" \| "timeline" \| "card" \| "inline" \| "workflow"` | no | View context for object-aware composition. | | `layout` | `"dashboard" \| "form" \| "detail" \| "list" \| "card" \| "timeline" \| "landing" \| "auto"` | no | Layout template. 'landing' is a content page (hero, sections, call to action) bound to no object; 'auto' picks one from the intent. | | `preferences` | `object` | no | Layout and appearance preferences. | | `actionMappings` | `object[]` | no | action mappings: flat, verb-keyed entries. | | `framework` | `"react" \| "vue" \| "html"` | no | Target framework for code generation. | | `styling` | `"inline" \| "tokens" \| "tailwind"` | no | Styling strategy for code generation. | | `profile` | `"draft" \| "build" \| "release"` | no | Validation profile passed to code_generate. build, the default, blocks on static checks; static checks do not install or run the generated app. | | `releaseEvidence` | `object` | no | Hash-bound release evidence forwarded unchanged to code_generate. | | `save` | `string \| object` | no | Optional schema save config. String for name-only, or { name, tags } for full control. Variant fields: name, tags. Read the full schema for each variant. | | `options` | `object` | no | Operation options. | ## Outputs | Name | Type | Required | Description | | - | - | - | - | | `payload` | `object` | no | The rendered page and the generated files, written to disk instead of returned (payloadMode). | | `warnings` | `object[]` | no | Notices about the reply, such as OODS-W004 when the page and the generated files were written to files because they were too large to return. | | `validationReceipt` | `validationReceipt` | yes | Mandatory generation-profile disclosure. Pipeline preserves code_generate checks and accepted caller-supplied evidence envelopes, verifies the child receipt against the requested profile and artifact, and records target resolution provenance. | | `schemaRef` | `string` | no | Schema reference returned by compose, reusable across tools. | | `schemaRefCreatedAt` | `string` | no | ISO timestamp when the schemaRef was created. | | `schemaRefExpiresAt` | `string` | no | ISO timestamp when the schemaRef expires. Save it with the schema tool (action: save) to keep it past expiry. | | `schemaRefTtlWarning` | `object` | no | Proactive warning when schemaRef TTL is approaching expiration (< 5 minutes remaining). | | `compose` | `object` | yes | | | `validation` | `object` | no | | | `render` | `object` | no | | | `code` | `object` | no | | | `saved` | `object` | no | | | `summary` | `string` | no | One-line natural language description of what was generated. | | `metrics` | `object` | no | Quality metrics for the pipeline output. | | `pipeline` | `object` | yes | | | `error` | `object` | no | | ## A real call Recorded by this site's `tools` run, step `pipeline`, with the published OODS Foundry 0.11.3. Its input: ``` { "object": "User", "context": "detail", "framework": "react" } ``` Its result, first lines: ``` { "validationReceipt": { "profile": "build", "defaulted": true, "rationale": "Build is the default blocking gate: target, bindings, dependencies and fallbacks must resolve under static checks; the static gate does not install or run the generated application.", "axes": { "scope": "generated-artifact", "enforcement": "blocking", "fallback": "forbidden", "target": { "requested": "react", "resolved": "react", "source": "explicit" } }, "checks": [ "schema-structure", "component-registry", "state-contract", "target-readiness", "normalization-fidelity", "binding-contract", "props-contract", "slots-contract", "events-contract", "dependency-closure" ], "notChecked": [ "fallback-policy", "rendered-evidence", "interaction-evidence", "accessibility-evidence", "theme-evidence", "determinism-evidence", "performance-evidence", "certification-evidence" ], "evidence": { "required": [], "provided": [], "missing": [], "mismatched": [], "accepted": [], "notApplicable": [], "artifactContentHash": "sha256:2367b6a15e30984625b483e2399f99b32c4159840785f3a5f47109ea4f2ecac0" } }, "compose": { "object": "User", "context": "detail", "layout": "detail", "componentCount": 12 }, "pipeline": { "steps": [ "compose", "validate", "render", "codegen" ], ``` [The whole call, 5 KB of JSON](https://oods-foundry.com/tools/pipeline-run/call.json) --- Source: https://oods-foundry.com/tools/registry-snapshot [Tools](https://oods-foundry.com/tools) / registry_snapshot # `registry_snapshot` Read mappings together with active traits and objects in one snapshot. Generated from @oods/foundry 0.11.3 One of the 26 tools your assistant sees by default. Use it when reading combined registry data; object_registry reads one definition and object_register saves one. Returns mappings, traits, objects, generatedAt, ETag and registry loader issues. Defaults to a summary; detail full adds schemas. includeInternal exposes hidden objects; otherwise hiddenInternal counts omitted entries. Team definitions and shadowing are reported from live sources. This read-only call writes no snapshot file. Historical mapping fields remain stored data and do not imply current capabilities. Full schema: oods\://schemas/registry_snapshot.input.json. ## Inputs | Name | Type | Required | Description | | - | - | - | - | | `includeInternal` | `boolean` | no | Also list OODS Foundry's internal (non-business) objects, after the business objects. Without it they are left out and registry.hiddenInternal counts them. | | `detail` | `"summary" \| "full"` | no | summary (default), or full definitions, best with names. | | `names` | `string[]` | no | Exact trait and object names; misses go in notFound. | ## Outputs | Name | Type | Required | Description | | - | - | - | - | | `registry` | `object` | no | Live object and trait names, source and any unused/shadowed definitions. | | `maps` | `object[]` | yes | | | `traits` | `object` | yes | | | `objects` | `object` | yes | | | `etag` | `string` | yes | | | `detail` | `"summary" \| "full"` | no | The detail level of traits and objects in this snapshot. | | `notFound` | `string[]` | no | Requested names that match no trait or object. | | `generatedAt` | `string` | yes | | ## A real call Recorded by this site's `system` run, step `registry-snapshot`, with the published OODS Foundry 0.11.3. Its input: ``` { "detail": "full" } ``` Its result, first lines: ``` { "maps": [], "traits": { "Addressable": { "name": "Addressable", "version": "1.0.0", "description": "Canonical multi-role address trait with validation metadata, geocoding, and international formatting hooks.\nProvides a single, reusable capability for billing, shipping, warehouse, and office addresses.", "category": "core", "tags": [ "address", "location", "validation", "delivery" ], "contexts": [ "detail", "form", "list" ], "viewExtensions": [ { "component": "AddressSummaryBadge", "context": "list", "position": "after", "priority": null, "props": { "field": "default_address_role" } }, { "component": "AddressCollectionPanel", "context": "detail", "position": "main", "priority": 60, "props": { "field": "addresses", "roleField": "address_roles", "defaultRoleField": "default_address_role", "roleParameter": "roles" } }, { "component": "AddressEditor", "context": "form", "position": "top", "priority": null, "props": { "field": "addresses", "roleParameter": "roles", "allowDynamicParameter": "allowDynamicRoles", "defaultRoleField": "default_address_role" } } ], "parameters": [ { "name": "roles", "type": "string[]", "required": true, "description": "Ordered list of supported address roles (billing, shipping, warehouse, etc.).", ``` [The whole call, 424 KB of JSON](https://oods-foundry.com/tools/registry-snapshot/call.json) --- Source: https://oods-foundry.com/tools/schema-read [Tools](https://oods-foundry.com/tools) / schema_read # `schema_read` Read saved composition schemas. Generated from @oods/foundry 0.11.3 One of the 26 tools your assistant sees by default. Use it when listing saved work or loading a named schema; use schema_store to save or delete one. Returns metadata or the schema with a new process-local schemaRef, valid for 30 minutes. Tool input schemas are separate MCP resources. Full schema: oods\://schemas/schema_read.input.json. ## Inputs | Name | Type | Required | Description | | - | - | - | - | | `action` | `"list" \| "load"` | yes | Choose list, load. | | `name` | `string` | no | Saved schema name in slug format. Actions: load (required). | | `object` | `string` | no | Object filter. Actions: list. | | `context` | `string` | no | Rendering-context filter. Actions: list. | | `tags` | `string[]` | no | Actions: list. | ## Outputs The package ships no output schema for this tool. ## A real call Recorded by this site's `tools` run, step `schema-load`, with the published OODS Foundry 0.11.3. Its input: ``` { "action": "load", "name": "user-detail" } ``` Its result: ``` { "schemaRef": "compose-f0dfe686", "name": "user-detail", "version": 1, "createdAt": "2026-11-02T05:29:27.077Z", "updatedAt": "2026-11-02T05:29:27.077Z", "tags": [], "object": "User" } ``` [The whole call, 1 KB of JSON](https://oods-foundry.com/tools/schema-read/call.json) --- Source: https://oods-foundry.com/tools/schema-render [Tools](https://oods-foundry.com/tools) / schema_render # `schema_render` Validate a UiSchema or render static HTML and fragments. Generated from @oods/foundry 0.11.3 One of the 26 tools your assistant sees by default. Use it when checking schema or patch contracts; use design_preview for a running app or schema_store to save. Returns diagnostics or rendered output. action selects validate/render; mode selects full/patch. apply:true enables rendering, without saving a schema. Render includes token CSS unless output.compact; oversized output or output.payloadMode:file writes only reply payloads. brand and scope options affect documents; ignored fragment options are diagnosed. Full schema: oods\://schemas/schema_render.input.json. ## Inputs | Name | Type | Required | Description | | - | - | - | - | | `action` | `"render" \| "validate"` | yes | Selects the per-action handler. 'render' -> schema_render action=render, 'validate' -> schema_render action=validate. | | `mode` | `"full" \| "patch"` | no | Full schema or patch mode. Actions: render, validate. | | `schema` | `object` | no | UiSchema. Actions: render, validate. | | `schemaRef` | `string` | no | Reference to a cached UiSchema returned by design_compose. Actions: render, validate. | | `patch` | `array \| object` | no | Required when mode='patch'. Accepts JSON Patch array or node patch object(s). Actions: render, validate. | | `baseTree` | `object` | no | Required when mode='patch' to provide the base UiSchema to patch. Actions: render, validate. | | `brand` | `string` | no | Brand to render. Actions: render. See full schema for details. | | `options` | `object` | no | Operation options. Actions: render, validate. | | `output` | `object` | no | Optional render output controls. Omitting this object preserves full-document behavior. Actions: render. | | `apply` | `boolean` | no | For render: When true and the schema validates, render it: the HTML document in html, or per-node fragments with output.format 'fragments'. Actions: render, validate. See full schema for details. | ## Outputs The package ships no output schema for this tool. ## A real call Recorded by this site's `tools` run, step `schema-render-validate`, with the published OODS Foundry 0.11.3. Its input: ``` { "action": "validate", "schemaRef": "compose-f0dfe686" } ``` Its result, first lines: ``` { "status": "ok", "mode": "full", "dslVersion": "2026.02", "registryVersion": "2026-10-10", "errors": [], "warnings": [], "normalizedTree": { "version": "2026.02", "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": "Stack", ``` [The whole call, 44 KB of JSON](https://oods-foundry.com/tools/schema-render/call.json) --- Source: https://oods-foundry.com/tools/schema-store [Tools](https://oods-foundry.com/tools) / schema_store # `schema_store` Save or delete a named composition schema. Generated from @oods/foundry 0.11.3 One of the 26 tools your assistant sees by default. Use it when retaining a UiSchema across sessions; use schema_read to list or load saved schemas. Returns the saved metadata or deletion result. save takes schemaRef, overwrites that name and increments its version; only the latest is loadable. Both actions write immediately. Full schema: oods\://schemas/schema_store.input.json. ## Inputs | Name | Type | Required | Description | | - | - | - | - | | `action` | `"save" \| "delete"` | yes | Choose save, delete. | | `name` | `string` | no | Saved schema name in slug format (letters, numbers, hyphens, underscores). Actions: save (required), delete (required). | | `schemaRef` | `string` | no | Reference to an in-memory schema produced by design_compose. Actions: save (required). | | `tags` | `string[]` | no | Optional tags for filtering and discovery. Actions: save. | | `author` | `string` | no | Optional author metadata. Actions: save. | ## Outputs The package ships no output schema for this tool. ## A real call Recorded by this site's `tools` run, step `schema-save`, with the published OODS Foundry 0.11.3. Its input: ``` { "action": "save", "schemaRef": "compose-f0dfe686", "name": "user-detail" } ``` Its result: ``` { "name": "user-detail", "version": 1, "createdAt": "2026-11-02T05:29:27.077Z", "updatedAt": "2026-11-02T05:29:27.077Z", "tags": [], "object": "User" } ``` [The whole call, 1 KB of JSON](https://oods-foundry.com/tools/schema-store/call.json) --- Source: https://oods-foundry.com/tools/structured-data-fetch [Tools](https://oods-foundry.com/tools) / structured_data_fetch # `structured_data_fetch` Fetch live registry datasets, archived token/export data, or captured-run artifacts. Generated from @oods/foundry 0.11.3 One of the 26 tools your assistant sees by default. Use it when you need complete datasets; catalog_list selects components and object_registry reads definitions. Returns data with provenance, version and cache metadata. Full remains the default; detail:summary gives section counts and meta.next for inline pages; follow meta.next until absent. dataset selects registry/export mode; version pins an archived export and listVersions lists dates. kind plus runPath selects captured artifacts, while derived_analysis reads an analysis directory via runPath; version/listVersions are refused in kind mode. includeInternal exposes hidden objects, and ifNoneMatch checks the canonical payload ETag. Full schema: oods\://schemas/structured_data_fetch.input.json. ## Inputs | Name | Type | Required | Description | | - | - | - | - | | `dataset` | `"components" \| "tokens" \| "manifest"` | no | Local structured dataset to return (components/tokens/manifest). Mutually exclusive with kind+runPath. | | `kind` | `"identity_graph" \| "capability_rollup" \| "object_rollup" \| "drift_report" \| "derived_analysis" \| "a11y_report" \| "report_index" \| "a11y_evidence" \| "run_manifest"` | no | Stage1 artifact kind, with runPath; excludes dataset. See full schema for details. | | `runPath` | `string` | no | Filesystem path to a Stage1 run directory or its artifacts/ subdirectory. Required when kind is set. | | `ifNoneMatch` | `string` | no | Return matched=true without payload when the ETag matches. | | `includePayload` | `boolean` | no | When false, omit payload even if no ETag match occurs. | | `version` | `string` | no | Request a specific date-stamped version (e.g., '2026-02-24'). Omit for latest. Applies to dataset mode only. | | `listVersions` | `boolean` | no | When true, return available version dates instead of payload. | | `includeInternal` | `boolean` | no | Live components dataset only: also list OODS Foundry's internal (non-business) objects, after the business objects. Without it they are left out and registry.hiddenInternal counts them; a dated export is served unchanged. | | `payloadMode` | `"inline" \| "file"` | no | Unset: inline, unless the payload exceeds 100,000 characters; then it is written to a file and warning OODS-W004 says so. inline always returns it; file always writes it and returns payloadFile. | | `detail` | `"summary" \| "full"` | no | Dataset only. summary returns section counts and the call for page 1; full (default) preserves the dataset. | | `page` | `integer` | no | Dataset only: read a 1-based page of lossless JSON Pointer entries, each reply below 100,000 characters. Omit for full data. | | `pageSize` | `integer` | no | Dataset entries per page, default 10, also bounded by serialized size. Reply meta gives next and full calls. | ## Outputs | Name | Type | Required | Description | | - | - | - | - | | `dataset` | `"components" \| "tokens" \| "manifest"` | no | Dataset that was requested (dataset mode only). | | `kind` | `"identity_graph" \| "capability_rollup" \| "object_rollup" \| "drift_report" \| "derived_analysis" \| "a11y_report" \| "report_index" \| "a11y_evidence" \| "run_manifest"` | no | Stage1 structured artifact kind that was requested (kind mode only). | | `schemaVersion` | `string` | no | Stage1 artifact schema_version (kind mode only). | | `runId` | `string` | no | Stage1 run_id extracted from the artifact (kind mode only). | | `version` | `string \| null` | no | Version tag (usually the YYYY-MM-DD stamp from the manifest). | | `generatedAt` | `string \| null` | no | Timestamp recorded in the payload. | | `etag` | `string` | yes | Stable hash of the payload (generatedAt excluded). | | `matched` | `boolean` | yes | True when ifNoneMatch matched the current ETag and payload was skipped. | | `payloadIncluded` | `boolean` | yes | True when the payload field is returned. | | `path` | `string` | yes | Resolved export path. For the live components projection, this supplies historical evidence and annotations; the returned definitions come from the live registry. | | `manifestPath` | `string \| null` | no | Manifest path when available. | | `sizeBytes` | `integer` | yes | Serialized payload byte size for the live projection; file size for committed exports. | | `schemaValidated` | `boolean` | yes | True when the payload was validated against a schema. | | `validationErrors` | `string[]` | no | Optional validation error messages. | | `warnings` | `string[]` | no | Non-fatal warnings encountered during resolution. | | `meta` | `object` | no | Lightweight summary for the payload. | | `payload` | `object` | no | Payload contents when payloadIncluded=true. | | `payloadFile` | `object` | no | Where the payload was written instead of being returned (payloadMode file, or a sized call over 100,000 characters); the directory is beside the saved-schema store. | | `availableVersions` | `string[]` | no | Available version dates when listVersions=true. | | `requestedVersion` | `string \| null` | no | The version that was requested (null if latest). | | `resolvedVersion` | `string \| null` | no | The version that was actually resolved (may differ from requested if nearest match used). | ## A real call Recorded by this site's `system` run, step `components-export`, with the published OODS Foundry 0.11.3. Its input: ``` { "dataset": "components", "payloadMode": "inline" } ``` Its result, first lines: ``` { "dataset": "components", "version": "2026-10-10", "generatedAt": "2026-10-10T03:40:00Z", "etag": "80c3f37bcd0a8fa947e92cda8554558223ef1252eaf78266ded1c518e86c06c9", "matched": false, "payloadIncluded": true, "path": "artifacts/structured-data/oods-components-2026-10-10.json", "manifestPath": "artifacts/structured-data/manifest.json", "sizeBytes": 727029, "schemaValidated": true, "meta": { "componentCount": 114, "traitCount": 49, "objectCount": 11, "domainCount": 1, "patternCount": 2, "source": "live-registry", "sourceEtag": "80c3f37bcd0a8fa947e92cda8554558223ef1252eaf78266ded1c518e86c06c9", "validationScope": "complete-dataset", "detail": "full", "next": { "dataset": "components", "payloadMode": "inline", "listVersions": false, "includeInternal": false, "page": 1, "pageSize": 10 }, "full": { "dataset": "components", "payloadMode": "file", "listVersions": false, "includeInternal": false, "detail": "full" } }, "payload": { "$schema": "./component-schema.json", "obligationScope": { "schemaVersion": "1.0.0", "decisionId": 2527, "disposition": "retain-all-obligations", "controllingObligationDenominator": 114, "approvedRuntimeCensus": null, "classificationStatus": "proposed-awaiting-approval" }, "generatedAt": "2026-10-10T03:40:00Z", "stats": { "componentCount": 114, "traitCount": 49, "objectCount": 11, "domainCount": 1, "patternCount": 2 }, "components": [ { "id": "AddressCollectionPanel", "displayName": "AddressCollectionPanel", "categories": [ ``` [The whole call, 1143 KB of JSON](https://oods-foundry.com/tools/structured-data-fetch/call.json) --- Source: https://oods-foundry.com/tools/tokens-build [Tools](https://oods-foundry.com/tools) / tokens_build # `tokens_build` Compile registered brand tokens with the shipped compiler. Generated from @oods/foundry 0.11.3 One of the 26 tools your assistant sees by default. Use it when you need fresh CSS and JSON; use brand_create to create a brand or brand_apply to change its source. Returns inline CSS variables, CSS and JSON plus artifact paths, hashes and sizes. apply:true builds in isolated artifact storage; omission previews the artifacts without writing. Requested brand/theme selects the inline scope; full CSS includes every registered scope. Source and shipped runtime files stay unchanged. Full schema: oods\://schemas/tokens_build.input.json. ## Inputs | Name | Type | Required | Description | | - | - | - | - | | `brand` | `string` | no | Selects values compiled from current source, returned inline as CSS variables, CSS and JSON and written on apply. Full CSS includes all registered scopes; TypeScript and Tailwind artifacts retain A/light defaults. | | `theme` | `"light" \| "dark" \| "hc"` | no | Token theme. | | `apply` | `boolean` | no | Write on true; otherwise preview. | ## Outputs The package ships no output schema for this tool. ## A real call Recorded by this site's `tools` run, step `tokens-build`, with the published OODS Foundry 0.11.3. Its input: ``` { "brand": "A", "theme": "light" } ``` Its result: ``` { "artifacts": [], "preview": { "summary": "Preview only: would return 5 token artifacts for brand A (light theme).", "notes": [ "artifact: tokens.light.json", "artifact: tokens.scope.css", "artifact: tokens.css", "artifact: tokens.ts", "artifact: tokens.tailwind.json" ], "specimens": [ "~/.oods-foundry/runtime/0.11.3-510074895fa1/artifacts/current-state/2026-11-02/tokens.build/tokens.light.json", "~/.oods-foundry/runtime/0.11.3-510074895fa1/artifacts/current-state/2026-11-02/tokens.build/tokens.scope.css", "~/.oods-foundry/runtime/0.11.3-510074895fa1/artifacts/current-state/2026-11-02/tokens.build/tokens.css", "~/.oods-foundry/runtime/0.11.3-510074895fa1/artifacts/current-state/2026-11-02/tokens.build/tokens.ts", "~/.oods-foundry/runtime/0.11.3-510074895fa1/artifacts/current-state/2026-11-02/tokens.build/tokens.tailwind.json" ] } } ``` [The whole call, 1 KB of JSON](https://oods-foundry.com/tools/tokens-build/call.json) --- Source: https://oods-foundry.com/tools/viz-render [Tools](https://oods-foundry.com/tools) / viz_render # `viz_render` Render one data-bound chart from rows or a structured data operand. Generated from @oods/foundry 0.11.3 One of the 26 tools your assistant sees by default. Use it when creating chart output; use artifact_certify instead to grade a normalized chart or dashboard_render for multiple panels and KPIs. Returns Vega-Lite or ECharts specs, chart identities and requested SVG/accessibility output. pattern uses bundled data and forbids explicit data/encoding/presentation overrides. Otherwise use chartType plus encodings, omit chartType for recommendations, or supply structured intent. ECharts-primary families require their matching hierarchy/network/geo operand. brand/theme controls pixels; output.includeNormalizedSpec returns the IR required by artifact_certify. Temporal rendering uses UTC. For native ECharts after JSON transport, restore currency and precision with @oods/foundry/echarts.js. Charts take inline data only; URLs, images and links in the input are refused. Full schema: oods\://schemas/viz_render.input.json. ## Inputs | Name | Type | Required | Description | | - | - | - | - | | `theme` | `"light" \| "dark" \| "hc"` | no | Chart token theme. HC preserves system colors and needs a forced-colors browser to resolve them. | | `brand` | `string` | no | CSS token brand for chart pixels. Omission resolves light/A. | | `opacity` | `number` | no | Constant mark opacity for Cartesian charts only; omission keeps renderer defaults. | | `rows` | `object[]` | no | Inline flat data rows. Use either rows or datasetRef. | | `datasetRef` | `string` | no | Previously cached dataset id; alternative to rows. | | `hierarchy` | `object` | no | Treemap/sunburst: {type:"nested",data:{name,value,children}} or {type:"adjacency_list",data:\[{id,parentId,value}]}. See full schema. | | `sankey` | `object` | no | Sankey input: {nodes:\[{name}],links:\[{source,target,value}]}; links refer to node names. Use chartType:"sankey". | | `chord` | `object` | no | Chord input: {nodes:\[{name}],links:\[{source,target,value}]}; links refer to node names; each directed pair must be unique. | | `network` | `object` | no | Force graph input: {nodes:\[{id,group}],links:\[{source,target,value}]}; max 250 nodes. Use chartType:"force_graph". Full contract: oods\://schemas/viz_render.input.json. | | `geo` | `object` | no | Inline geojson or topojson plus topoObjectName, rows, join, valueField; optional point/flow coordinate fields. No network fetch. Re-register echartsSpec.\_\_registration before rendering. Read full schema. | | `chartType` | `"bar" \| "line" \| "area" \| "scatter" \| "heatmap" \| "treemap" \| "sunburst" \| "sankey" \| "force_graph" \| "choropleth" \| "bubble_map" \| "flow_map" \| "chord"` | no | Chart family for explicit mode. Cartesian charts need rows/datasetRef and encodings; other families need their named data input. Omit to suggest from rows. | | `encodings` | `object` | no | Cartesian bindings: each needs field; optional type, aggregate, title, format (d3-format), currency (ISO 4217). | | `id` | `string` | no | Optional stable identifier for the produced spec. | | `name` | `string` | no | Optional human-friendly chart title. | | `description` | `string` | no | Optional override for the synthesized accessibility description. When omitted, a non-empty description is generated from the encodings. | | `strictFields` | `boolean` | no | Warn about unresolved fields and unmatched map joins (OODS-V131/V134). Default false preserves existing behavior. | | `a11yEquivalence` | `boolean` | no | Check Vega-Lite accessible equivalents (default true). Errors stop rendering; warnings are returned. ECharts-primary scaffolds are not checked here. | | `output` | `object` | no | Options: svg, width, height, compact, echarts, includeNormalizedSpec, includeA11y, includeVegaSpec, titlePlacement (chart or figure). SVG is opt-in; compact defaults true. | | `intent` | `object` | no | Structured request: goal, measures:\[{name}], dimensions:\[{name}], optional chartFamily and measureRef. Uses rows or datasetRef; alternative to explicit chartType/encodings. | | `pattern` | `"pattern:viz:bubble-distribution" \| "pattern:viz:correlation-matrix" \| "pattern:viz:correlation-scatter" \| "pattern:viz:detail-overview-bar" \| "pattern:viz:diverging-bar" \| "pattern:viz:drilldown-stacked-bar" \| "pattern:viz:facet-small-multiples-line" \| "pattern:viz:facet-target-band" \| "pattern:viz:focus-context-line" \| "pattern:viz:grouped-bar" \| "pattern:viz:histogram" \| "pattern:viz:layered-line-area" \| "pattern:viz:multi-series-line" \| "pattern:viz:running-total-area" \| "pattern:viz:simple-bar" \| "pattern:viz:sparkline-grid" \| "pattern:viz:stacked-100-bar" \| "pattern:viz:stacked-area-projection" \| "pattern:viz:stacked-bar" \| "pattern:viz:target-band-line" \| "pattern:viz:time-grid-heatmap" \| "pattern:viz:waterfall"` | no | Exact registered pattern identity; preserves source data and presentation. Cannot combine with chartType, data, intent or identity/presentation overrides. | ## Outputs | Name | Type | Required | Description | | - | - | - | - | | `status` | `"ok" \| "error"` | yes | Whether rendering succeeded. | | `chartType` | `string` | no | Resolved registered chart type; omitted on error. | | `mode` | `"explicit" \| "suggest"` | no | Whether the chart type was supplied explicitly or chosen by the recommender. | | `spec` | `object` | no | Vega-Lite source with scoped OODS tokens, before the renderer's high-contrast quantized legend and output.width/height sizing adjustments. Use output.includeVegaSpec for the exact compiled Vega spec that reproduces the rendered chart. Scope changes alter chart content and pixel hashes. | | `echartsSpec` | `object` | no | Compiled ECharts option. Primary ECharts chart types include scoped OODS canvas, borders, labels and title chrome. Series palettes use the same scope; where no themed palette exists they retain the light palette. Formatted axes/tooltips carry JSON-safe \_\_oodsFormat descriptors. Pass the option through restoreEChartsFormats from @oods/foundry/echarts.js before echarts.setOption; no code evaluation is required. | | `normalizedSpec` | `object` | no | The intermediate NormalizedVizSpec IR. Present only when output.includeNormalizedSpec is true. | | `a11yDescription` | `string` | no | The non-empty accessibility description carried by the spec (always synthesized when not provided). | | `a11y` | `object` | no | Structured two-part text alternative (accessible data table + narrative summary) derived from the same data source the chart renders from. Present only when output.includeA11y is true (additive; default-off keeps the wire byte-identical). An agent reads this to verify/iterate its own chart without re-deriving the data. | | `suggestion` | `object` | no | Present in suggest mode: the recommender pick that drove the chart type, with the data-aware rationale and runner-up alternatives. | | `lowConfidence` | `boolean` | no | Suggest mode only: true when no pattern matched confidently — the chartType is a low-confidence fallback rather than a positive recommendation (the previously-silent bar default, now surfaced). | | `svg` | `string` | no | Server-rendered SVG bytes, present only for output.svg:true. ECharts allocator tokens are normalized before return; Vega-Lite retains its accessible graphics roles. | | `svgHash` | `string` | no | SHA-256 of the exact returned SVG bytes. At default intrinsic dimensions and light/A scope, cartesian svgHash equals artifact_certify determinism.renderHash for the same normalized spec. Scope and dimension changes alter the hash. | | `svgBytes` | `integer` | no | UTF-8 byte length of svg. | | `svgRef` | `string` | no | Temporary pipeline reference caching exactly the svg string, with the same lifetime as specRef. | | `render` | `object` | no | Actual SVG dimensions, primary engine and rendered scope. | | `specRef` | `string` | no | Temporary reference to the produced spec for pipeline reuse (mirrors the retired chart scaffold schemaRef). | | `specRefCreatedAt` | `string` | no | ISO timestamp when the specRef was created. | | `specRefExpiresAt` | `string` | no | ISO timestamp when the specRef expires. | | `contentHash` | `string` | no | Deterministic SHA-256 (hex) over the canonicalized primary payload (the Vega-Lite spec, or the JSON-projected ECharts option for ECharts-primary types) — the content identity of exactly what specRef caches. Unlike specRef (a random, expiring cache handle), contentHash is stable across calls: the same input yields the same hash. Default-on; omitted only on error outputs. | | `tokenCssRef` | `string` | no | Content-addressed identity of the active token CSS when compact mode is enabled: tokens_build#sha256:\. Use tokens_build to obtain the full CSS. | | `output` | `object` | no | Echoes the normalized output controls used by the renderer. | | `errors` | `issue[]` | no | Fatal errors (present and non-empty when status is 'error'). | | `warnings` | `issue[]` | yes | Non-fatal issues encountered during rendering. | | `meta` | `object` | no | | | `vegaSpec` | `object` | no | The exact Vega spec parsed by the renderer after legend and sizing adjustments. Present for Vega charts only when output.includeVegaSpec is true. Rendering with the bundled Vega version reproduces the SVG apart from its accessibility and stable-ID post-processing. | ## A real call Recorded by this site's `harbor` run, step `chart`, with the published OODS Foundry 0.11.3. Its input: ``` { "chartType": "bar", "brand": "Harbor", "theme": "light", "rows": [ { "warehouse": "Lakeside Distribution", "pallets": 640 }, { "warehouse": "North Yard", "pallets": 760 }, { "warehouse": "Harbor Cold Store", "pallets": 2400 } ], "encodings": { "x": { "field": "warehouse", "type": "nominal" }, "y": { "field": "pallets", "type": "quantitative" } }, "output": { "includeNormalizedSpec": true, "includeA11y": true } } ``` Its result, first lines: ``` { "status": "ok", "chartType": "bar", "mode": "explicit", "spec": { "$schema": "https://vega.github.io/schema/vega-lite/v6.json", "title": "Bar chart", "description": "Bar chart of pallets by warehouse.", "data": { "values": [ { "warehouse": "Lakeside Distribution", "pallets": 640 }, { "warehouse": "North Yard", "pallets": 760 }, { "warehouse": "Harbor Cold Store", "pallets": 2400 } ] }, "autosize": { "type": "fit-y", "contains": "padding" }, "config": { "background": "#FFFFFF", "font": "'DM Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif", "title": { "color": "#070B0B", "font": "'DM Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif", "fontSize": 24, "fontWeight": 600, "anchor": "start" }, "axis": { "titleColor": "#070B0B", "titleFont": "'DM Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif", "labelColor": "#4C5455", "labelFont": "'DM Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif", "gridColor": "#E1E6E7", "domainColor": "#CFD6D7", "tickColor": "#CFD6D7" }, "axisX": { "grid": false }, "axisY": { "grid": true, "tickCount": { "expr": "min(5, ceil(height / 40))" } }, "legend": { "titleColor": "#070B0B", "titleFont": "'DM Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif", "labelColor": "#4C5455", ``` [The whole call, 7 KB of JSON](https://oods-foundry.com/tools/viz-render/call.json)