System · Vellum

Platform

Shared architecture for every design contract — MCP, filenames, JSON keys.

platform.md

Design contracts — platform law

One architecture. Many aesthetics.
Structural change happens once — in lib/platform/skeleton.ts — and applies to every contract.

Agent stack (product)

LayerRequired?Job
design.md / agents.md / DNA docsYesLaw book
{id}-* skillsYesVerified cookbook per DNA
npm run validate / check:*YesFail-closed bailiff
Contract MCPOptionalQueryable accelerator

Marketing: /stack · homepage #stack · stack.md.

The split

LayerShared across all contracts?Where
MCP tool names + arg shapesYES — lockedlib/platform/skeleton.tspackages/contract-mcp
Machine filenames (design.md, agents.md, …)YES — lockedMACHINE_FILES
Route slots (/{id}/theme, /surfaces, …)YES — lockedROUTE_SLOTS
Contract JSON keysYES — lockedCONTRACT_JSON_KEYS + buildContractEnvelope
agents.md section orderYES — lockedAGENTS_MD_SECTIONS
Task recipe idsYES — lockedlib/contracts/task-recipes.ts
Price (open source / $0)YES — lockedMCP_PRICE_USD · PRICING_MODEL · pricing.md
OKLCH values, cinema voice, paper toneNO — DNAapp/contract-skins.css via [data-contract="{id}"] + lib/contracts/dna/{id}.ts
Marketing copy / film narrativeNO — DNAcontract pages / content
Platform homepage chromePlatform onlyapp/(platform)/* + :root in globals.css — never a contract skin

Agent rule (non-negotiable)

If you change architecture, a filename used by MCP/API/download, a JSON key, a route slot, or an MCP tool:

  1. Edit lib/platform/skeleton.ts (and the shared builder / MCP server).
  2. Run npm run gen:contract so every public/r/{id}.contract.json updates.
  3. Update every live contract’s docs that mention the old name (agents.md sections stay; links may need regen).
  4. Run npm run check:platform — must be green.

MUST NOT invent a Meridian-only (or Harbor-only) MCP tool, machine filename, or JSON shape.

Design DNA may differ: Harbor can feel like quiet ops paper while Meridian stays cinematic — as long as agents still call get_contract / validate_ui the same way and still fetch /{id}/design.md.

Pipeline

lib/platform/skeleton.ts          ← structural SSOT (tools, routes, filenames)
lib/platform/consistency.ts       ← agent MUST / MUST NOT + closed intents
lib/contracts/dna/{id}.ts         ← aesthetic SSOT per contract
lib/platform/build-contract.ts    ← merge → slim consistency-kit JSON
packages/contract-mcp             ← lightweight MCP; CONTRACT_ID selects DNA
public/r/{id}.contract.json       ← generated for ALL ids (mandate + tokens + recipes)
check:platform                    ← parity + slim-kit gate

MCP responses always include obey.must / obey.mustNot. Fat prose stays in markdown.

Skins (homepage ≠ contracts)

SurfaceSkin owner
/ platform index:root platform tokens + components/chrome/platform-*
/{id}/**[data-contract="{id}"] in contract-skins.css + ContractFrame

Landing a contract must feel like that DNA end-to-end (chrome included). The catalog stays on the platform shell so systems can be compared without guessing.

Adding a new contract

  1. Add lib/contracts/dna/{id}.ts and register in dna/index.ts.
  2. Add a [data-contract="{id}"] (+ dark) block in app/contract-skins.css.
  3. Wrap app/{id}/layout.tsx in <ContractFrame contractId="{id}">.
  4. Do not invent new MCP tools or machine filenames.
  5. npm run gen:contract — emits /r/{id}.contract.json with the shared shape.
  6. Add app/{id}/… pages for every ROUTE_SLOTS segment (install, ui, theme, surfaces, design, skills, system, for-agents, …) plus MACHINE_FILES route handlers (design.md, agents.md, …). check:platform asserts the files exist.

Gates

npm run check:platform
npm run gen:contract
npm run validate
Raw