| *English | 中文* |
One format, two readers.
People and AI agents now co-write the same document.
Legible for people; addressable, verifiable, and versioned for machines.
GEML is plain text — organized by one typed block for everything, remembered by a .gemlhistory sidecar.
▶ Try GEML in the Playground — edit on the left, rendered on the right, and the build verdict flips the moment a reference breaks. No install.
GEML is a markup language for structured documents. A .geml file reads as plain text, so you never need a renderer to read it. And instead of a separate mini-syntax for each kind of content, GEML puts everything on one construct: the typed block.
=== code {#hello lang=python}
print("hi")
===
Code is a block. So are tables, diagrams, math, callouts, and document metadata. The shape is the same every time, which makes the format easy to learn and hard to get wrong.
Markdown was designed for documents that people hand-write and people read. Today the same documents are also written, edited, reviewed, and queried by AI agents and CI pipelines — and that shift asks three things of a format that Markdown was never built to give:
GEML is built around those three. The goal wasn’t to bolt “AI features” onto a document format. It was to pick a format that is both simpler for people and more dependable for machines.
Plenty of formats do one or two of these. What’s unusual about GEML is that one plain-text format does all three:
=== type {…} typed block. One grammar to learn, one grammar to generate correctly: no per-feature syntax, no HTML fallback.#id on any block and reference it anywhere; a dangling reference or a broken cross-document link is a build error, not a silent 404. Automated edits can’t quietly rot..gemlhistory file reconstructs any past revision and rolls the document back — offline, with no git and no service — and it’s plain text an agent can read to understand how the document evolved.For a fuller side-by-side across Markdown, HTML, CommonMark, AsciiDoc, and Org-mode, see the format comparison.
One shape, every type. A block is always === type {#id .class key=val} … === — only the type (and how its body is read) changes:
=== code {lang=python}
print("hi")
===
=== note {.intro}
Parsed prose with *emphasis* and a [[#budget]] reference.
===
=== meta
title = "Budget plan"
===
A run of = (three or more) opens a block; an equal-length run closes it; longer fences nest inside shorter ones. A block that carries an #id can also close with the labeled fence === #id — no fence-length counting, which makes long or nested blocks much harder to get wrong. The type decides how the body is read — raw (verbatim: code, diagram, math, table), flow (parsed prose with inline markup: note), or data (one key=val per line: meta) — and every block may carry an attribute object {#id .class key=val}, where a .class is a semantic label, never a styling hook. The full inline grammar (emphasis, links, [[#id]] auto-references, media, footnotes, inline $math$) is in the spec.
Write a table visually:
=== table {#budget caption="Annual cost"}
| Plan | Months | Rate |
|-------|-------:|-----:|
| Basic | 1 | 30 |
| Pro | 2 | 30 |
===
…or as data, with computed columns and a summary row:
=== table {#fy25 format=csv header=1 compute="FY [%.1f] = Q1 + Q2 + Q3 + Q4" summary="Segment = 'Total'; FY [%.1f] = sum(FY)"}
Segment, Q1, Q2, Q3, Q4
Cloud, 8, 10, 12, 14
Platform, 5, 6, 7, 9
Services, 3, 4, 4, 5
===
Both forms describe the same model. The FY column and Total row are computed at build time:
| Segment | Q1 | Q2 | Q3 | Q4 | FY |
|---|---|---|---|---|---|
| Cloud | 8 | 10 | 12 | 14 | 44.0 |
| Platform | 5 | 6 | 7 | 9 | 27.0 |
| Services | 3 | 4 | 4 | 5 | 16.0 |
| Total | 87.0 |
compute runs + - * / ( ) per row over columns; summary adds a foot row from the aggregates sum / avg / min / max / count (with arithmetic over them, e.g. weighted ratios); a trailing [printf] sets numeric display.
Tables can also pull their data from an external CSV via src="regions.csv".
=== math {#gauss caption="Gaussian integral"}
\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
===
GEML never interprets a diagram body; it routes it to a pluggable renderer (an unknown format is a warning, body preserved):
=== diagram {#flow format=mermaid caption="Review flow"}
graph LR
A[Draft] --> B{Review} -->|ok| C[Publish]
===
graph LR
A[Draft] --> B{Review} -->|ok| C[Publish]
A diagram can also chart a table — single source of truth, with the column references checked at build time and no data copied:
=== diagram {format=geml-chart data=#fy25 type=bar x=Segment y=FY}
===
Drawn from the #fy25 table above:
xychart-beta
title "FY by segment"
x-axis [Cloud, Platform, Services]
y-axis "FY"
bar [44, 27, 16]
To really feel how powerful and flexible a single GEML primitive is, let’s try it on a code graph — a familiar but demanding case for programmers:
your whole codebase’s call graph, written as GEML. geml codemap build lays the call graph out as a tree of GEML documents — every method an #id block, with #calls / #called-by edges both ways. The downstream chain (what a method calls) for troubleshooting, the upstream chain (who calls it) for the blast radius — all visible in a second;

npm i -g @geml/geml # needs Node 22+
geml codemap build # --root defaults to . : detect languages -> index -> one merged graph in ./.geml-code-graph/
geml codemap serve # opens your browser on the graph
TS/JS — zero setup:
buildfetches the scip indexer by itself. Java / C / Python / Go / Kotlin — one extra download, Joern: unzip its release package and pass that folder to build, e.g.--joern C:\joern\joern-cli(or put it on PATH and skip the flag). Mixed front-end + back-end repo — everything merges into one graph.
geml-code-graph is itself a diagram format — one line embeds it in any GEML document (=== diagram {format=geml-code-graph src=.geml-code-graph/index.geml} ===), and every code change auto-triggers a rebuild, so the graph never drifts. Scale is no obstacle: the graph is plain-text data tables — tens of thousands of files and hundreds of thousands of edges stay instant to open and query (pan across the whole thing and its dense, web-like symmetry is genuinely striking), and you can grep any method name to trace its call chain.
.geml link and watch it render — the GEML spec itself (dogfood — the spec is a GEML document, rendered at scale), the showcase (a computed table, four charts, a Mermaid flow, and math), or playground/sample.geml for the interactive code-graph.The same shape that makes GEML pleasant to read directly is what makes it reliable under automation:
.geml directly. What it sees is the document.diagnostics array, so agents and CI get a structured pass/fail signal.GEML is meant to be written and edited by models — precisely. To change one
thing, an agent needn’t re-read and re-emit the whole document: it addresses a
single block by id, then validates. The CLI is designed against one bar — can a
single agent run a document’s whole life from the shell? — so its verbs aim to be
complete (a verb for every step), ergonomic (few flags, pipeline-friendly
I/O), and consistent (name a target #id and the content adopts it; every
write is guarded).
npm i -g @geml/geml # installs the `geml` command
geml doc.geml # document-model JSON (default --to json)
geml doc.geml --to md|html|geml # convert (geml notes.md -> GEML; -o writes a file)
geml get doc.geml ['#id'] # list every id, or print ONE block (a heading id = its section)
geml set doc.geml '#license' --in template.geml#mit # replace a block, forking another (id adopts #license)
geml add doc.geml --after '#intro' --in snippet.geml # insert a fragment (keeps its own ids)
geml delete doc.geml '#draft' '#tmp' # remove one or more blocks
geml rename doc.geml '#old' '#new' # rename an id + every reference to it
geml revert doc.geml '#plan' --rev -1 # roll ONE block back to an earlier revision
One entry, geml <file> [--to <fmt>], converts in either direction: the input
format is inferred (--from overrides > extension > GEML) and the target is
--to (default: a GEML input → JSON, a Markdown input → GEML). To mutate, four
verbs cover the whole block lifecycle: set replaces a block (forking content
from a file or stdin and adopting the target id), add inserts a fragment at a
position, delete removes one or more blocks, and rename rewrites an id and
every reference to it. Each mutation writes the whole updated document — in place
for a file, to stdout for -, -o to redirect — so edits pipe cleanly, and each
is guarded: re-parsed and refused if it would break the document. Read-and-patch
by id keeps every edit small and precise — a fraction of the tokens of shipping
the whole file.
.claude/skills/ — geml/ for authoring,
geml-code-graph/ for the call
graph — into ~/.claude/skills/. Claude auto-loads them: it runs geml check
whenever it touches a .geml file, and builds/opens the code graph when you
ask “show me the code graph” or “who calls X” — no CLI or prompting needed.geml check on the output for a hard pass/fail.GEML primer. Write the document as GEML. Every block is
=== type {#id .class key=val}…===; the closing fence is a run of=of the exact opening length, and a longer fence nests a shorter one — or, when the block has an#id, close it with the labeled fence=== #id(no length counting; prefer this for long or nested blocks). Block types:code/diagram/math/table(verbatim body),note(prose with inline markup),meta(onekey=valper line). Headings are ATX#only — no---frontmatter (use=== meta). Every#idis unique and every reference ([[#id]],[text](#id),[^id], chartdata=#id) must resolve. No raw HTML. Inline:*em*,**strong**,`code`,$math$,[text](url). The normative spec isGEML-spec.md.
This package includes a standard Model Context Protocol (MCP) server that exposes GEML document CRUD operations. It runs locally and supports Windows, macOS, and Linux.
To connect it to an MCP-compatible client, provide the npx execution command and specify the --root argument (the directory containing your .geml files).
Point --root at a repository that has a code graph (geml codemap build) and the same server also exposes the read-only call-graph tools — one entry, not two.
Add to your claude_desktop_config.json:
{
"mcpServers": {
"geml": {
"command": "npx",
"args": [
"-y",
"@geml/geml@latest",
"mcp",
"--root",
"/absolute/path/to/your/docs"
]
}
}
}
Run the following command to add the server:
/mcp add npx -y @geml/geml@latest mcp --root /absolute/path/to/your/docs
geml CLI — one command for the whole document lifecycle (@geml/geml on npm; source: geml-parser/):
npm i -g @geml/geml
geml check doc.geml # validate: broken refs are errors, non-zero exit — CI-ready
geml doc.geml --to html -o doc.html # one self-contained, interactive page
geml notes.md # come from Markdown; `--to md` goes back
Everything parses to a document-model JSON with a diagnostics array, so scripts and agents get a structured pass/fail — the block editor (get/set/add/delete/rename), versioning, formatter, and code graph below are all the same command.
integrations/geml-viewer/ renders .geml locally (file://) and on the web: tables with computed columns, geml-chart as inline SVG, Mermaid diagrams, KaTeX math, and the build-time diagnostics shown as a banner. Install: build it, then chrome://extensions → Load unpacked (steps). See it in one click: with the extension loaded, open a raw .geml URL (the raw file, not the GitHub blob page — that one is HTML) and it renders in place — try the showcase (a computed table, four charts, a Mermaid flow, and math) or the GEML spec itself, a full document rendered at scale. For the interactive geml-code-graph, download playground/sample.geml with its codemap/ folder and open it over file://.geml get <file.geml> #id prints one block by id; set, add, delete, and rename mutate one block, a fragment, or an id at a time — each re-parsing and refusing any write that would break the document. A heading’s #id addresses its whole section (through the next same-or-higher heading), so an agent edits one section — heading, prose, and nested blocks — without re-reading or re-emitting the whole file.geml history <commit | verify | show | restore | log> <file.geml> over the self-contained .gemlhistory sidecar, plus geml revert <file.geml> #id [--rev -1] to roll a single block back to an earlier revision (by -N offset, 0 for the tip, or an id prefix; --rev changed skips to the last revision that actually changed that block). Addressable and versioned — the substrate for an agent that revises a document step by step and can rewind any one section. revert is the block-level undo: it splices changed content back, resurrects a deleted block, or removes one that did not exist at the target revision — the inverse of set/delete/add (and rename undoes itself with rename #new #old).geml mcp --root <dir> serves the block editor to an MCP client, so an assistant changes one block instead of rewriting a file (claude mcp add geml -- geml mcp --root /abs/path/to/repo). Nine tools: list/read/check/history, plus write/add/delete/rename/revert. A write is parsed before it reaches disk and refused with its diagnostics if it would break the document; every write first records a .gemlhistory revision, so geml_revert_block can undo a single block while the rest of the file stays byte-identical. Paths are confined to --root, which a client cannot widen. When that root holds a code graph (<root>/.geml-code-graph, or --graph <dir>), the same server also serves the read-only resolve_name / open_symbol / get_backlinks — one client entry and one process for both, instead of registering a second server. See docs/mcp-guide.md.geml <file.geml> --to geml [-o out.geml] re-serializes the document model back to canonical GEML (the inverse of the parser). parse(serialize(parse(x))) is the same model — a round-trip property checked across the test suite — and the output is idempotent.geml <file.md> [-o out.geml] (a Markdown input defaults to --to geml). Maps frontmatter → meta, fenced code → code, ` ```mermaid/graphviz/… ` → diagram, $$ → math, blockquote → note, GFM tables → table, footnotes, autolinks, and setext → ATX.geml <file.geml> --to md [-o out.md] projects a document to GFM: frontmatter from meta, computed tables as GFM tables, note as blockquotes, footnotes, fenced code/mermaid, $$ math. Lossy by nature — Markdown has no typed-block primitive — so each unmappable construct (geml-chart, {hidden}, block ids) is reported as a note.geml <file.geml> --to html -o out.html turns a document into one self-contained, interactive HTML file: sortable/filterable tables, geml-chart as inline SVG drawn from its table, rendered diagrams, and the build-time checks carried through to a non-zero exit. See the showcase.geml source in docs/examples/.GEML is 1.0 — stable, and used to write real documents (this repo’s own spec is one).
Maturity signals. A complete core spec (§1–§8) plus a history-extension spec, both EN / 中文; a working reference parser, renderer + CLI; a conformance suite (input → projected document model) that a second, independently-written parser must reproduce exactly — two separate implementations agreeing case-for-case is what keeps subtle rules like emphasis and lists from drifting — backed by 600+ unit and conformance checks (~99% line coverage; CI-gated at ≥95% lines / statements / functions / branches); and self-hosting — GEML-spec.geml is the specification written in GEML, parsed clean on every test run.
Design boundaries (non-goals). GEML stays small on purpose:
--- frontmatter, no thematic-break guesswork.Contributing. Contributions of every kind are welcome — bug reports, tooling and integrations, broader conformance coverage, and the spec itself. GEML is 1.0, but the format can still evolve: substantive spec changes are discussed and land through a GEP, each with its conformance case. The reference parser’s test suite is the contract, so code changes should keep npm test green and the dogfood spec parsing clean. The most valuable contribution is an independent parser in another language — a portable conformance suite makes it a weekend project; see docs/WRITING-A-PARSER.md.
| Document | English | 中文 |
|---|---|---|
| Core spec | GEML-spec.md |
GEML-spec_CN.md |
| History extension | GEML-history-spec.md |
GEML-history-spec_CN.md |
spec/ Core spec + .gemlhistory extension (EN / 中文), the dogfood
GEML-spec.geml, the CC-BY spec license, and proposals/ (GEPs)
geml-parser/ Reference parser, renderer, CLI + codemap toolkit (TypeScript, Node 22)
integrations/ Everywhere GEML plugs in: geml-viewer (browser extension),
geml-check-action (CI), vscode, obsidian, tree-sitter (brief)
playground/ In-browser playground (+ a live geml-code-graph of this repo)
docs/ Guides, design notes, the format COMPARISON (EN / 中文),
assets, and an example .geml document to render
Code (geml-parser/, integrations/geml-viewer/, integrations/geml-check-action/) is MIT (LICENSE). The specification documents are CC-BY-4.0 (LICENSE-spec.md) — a spec is not software, and anyone may build a conformant implementation. See GOVERNANCE.md for how decisions are made and CONTRIBUTING.md to get involved.