@rationallyprime/morphe
v0.11.0
Published
Morphe — a stratified adaptive-UI core. Phase 0 keystone.
Readme
Morphe
Morphe is a stratified adaptive-UI substrate. UI is authored as data: a typed
Node tree rendered through a fixed grammar, a context algebra, a three-layer
token system, and a swappable dialect. The authored tree says "role, priority,
intent"; it never says pixels, hex values, or framework component trivia.
This repository owns the reusable package, the local CMS/tooling surface, the adaptive sidecar contract, a neutral playground, and the stripped deployment viewer. Consumer applications import Morphe through its published package seams.
Quick Start
bun install
just gates # every gate CI runs, across the web, viewer, and Python stacks
just dev # neutral playground at http://localhost:5173/
just hooks # install the prek git hooks once per checkoutUseful focused gates:
bun run check # svelte-check
bun run test # vitest + DOM vitest config
bun run build # SvelteKit/Vercel build for the playground host
bun run compiler-id:check # compiler receipt identity matches its runtime closure
bun run test:edge-e2e # signed source -> compiler -> renderer in Chromium + Firefox
bun run pack:verify # installed-tarball source admission and Python/TS oracle proof
just viewer-build-node # stripped adapter-node viewer build
just py-test # pytest over py/
just schema-check # committed grammar artifacts equal fresh emission
just py-pack-verify # wheel/sdist carry verified dialect masksStack: SvelteKit + Svelte 5 runes, Vite, TypeScript strict, bun, Biome, Vitest, uv, ruff, ty, Pydantic v2, FastAPI, and prek.
The Package
Morphe publishes as the public npm package @rationallyprime/morphe
(MIT, registry.npmjs.org). The package root is src/lib; consumer apps import
only the public seams:
@rationallyprime/morphe— grammar, context, compounds, dialects, delegation, state, render contracts, token helper types.@rationallyprime/morphe/components—MorpheRoot,RenderNode, and primitive Svelte components for harnesses and inspection.@rationallyprime/morphe/surface-edge— server-only signed source admission, deterministic TypeScript compilation, evidence, and compilation receipts.@rationallyprime/morphe/tokens— intent constants and slot helpers.@rationallyprime/morphe/styles.css— public token CSS.@rationallyprime/morphe/schemas/*— the generated JSON Schema artifacts (grammar, decision, delta, constrained-decode masks, CMS), pinned to the installed grammar version.
Typical consumer use:
<script lang="ts">
import "@rationallyprime/morphe/styles.css";
import type { Node } from "@rationallyprime/morphe";
import { MorpheRoot } from "@rationallyprime/morphe/components";
const tree: Node = {
kind: "frame",
role: "section",
children: [{ kind: "text", value: "Hello Morphe", as: "heading" }],
};
</script>
<MorpheRoot {tree} />Package publication and registry proof live in PACKAGING.md.
The Algebra
Four foundation lemmas carry the substrate, and the code treats them as gates, not as vibes:
| Lemma | Claim | Canonical source |
|---|---|---|
| 1 — Grammar | UI is a discriminated Node union; inaccessible inputs and fake clickable divs are unrepresentable. | src/lib/grammar/types.ts |
| 2 — Context algebra | Child context is a pure function of parent context and role; Frame is the only reset. | src/lib/context/ |
| 3 — Fixed point | The same authored tree survives dialect swaps unchanged. | src/lib/dialects/dialects.test.ts |
| 4 — Dialects | A dialect remaps the intent layer and bounded priors, and nothing else. | src/lib/dialects/ |
The current tower also wires the reserved sockets that make adaptation
stratified instead of ad hoc: bind paths flow through the client store,
Button.action ids resolve at MorpheRoot.actions, and Vary / targeted
Within choices flow through MorpheRoot.choices plus the Delta machinery.
Within can adapt one owned subtree through typed density, budget-conserving
emphasis, or native disclosure semantics. The renderer never sees epochs or
handlers. The tree stays declarative.
Nine dialects ship: gallery (default), night, icelandic-archive,
clinical, reykjavik-registry, timaeus, ledger, estate, and foundry.
Every shipped dialect preserves the contract keyset.
clinical additionally restricts compound vocabulary to the full seventeen-definition promoted
package catalog, excluding unreviewed consumer compounds without hiding reviewed package shapes;
generated decoder masks make every dialect's explicit structural policy available through both
package distributions.
Repository Map
| Path | Purpose |
|---|---|
| src/lib/grammar | The typed Node union and grammar version. |
| src/lib/context | Context algebra, emphasis budget, and Svelte context boundary. |
| src/lib/compounds | Compound definitions as data, plus the validation gate. |
| src/lib/dialects | Dialect data, registry, active dialect store, and arrival resolution. |
| src/lib/delegation | Envelope, epoch, Delta, Vary, and mid-loop seams. |
| src/lib/state | Store, tiered events, actions, digest, and escalation. |
| src/lib/render | Recursive renderer and package component entry points. |
| src/lib/primitives | Svelte implementations of the grammar primitives. |
| src/lib/surface-edge | Source-v1 admission, TypeScript compiler, receipts, and build identity. |
| src/lib/tokens | Scales, intents, slot helpers, and public token CSS. |
| py/morphe_grammar | Pydantic grammar mirror, JSON Schema, TS codegen, and masks. |
| py/morphe_cms | Local CMS contracts, presenter, validation, store, tools, and MCP surface. |
| py/morphe_agent | Optional adaptive decision sidecar and deterministic fallback. |
| py/morphe_surface | Surface compiler contracts used by the viewer path. |
| src/routes | Neutral playground, CMS preview/publication routes, and adaptive API bridge. |
| viewer | Stripped SvelteKit deployment viewer. |
| schema | Committed contract artifacts generated from the Python grammar/CMS models. |
Demo Host
The root app is a neutral proof host, not a consumer marketing site:
/— Morphe workbench index./substrate— full playground with all dialects, actions, bind paths, the deterministic Delta/choice circuit and bounded outcome ledger, the complete promoted compound proof, six sealed signed Krepis source-v1 fixtures, neutral assets, adaptive fallback rendering, and nested dialect proof. The fixtures demonstrate the generic source/compiler/render boundary without importing kernel models or authority./preview/[artifactId]/[revisionId]— local CMS compiled-tree preview./p/[slug]— publication pointer route./dignity— compatibility redirect to/substrate./api/adaptive/decision— bridge toMORPHE_AGENT_BASE_URL, with a deterministic schema-valid fallback when no sidecar is configured.
Static demo assets live under static/images/demo/. Consumer brand assets and
consumer-specific pages belong in the consumer repo.
Adaptive Sidecar
py/morphe_agent serves POST /v1/morphe/decision and always returns a
schema-valid decision response. Without live credentials it uses the
deterministic fallback. With live settings it routes through the Pydantic AI
Gateway and constrains structured output with the exact installed schema for
the requested dialect. Validation failures retry through the model protocol
and ultimately fall back without breaking the render path.
MORPHE_AGENT_LIVE=1 \
MORPHE_AGENT_MODEL=... \
PYDANTIC_AI_GATEWAY_API_KEY=... \
uv run uvicorn morphe_agent.app:app --host 127.0.0.1 --port 8042
MORPHE_AGENT_BASE_URL=http://127.0.0.1:8042 just devMORPHE_AGENT_GATEWAY_BASE_URL can override the default OpenAI-compatible
Pydantic Gateway proxy. CI and local gates do not require a live model call.
Stripped Viewer
viewer/ is a stripped SvelteKit app for artifact rendering. It shares the
same src/lib substrate, exposes declared /s/[source]/[surfaceId] routes,
the compatible /surfaces/[artifactId] route, and /healthz. Each declared
surface independently selects the untouched compiled-tree reader or the
source-v1 path: bounded JSON admission, Ed25519 testimony verification,
TypeScript compilation, link rewriting, then the final grammar/dialect gate.
It exists so the playground's outbound-capable adaptive bridge does not ship
in the deployment image.
just viewer-build-node
docker build -f viewer/Dockerfile -t morphe-viewer .Reading Order
| Document | What it answers |
|---|---|
| CONTEXT.md | Canonical domain vocabulary. |
| VISION.md | Why the stratified adaptive tower exists. |
| CONTRACT.md | What the locked Phase 0 substrate guarantees. |
| DESIGN.md | The design-system frame and dialect craft rules. |
| PACKAGING.md | Package boundary, exports, and publication proof. |
| STATUS.md | Last verified status snapshot. |
| docs/adr/ | Architectural decisions and their reasons. |
Working Rules
- Library code under
src/lib/**uses.jsextensions on relative imports andimport typefor types. - Authored trees emit roles, priorities, and intents only. Do not hardcode colors, scale names, geometry, or event handlers into tree data.
- Interactive chrome and host controls live outside the Morphe tree as native
elements styled by
--mo-*tokens.MorpheRootrenders the authored/result tree. - Compounds vary through node params and slots only. Raw string fields such as
Badge.label,Link.href,Button.label,Media.src, and input labels are authored directly in presenters. - App-specific presenters, routes, brand assets, outbound integrations, and product copy belong in consumer repositories unless they are neutral playground/CMS proofs.
