What export_build_package returns
The tool is read-only, so it works with a personal token created with the Read-only box ticked, and with a claude.ai connector granted only Read your documents. Its arguments: project, the name for the headings, cut at 120 characters, defaulting to your first process, else your first sequence, else Runic project; documents, an array of ids or exact names to include, defaulting to every document, with “None of those ids/names matched a document.” when nothing matches; spec, an optional JSON object in the typed shape the build-spec prompt produces, normalised by the same code the app uses on the model's output; only, whose single value is "lint"; and paths, an array of package paths to return whole. An account with no documents gets “The account has no documents to package.”
The full response is one compact JSON object with project, lint as { score, failing: [{ id, title, detail }] }, paths, the list of every path in the package, and files as [{ path, content }]. The files are the app's: CLAUDE.md, KICKOFF.md, docs/spec.md, docs/plan.md, docs/design-brief.md, docs/decisions.md, .claude/rules/runic-dsl.md, then .claude/settings.json only when spec.stack.commands.test is non-empty, then docs/flows/*.runic and docs/sequences/*.runic. Processes are numbered F1, F2 in your sidebar order among the chosen documents; there is no seed, so there is no entry-first reordering, and the process you want as Milestone 1 goes first in the sidebar. The interview is always empty over MCP, so the spec's Appendix: Interview prints None yet, which the placeholder tell exempts. Without spec every spec section prints None yet and most tells fail, which is the loop's starting score, not an error.
only: lint and paths: the fix-and-retry loop
Claude Code caps an MCP tool result at about 25,000 tokens, and a mid-sized package is past that, because every flow is embedded twice, in the spec and in the brief. So the tool budgets its reply at 80,000 characters, about 20,000 tokens. When the files together exceed it, every file is cut to its head, at most 80,000 divided by the file count characters and never fewer than 300, plus “…”, and marked truncated: true; once the heads themselves would pass the budget, the remaining files are listed with an empty content and omitted: true. The response then carries truncated: true, an omitted list when there is one, and a note: “The files together exceed ~20k tokens, so each is cut to its head plus "…" … Call again with paths: ["docs/spec.md"] (one or a few at a time) for whole files, and with only: "lint" while fixing tells.”
only: "lint" returns { project, lint: { score, failing }, paths } and no file contents at all, so a round of the loop costs a few hundred tokens: the model reads failing, amends its spec object, calls again. paths: ["docs/spec.md"] returns only those files, whole, never truncated by the head rule unless the requested set itself exceeds the budget; when none of the requested paths is in the package the tool answers “None of those paths is in the package. Paths: …” with the full list, but an unknown path beside a valid one is dropped without a note and the valid file comes back alone. The lint is the app's ten tells, computed on the same rendered files, so a package that scores 100 over MCP scores 100 in the app for the same spec.
The build-spec prompt
The prompt is listed as build-spec, titled Build spec from the flows, with one optional argument, documents, a comma-separated list of ids or exact names, defaulting to every document; an empty workspace answers “The workspace has no documents yet.” and no match “None of those ids/names matched a document.” In Claude Code it is the slash command /mcp__runic__build-spec. Runic's server assembles one user message and sends no model call: the same SPEC_RULES the app's spec route uses, including the typed shape and the fidelity rules; a nine-point interview the client's model is to run with you in the flows' language, asking only what the documents do not answer: 1 stack and the exact commands, 2 roles with allow, deny, own-only or approval-required per entity operation and the decisions each gates, 3 data fields per .input and payload with the status field and its transitions, 4 failures and edge cases per .fail and section, 5 external systems and what is stubbed, 6 numbers with a comparator and a unit, 7 sign-in method and identity field, 8 design tone, platform, design system and what to avoid, 9 the success metric and what is out of scope; then the deterministic id forms; then the loop; then the chosen flows and sequences embedded under PROCESS FLOWS and SEQUENCE DIAGRAMS.
The loop as the prompt states it: call export_build_package with the JSON as spec, documents as the chosen names and only: "lint"; read lint.failing, each entry a mechanical tell such as an uncovered branch, an orphan field, an NFR without a number or a role without a row; amend the spec, never the flows, and call again with only: "lint" until failing is empty or every remaining tell is one you have told it to accept; then call once without only for the files; if the response says truncated, fetch each file whole with paths; write every returned file into the repository as-is, including the .claude/ directory; and report the score and what M0 and M1 will do. From there the handoff is the app's: run claude --permission-mode plan and paste KICKOFF.md, or keep going in the same session.
How it differs from Build in the app
The model is the client's. Runic's server parses, assigns ids, renders and lints; the interview, the spec JSON and the fixing are done by the Claude your subscription or API key runs, so an MCP build touches neither Runic's AI budget, nor your bring-your-own key, nor the 12-per-hour build limit. What applies instead is the MCP limit of 600 calls per account per hour, and each lint round is one call. There is no brief and no plan over MCP: the spec's Overview has no verbatim brief and no assumptions, Personas has no Actors from the plan, CLAUDE.md has no “Assumed while planning” gotchas, and the design brief's audience comes from the spec's personas. The ids are identical, because the same code assigns them, and the files are identical for the same spec and documents, apart from the date line and the interview appendix. Renaming over MCP does not rewrite .do and .go lines, so rename in the app before packaging.
Limits and gotchas
The 80,000-character budget applies to whatever the call returns, so paths with a long list of files truncates like the full call; ask for one or a few at a time. The tool takes any number of documents; the app's 40 and 20 caps are on its AI routes, not on the renderer, but the build-spec prompt embeds every chosen document in one message, and a very large workspace is better passed as a documents list. Prompt argument values are cut at 4,000 characters. A spec passed with unknown keys has them dropped, and a legacy string criterion is accepted but fails the One When tell. The tool never writes to your workspace; the files land only where the client writes them. Team documents you created are included; a teammate's are not reachable through your token.
How to use it
- Connect RunicUnder Settings → Claude & MCP create a token, read-only is enough, and run the printed claude mcp add command in the repo; or in claude.ai add https://runicflow.ai/api/mcp as a custom connector and press Allow.
- Run the promptIn Claude Code type /mcp__runic__build-spec, optionally with the document names to include. The message arrives with the rules, the interview and your flows embedded.
- Answer the nine-point interviewStack and commands, roles, data, failures, external systems, numbers, sign-in, design, success metric and scope. Skip honestly; what you skip becomes an open question.
- Let it loop on lintThe model calls export_build_package with the spec and only: "lint", reads lint.failing, amends the spec and calls again. Watch the score climb; tell it which tells to accept if any.
- Fetch and write the filesOne call without only returns the files, or truncated heads with a note; the model then fetches each with paths and writes them all into the repo, .claude/ included.
- Kick offRun claude --permission-mode plan in the repo and paste KICKOFF.md, exactly as with the zip.
Commands & shortcuts
| export_build_package | Read-only tool: project, documents, spec, only, paths → { project, lint, paths, files }. |
| only: "lint" | Returns { project, lint: { score, failing }, paths } with no file contents; the cheap call for the loop. |
| paths: ["docs/spec.md"] | Returns only those files, whole; use after a truncated response. |
| lint.failing | The failing tells as [{ id, title, detail }], the detail naming the ids at fault. |
| truncated / omitted | Set when the files pass 80,000 characters: each file cut to its head plus …, the rest listed with empty content. |
| /mcp__runic__build-spec | The prompt as a Claude Code slash command; argument documents, comma-separated ids or names. |
| Read-only | The token checkbox under Settings → Claude & MCP; the build tool and the prompt need no more. |
Tips
- Put the entry flow first in the sidebar before you export. Over MCP there is no seed, so F1 and Milestone 1 are whichever chosen process lists first.
- Pass documents explicitly on a big workspace. The prompt embeds every chosen flow in one message, and the default is all of them.
- Ask for the spec first with paths: ["docs/spec.md"] when a response is truncated; it is the file the other files cite, and the one worth reading whole.
- Accept a tell on purpose when it is right to. A one-screen product cannot reuse a component, and a package without sequences has no contracts; say so and the loop stops.
- Use the same token for the kickoff session. Once Claude Code is building, references, read_document and diff_versions let it follow a flow that changed instead of the snapshot it wrote.
Questions
Which model writes the spec over MCP?
The client's: Claude Code's, Claude Desktop's or claude.ai's model, on your subscription or key. Runic's server calls no model for any MCP tool or prompt, and MCP traffic never touches your Runic AI budget or bring-your-own key.
Does it need write scope?
No. export_build_package is a read-only tool and the prompt only reads documents; a read-only token or a Read your documents grant is enough. Writing the files into the repo is the client's job.
Why is the response cut?
Claude Code caps a tool result at about 25,000 tokens and a package embeds every flow twice. Past about 20,000 tokens each file is cut to its head with truncated: true; paths returns any file whole and only: "lint" skips the files entirely.
Are the files the same as the zip?
Yes for the same spec and documents, apart from the generation date and the interview appendix, which is empty over MCP. The ids, the contracts, the derived screens and the lint come from the same code.
Can I pass the spec the app generated?
The app does not export the spec object, only the rendered files. Over MCP the client's model writes the object from the prompt; the tool accepts any object in that shape and normalises it.