rune builds a backend by shaping it instead of writing it. You describe a module
as a tiny .rune spec — its endpoints, data contracts, and seams — and rune
generates a typed, validated, lint-clean TypeScript tree from it. That generated
code runs on rune's runtime (@mrg-keystone/rune on JSR): a Deno backend that
turns your modules into a routed, documented, self-verifying app. The spec is how
you shape the thing; the runtime is the thing your shape runs on. You regenerate
from the spec — you don't hand-edit the structure — and the same spec carries you
from "write it" to "watch it run green."
- The shaping layer — the
.runespec language and theruneCLI (sync,manifest,check,lint,dev,validate, self-update), plus the architecture linter and the Rustrune-lsp/rune-syntaxhelpers. It lives insrc/(the engine, shipped as prebuilt binaries via the rollinglatestGitHub release),lang/(the grammar andlang/keywords.json, the language's single source of truth), and Rune Studio (rune-studio/, the visual editor for it). - The runtime layer — rune's runtime, published to JSR as
@mrg-keystone/rune: the Deno backend the generated code targets — DI bootstrap, auto Swagger, the interactive cake, the live system map, deny-by-default auth, a headless runner; built on@danet/core. It lives inkeep/, which holds only the publishable package (src/, manifest, README, assets) — seekeep/README.md. The package name@mrg-keystone/runeis a stable identifier, not a separate product.
Everything else is shared across both layers and lives in exactly one place:
claude/ (Claude Code assets — the eight rune skills under claude/skills/ — rune:scope/spec/data/build/cake/framework/docs/diamond — plus claude/agents/), examples/ (spec→code
demos and runnable backends), e2e/ (the spec→runtime acceptance suite), docs/,
todos/.
The repo is a Deno workspace: the root deno.json is rune's config. Its members are
the self-contained sub-projects — keep (the runtime library), the two integration
acceptances (e2e/cake, e2e/checkout), and the examples/in-process-client demo
— so they resolve the runtime from the in-tree source (keep/) and you can test
rune against an unreleased runtime. Generated user projects still pin
jsr:@mrg-keystone/rune@^3 (they live outside this repo) — that is intentional and
unchanged. (rune-studio/ is a standalone Vite app with its own lockfile, run via
its own deno task dev.)
curl -fsSL https://github.com/mrg-keystone/rune/releases/download/latest/install.sh | sh
rune --helpThe installer is idempotent: it first removes any existing rune (from every
known location — ~/.deno/bin, ~/.cargo/bin, ~/.local/bin, …) and then drops
in one fresh copy, so you never end up with stale or duplicate binaries on your
PATH. Pulls the latest prebuilt release (rune + the rune-lsp / rune-syntax
helpers) into ~/.deno/bin — no Deno or Rust toolchain required. It also installs
the rune Claude Code skills into ~/.claude/skills/rune:*/ (plus any bundled
agents into ~/.claude/agents/; skipped when ~/.claude doesn't exist), so Claude
always matches the installed toolchain.
Already installed? rune update (alias: rune upgrade) re-runs this installer —
binaries, skills and agents. Options:
-
RUNE_INSTALL=/usr/local/bin— install somewhere else (must be on yourPATH). -
RUNE_VERSION=v0.1.0— pin a specific snapshot instead of the rolling latest. -
RUNE_VERSION=develop— install the rolling develop build (latest integration work, ahead of stable):curl -fsSL https://github.com/mrg-keystone/rune/releases/download/develop/install.sh | RUNE_VERSION=develop sh
Supported targets: Apple-silicon macOS, Intel macOS, Linux x86-64. On macOS the script de-quarantines the binaries so Gatekeeper doesn't block them.
curl -fsSL https://github.com/mrg-keystone/rune/releases/download/latest/uninstall.sh | sh
# or, from a checkout: deno task uninstallRemoves rune + rune-lsp + rune-syntax from every known install location,
plus the managed skills (~/.claude/skills/rune:*/, and any legacy
~/.claude/skills/rune/ or ~/.claude/skills/keep/ now folded into them) — anything else you keep
in that folder (evals, notes) is left alone.
Installed for you: the skills (and any agents) ship inside every release tarball,
and every install path (scripts/install.sh, deno task install, rune update)
drops them into ~/.claude/skills/rune:*/ and ~/.claude/agents/ so Claude knows
the syntax, lifecycle, and pitfalls of the version you actually have — a pinned
RUNE_VERSION install gets the skills matching those binaries. Source lives in the
repo's claude/ dir (claude/skills/, claude/agents/). Working on them?
deno task install copies them straight from your checkout.
deno task build # compiles dist/rune (+ rune-lsp, rune-syntax helpers)
./dist/rune --help # see all commands
deno task install # or: build from this checkout straight into ~/.deno/binOr run from source without compiling: deno run -A src/bootstrap/mod.ts <args>.
# 1. write a spec (one per module) at src/<module>/<module>.rune
# (copy examples/todos/src/tasks/tasks.rune as a starting point)
# 2. generate the module from it (also writes the project's deno.json import map)
rune sync src/<module>/<module>.rune --artifact lang/keywords.json
# 3. fill in the bodies (the dev-owned mod.ts files); the sig.ts contracts are
# generated for you. then verify, from the project dir:
deno check src/**/*.ts
# 4. lint the result against the architecture
rune . # "All clear — no violations found." = exit 0Edit the spec and re-run rune sync anytime — deno check shows you exactly what
to reconcile (a new abstract method to implement, or a stray one to delete).
rune sync --force prunes files a spec no longer declares.
- Constraints in the spec:
[TYP:uuid] id: string,[TYP:min=0,max=100] qty: number— comma-separated[TYP]modifiers (uuid,email,url,nonempty,json,int,min=N,max=N,positive; they compose withext/core) become class-validator decorators on the generated DTO fields.jsonmarks a string that carries a JSON blob and checks it parses (@IsJSON()) so invalid JSON 422s at the seam, not downstream. - Asserts at every seam: generated coordinators validate input, adapter
reads/writes, and the result via
assertfrom#assert(rune's runtime). A failed contract throwsRuneAssertError, which the runtime maps to HTTP 422 with{ target, context, failures }and dotted paths (lines.1.qty). RUNE_ASSERT=offturns every assert into a passthrough (trusted prod); theno-dto-castlint keeps hand-written coordinator code from bypassing the seams with blindas XxxDtocasts.
The language itself — tags, codegen templates, lint rules, folder layout — lives in
lang/keywords.json (the single source of truth), edited visually in Rune Studio:
deno task studio- Syntax reference:
lang/docs/spec.md - Enforced rules:
lang/docs/constraints.md - Worked examples:
examples/todos/
| Command | Does |
|---|---|
rune init <project-name> |
scaffold a fresh composed monorepo — a Deno-workspace git root (deno.json with workspace: ["./ui","./server"], a generated serve.ts) composing a ui/ package (sprig UI) and a server/ package (server/deno.json, server/bootstrap/, shared spec/runes/core.rune at the git root) — author specs in spec/runes/, rune sync spec/runes/<m>.rune generates into server/src/<m>/ |
rune [dir] |
lint a project against the architecture |
rune sync <file.rune> |
generate/update a module from its spec (+ runtime bootstrap in server/bootstrap/) |
rune manifest <file.rune> |
one-shot generate (no prune) |
rune validate <keywords.json> |
validate the artifact |
rune lsp / rune fmt <file> |
language server / format (Rust helpers) |
rune update [tag] |
self-update binaries + Claude skill (alias: upgrade) |
rune's runtime (@mrg-keystone/rune on JSR) is the Deno backend rune-generated
projects target — DI bootstrap, token/Firebase auth, auto Swagger docs, in-process
API client, Fresh embedding; built on @danet/core. It lives in keep/,
which holds only the publishable package; the package name is its stable id, not a
separate product. Its assert runtime is what rune's generated seams import via
#assert (resolved in-tree to keep/src/assert/mod.ts here, and to
jsr:@mrg-keystone/rune@^3/assert in generated user projects). The lockstep guard
(deno task check:lockstep) machine-checks that the class-validator /
class-transformer / reflect-metadata ranges rune emits match the ranges the runtime
declares in keep/deno.json — a single decorator stack across both.
deno task test:keep # the runtime's test suite
deno task check:keep-jsr # the runtime's JSR publish preflight (dry-run)deno task verify # lockstep guard + the full L0–L7 verify ladder
deno test -A src/ # the engine
deno task test:keep # the runtime's unit suite
deno task test:e2e # the spec→runtime integration acceptance (e2e/)
(cd rune-studio && deno test -A tests/)
(cd lang && cargo test --workspace) # parser + LSPCI is path-filtered by layer:
release-runerebuilds rune's rollinglatestrelease — the three binaries plus the Claude Code assets (claude/skills/rune:*+claude/agents/, bundled asskill/andagent/dirs inside each tarball) — on any push except ones touching only runtime-owned or non-binary facets (keep/,e2e/,examples/,docs/,todos/).publish-keeppublishes the runtime,@mrg-keystone/rune, to JSR on pushes tokeep/**. The skill now ships once (with rune), so this is a pure JSR publish.