GEML — General Expressive Markup Language
English | 中文
GEML is a markup language people and AI agents can write in the same document.
One format, two readers. For people, plain text that reads clean; for agents, a "Doc-as-a-Base" — addressable, verifiable, traceable, revertible.
GEML is minimal. It is dead simple — one block syntax for the whole language; it is plain text — still clean with no renderer in sight; it is machine-friendly — addressable, verifiable, referenceable structure, natively.
A .geml file is plain text, so you never need a renderer to read it. And instead of a separate mini-syntax for each kind of content, GEML carries every kind in one container: the typed block. Code is a block. So are tables, diagrams, math, callouts, even metadata — and a run of prose can be one too (=== text), whenever you want it addressable. Extending it later is just as plain. The shape is the same every time, which makes the language easy enough to learn that it's hard to get wrong.
=== code {#hello lang=python}
print("hi")
===
geml get doc.geml '#hello' # by name, just this block
Blocks have names so the verbs have somewhere to land — the full syntax is in the format in 1 minute.
Contents: Why now · What's different · The format in 1 minute · A gift for programmers · Get hands-on · With an LLM · Maturity & versions · Contributing · License
Why a new format now
Because the reader has changed.
For decades, a text was optimized either for human reading (e.g., Markdown, Word) or for machine parsing (e.g., JSON, Schema). But in the LLM era, humans and agents are co-reading, co-authoring, and rewriting the same document together for the first time. The old ways of working are breaking down: every time we provide context or prompts, we manufacture copies. The engineering Source of Truth gets infinitely duplicated, fragmented, and eventually drifts away.
💡 Deep Dive: If you are interested in the dilemma of engineering documents in the LLM era and why we need to redesign a plain-text format from the ground up, read our full article: "Why Do We Need a New Text Format in the Era of LLMs?"
To solve this crisis of "copy explosion" and "broken dependencies," we need to ensure that knowledge fragments in plain text can be precisely held and verified by machines. Therefore, the format carrying the text must provide four core capabilities at the syntax level:
- Block-level Addressing: Every block has a unique
#id; we no longer address just the whole file. - Reference-based Projection (Transclusion): Assembling context by looking up values, not copying them (
embed). - Build-time Verification: Any broken link causes an immediate build error instead of decaying silently.
- Block-level Revert: Fine-grained, single-block history rollbacks, independent of Git.
This is exactly why GEML was created. We are not asking anyone to abandon their existing formats; instead, we are adding this missing network to the existing ecosystem.
What's different about GEML
The four capabilities were established a chapter ago — addressing, projection, verification, revert. This chapter is where each format lands against them, and where GEML draws its boundaries.
How other formats compare
Each of the four has mature solutions in its own field; what's unusual is meeting all four in one plain-text format:
| Family | What the state really is | Addressable / referenceable | Projectable / embeddable | Verifiable | History / traceability |
|---|---|---|---|---|---|
| Word / Docs | Opaque state | ❌ No block-level keys; access via platform APIs | ❌ Copy-paste only | ❌ No checking at all | ⚠️ Platform server-side, not in the file |
| Markdown / AsciiDoc | A stream of characters | ⚠️ Heading anchors or dialect ids; no read/write verbs | ⚠️ Dialect embeds (Obsidian ![[…]], include::) — break silently | ❌ Broken links fail silently | ❌ None in-format — external git required |
| JSON / XML | Data serialization | ✔️ (id / schema) | ⚠️ XML only (XInclude, external) | ✔️ Via an external toolchain | ❌ None in-format — external git required |
| GEML | Plain text + block structure | ✔️ A unique #id per block (referenceable natively) | ✔️ === embed: a reference is a lookup (native) | ✔️ A build-time error | ✔️ .gemlhistory next to the file (traceable natively) |
Item by item: vs. CommonMark · vs. XML and JSON · a 7-format capability matrix.
And the coexistence story in one line: Markdown owns the mainstream surfaces, so GEML positions itself as the editing source of truth, not the delivered artifact — project one way with geml <file> --to md|html and ship .md or .html as before. Collaboration, not lock-in. (Projection is lossy: block ids and table-bound charts don't survive it.)
Design boundaries (non-goals)
GEML stays small on purpose:
- No raw-HTML escape hatch — semantics stay portable, tied to no backend or renderer.
- Hosts external diagram DSLs (Mermaid, Graphviz, D2, …) rather than inventing one.
- Tables compute, but aren't a spreadsheet engine — per-row formulas and summary aggregates, not cell addressing, lookups, or macros.
- ATX headings only — no setext, no
---frontmatter, no thematic-break guesswork.
The same restraint governs the command set. It is honed 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, so nothing forces a whole-file rewrite to change one block), ergonomic (few flags, sensible defaults, pipeline-friendly I/O), and consistent (name a target #id and the content adopts it; a file is edited in place while - streams to stdout; every write is guarded).
The format in 1 minute
Typed blocks
One shape, every type. A block's basic syntax is === type [attributes] … === (where attributes like {#id .class key=val} are optional) — 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 blocks much harder to get wrong (nesting still requires a longer outer fence: a same-length bare === in the body closes the block early, labeled or not). The type decides how the body is read — raw (verbatim: code, diagram, math, table), flow (parsed prose with inline markup: note, text), or data (one key=val per line: meta); embed carries no body at all — its src= names the block it stands for — 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.
Tables — two bodies, one model
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
=== math {#gauss caption="Gaussian integral"}
\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
===
$$\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}$$
Diagrams & charts — host a DSL, or chart a table
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]
Embeds — reference, don't copy
One block can stand for another — in the same document by #id, or across documents by src=other.geml#id — and renders that block's current state in place:
=== embed {src=#fy25}
===
The body stays empty (the target lives in src=), and the target is checked like any reference: if it goes missing, geml check fails the build.
A gift for programmers — geml-code-graph
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
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
[!NOTE] Requirements. Node 22+ for the CLI (
npm i -g @geml/geml). Everything below is optional and used only where noted: Joern for non-TS/JS languages in the code graph, and Chrome for the viewer extension.
[!TIP] 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 ~/joern/joern-cli(--joern C:\joern\joern-clion Windows), 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 an optional per-commit hook (bundled with the Claude skill) rebuilds it as the code moves, so the graph doesn't drift.
Scale is measured, not promised: on Apache Flink's codebase — 13,585 Java source
files, ~81,000 methods, 266,821 call edges — the plain-text data tables still
open and query instantly, and you can grep any method name to trace its call chain.
Reproduce it yourself: clone apache/flink and run geml codemap build --joern … at
its root.
Next — get hands-on now
▶ Try writing GEML in the Playground — edit on the left, rendered live on the right, and the build verdict flips red the moment a reference breaks. No install, nothing to read first.
Then, in the order that suits you:
- See it render in your browser. Install the extension and open a raw
.gemllink (the raw file, not the GitHub blob page — that one is HTML): 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. - Run it locally.
npm i -g @geml/geml(Node 22+), thengeml checka document, or point it at your own repo withgeml codemap build. - Read the grammar. The full spec (EN / 中文) is normative and short enough to read in a sitting.
Using GEML with an LLM
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.
npm i -g @geml/geml # installs the `geml` command (Node 22+)
geml doc.geml # document-model JSON (default --to json)
geml doc.geml --to md -o doc.md # project out; also --to html, --to geml
geml notes.md --to geml -o notes.geml # and Markdown back in
geml get doc.geml # list every addressable block + its address
geml get doc.geml '#hello' # print ONE block (a heading id = its whole section)
geml get doc.geml '=== note' # every block of a type; '@a3f9c1d2' names an id-less one
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 history save doc.geml # record a .gemlhistory revision
geml revert doc.geml '#plan' --rev -1 # roll ONE block back (needs a .gemlhistory)
geml check doc.geml # validate only: diagnostics + exit code
Every line above runs as written. Every mutation writes the whole updated document —
in place for a file, to stdout for - — so edits pipe cleanly; each is re-parsed
before the write and refused if it would break the document. Option by option:
parser README.
-
Claude Code / Claude CLI — one command:
npx -y @geml/geml skill installinstalls everything user-global: the authoring skill (resident in
~/.claude/skills/geml), thegemlCLI itself (npm i -g, skipped when already present), and the user-scope MCP server registration. Nosettings.jsonedits, no hooks; re-run after an upgrade to refresh. Prefer plugins?claude plugin marketplace add geml-spec/geml, then/plugin install geml@geml— same skill, MCP server bundled. Thegeml-code-graph/skill (call graphs — "show me the code graph", "who calls X") remains a manual copy from.claude/skills/. -
ChatGPT, Gemini, or any model. Paste the primer below so the model emits valid GEML, then run
geml checkon the output for a hard pass/fail.
GEML primer. Write the document as GEML. Every block is
=== type [attributes]…===; 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 blocks — nesting still needs the longer outer fence). Block types:code/diagram/math/table(verbatim body),note/text(prose with inline markup),meta(onekey=valper line),embed(empty body;src=doc.geml#idrenders that block in place). 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.
MCP Server
A standard Model Context Protocol server ships with the package, so your agent
edits one block at a time instead of rewriting whole files. It runs locally on
Windows, macOS, and Linux; --root is the directory holding your .geml files.
Claude Code / any CLI client — one command:
claude mcp add geml -- npx -y @geml/geml@latest mcp --root /absolute/path/to/your/docs
Claude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"geml": {
"command": "npx",
"args": [
"-y",
"@geml/geml@latest",
"mcp",
"--root",
"/absolute/path/to/your/docs"
]
}
}
}
Then just ask for the change you want — "fix the Q3 row in the FY26 table" — and
the agent addresses that one block. You never learn a tool name: each mirrors a
CLI verb (geml set → geml_set), so one vocabulary covers the terminal and the
agent.
Two guarantees make this better than letting a model rewrite the file: a write is
parsed before it reaches disk and refused with its diagnostics if it would
break the document, and every write first records a .gemlhistory revision — so a
bad edit is both prevented and undoable (geml_revert restores one block, the
rest of the file byte-identical). Paths stay confined to --root, which a client
cannot widen.
Point --root at a repository that has a code graph (geml codemap build) and the
same server also answers "who calls this" — four read-only geml_codemap_* tools,
one client entry instead of two. Every tool and option:
docs/mcp-guide.md.
Ecosystem and maturity
GEML is a small, young spec — but a stable one: 1.0 is released and usable for real documents (this repo's own spec is one), with a strict conformance suite, a reference implementation that passes it, and an open proposal process.
Both specs are bilingual:
| Document | English | 中文 |
|---|---|---|
| Core spec | GEML-spec.md | GEML-spec_CN.md |
| History extension | GEML-history-spec.md | GEML-history-spec_CN.md |
Versions and compatibility
If you are deciding whether to depend on this, these are the terms:
- The spec is versioned independently of the implementation. This document set
is GEML 1.0. The npm badge above is the
@geml/gemlpackage version, which follows its own release cadence and says nothing about the spec version;geml --version --jsonprints both, as{"parser","spec"}. - What "stable" means: the rules already in 1.0 will not shift under you. A breaking spec change bumps the spec version and ships with updated conformance cases — never one without the other (GOVERNANCE).
- Forward compatibility is in the grammar. A processor must degrade gracefully
on constructs it does not recognize (spec §8.2), which is why adding a block type
or a diagram format is not a breaking change. The type registry is open:
unregistered type names should contain a hyphen (
acme-invoice), leaving hyphen-free names to future versions of the spec (§8.5). - Claiming conformance. An implementation declares itself conformant to GEML 1.0 once it reproduces the conformance suite case for case (§8.5). No permission needed, and no sign-off from this repo.
- On the wire. Extension
.geml(version sidecar.gemlhistory), media typetext/geml, ortext/vnd.gemlwhere a registered type is required —text/gemlis not registered with IANA yet. A fragment identifier on a.gemlURL names the block bearing that id (§0.6).
Maturity signals. A complete core spec (§1–§8) plus a history-extension spec, both EN / 中文; a working reference implementation, renderer + CLI; a conformance suite (input → projected document model) that a second, independently-written parser must reproduce case for case — two separate implementations agreeing on every case is what keeps subtle rules like emphasis and lists from drifting. Behind that: 600+ checks in npm test, covering unit tests, the conformance corpus, the independent second implementation, round-trip serialization, and end-to-end CLI runs, with 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.
Two honest caveats. No mainstream surface renders .geml natively yet: the viewer, the CI Action, and the projections below are how it travels today. And models are less fluent in it than in Markdown, because nothing has been pre-trained on GEML at scale; the uniform block syntax and --json diagnostics let an agent check and repair its own output, but the starting fluency really is lower.
Where a .geml file can land — every one of these is in this repo, ready to use or read:
| Scenario | Where | State |
|---|---|---|
| From the command line — validate, convert, edit by block, version history, all in one command | @geml/geml (source geml-parser/) | Available |
Read it in the browser — open any raw .geml link and it renders in place: computed tables, charts, Mermaid, math, with diagnostics as a banner | Chrome Web Store · source | Available |
| Let an agent edit by block — an MCP server; the agent changes one block instead of rewriting the file, and every write is validated before it reaches disk | docs/mcp-guide.md | Available |
| Turn a codebase into a document — the whole call graph as a tree of GEML documents, browsable | geml codemap build (design) | Available |
| Write it in your editor — syntax highlighting + build-time reference checking | integrations/vscode/ | Built — install from source; not on the Marketplace yet |
| Render it in Obsidian — the reference parser + the viewer's renderer, the same code path as the web | integrations/obsidian/ | Built, not in the community store |
Stop bad documents in CI — dangling [[#id]], broken cross-document links, duplicate ids, and parse errors all fail the build | integrations/geml-check-action/ | Available |
Feed a RAG / agent framework — block-level loaders (one chunk per block, carrying block_id) + agent editing tools | integrations/langchain+llamaindex/ | Reference implementation |
| Try it without installing anything — edit on the left, live render on the right | Playground | Available |
Conversion between formats is collected behind one entry, geml <file> [--to json|html|md|geml]: in and out of Markdown, projected to self-contained HTML, re-serialized back to canonical GEML, or emitted as document-model JSON with its diagnostics — which is how scripts and agents get a structured pass/fail signal.
Status & contributing
This design has a manifesto. It has no signature page — writing one file in the GEML format is the signature; the four paths below are ways to write that signature larger.
Practical starting points: CONTRIBUTING.md for how to send
work, GOVERNANCE.md for how decisions get made, and
CODE_OF_CONDUCT.md for the one rule about people —
disagree with the design as sharply as you like, not with the person.
Four ways in — pick by the kind of mark you want to leave:
- The standard's path — write the second parser. Two independent implementations agreeing is what turns a spec into a standard, and it is the contribution the project needs most. Rust, Go, Python, Java, C, any of them: the portable conformance suite lets you self-certify and docs/WRITING-A-PARSER.md is the build order. Finding the places where the spec is ambiguous is itself the contribution, whether or not that parser ever ships.
- The plugin's path — take Obsidian the rest of the way. Rendering already works, on the same code path as the web viewer; what's missing is CodeMirror-level editing and the community-store submission.
integrations/obsidian/is waiting for someone who knows the Obsidian API. - The client matrix — prove the MCP server beyond Claude. The block-editing server is end-to-end verified on Claude only. Run it from your client — Cursor, Windsurf, Cline, anything that speaks MCP — and report what differs: docs/mcp-guide.md is the contract to hold it to.
- The steward's path — help govern the spec.
GOVERNANCE.mdis explicit that single-maintainer is a transitional state: the target is three or more maintainers from more than one party, with the spec ending up under neutral, multi-party stewardship. Sustained reviewers, GEP authors, and implementers are exactly who that invitation was written for.
Everything currently open, in one place: the gap table below. Smaller, well-bounded work — more languages in the code graph, the parked D2 / Graphviz engines, symbol visibility, incremental emit, broader conformance coverage — is claimed the same way: open an issue saying which piece you want.
Think the design falls short? Come argue with it
If "why not just Markdown" seems obvious to you — in either direction — we would rather hear you say it than have you agree quietly. GEML is 1.0, but "stable" means the rules already there won't shift under you, not that the design is settled: there is exactly one implementation, and one set of opinions behind the spec. An objection you raise now can still change the format itself, not just its tooling.
Read the argument before you object — how each decision was fought out at the time:
- What the spec is bound by —
GOVERNANCE.md: the spec is defined by its conformance suite, so a change is only real once it has conformance cases. A spec change lands together with those cases, never without them — that is what makes two implementations hold each other in check. - How the CLI's verb set was derived — block-mutation design and the undo half. Working notes, written to implement from, not polished prose.
- Why a code graph is expressed as GEML — DESIGN-geml-code-graph.md, with GEP 0002 / 0003.
Two questions that are genuinely open, if you want something concrete to chew on:
- Projection is lossy.
--to md/--to htmldrop block ids and a chart's binding to its table, because neither target format has anywhere to put them. Fine as delivery, bad as a round trip. Is a lossless projection worth having — and where would it encode any of this? - Heading levels inside an embed. An embedded section keeps its source heading levels, which can invert the host's hierarchy — render as-is, or remap? The transclusion design deliberately leaves this open (S10).
An objection that arrives with a case we can run is worth more than agreement.
Build an integration
The scenario table above is what already exists; this is what's missing — every row is a piece you can claim:
| Gap | Where it stands | What it takes |
|---|---|---|
| Deeper Obsidian integration | Renders, but not in the community store yet | Editing at the CodeMirror layer and seamless two-way rendering, plus the store submission itself. Wants someone who knows the Obsidian API. |
| A tree-sitter grammar | A design brief, nothing more | Writing the grammar — one of them lights up Neovim, Helix, and Zed at once. |
| An LSP | VS Code has highlighting + build-time checks only | Rename-aware refactoring, go-to-block, live diagnostics while editing. |
Block-level revert across rename | A documented limitation with a sketched fix (a rename lineage log) | History-layer design + implementation; the hash chain that makes history verifiable must survive it. |
| Logseq plugin / Notion import-export | Blank | All of it. |
| A Pandoc reader / writer | Blank | Once it exists, GEML reaches every pipeline Pandoc already serves. |
| The viewer on other browsers | Chrome works | Firefox / Safari ports. |
| Packaging the RAG integrations | LangChain / LlamaIndex are reference implementations | Publishing to PyPI; and wiring up other frameworks (Haystack, DSPy, …). |
| MCP client verification | Only exercised end-to-end on Claude | Verify against other MCP clients and report the differences back. |
The rendering core is reusable: the viewer, the Obsidian plugin, and --to html all go through the same renderer, so wiring up a new host is mostly glue, not a new parser.
Repository layout
spec/ Core spec + .gemlhistory extension as .md (EN / 中文), the
CC-BY spec license, and proposals/ (GEPs)
spec/in_geml_format/ The dogfood: those same specs written in GEML, with their
.gemlhistory sidecars
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, the long-form "why a new format" article (EN / 中文),
design notes, comparisons/ (COMPARISON + vs-CommonMark +
vs-XML-and-JSON), assets, and an example .geml to render
.claude/skills/ Claude skills: GEML authoring, and the code graph
.github/ CI + geml-check workflows, MCP registry publish, and issue
templates (bug, GEP, new implementation)
_includes/ GitHub Pages head include (site analytics)
License & governance
Code is MIT (LICENSE): everything in this repository —
geml-parser/, all of integrations/, playground/, .claude/skills/, the GEPs
in spec/proposals/ — except the specification documents.
The specification documents are CC-BY-4.0 (LICENSE-spec.md,
which lists them exactly): spec/GEML-spec*, spec/GEML-history-spec*, spec/in_geml_format/*, and
docs/comparisons/COMPARISON*. A spec is not software, so anyone may build a conformant
implementation without permission — and call it conformant to GEML 1.0 once it
passes the conformance suite.
Using the name. You need no permission to implement GEML, to name an
implementation after the format (geml-rs, pygeml, a geml package on your
language's registry), or to state that your tool reads and writes GEML. Two
requests, neither of them a legal restriction: call an implementation conformant to
GEML 1.0 only once it passes the conformance suite, and don't imply that this
project wrote, endorses, or maintains it. Attribution for the specification text
itself is what CC-BY-4.0 already asks for.
See GOVERNANCE.md for how decisions are made,
CONTRIBUTING.md to get involved, and
CODE_OF_CONDUCT.md for how we argue.