CLI toolchain and contract engine for the Strata layout protocol. Validates YAML contracts, generates TypeScript types, and scaffolds routes and components.
npm install @shobman/strata-cliInitialise a project with Strata contracts and AI skill file. Idempotent — safe to run multiple times.
npx strata initCreates:
.claude/skills/STRATA-SKILL.md # AI agent skill file
components/atoms/_contract.yml # atom level contract
components/molecules/_contract.yml # molecule level contract
components/organisms/_contract.yml # organism level contract
routes/_contract.yml # root route contract
Also adds strata:check and strata:build scripts to your package.json.
Validate all contracts (YAML only, no source code). Fast — runs in CI.
npx strata checkExit code 1 if errors are found. Output format:
error fills-reference-real-slots routes/funds/index/_contract.yml
Fill "nonexistent" does not match any slot in ancestors or self
warn route-level-consistency routes/funds/_contract.yml
Route-level contract should use level: route, rank: 3
Validation rules:
| Rule | Severity | Description |
|---|---|---|
fills-reference-real-slots |
error | All fills must reference slots declared by ancestors or self |
required-slots-satisfied |
error | Required slots must be filled through the default/redirect chain |
default-redirect-mutual-exclusivity |
error | A route cannot have both default and redirect |
default-redirect-target-exists |
error | Named child must exist as a subfolder |
param-route-excluded-from-default-redirect |
error | Dynamic routes ([param]) cannot be defaults or redirects |
route-level-consistency |
warn | Routes should be level: route, rank: 3 |
component-level-consistency |
warn | Components should match their directory level |
Generate TypeScript types from YAML contracts.
npx strata buildCreates .strata.types.ts next to each _contract.yml:
// AUTO-GENERATED by strata build — do not edit
export type FundsFundIdSlots = "tabs" | "contextPanel";
export type FundsFundIdRequiredSlots = "tabs";
export type FundsFundIdInheritedSlots = "breadcrumb" | "actions";
export type FundsFundIdAllSlots = FundsFundIdSlots | FundsFundIdInheritedSlots;Type naming convention: path segments are PascalCased and joined. routes/funds/[fundId] becomes FundsFundId.
Scaffold a new route with contract, page stub, and optional layout.
npx strata add route funds/[fundId]/compliance
npx strata add route funds --fills menu --slots listActions --default index| Flag | Description |
|---|---|
--fills <slots> |
Comma-separated slot names this route fills |
--slots <slots> |
Comma-separated slot names this layout declares (generates _layout.tsx) |
--default <child> |
Child that renders at this route's URL (index route) |
--redirect <child> |
Child that this route redirects to |
--param <name> |
Route parameter name (auto-detected from brackets) |
Creates _contract.yml and index.tsx. If --slots is provided, also creates _layout.tsx with SlotProvider/SlotTarget boilerplate. Runs strata build automatically after scaffolding.
Scaffold a component at the specified level.
npx strata add atom Button
npx strata add molecule SearchBar
npx strata add organism FundPanelCreates components/<level>s/<Name>/index.tsx and the level's _contract.yml if missing.
Every route directory contains a _contract.yml:
param: fundId # route parameter name (optional)
level:
name: route # atom | molecule | organism | route
rank: 3 # 0 | 1 | 2 | 3
fills: [breadcrumb, actions] # ancestor slots this route fills
layout:
slots:
tabs: required # slot declarations (required or null)
contextPanel:
default: overview # child renders at this URL (index route)
redirect: performance # parent URL redirects to child URLThe contract engine is available as a library:
import {
buildContractTree,
validateContracts,
resolveAvailableSlots,
} from "@shobman/strata-cli";| Export | Description |
|---|---|
buildContractTree(rootDir) |
Build hierarchical contract tree from filesystem |
validateContracts(tree) |
Run all validation rules, returns diagnostics |
resolveAvailableSlots(node) |
Get all slots available to a node (own + ancestor) |
resolveAncestorSlots(node) |
Get ancestor slots only |
isSlotFilledInChain(node, name) |
Check if slot is filled through default/redirect chain |
parseContractFile(path) |
Parse a single _contract.yml |
[fundId] is valid YAML array syntax. All _contract.yml references to parameterised folders must use quotes:
# Correct
default: "[fundId]"
# Wrong — YAML parses this as an array
default: [fundId]The strata add command handles this automatically when generating contracts for bracket segments.