Skip to content

Development ​

bash
pnpm --filter @spelling-creator/mcp start        # run the stdio server directly
pnpm --filter @spelling-creator/mcp test         # doc-builder + auth + tool-surface + validation tests
pnpm --filter @spelling-creator/mcp build:views  # rebuild the interactive views after editing views/

Where things live ​

FileResponsibility
src/tools.jsTool definitions and handlers, transport-agnostic.
src/standards.mdThe authoring standard's prose half: the rules that need judgement.
src/validate.jsThe write path's side of validation, over the checks in @spelling-creator/core/lessonChecks. See Lesson validation.
src/api.jsThe hub client (the same Worker endpoints the web app uses).
src/git.jsVersion history: committing edits, forking, proposing, and reviewing or merging a proposal.
src/auth.jsSupabase token rotation.
src/views.jsThe ui:// resources behind interactive views.
views/Source for those views (markup + script), built into src/views/*.html.

Two pieces the tools lean on live in packages/core, so the web editor and the Worker can build and patch lessons the same way: @spelling-creator/core/lessonBuild builds the canonical editor document (and throws on input it can't turn into one), and @spelling-creator/core/lessonPatch applies id-addressed edit operations to an existing document.

src/standards.md is prose, so it is edited as a document rather than as an escaped JavaScript string, and src/standards.js is only the seam that loads it. Getting a markdown file into both runtimes takes a per-runtime resolution: #standards-md (a subpath import declared in apps/mcp/package.json) points at standards.workerd.js under the workerd condition, which imports the markdown as a Text module; wrangler needs the rules entry in apps/api/wrangler.jsonc to load .md that way, and it matches on the import specifier, which is why the shim names the file by a literal relative path. Everywhere else it points at standards.node.js, which reads the file off disk (src/ ships whole in the .mcpb bundle, so the path holds for an installed server too).

A view is one self-contained HTML file, because the host renders it in a sandboxed iframe that may fetch nothing at runtime. pnpm build:views bundles views/<name>.js with esbuild and inlines it into views/<name>.html, writing the result to src/views/. That output is committed: the server has no build step of its own (dev:mcp runs from source, the .mcpb bundle copies src/ wholesale, and wrangler reads the same file as a Text module), so shipping the built HTML keeps all three paths working. Rebuild and commit whenever you change anything under views/.

test/validate.test.js is built around one lesson written exactly to the standard, which must produce no errors and no warnings; the other cases mutate that fixture a rule at a time. Keep it that way: a false positive blocks an author who did nothing wrong, so the clean-lesson case is the one that matters most.

Copyright © 2026 Spelling Creator.