Skip to content

GEMLA lightweight markup language with uniform, addressable blocks and standard verbs.

Easy for humans to read, safe for agents to mutate.

MCP ToplistMentioned in Awesome AI PluginsMentioned in Awesome Markdown
GEMLGEML

Syntax at a glance ​

In GEML — the General Expressive Markup Language — every kind of content is one block shape: === type {attributes}, a body, ===. Headings are blocks too, and every block has a name.

=== meta
title = "Budget plan"
===

# Budget plan {#top}

Prose with *emphasis*, a [[#fy25]] reference and a footnote[^addr].

=== table {#fy25 format=csv header=1}
Segment,  Q1, Q2, Q3, Q4
Cloud,     8, 10, 12, 14
Platform,  5,  6,  7,  9
===

=== view {#fy25-total src=#fy25 compute="FY = Q1 + Q2 + Q3 + Q4"}
===

=== diagram {#rev format=geml-chart data=#fy25-total type=bar x=Segment y=FY}
===

=== embed {src=#fy25}
===

=== note {#addr}
Every block above has an address.
===
ConstructSyntax
Typed block=== type {#id key=value} … ===
Heading with an id## Title {#id} — derived from the text when omitted
Reference[[#id]] · across documents [[doc.geml#id]]
Link[text](https://example.com)
Embed (a projection, not a copy)=== embed {src=doc.geml#id}
Inline projection![[doc.geml#id]]
Tablepipes, or === table {format=csv header=1}
Derived view=== view {src=#table compute="…" summary="…"}
One cell, one leaf#fy25[2]["Q1"] · #intake["fields"][1]["name"]
Data=== data {format=json} (also jsonl, yaml, edn)
Chart bound to data=== diagram {format=geml-chart data=#id type=bar x=… y=…}
Meta value in prose{{title}}
Footnote[^note] … === note {#note} — any block with that id
Hidden block · author note{hidden} · a line starting with %%
Prose as a block=== text {#id} … ===
Vocabularyprofile = "geml-media/v1" in === meta

The cheat sheet lists every construct with an example. The playground has seven chapters, each a real .geml file you can edit.

Verbs on your Markdown ​

Nothing is converted. plan.md stays plan.md; every heading is an address.

console
$ geml list plan.md
#data-warehouse-migration  heading  h1    L1-39   Data warehouse migration
#summary                   heading  h2    L3-8    Summary
#migration-plan            heading  h2    L9-17   Migration plan
#capacity-and-cost         heading  h2    L18-27  Capacity and cost
#risks                     heading  h2    L28-33  Risks
#open-questions            heading  h2    L34-39  Open questions

$ geml set plan.md '#migration-plan' --in new-plan.md
wrote plan.md
$ git diff --stat
 plan.md | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

$ geml set plan.md '#risks' --in bad.md
error: replacement would break the document: unresolved reference `#checksum-job` (line 30); not written
exit=1

$ geml revert plan.md '#summary' --rev changed
reverted #summary to 20260929T133449Z-6b606e52

get reads one section. set replaces one section and leaves every other byte alone. A write whose result would be broken is refused before it reaches disk. revert rolls one section back and keeps the edits made elsewhere in the meantime.

Headings are as fine as Markdown goes. When a section is too coarse — a table, one cell, a chart that must agree with its table — the .geml format gives every block a name and every cell a coordinate.

Install ​

sh
npm i -g @geml/geml                    # the geml command (Node 22+)
npx -y @geml/geml skill install        # Claude Code: authoring skill + CLI + MCP server, user-global
claude mcp add --scope user geml -- npx -y @geml/geml mcp --root .   # or any MCP client

Read .geml in the browser with the Chrome extension; editor and agent integrations are listed under Get Started.

Why GEML ​

  • A name for every block. Pointing at a place costs one word, not a quoted paragraph.
  • A write that is checked before it lands. A broken reference is refused with a diagnostic and a non-zero exit — a gate an agent loop can stand behind.
  • A reference is a lookup, not a copy. An embed, a chart bound to a table, a view over data: the value exists once, so copies cannot drift.
  • History at the grain of the mistake. A .gemlhistory sidecar rolls one block back and leaves concurrent edits alone.
  • One grammar, many vocabularies. Code graphs, styling, media production and revision history are profiles of the same block shape, each checked by geml check.

Scope ​

  • Not a Markdown dialect. The verbs run on your .md unchanged; .geml is a separate language with one normative specification and a conformance suite, and it projects back to Markdown or HTML with --to md|html — block ids and live charts are reported as lost, not hidden.
  • On Markdown, addressing stops at headings. Cells, views and bound charts need .geml.
  • Validation stops broken structure, not bad prose. A mangled paragraph with valid links passes check; that is what revert is for.
  • Not a database. No index, no transactions. It borrows a database's operations, not its runtime.
  • Young. Spec 1.0 is stable and self-hosted. Besides the reference parser there is one independent implementation, geml-parser-rs (Rust + WebAssembly), written from the specification and its conformance suite alone; it passes all 429 cases.

Influences ​

  • Markdown — plain text that reads clean is the ground everything stands on; GEML reads it as input.
  • REST — one naming scheme and one set of verbs, so no client needs to know each server.
  • XInclude and Sphinx cross-references — an embed evaluates; a reference is checked.
  • Make — every artifact records its inputs, so a change names what is stale.
  • djot — a grammar that parses in linear time with no ambiguity is kinder to people, tools and models alike.

Reference ​

  • Specification · 中文 — normative, with Appendix A's diagnostic catalogue
  • Profiles — how GEML is extended, the six vocabularies so far, and a one-page usage guide for each
  • Proposals (GEPs) — the change process, and every accepted proposal
  • Writing a parser — the conformance suite a second implementation must reproduce
  • Claude Code & MCP — the eleven tools and one-line setup
  • Comparisons — against Markdown, CommonMark, XML and JSON
  • Benchmarks — what addressing by block saves, measured
  • Manifesto — Doc-as-a-Base: four laws and their boundaries
  • Source — spec, parser, integrations; issues and critique welcome

The parser is @geml/geml on npm. Spec 1.0 is stable: rules already in it will not shift under you; a breaking change bumps the spec version and ships with updated conformance cases.