1. Why this page exists
We recently locked the hosted MCP endpoint behind sign-in. A shared inference budget cannot survive anonymous abuse, and we'd rather meter our own compute than throttle the protocol. Some readers worried that meant Eternity stopped being open. It didn't.
The protocol — the grammar, the .ety syntax, the intent / implementation / verification split, the MCP contract — is still an open contribution by RMDJ. Copy it, fork it, train on it, build a competing product. This page tells you exactly how.
2. What's free, what's not
- · The
.etygrammar & syntax - · The intent / implementation / verification split
- · The MCP tool contract (names, schemas)
- · The Eternity book + all docs on this site
- · Training a model on any public .ety corpus
- · Self-hosting your own compiler / verifier / MCP server
- · Our hosted MCP endpoint at
/api/mcp(we pay the inference bill) - · The orchestration layer, agent registry, multi-agent routing
- · Hosted publishing at
/p/<slug>
The dividing line is simple: if our servers are doing work for you, you pay. If you're doing the work, the protocol is yours.
3. Step-by-step: run Eternity yourself
- Read the grammar. Section 4 below has the full syntax in one block — copy it into your repo.
- Pick a model. Any instruction-tuned LLM works (OpenAI, Anthropic, Gemini, Llama, Mistral, your own fine-tune). Eternity is model-agnostic.
- Write a system prompt that includes the grammar + the intent template (§5). Ask the model to emit a single
.etyintent file from the user's description. - Parse the .ety. A regex-free PEG parser is roughly 200 lines; you can also use the model itself as the parser by asking for structured JSON.
- Derive verification predicates from the
must always,must never, andverifyclauses (§7). These run at build-time and at runtime. - Generate the implementation. Second LLM call with the intent + the verification report. Output is an implementation
.etyfile or your target language directly (§6). - Re-verify. Run the predicates against the implementation. If anything blocks, loop back to step 6 with the failure as feedback.
- Expose it over MCP (optional, §8) so any MCP client — Claude Desktop, Cursor, your own agent — can call your pipeline.
That's the entire reference pipeline. The hosted Builder does the same five steps; it just hides them behind a "Compile" button.
4. The grammar (copy this verbatim)
This is the canonical .ety grammar. Drop it into your model's system prompt, your parser tests, or your fine-tune dataset.
// .ety — canonical grammarfile := (boundary | configure | intent | define | start)*boundary := 'boundary' IDENT NEWLINE('can access:' list)?('cannot access:' list)?('can use network:' yesno)?('can write files:' yesno)?('can read environment:' (list | 'all' | 'none'))?'end'configure := 'configure' NEWLINE ('use' IDENT NEWLINE)+ 'end'intent := 'intent' IDENT NEWLINE'purpose:' STRING('requires:' PHRASE)*('boundary' PHRASE)* // 'can …' / 'cannot …'('must always:' PHRASE)*('must never:' PHRASE)*('verify:' PHRASE)*('on failure:' PHRASE)?'end'define := 'define' IDENT NEWLINE'given' PARAMS NEWLINEBLOCK'end'start := 'start' NEWLINE BLOCK 'end'// Reserved keywords:// intent, define, start, end, boundary, configure, use,// purpose, requires, must always, must never, verify, on failure,// given, can, cannot, access, network, files, environment// Phrases are plain English. No symbols. No operators in the contract layer.
5. Intent file template
The intent file is the human layer. Anyone — engineer or not — should be able to read it. Copy this template and adapt it:
01boundary pomodoro02can access: time, storage03cannot access: network04can use network: no05can write files: yes06can read environment: none07end0809intent pomodoro_timer10purpose: 'run a 25-minute focus timer and track daily streaks'1112requires:13a way to read the current time14persistent local storage1516must always:17show the remaining seconds to the user18persist completed sessions across reloads19let the user pause and resume the current timer20must never:21send data over the network22silently lose a completed session2324verify:25remaining_seconds is between 0 and 150026streak_days is at least 027completed_sessions is never negative2829on failure:30say 'state corrupted — restoring from last snapshot'31end
6. Implementation file template
The implementation file is the AI layer. It fulfils every rule in the intent file and stays in the same plain-English register. Same .ety extension, but it uses define and start blocks:
01configure02use time03use files04end0506define start_session07given duration_seconds08set remaining to duration_seconds09set paused to false10while remaining is greater than 0 and not paused11wait one second12decrease remaining by 113end14if remaining equals 015append today to completed_sessions16save completed_sessions to 'sessions.json'17end18end1920define current_streak21given sessions22set days to count of distinct dates in sessions23give back days24end2526start27set remaining_seconds to 150028set streak_days to current_streak of (load 'sessions.json')29start_session with 150030end
7. Writing a verifier
The verifier reads the intent file and emits typed predicates. Each predicate has a severity (blocking, warning, info) and is phrased so either a test or a careful reader can check it.
A minimal verifier is roughly 150 lines and follows this shape:
// pseudo-code, port to any languagefunction verify(intentAst, implAst) {const predicates = []// 'must always' → blocking runtime assertionsfor (const phrase of intentAst.mustAlways) {predicates.push({severity: 'blocking',kind: 'invariant',phrase,checker: deriveChecker(phrase, implAst),})}// 'must never' → blocking forbidden-behavior checksfor (const phrase of intentAst.mustNever) {predicates.push({severity: 'blocking',kind: 'prohibition',phrase,checker: deriveForbiddenChecker(phrase, implAst),})}// 'verify' → runtime contract checks (numeric / shape)for (const phrase of intentAst.verify) {predicates.push({severity: 'warning',kind: 'contract',phrase,checker: deriveContractChecker(phrase),})}// 'boundary' violations are always blockingfor (const b of intentAst.boundary) {predicates.push({severity: 'blocking',kind: 'boundary',phrase: b,checker: deriveBoundaryChecker(b, implAst),})}return {blocking: predicates.filter(p => p.severity === 'blocking'),warnings: predicates.filter(p => p.severity === 'warning'),info: predicates.filter(p => p.severity === 'info'),}}
8. Self-host the MCP server
The MCP contract is open: any server that exposes the four tools below with matching schemas is a valid Eternity MCP server. Clients (Claude Desktop, Cursor, custom agents) will discover and call it the same way they call ours.
{"$schema": "https://eternity.rmdj.dev/schemas/mcp-tool-contract.json","protocol": "mcp/1.0","transport": "streamable-http+jsonrpc-2.0","tools": [{"name": "compile_intent","description": "Compile a natural-language description into a .ety intent file.","inputSchema": {"type": "object","properties": {"description": {"type": "string"}},"required": ["description"]},"outputSchema": {"type": "object","properties": {"ety": {"type": "string"}},"required": ["ety"]}},{"name": "verify_intent","description": "Derive runtime predicates from a .ety intent file.","inputSchema": {"type": "object","properties": {"ety": {"type": "string"}},"required": ["ety"]},"outputSchema": {"type": "object","properties": {"blocking": {"type": "array","items": {"type": "object"}},"warnings": {"type": "array","items": {"type": "object"}},"info": {"type": "array","items": {"type": "object"}}}}},{"name": "generate_plan","description": "Produce a per-project implementation plan from a verified intent.","inputSchema": {"type": "object","properties": {"ety": {"type": "string"}},"required": ["ety"]},"outputSchema": {"type": "object","properties": {"plan": {"type": "string"}},"required": ["plan"]}},{"name": "generate_project","description": "Generate a runnable implementation from intent + plan.","inputSchema": {"type": "object","properties": {"ety": {"type": "string"},"plan": {"type": "string"}},"required": ["ety","plan"]},"outputSchema": {"type": "object","properties": {"files": {"type": "array","items": {"type": "object","properties": {"path": {"type": "string"},"content": {"type": "string"}},"required": ["path","content"]}}}}}]}
Transport is plain Streamable HTTP with JSON-RPC 2.0 — no framework needed. Any tiny HTTP server in any language can host it. We deliberately do not publish our orchestration layer (agent registry, multi-agent routing, the planner's credit-aware scheduler) — that's the part we keep proprietary so we can fund the open protocol.
9. Verify locally (no hosted Builder needed)
Here's the minimum command sequence to run the entire intent → verify → implement → re-verify loop on your own machine. Swap any step for your preferred model or language — the contract is the .ety, not the tooling.
- Create a project folder and drop in the two starter files (download buttons in §5 and §6).
- Add a
tools/directory with four tiny scripts:parse-ety.mjs,derive-predicates.mjs,generate-impl.mjs,verify.mjs. Each is one LLM call plus a JSON read/write. - Export your model key:
export OPENAI_API_KEY=…(or Anthropic / Gemini / local Ollama — the pipeline doesn't care). - Run the script below. Total runtime is dominated by the two LLM calls — usually under 30 seconds end-to-end.
#!/usr/bin/env bash# verify-local.sh — run the full Eternity pipeline on your own machine.# Requires: node 20+, an OPENAI_API_KEY (or swap to any other model).set -euo pipefailINTENT_FILE="${1:-pomodoro.intent.ety}"IMPL_FILE="${2:-pomodoro.impl.ety}"echo "→ 1/4 parsing intent"node ./tools/parse-ety.mjs "$INTENT_FILE" > .build/intent.jsonecho "→ 2/4 deriving predicates"node ./tools/derive-predicates.mjs .build/intent.json > .build/predicates.jsonecho "→ 3/4 generating implementation (LLM call)"node ./tools/generate-impl.mjs .build/intent.json .build/predicates.json > "$IMPL_FILE"echo "→ 4/4 re-verifying implementation"node ./tools/verify.mjs "$INTENT_FILE" "$IMPL_FILE"echo "✓ done — implementation passes every blocking predicate"
Expected output: four checkmarks and an implementation passes every blocking predicate line. If a predicate fails, the script exits non-zero and prints the failing phrase — feed that back into step 3 as additional context and re-run.
10. Train a model on .ety
You're free to fine-tune any model on the public .ety corpus: the protocol page, the docs, the examples, and any /p/<slug> page (which publishes both the intent and implementation .ety).
We ask one thing: credit RMDJ as the protocol author and don't pass off our orchestration outputs as the protocol itself. The protocol is the contract; our agents are not.
11. FAQ — what's metered vs free
This is the single source of truth. If the homepage, docs, or any older blog post says something different, trust this section.
12. License & attribution
Protocol & documentation: open — free for any use including research, education, training open models, and building your own tools. Just credit RMDJ as the protocol author.
What we keep: the agent orchestration layer, the multi-agent registry, our hosted Builder UI, and the proprietary verifier extensions live inside our infrastructure. They're how we fund the open contribution.