A structured catalog of recorded-music traditions in 13-dimensional parameter space, and an engine that turns a song specification into a tightly compressed structural recipe — a descriptor stack that tells you how to record it. The catalog spans 2,503 traditions and 1406 instruments (with per-part variant decomposition), 256 rooms, 84 chain archetypes, and 120 tunings.
The headline operation is recipe generation; the same catalog also supports tradition
blending, axis-profile matching, structural diffing, and catalog introspection. The
browser app builds into a dependency-free codex.html — a lazy shell that loads
the catalog on demand from the static api/ served beside it, scaling past the
single-file memory ceiling. A fully-embedded single-file variant (--embedded) still
builds, and a gate proves the shell behaves identically to it.
npm ci # install dev tooling from the lockfile
npm ci --prefix mcp # the connector's own deps (mcp/ is a separate package)
npx playwright install chromium # browser for the UI + mobile-layout gates
npm run build:html # build the lazy-shell catalog app → codex.html (+ api/)
npm run validate # cross-reference integrity check
npm run test # recipe + preface + slot-pick + app-parity + equivalence + lazy-parity + connector-parity regressionThe two install lines beyond npm ci are not optional extras: npm run test
ends in gates that drive a real browser and gates that build the real MCP server,
and without them the suite fails partway (or, worse, skips itself quietly).
CI has always run all three — they were just never written down here, so a fresh
clone followed this section and broke.
Every operation is an npm run script (see package.json):
| Command | What it does |
|---|---|
npm run build |
Canonical ship: validate → audit → regression → smoke → build HTML → UI reachability (~20 min) |
npm run build:fast |
Same, skipping the slow catalog-wide smoke + UI checks |
npm run build:html |
(Re)build the lazy-shell codex.html from references/ + src/, with a post-build syntax + no-table-leak check (--embedded for the self-contained single-file variant) |
npm run build:api |
Pre-compile every tradition into the static, server-free JSON "API" under api/ + llms.txt/sitemap.xml |
npm run validate |
Reference-integrity check (fatal on broken refs, axis violations, duplicate ids) |
npm run check:api |
Static-API contract gate: the published api/ honors every documented promise — complete counts, ≤1000-char recipes, every config id resolves |
npm run audit |
Data-quality audit (advisory warnings) |
npm run audit:coherence |
Substantive coherence audit: field-vs-field consistency (recording-era clashes, stamped vocal-tradition defaults, non-12-TET tuning contradictions) |
npm run test |
Regression + acceptance (7 regression suites + capability eval): recipe snapshots + preface assignments + slot-pick lock-ins + browser-app recipe parity + node↔browser equivalence + lazy-shell↔embedded parity + connector⇄app parity + black-box capability eval |
npm run eval |
Black-box capability acceptance eval: 28 scenarios over every CLI surface + the static API (non-empty output, ≤1000-char recipe ceiling, determinism, loud failure on bad input). Also runs as the final step of npm run test |
npm run smoke |
Catalog-wide pipeline health across every tradition (slow) |
npm run tandem |
End-to-end coherence across source + HTML artifacts |
npm run reachability |
Drives every UI control in the built HTML (Playwright) |
npm run check:mobile |
Mobile layout gate: on 7 viewports (360px→1280px) the layout viewport must equal the device width — no zoom-out blowout — with no horizontal overflow and every primary header control on-screen and tappable |
npm run check:names |
Name-isolation gate: renames every OTHER tradition with an adversarial era/gear payload and asserts the sampled tradition's compiled config is unchanged |
npm run check:publish |
Publish-guard gate: replays the sync-pages race in a synthetic repo and asserts a superseded build stands down while a legitimate one still publishes |
npm run check:promises |
Promise→gate coverage: every documented promise has a gate and vice-versa (0 orphans) |
npm run check:fresh |
Reproducibility gate: rebuilds api/+codex.html and byte-diffs vs the committed copy |
npm run faults |
Fault-injection: plants a defect per gate-class and asserts each gate catches it |
npm run lint / npm run format |
ESLint / Prettier |
npm run ci |
lint + full build |
npm run assets:* |
Regenerate embedded emoji / icon / photo assets (occasional) |
npm run build:api pre-compiles every tradition into plain JSON files under api/,
which GitHub Pages serves as-is — no server, no key, no per-call cost. An agent (or a
deep-research LLM) fetches a URL and reads the recipe:
api/all.json— every recipe in one fetch (the universal "paste one link" payload)api/index.json— endpoint map + countsapi/traditions/index.json→api/traditions/{id}.json— recipe + arrangement per traditionapi/instruments/index.json→api/instruments/{id}.json— instrument data
The site root (index.html) is dual-purpose: human browsers redirect to the app; LLM
fetchers read an inline agent guide pointing at api/all.json. So one link —
the root URL — serves both audiences.
Discovery surface: root llms.txt, robots.txt, sitemap.xml, server.json (the MCP
registry manifest), and AGENTS.md (the agent guide). All compute happens at build time;
see scripts/build_static_api.js and scripts/build_discovery.js.
A hosted Model Context Protocol server (mcp/, deployed on Render, auto-deploys from
main) exposes the full editable engine as MCP tools — the headless twin of the browser
app: seed a recipe, then edit prefaces / variants / room / chain / tuning, add/remove
instruments and traditions, and re-render. Streamable HTTP, no auth, read-only and
deterministic.
- Endpoint:
https://codex-musica-mcp.onrender.com/mcp - Server card (zero-config discovery):
https://codex-musica-mcp.onrender.com/.well-known/mcp.json - Registry manifest: root
server.json(publish to the official MCP registry withmcp-publisher publish) - Transport, privacy, and the tool contract: see
mcp/README.mdandmcp/PRIVACY.md.
The published page carries a chat bar that drives the same nine tools in plain language — no connector setup, no account. Type a request, get the recipe back verbatim, with the tool calls that produced it listed underneath.
The page is static, so it cannot hold a model key: the bar posts to /chat on the same
Render service that hosts the connector, and that service calls Gemini. The conversation
and the recipe workspace live in the browser and are posted back each turn — the server
stores nothing, the same promise the connector makes. The envelope is HMAC-signed so a
caller can only extend a transcript the server itself wrote.
- The model never sees the workspace. It is stripped from the function declarations and
injected server-side (
mcp/gemini_tools.jsexplains why it cannot be typed). - Rate-limited per IP, capped on daily spend, and bounded in tool calls per message.
Every limit is env-overridable; see
CHAT_LIMITSinmcp/chat.js. node scripts/probe_gemini.mjsdrives eleven prompts through the real MCP server and reports pass/fail, tokens and measured cost per conversation. It calls the live API, so it needsGEMINI_API_KEYand is deliberately not part ofnpm test.
references/— the catalog data (01_…–08_…) plus base/vocabulary JSON. Data only.src/— the browser app (app.js) and HTML template (the shared family-parts merge it inlines is authored inscripts/_merge.js).scripts/— build orchestration, the recipe engine, and all verification tooling.tests/— regression snapshots and fixtures.SKILL.md— the contract: schema, recipe pipeline, output rules, and invariants. Read this to understand or extend the catalog.
Node ≥ 22. The shipped codex.html has zero runtime dependencies (no framework, no
build step in the browser); as the lazy shell it loads catalog JSON from the api/
directory served beside it, so deploy the two together (GitHub Pages serves both from
the repo root). The dev tooling (ESLint, Prettier, jsdom, Playwright, sharp) is declared
in package.json.