Open contribution · by RMDJ

Use Eternity for free. Forever.

The hosted Builder spends credits because it runs AI on your behalf. The protocol itself does not. This page is the full DIY path — copy the grammar, write your own .ety files, wire it to any model, and run the whole pipeline yourself. No account, no key, no lock-in.

Starter pack

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

✓ Free forever · self-serve
  • · The .ety grammar & 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
⚡ Costs credits · only when we run it
  • · 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

  1. Read the grammar. Section 4 below has the full syntax in one block — copy it into your repo.
  2. Pick a model. Any instruction-tuned LLM works (OpenAI, Anthropic, Gemini, Llama, Mistral, your own fine-tune). Eternity is model-agnostic.
  3. Write a system prompt that includes the grammar + the intent template (§5). Ask the model to emit a single .ety intent file from the user's description.
  4. 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.
  5. Derive verification predicates from the must always, must never, and verify clauses (§7). These run at build-time and at runtime.
  6. Generate the implementation. Second LLM call with the intent + the verification report. Output is an implementation .ety file or your target language directly (§6).
  7. Re-verify. Run the predicates against the implementation. If anything blocks, loop back to step 6 with the failure as feedback.
  8. 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 grammar
file := (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 NEWLINE
BLOCK
'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 pomodoro
02 can access: time, storage
03 cannot access: network
04 can use network: no
05 can write files: yes
06 can read environment: none
07end
08 
09intent pomodoro_timer
10 purpose: 'run a 25-minute focus timer and track daily streaks'
11 
12 requires:
13 a way to read the current time
14 persistent local storage
15 
16 must always:
17 show the remaining seconds to the user
18 persist completed sessions across reloads
19 let the user pause and resume the current timer
20 must never:
21 send data over the network
22 silently lose a completed session
23 
24 verify:
25 remaining_seconds is between 0 and 1500
26 streak_days is at least 0
27 completed_sessions is never negative
28 
29 on failure:
30 say '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:

01configure
02 use time
03 use files
04end
05 
06define start_session
07 given duration_seconds
08 set remaining to duration_seconds
09 set paused to false
10 while remaining is greater than 0 and not paused
11 wait one second
12 decrease remaining by 1
13 end
14 if remaining equals 0
15 append today to completed_sessions
16 save completed_sessions to 'sessions.json'
17 end
18end
19 
20define current_streak
21 given sessions
22 set days to count of distinct dates in sessions
23 give back days
24end
25 
26start
27 set remaining_seconds to 1500
28 set streak_days to current_streak of (load 'sessions.json')
29 start_session with 1500
30end

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 language
function verify(intentAst, implAst) {
const predicates = []
 
// 'must always' → blocking runtime assertions
for (const phrase of intentAst.mustAlways) {
predicates.push({
severity: 'blocking',
kind: 'invariant',
phrase,
checker: deriveChecker(phrase, implAst),
})
}
 
// 'must never' → blocking forbidden-behavior checks
for (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 blocking
for (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.

  1. Create a project folder and drop in the two starter files (download buttons in §5 and §6).
  2. 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.
  3. Export your model key: export OPENAI_API_KEY=… (or Anthropic / Gemini / local Ollama — the pipeline doesn't care).
  4. 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 pipefail
 
INTENT_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.json
 
echo "→ 2/4 deriving predicates"
node ./tools/derive-predicates.mjs .build/intent.json > .build/predicates.json
 
echo "→ 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.