Skip to main content
Two things serve a coding agent writing Slurp: the MCP server, which runs the real compiler, and the llms.txt files, which carry the reference as plain text.

Common model errors

Slurp is close enough to several familiar languages to make a guess plausible:
  • It is small enough not to be in the training data. There are 13 value filters, 4 loop filters, 9 setting kinds and one page of tags. Models reach for {% for %}, {{ }}, ??, ?., Math.max, items.length and arrow functions. None of those exist.
  • It looks like JavaScript and is not. ${ } is Slurp’s own interpolation, evaluated server-side against a JSON context. There are no callable functions at all, so Math.max(a, b) parses fine and evaluates to null.
  • Mistakes are silent. A missing property renders the empty string, a loop past 1000 items is truncated, unknown frontmatter is skipped, and an unresolvable component renders a placeholder. The build exits 0, so a model checking its work by “did it compile” gets a green light on a broken page.
Quoting means opposite things on two constructs that look identical, which is the most common mistake in the language:
Nothing reports the middle line. The page renders, and it says Hi ${name}. An agent needs a way to look the language up and a way to check what it just wrote. The MCP server provides both.

The MCP server

@bytesell/slurp-mcp runs the real compiler in-process through @bytesell/slurp-compiler-wasm. No subprocess, no slurp binary on PATH, and no second implementation of any rule in TypeScript. A diagnostic it reports is a diagnostic the compiler produced, with the same code, message, line and column.

Register it

Add -s user to the Claude Code command to register it for every project rather than the current one. A .mcp.json at a repository root is the shared form, so everyone working on the theme gets the same tools. The server speaks JSON-RPC over stdio. It writes exactly one line to stderr on startup and nothing at all to stdout except protocol frames, because on stdio stdout is the protocol:
Nothing here is published to npm yet, so npx -y @bytesell/slurp-mcp will not resolve until the first release. Until then, clone the repository, run pnpm install && pnpm build in mcp/, and use the third configuration above.

The five tools

They are split by the question they answer rather than by compiler entry point.
Compile-checks a template and returns structured diagnostics. It reports exactly what slurp build enforces, including the compile-time security walk, so an unfiltered ${ } in a <script> body, a | js slot in JavaScript statement position, env.SLURP_SECRET_* access and request.* outside middleware all surface here rather than at build time.
input
output
Pass files instead of source to check several templates in one call, and is_middleware: true only for a file that really will be compiled as middleware, because the rules differ.Two limits: the security walk stops at its first violation, so at most one security diagnostic appears per call, and nothing here resolves imports across files, so a missing component is not reported.
Renders against a JSON context and returns the HTML plus every diagnostic. Seeing the output is often the only way to catch a mistake that produces valid HTML with the wrong text in it.Rendering uses development mode, where two advisories are recorded that production drops: CSS-structural characters stripped from a style value slot, and an un-annotated interpolation in a JavaScript-evaluated attribute. {debug expr} also renders only here.It is deterministic and side-effect free. No network request is made and no file is read; {fetch} picks a branch by reading its name out of the context you passed.Components cannot be resolved, because there is no cross-file registry, so each renders as a <div data-slurp-component="Name" ...> placeholder. The response says so:
The only tool here that is not a view onto compiler diagnostics. Every rule describes a construct that slurp validate and slurp build both accept with zero output, and that then renders the empty string or the wrong string.Each finding carries a fix:
An agent cannot discover any of these from a failing build, because the build does not fail. Run it alongside slurp_validate, not instead of it: the two sets do not overlap.
Returns what a template declares in frontmatter: its section { } or block { } schema with every setting, kind, default and nested block, plus its props, its imports and its middleware name.This is how an agent discovers what a section exposes before changing it, and what a component expects before calling it.
A null schema is not an error. Most templates declare none, and the response says so.
The language reference, queryable by topic: overview, tags, expressions, filters, components, scripts, frontmatter, schema, errors, gotchas, limits.Call it with no arguments for the index plus the overview. Pass an error code or a filter name as query with no topic to jump straight to it:
That returns when the code fires, the fix, and a wrong/right pair.

Resources

Three, for pulling context in without a tool round-trip per topic: The server ships instructions that a client shows the model on connect:
1

Read the gotchas before writing anything

slurp_reference({ topic: "gotchas" }). Most of them cost nothing to avoid and are invisible afterwards.
2

Validate after every edit

slurp_validate. It reports what slurp build enforces rather than only what parses.
3

Lint as well, always

slurp_lint. A clean validate does not mean the template renders correctly. The constructs lint reports are precisely the ones validate cannot see.
4

Render when the output matters

slurp_render with a realistic context, and read the HTML. It catches a page that compiles and says the wrong thing.

llms.txt and llms-full.txt

For tools that read the llms.txt convention rather than speaking MCP, the same reference is served as two files at the repository root: llms-full.txt is generated from the same data the MCP server serves, so the two cannot drift. CI enforces it: the file is regenerated on every run and the job fails if it differs from what is committed.
The reference data underneath is itself checked against the compiler. The test suite compiles every “right” example in the error reference and requires it to validate clean, compiles every “wrong” example that claims an error and requires that error, and re-derives the truthiness table, the operator semantics, the loop variables and the filter list from real renders. A compiler change that invalidates a documented claim turns the suite red.
Prefer the MCP server if your client speaks MCP. llms-full.txt tells a model what the language is; the server also tells it whether the thing it just wrote is correct.

Without either

If you cannot run an MCP server and cannot feed a file into context, the practical minimum is to have the agent shell out after every edit:
That catches the hard errors, including the security walk. It will not catch the silent-failure classes slurp_lint covers, so pair it with Common mistakes in the prompt.

Next

Common mistakes

The silent failures, collected.

Errors

Every diagnostic code, and the fix.

CLI

The same checks from a shell.

Editor setup

The VS Code extension and the Prettier plugin.