geml
OfficialUse this MCP server to inspect, search, validate, convert, edit, and version-control GEML (and Markdown) documents at block granularity, with safe validated writes and per-block rollback.
geml_list: enumerate every addressable block in a document.geml_find: search block content across.geml/.mdfiles and get matching block addresses.geml_get: read one block or section by id, heading, type, attributes, content hash, or line range; optionally slicehead/intro/bodyor follow embeds.geml_check: validate a document and return diagnostics.geml_history: list revisions or read the full text of a past revision.geml_to: convert whole documents between GEML, Markdown, JSON, and HTML without writing.geml_set: replace one block or section part, validated before writing.geml_add: insert new GEML/Markdown content by appending or placing before/after an anchor.geml_delete: remove one or more blocks by id.geml_rename: rename a block id and all references to it atomically.geml_revert: undo one block’s change from history while leaving other blocks untouched.Every write is validated first, returns diagnostics and a revision, is sandboxed to
--root, and can be rolled back.
Allows agents to list, find, get, set, and replace content within existing Markdown files by addressing sections and blocks, without converting files or rewriting the whole document.
GEML — General Expressive Markup Language
English | 中文
GEML is a lightweight markup language with uniform, addressable blocks and standard verbs. Easy for humans to read, safe for agents to mutate. In agent-driven development and knowledge work, plain text and Markdown have no deterministic block boundaries: a program and a model trade the whole file in and the whole file back out — at best probing for it with line windows, and restating the original verbatim to rewrite it. Token cost grows with the length of the document, and the operation turns bloated. After a few rounds of rewriting, the copies excerpted elsewhere start to drift.
You can start without changing a thing. geml list, geml find and geml get address the Markdown you already have — nothing is converted, no new files, your .md stays .md:
geml list README.md # every section, as an address
geml get README.md '#key-features' # read ONE section, not the file
geml set README.md '#key-features' --body # write one section back
geml replace README.md 'old text' 'new text' # swap a string, told which block held it
geml history save README.md -m 'tighten intro' # a revision into README.md.gemlhistory, beside the fileOnly that section enters the agent’s context — a couple of KB, not the whole file, however long it grows. And every save is a revision you can read back or roll back, one block or the whole file.
▶ Try it in the Playground — no install, nothing to read first.
Need finer than a section — one block, one chart, one table? Let .geml stand in the middle ground: edit at that grain, and the --to md you ship never drifts from it.
A block has a name; the things inside it have a coordinate. A table's cell, a
data block's leaf, a key in meta — each has a coordinate the structure already
gives it, and get and set land on exactly that value.
geml get doc.geml '#fy[2]["Q1"]' # one cell
geml set doc.geml '#intake["fields"][1]["name"]' # one leaf in the JSONFor people, it is plain text that reads clean; for agents, it is an addressable, verifiable, traceable, revertible "Doc-as-a-Base".
GEML is minimal. It is plain text — still clean with no renderer in sight; one block syntax for the whole language; addressable, verifiable, referenceable structure, natively.
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 blockBlocks have names so the verbs have somewhere to land — the full syntax is in the format in 1 minute.
Contents: What it solves · Why now · What's different · The format in 1 minute · Profiles · Get hands-on · With an LLM · Maturity & versions · The design · Roadmap · Take part · License
What it solves
Problems solved
Context load and token bloat
Status quo: data formats like JSON/XML carry heavy wrapper tags and syntax symbols; Markdown lacks strict structural metadata and a reference mechanism.
Approach: tuned markup density and syntax overhead, reading and writing only the target block — context cost no longer grows with document length, keeping agent reads and writes lightweight.
AST-level precision and parsing determinism
Status quo: unstructured text degrades over multiple rounds of LLM reads and writes — broken formatting, semantic drift, parsing hallucinations.
Approach: a deterministic grammar that maps directly to an abstract syntax tree (AST), so programs and LLMs perform atomic block-level create/read/update/delete.
Document copy fragmentation
Status quo: multi-agent collaboration and shared pipelines pass content around by copy-paste, leaving multiple disconnected copies.
Approach: Single Source of Truth by design — standardized module references and data binding eliminate redundant copies and version divergence.
Key features
1. AST-level structured operations
Uniform node definitions; a document parses directly into a typed document tree (AST).
Agents pinpoint the target section, attribute or component; partial patches and idempotent updates replace whole-file rewrites. Writes land as byte splices with whole-document re-validation — the tree serves reading and validation, and every untouched byte is guaranteed unchanged.
2. Low-token reads and writes
What is saved is not markup characters — it is the part never read:
#idhits one semantically complete block, and the rest never enters the context.For the same semantics, markedly lower prompt-token cost: better model throughput, lower inference cost.
3. Single source of truth, modular references
Native cross-document, cross-fragment component references.
Change the source node once and every reference follows — no version skew.
4. Robust two-way reads and writes
One block shape for the whole language — easy to generate and hard to get wrong, a good match for mainstream LLM output distributions.
A strict validator with precise error locations and actionable repair feedback.
5. Profile-based domain extensibility
Zero dialect chaos: extend domain vocabularies (e.g. design styles, interactive forms, code graphs, media timelines) through declarative
profilemetadata without inventing new syntax or breaking parsers.Static type and constraint checking with safe fallback to standard blocks in unknown environments.
Comparison
Dimension | Markdown | JSON / YAML | GEML |
Context cost (block-wise I/O) | High (whole file in and out) | High (whole file + syntax noise) | Minimal (only the target block) |
Precise AST operations | Weak (no strict semantic nodes) | Strong | Strong (built for agent reads and writes) |
Human readability | High | Medium | High |
Single-source references | Unsupported | Needs protocol extensions | Native (modular embeds) |
Domain extensibility | Fractured (proprietary syntax hacks) | Schema-dependent | Native Profiles (zero new syntax + verified) |
Write safety | Weak | Medium | Strong (a bad write is refused before landing + single-block revert) |
Related MCP server: RBT Document Editor
Why the LLM era needs a brand-new text format
Because both the producer and the consumer of a document have changed.
In traditional software engineering, a document was either a static explanation for people to read, or a serialized data file for programs.
Today, people and AI agents collaborate on the same document at high frequency. When the agent becomes the document's "second reader and co-author", the old balance breaks for good:
Context is scarce compute: every whole-document read or write burns an agent's limited attention window and reasoning budget;
Human–machine collaboration needs an isomorphic carrier: people need to read it at a glance, agents need to read and write it precisely, block by block;
Knowledge must have a single source of truth: scattered prompts and copy-pasted Markdown are destined to decay with every iteration.
Yet none of our existing text infrastructure was designed for this scene:
Markdown (typeset for people): no stable structural blocks, no machine keys. To change one parameter, an agent must read and write the whole text — wasting context budget across multi-turn loops, and inviting drift in both format and meaning.
JSON / XML (serialized for machines): full of wrapper syntax and structural noise — blocking natural human reading, while quietly eating expensive tokens in long contexts.
Scratch memory and scattered files (no single source of truth): context is torn across chat history and Markdown copies everywhere; a copy is drift from the moment it is made, and version skew and hallucinated distortion follow.
The root of all three failures is each tool's own virtue: Markdown's "never error, write anything" is what gives people their freedom to write — and exactly why a machine cannot trust the structure it reads back; JSON/XML's strict schema is what gives machines their certainty — and exactly why nobody writes prose in it. The virtue is the defect, which is why patches cannot fix this: bolting "a broken reference must fail the build" onto Markdown betrays its contract, and stripping the wrapper syntax from JSON denies its nature. When people and agents start co-writing the same text at high frequency, what is needed is not a compromise between the two poles, but a format that treats "readable by people" and "operable by machines" as one design constraint from day one.
The answer: "Doc-as-a-Base"
GEML invents no heavy new runtime. Borrowing from the REST architectural style of Dr. Roy Fielding's dissertation, it gives plain-text documents one standard set of operational semantics:
Old pain | The matching capability (the four laws) | What it buys developers and agents |
Changing one spot means rewriting the whole text | The Law of Addressing | Every block carries an |
Copies everywhere, all drifting | The Law of Projection |
|
Bad formats / broken references pollute downstream | The Law of Validation | References and syntax are checked at build time; a bad write is stopped before it lands, with no waiting for human review. |
One bad edit forces a whole-file rollback | The Law of Rollback | The companion |
A document no longer needs just a format — it needs a set of verbs. GEML keeps plain-text readability and adds deterministic block-level operations.
💡 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 on the blog: "Why Do We Need a New Text Format in the Era of LLMs?"
What's different about GEML
GEML stays small on purpose — the thinking, what it refuses, and what is still open are in how we thought about the design.
The four capabilities were established a chapter ago — addressing, projection, validation, rollback. 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 | ❌ 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 | ✔️ | ✔️ A build-time error | ✔️ |
Item by item: vs. CommonMark · vs. XML and JSON · a 7-format capability matrix · the Markdown variants and tools in awesome-markdown (Chinese, an HTML page).
Coexisting with Markdown: GEML is the editing source of truth, Markdown is 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.)
Don't take the table's word for it — re-run it. This is what I asked the model:
Based on your own experience editing the READMEs just now, describe the command steps you go through on a document (I saw you using grep and such), and whether you cache documents to save tokens — let's compare, and from that see which parts of GEML would actually earn their place.
What came back: what one edit costs and a real day replayed. Paste the question to your own model and see what it tells you.
PS: I am still trying to work out whether the upstream chain (who calls this) and the downstream chain (what it calls) that codemap produces can pin down functions and call sites — and change project code — the same way. I will post a report when I have one.
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. A table holds the facts; a view over it derives the
computed columns and the summary row:
=== table {#fy25 format=csv header=1}
Segment, Q1, Q2, Q3, Q4
Cloud, 8, 10, 12, 14
Platform, 5, 6, 7, 9
Services, 3, 4, 4, 5
===
=== view {#fy25-report src=#fy25 compute="FY [%.1f] = Q1 + Q2 + Q3 + Q4; n = 1" summary="Segment = 'Total'; FY [%.1f] = sum(FY); n = sum(n)"}
===Both table forms describe the same model. The FY column and Total row are computed at build time, by the view:
Segment | Q1 | Q2 | Q3 | Q4 | FY | n |
Cloud | 8 | 10 | 12 | 14 | 44.0 | 1 |
Platform | 5 | 6 | 7 | 9 | 27.0 | 1 |
Services | 3 | 4 | 4 | 5 | 16.0 | 1 |
Total | 87.0 | 3 |
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. n above is the row-count idiom — count tallies non-empty cells in one column, so a constant column summed is what counts rows.
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-report type=bar x=Segment y=FY}
===Drawn from the #fy25-report view above — FY is a computed column, so the
chart binds to the view that derives it, not to the base table:
xychart-beta
title "FY by segment"
x-axis [Cloud, Platform, Services]
y-axis "FY"
bar [44, 27, 16]Data — a value, not just text
Every block type names what it holds: code a region of code, table a grid, math a formula. data holds a data value, and it is where the data formats live — json (the default), jsonl, and yaml for a declared subset; toml reserved. Being typed means the body is read, not just displayed: a missing comma fails the build, geml get --json returns the value itself, and a chart can read it directly.
=== data {#log format=jsonl}
{"ts":"09:00","p95":41}
{"ts":"09:10","p95":58}
===
A jsonl body holds one record per line, which a program can blind-append at end-of-file. Records can also stay in their own file: src=ops/latency.jsonl#L900-999 names the file and, optionally, a line window — so the log keeps being appended and tailed as before, while the document is its verified, addressable, chartable view of it.
Embeds — a dynamic reference, not a copy
One block can stand for another: in the same document by src=#id, across documents by src=other.geml#id. An embed is a dynamic lookup of the source at render time — change the source once and every embed follows; delete it and geml check fails the build on the spot.
=== embed {src=#fy25}
===The body stays empty; the target lives in src=.
Markdown can't show you the projection. To see it live: install the browser extension, open the raw link to sample.geml, and scroll to the Transclusion section — a same-document projection (src=#roadmap), cross-document projections, and even chained resolution (an embed pulls a chart, which itself binds to a table in another file) all render in place: nothing is written there, yet edit the source once and the projection follows.
Profiles — domain vocabularies, assembled like Lego bricks
Want to author interactive forms, define a design token system, or map an entire codebase's call graph inside your documents?
In traditional Markdown, this requires proprietary plugins (:::note, custom JSX tags), inevitably fracturing into incompatible dialect silos.
GEML solves this with Profiles (Application-layer vocabularies, spec §8.6): A single-line declaration that unlocks domain-specific structured superpowers on demand.
=== meta
profile = "geml-style/v1 geml-form/v1"
===
==== form {#signup handler=subscribe}
=== form-field {name=email label="Work email" type=text required pattern="[^@]+@acme\\.com"}
===
====
=== style-rule {#cta match="button.cta" bg="{{brand}}" radius="6px"}
===Extension without fragmentation
• 🧩 Mix & match like Lego bricks
The core syntax stays minimal and frozen, while domain capabilities expand infinitely. Call graphs, design tokens, form validation, version history... compose multiple domain vocabularies with one profile = "..." line.
• ⚡ Zero-plugin overhead with instant tooling support
Adding a new domain block requires zero parser forks or custom plugins. Custom blocks instantly inherit the entire infrastructure: deterministic #id addressing, geml get/set blockwise mutation, CLI verbs, MCP protocol, and autonomous AI Agent control.
• 🛡️ Naturally portable, never locked in Extend capabilities without breaking interoperability. In any third-party or unfamiliar processor, documents maintain 100% structural integrity and block-level addressability, ending the nightmare of broken formatting when switching tools.
Standard Published Profiles
Profile (guide) | Status | What it's for | Superpowers Admitted | CLI | Live Demo / Example |
stable | Generates your codebase's call graph as GEML documents: one block per method, so you can see who calls it and what it calls; front-end and back-end merge into one graph |
|
| ||
draft | Describes a video timeline in one document: assets, clips, subtitle and voice tracks; export it as a web player, or render an MP4 with ffmpeg |
|
| ||
draft | Colours, spacing and layout live in a separate stylesheet document whose rules apply to your content; the content document itself stays unchanged |
|
| ||
stable | Keeps past versions in a |
|
| ||
draft | Describes a form in a document: its fields, their types, which are required, allowed ranges; the browser extension and the playground draw a preview |
| — | ||
draft | A translation document holds no translated text: it embeds the source and names the target language, and the browser extension machine-translates it on open, so it follows every change to the source |
| — | — |
💡 Want to see Profiles in action? •
geml-medialive demo: One cut document and one command (geml media build ep01-cut.geml --out ep01.mp4 --burn-subs) orchestrates ffmpeg to align audio/video, mix tracks, and burn subtitles into a finished video (see it). •geml-stylelive demo: Content stays pure text inpage.geml, while styles and layout live ingithub.style.geml— rendering a 1:1 pixel-accurate replica of GitHub's blob page without CSS lock-in (see it). • Every profile name in the table opens its one-page guide — what it does, the first command, everyday use. If you write code, start withgeml-codemap. You can also easily create your own custom domain profile.
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.See a whole page laid out from a document. The style demo is a 1:1 replica of a GitHub blob page — top bar, file tree, breadcrumb, Preview/Code/Blame, dropdown menus — where
page.gemlholds every string andgithub.style.gemlholds every colour and length, and the viewer knows about neither. It opens in any browser — the viewer's own code draws it — with the GEML that makes it right below.Run it locally.
npm i -g @geml/geml(Node 22+), thengeml checka document, or point it at your own repo withgeml codemap build.Set up Claude Code — one command.
npx -y @geml/geml skill installputs the authoring skill, the CLI and the MCP server in place, user-global, for every project. It edits no settings and installs no hooks. Details.Read the grammar. The full spec (EN / 中文) is normative and short enough to read in a sitting.
Or see it worked through, rule by rule. GEML, illustrated (EN and 中文) — eleven self-contained pages, one per block type, per profile, and for the CLI: GEML on the left, what the processor actually does on the right (
geml checkdiagnostics,geml listaddresses,--to htmlmarkup), each rule tagged with its source and status.
Using GEML with an LLM
The goal is one thing: your model edits a block at a time, and verifies — never re-reads and re-emits a whole file to change one paragraph. Getting there takes one step, and which step depends on what you use.
Using Claude Code, Gemini or Qwen — run this
npx -y @geml/geml skill installIt installs the authoring skill, the geml CLI and the MCP server, user-global,
for every project. No settings.json edits, no hooks; re-run after an upgrade.
(Prefer plugins? claude plugin marketplace add geml-spec/geml, then
/plugin install geml@geml — same skill, MCP server bundled.)
Using DeepSeek Harness — add this bundle
The same setup, packaged as a dsh bundle — the geml MCP server plus the authoring and code-graph skills:
dsh plugin --profile web add @geml/dsh-plugin # web = the profile dsh boots by default; use your own profile name if you run anotherListed on dshmarket and awesome-dsh-plugin; source in integrations/dsh-plugin/.
Using Codex — install the plugin
The same payload once more, packaged for Codex: both skills, the MCP server, and
a SessionStart hook. Start Codex in a checkout of this repo and it shows up in
/plugins (the marketplace source is committed at
.agents/plugins/marketplace.json); to add it without cloning, the git-subdir
entry is in integrations/codex-plugin/.
Then say it once in a session, and the project has switched:
This project uses GEML as its base document format; generate other formats from it as needed.
Using anything else — paste this, then check the output
A model with no skill to read needs the rules once. Paste the prompt below, and
keep geml check as the gate on whatever it writes back — the CLI is
npm i -g @geml/geml (Node 22+).
Write the document as GEML: every block is
=== type [attributes]…===(the format in 1 minute lists the types). Four rules are the ones models get wrong: the closing fence is a=run of the exact opening length, and a body containing===needs a longer outer fence; headings are ATX#only, with no---frontmatter (metadata is=== meta); every#idis unique and every reference ([[#id]],[text](#id),[^id],data=#id) must resolve; there is no raw HTML. The normative spec isGEML-spec.md.
What it will do with it
geml list doc.geml # CALL FIRST: every block, its address, kind, lines
geml find "words" doc.geml # search block content -> an address, not a line number
geml get doc.geml '#hello' # read ONE block (a heading id = its whole section)
geml get doc.geml '#hello' --intro # a section cuts three ways: --head | --intro | --body
geml set doc.geml '#license' --in template.geml#mit # replace that block, forking another
geml add doc.geml --after '#intro' --in snippet.geml # insert a fragment (keeps its own ids)
geml revert doc.geml '#plan' --rev -1 # roll ONE block back
geml check doc.geml # validate only: diagnostics + exit codeAny section cuts three ways, on get and set alike: --head is the heading
line, --intro what it says before its first subheading, --body everything
under it — so --body always contains --intro, and equals it when there is no
subheading. A section's opening can be edited without pulling its subsections
into context.
Every mutation is re-parsed before it writes and refused if it would break the
document — which is what makes editing unattended safe. The rest of the verbs
(delete, rename, history, --to md|html|geml conversion, addressing a
block by type or content hash) are in the
parser README.
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 — on Markdown and
GEML alike. It runs locally on Windows, macOS, and Linux; --root is the
directory the server is confined to (use . or ${workspaceFolder} to bind to
the active project).
Nothing to install — the same tools run on Cloudflare at
https://geml-mcp.supermarket.workers.dev/mcp. There the document travels in
each call and a write comes back as text; see
the Worker's README.
Claude Code — one-command setup (installs skill, CLI, and MCP server):
npx -y @geml/geml skill install(Or register manually via CLI: claude mcp add --scope user geml -- npx -y @geml/geml mcp --root .)
Cursor — add .cursor/mcp.json to your project:
{
"mcpServers": {
"geml": {
"command": "npx",
"args": ["-y", "@geml/geml", "mcp", "--root", "${workspaceFolder}"]
}
}
}(Or in Cursor Settings → Features → MCP: name geml, command npx -y @geml/geml mcp --root .)
VS Code — nothing to configure: the
GEML extension offers both servers to chat, the hosted
one and geml mcp --root . for each workspace folder. Accept whichever you want
when the editor asks.
Claude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"geml": {
"command": "npx",
"args": [
"-y",
"@geml/geml",
"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 (versioned independently of the spec), and an open proposal process.
There is one specification, and it is bilingual. The .gemlhistory sidecar
is defined by the geml-history/v1 profile — an application layer on top of
the spec rather than part of it, which is also why it is MIT and the spec is
CC-BY (LICENSE-spec.md says why):
Document | English | 中文 |
The specification | ||
|
Every profile this project publishes: spec/profiles/.
Versions and compatibility
Self-hosting —
GEML-spec.gemlis the specification written in GEML, required to parse clean on every test run.A conformance suite is what holds separate implementations compatible.
A reference implementation of the parser. 1,700+ unit tests today, plus the conformance corpus, round-trip serialization and end-to-end CLI runs, with coverage CI-gated at ≥95% lines / statements / functions / branches.
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: an unregistered type name should contain a hyphen (
acme-invoice), leaving hyphen-free names to future versions of the spec (§8.5).Claiming conformance. An implementation may call 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/vnd.geml— a vendor-tree name; the standards-treetext/gemlcan be applied for if the spec is ever published through the IETF.A fragment identifier on a
.gemlURL names the block bearing that id (§0.6) — which is not what#tagmeans on an HTML page.
How we thought about the design
What the design follows
Human–Agent Isomorphism, Not a Compromise Instead of splitting the difference between human-readable Markdown and machine-readable JSON, GEML treats human readability and machine determinism as a single, uncompromising constraint. Humans get clean, distraction-free prose; agents get a strongly typed AST—eliminating translation loss between two separate formats.
Doc-as-a-Base, Not a Stream of Characters Traditional documents are fragile streams of characters where editing one sentence often forces a full-file rewrite. GEML treats a document as an addressable database of structured records with stable primary keys (
#id). Every block has an independent lifecycle, spatial coordinate, and atomic CRUD interface suited for O(1) agent reads and writes.One Syntax Primitive, Infinite Domain Vocabularies Refuse to invent syntax patches for every new kind of content. GEML uses a single typed-block primitive (
=== type) to carry code, data, tables, math, and layout. Domain capabilities expand infinitely through Profiles (profile = "..."): the grammar stays 100% frozen, while vocabularies remain open—ending dialect fragmentation at the root.Transclusion over Duplication: Kill the Incentive to Copy Traditional hyperlinks are signposts pointing elsewhere, encouraging copy-pasting that inevitably causes copies to drift out of sync. GEML references are dynamic viewports (
=== embed): define once at the source, and project live everywhere. Maintain a single source of truth by removing the motivation to copy.Compiler-Grade Integrity: Treat Documentation Like Code Markdown's ethos is "never fail, render something"—the primary breeding ground for agent hallucinations and silent documentation decay. GEML enforces strict build-time static validation. Broken
#ids, invalid attributes, and cyclic references fail the build with a non-zero exit code. Catch errors before they pollute downstream systems.Local-First History, Not Cloud Lock-in or Git Overhead Data belongs on the local filesystem, and versioning belongs at block granularity. GEML refuses to lock version history behind proprietary cloud platforms (like Notion or Google Docs), while avoiding the heavy whole-repo commit overhead of Git for micro-edits. The companion
.gemlhistorygives plain text local-first atomic snapshots and surgical rollback (geml revert doc.geml '#id'), ensuring true data sovereignty and safety.
What it therefore refuses
Refused | Why |
A diagram language of its own | External DSLs are hosted (Mermaid, Graphviz, D2, …); the format defines only the hosting protocol |
A raw-HTML escape hatch | Semantics stay portable, tied to no backend or renderer |
Setext headings / | ATX |
A full spreadsheet engine | Per-row formulas and summary aggregates are enough; no cell addressing, lookups, or macros |
Roadmap
The GEML
1.0specification, in English and Chinese, with a conformance suite — plus thegeml-history/v1profile that defines the.gemlhistorysidecarReference implementation
@geml/geml: parser, CLI, block-level.gemlhistorytrackingOfficial MCP server (
geml mcp) for Claude Code, Cursor, Codex and other MCP hostscodemap — a whole codebase's call graph, written as GEML
The VS Code extension published on the Visual Studio Marketplace (publisher
geml)Ecosystem integrations: VS Code highlighting and reference checking, tree-sitter, Obsidian, Logseq (two-way sync against a live DB graph), the browser viewer, a GitHub Action, LangChain / LlamaIndex, and the agent-harness plugins — Claude Code, Codex, Grok, DeepSeek Harness, plus root manifests for Gemini CLI and Kimi Code
The Logseq plugin listed in the Logseq marketplace (PR #893) and the Grok plugin listed in
xai-org/plugin-marketplaceA second implementation,
geml-parser-rs/— Rust, compiled to WebAssembly, written from the spec and the conformance suite alone, without reading the reference parserImplementations by other hands — Python, or whatever you write in; the spec and the conformance suite are public, and we are glad to help line them up
Take part
GEML is 1.0, but "stable" means the rules already there won't shift under you,
not that the design is settled. There are two implementations so far, but one author
behind both — so there is still one set of opinions behind the spec. Your thinking can still change the spec itself.
If you want a hand in it:
Come argue about these, the proposals still in draft:
GEP-0008 · A
formtyped block — addressable fields, an inert destinationGEP-0010 · Projections along the language axis — a translated document is a view, not a copy
Something else on your mind? Start a discussion.
Or claim a piece:
Gap | Where it stands | What it takes |
Skill installation for more agent tools | Gemini CLI, Qwen Code and AGENTS.md are installed by detection already; the MCP server works with any client | Add the rest the same way: Cursor, GitHub Copilot, Cline — their rule-file conventions move fast, so check the current docs before writing one in |
How well the primer holds on other models | Only exercised on Claude | Have GPT / Gemini / a local model each write a batch of GEML from the primer, count how many pass |
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. |
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, …). |
Write an implementation of the spec in your language — a new GEML parser, from the spec alone (how to write a parser);
geml-parser-rs/was written that way and is the worked example to compare againstFinding the places where the spec is ambiguous is itself the contribution, whether or not that parser ever ships.
Or propose something new:
A GEP: the proposal, the spec edit and the conformance cases land together (process)
Or put it to use:
Scenario | Where | State |
From the command line — validate, convert, edit by block, version history, all in one command |
| Available |
Read it in the browser — open any raw | 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 | Available | |
Use it from DeepSeek Harness — the geml MCP server plus the authoring and code-graph skills, one installable bundle | Available | |
Use it from Codex — the same payload again: both skills, the MCP server, and a | Available from this repo; not in the public plugin directory yet | |
Use it from Grok — the same payload once more: both skills and the MCP server | Available from this repo; the | |
Sync a Logseq graph to plain text — a Logseq 2.0 DB graph as continuously synced GEML files, addressable and git-friendly, with | Watcher on npm; the plugin installs from a release zip — the marketplace listing (PR #893) is not merged yet | |
Turn a codebase into a document — the whole call graph as a tree of GEML documents, browsable | Available | |
Write it in your editor — syntax highlighting + build-time reference checking | Available | |
Write it in Android Studio / IntelliJ — highlighting, diagnostics as you type, preview, structure view, block revert from | Built; installs from a zip you build (Install Plugin from Disk), not on the JetBrains Marketplace | |
Render it in Obsidian — the reference parser + the viewer's renderer, the same code path as the web | Built, not in the community store | |
Feed a RAG / agent framework — block-level loaders (one chunk per block, carrying | Reference implementation | |
Try it without installing anything — edit on the left, live render on the right | Available |
Three files to read first: GOVERNANCE.md for how decisions get
made, CONTRIBUTING.md for how to send work, and
CODE_OF_CONDUCT.md for the one rule about people —
disagree with the design as sharply as you like, not with the person.
Repository layout
spec/ The specification as .md (EN / 中文) and the CC-BY spec
license, with profiles/ (application layers — geml-history,
geml-codemap, geml-style, geml-form, geml-media,
geml-translator — each a reference beside a one-page usage
guide) and proposals/ (GEPs), both MIT
spec/in_geml_format/ The dogfood: the specification written in GEML, with its
.gemlhistory sidecar
geml-parser/ Reference parser, renderer, CLI + codemap toolkit (TypeScript, Node 22)
geml-parser-rs/ The second implementation: the same spec in Rust, compiled to
WebAssembly, written from the spec and the conformance suite alone
integrations/ Everywhere GEML plugs in: chrome-geml-viewer (browser extension),
geml-check-action (CI), vscode, intellij+androidstudio-plugin,
obsidian, logseq (two-way vault sync + the watcher), tree-sitter (brief),
langchain+llamaindex (RAG loaders), windows-icon
(Explorer file icons), the agent-harness plugins —
claude-plugin, codex-plugin, grok-plugin, dsh-plugin — and
website (what this repository pushes to the site)
.agents/, .claude-plugin/ Plugin marketplace manifests, so the plugins show up
from a checkout (Codex `/plugins`, Claude Code `/plugin`)
docs/ Guides (MCP, writing a parser), design records, the release
runbook, assets (logos)
.claude/skills/ Claude skills: GEML authoring, and the code graph
.github/ CI, security-scan, release and site workflows (npm, MCP
registry, VS Code, viewer, website), issue templates (bug,
GEP, new implementation) and the PR template
(website) The homepage, playground, demos, blog, comparisons,
benchmarks, manifesto and illustrated pages live in their
own repository, geml-spec/geml-spec.github.io, which links
here for the spec and guides; the website workflow pushes it
the playground bundle, code graph and logos. What
this repository publishes at geml-spec.github.io/geml/ is
site/ — a forward to the same path on the new site.License & governance
Code is MIT (LICENSE): everything in this repository —
geml-parser/, geml-parser-rs/, all of integrations/, .claude/skills/, docs/,
the profiles in spec/profiles/, 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* and spec/in_geml_format/*. There is one
specification; the profiles under spec/profiles/ are application layers and are MIT.
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.
Available Tools
11 toolsgeml_addInsert new contentAInspect
Insert new content — one or more blocks, or prose — at the end of the document (position: append) or before/after the block named by anchor. Use this for content that does not exist yet; to change a block that does, use geml_set. Ids inside the content are kept. In a .md file Markdown lands as written, and GEML content is converted to Markdown as to: "md" converts it, the result's notes saying so; content Markdown cannot hold, such as a view without its source, is refused. Like every write here it is validated first: a missing anchor, an id that clashes with an existing one, or content that would break the document is refused. Returns {ok, file, diagnostics, revision}, with notes when the write did something to say out loud (a block it dropped, an address it changed); a refusal is ok: false with a hint, and the file is unchanged.
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | Document path relative to the server's --root directory, e.g. notes/spec.geml | |
| anchor | No | The block the insertion is relative to — an id, or any address geml_list prints; it must name one block. Required for before/after | |
| content | Yes | The GEML fragment to insert | |
| position | Yes | Where to insert |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover the safety profile (readOnlyHint false, destructiveHint false, idempotentHint false, openWorldHint false); the description goes well beyond them by disclosing pre-write validation, the exact refusal conditions (missing anchor, id clash, document-breaking content), the .md conversion rule and the refusal of content Markdown cannot hold, and the return shape including `notes`, `diagnostics`, `revision`, and `ok: false` with a `hint` leaving the file unchanged. No statement conflicts with the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and the geml_set contrast are front-loaded, and the paragraph flows from what it does to how it behaves to what it returns. It is dense and parenthetical-heavy (nested clauses about .md conversion), which costs it a point, but essentially every sentence carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries the return contract — `{ok, file, diagnostics, revision}` plus optional `notes` and the `ok: false` + `hint` failure shape with the file left unchanged. Combined with the validation and conversion rules, an agent has everything needed to call this mutation tool and interpret both success and refusal.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the structured baseline is 3; the description nevertheless adds real meaning, explaining that ids inside `content` are preserved, that `position: append` means the end of the document while before/after bind to `anchor`, and that anchor may be 'an id, or any address geml_list prints'. It stops short of documenting enum edge cases or content size limits, keeping it at 4 rather than 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Insert new content — one or more blocks, or prose') and immediately scopes it with the two insertion modes (append vs before/after anchor). It explicitly names the sibling it must not be confused with ('to change a block that does, use geml_set'), so an agent can route correctly without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit when-to-use rule ('content that does not exist yet') paired with the exclusion and the alternative ('to change a block that does, use geml_set'). It also states the precondition that before/after requires an anchor naming exactly one block, so there is nothing left to infer.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
geml_checkValidate a documentARead-onlyInspect
Validate a GEML document without changing it: returns every diagnostic with a stable code, a severity and a line, and an empty list means the document is valid. Use it to confirm a document is sound before reporting work as finished. Every write through this server runs the same check before it lands, so a refused write already carries this information.
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | Document path relative to the server's --root directory, e.g. notes/spec.geml | |
| root | No | Directory (inside the server root) against which cross-document references resolve. Defaults to the server root itself. This is a REFERENCE root and is distinct from the server's own --root sandbox, which it can only narrow. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only cover readOnlyHint=true and openWorldHint=false; the description goes well beyond them by disclosing the return contract (every diagnostic with a stable code, severity and line, empty list means valid) and the cross-cutting behavior that all writes run the same check. This is substantive context an agent cannot get from the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each doing distinct work: what it does, how to read the result, and why a re-check may be redundant. The non-mutating constraint is front-loaded and nothing is padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, but the description supplies the return semantics (diagnostic fields, empty-list-means-valid), so an agent knows how to interpret results. Combined with the schema covering both parameters, nothing needed to call or read this tool is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and both parameters (file, root) are documented in the schema itself, including the subtle reference-root vs. sandbox-root distinction. The description adds no parameter-level meaning, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Validate a GEML document') plus the crucial constraint 'without changing it', which immediately separates it from the write siblings (geml_set, geml_add, geml_delete, geml_rename, geml_revert). An agent can pick this out of the sibling list without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives an explicit use case ('confirm a document is sound before reporting work as finished') and an implicit when-not-to-use: since every write already runs the same check, a refused write already carries this information, so re-validating is often redundant. It stops short of naming a specific sibling alternative, but the guidance is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
geml_deleteDelete blocksADestructiveIdempotentInspect
Remove one or more blocks, each named by an id or any address geml_list prints; a filter (=== type, {key=value}) removes every block it matches. Each block takes the blank line that separated it from its neighbours, so deleting what geml_add inserted leaves the file as it was. To undo a deletion, geml_revert the removed id; to change a block rather than remove it, use geml_set. References left pointing at a removed block come back as diagnostics but do NOT block the deletion — read them, then repair the references or revert. A selector that names nothing is skipped, so repeating a call changes nothing. Returns {ok, file, diagnostics, revision}, with notes when the write did something to say out loud (a block it dropped, an address it changed); a refusal is ok: false with a hint, and the file is unchanged.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | Yes | The blocks to remove: ids or addresses | |
| file | Yes | Document path relative to the server's --root directory, e.g. notes/spec.geml |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructive/idempotent/not-read-only, and the description goes well beyond them: dangling references produce diagnostics but do NOT block deletion, repeated calls with unmatched selectors change nothing, a refusal returns ok:false with a hint and leaves the file unchanged, and notes appear when the write altered addresses. This is the exact behavioral context needed for a destructive mutation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The paragraph is long but front-loaded with the core action and every sentence carries non-trivial information (rollback, idempotence, diagnostics, refusal semantics). It loses a point only because the return-value detail could be tighter given no output schema exists to carry it.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates fully by spelling out the return shape (`{ok, file, diagnostics, revision}`, optional `notes`, refusal with `hint`). Combined with the behavioral warnings, an agent has everything needed to invoke and interpret the call.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description materially enriches the `ids` parameter: it accepts ids or 'any address geml_list prints', plus filter syntax (`=== type`, `{key=value}`) that removes every match. That selector grammar is not in the schema and is essential to calling the tool correctly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (remove) and resource (one or more blocks), and immediately distinguishes the operation from siblings by name (geml_add inserts, geml_set changes, geml_revert undoes). An agent can tell exactly what this does versus the other ten tools.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit routing: 'To undo a deletion, geml_revert the removed id; to change a block rather than remove it, use geml_set.' It also covers the no-op case (a selector naming nothing is skipped) and what to do about dangling references, so both when-to-use and when-not-to-use are covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
geml_findFind the blocks that hold some textARead-onlyInspect
Search block CONTENT across the served documents; each hit is one <file>\t<address> row. geml_list says what a document contains, this says which block holds the words — as an address that pastes straight into geml_get or geml_set, not a line number the next edit invalidates. The address is the innermost block holding the match, and a block matching on many lines is reported once. Substring, case-insensitive unless case is true. Omit path to search every *.geml and *.md under the server root; a file you name is searched whatever its extension, a directory walks *.geml and *.md. No match is an empty result, not an error.
| Name | Required | Description | Default |
|---|---|---|---|
| case | No | Match case exactly (default: case-insensitive) | |
| head | No | Add the matching line as a third column | |
| path | No | Optional file or directory under the server root; default: the whole root | |
| within | No | Optional: only look inside the blocks this selector names, e.g. `#install` for a section or `=== table` for every table. It takes the same selector forms as geml_get's `id`. | |
| pattern | Yes | Text to look for inside block bodies |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare readOnlyHint and openWorldHint, so the description carries the real burden and does it well: substring/case-insensitive matching semantics, the innermost-block address rule, deduplication of multi-line matches, the default search scope (`*.geml` and `*.md` under the root) versus a named file searched regardless of extension, and the important fact that no match is an empty result rather than an error.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Every sentence earns its place and the output format, sibling contrast, and matching rules are front-loaded. The em-dash asides make individual sentences long and slightly dense to parse, which costs a point but not readability overall.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description still specifies the return shape precisely (tab-separated file/address rows, plus the optional third column behind `head`) and the empty-result case. For a 5-parameter read tool with annotations covering safety, nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds genuine meaning: it fixes matching semantics for `pattern` (substring, case-insensitive unless `case` is true), pins the default and the file-vs-directory behavior of `path`, and explains that `within` shares geml_get's `id` selector forms. That is more than restating the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Search block CONTENT across the served documents') and immediately defines the output shape ('each hit is one `<file>\t<address>` row'). It explicitly distinguishes itself from the sibling geml_list ('geml_list says what a document contains, this says which block holds the words'), so the agent can route without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the alternative tool (geml_list) and the condition that selects this one, and points the agent onward by noting the address 'pastes straight into geml_get or geml_set'. It does not cover when to prefer this over non-search siblings like geml_check or geml_history, nor state any exclusion beyond that single contrast.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
geml_getRead one blockARead-onlyInspect
Read ONE block from a GEML document instead of the whole file: only that block comes back, typically a few percent of the document. Pass the address geml_list prints as id — it also reaches blocks with no #id; to locate a block by its words instead, use geml_find first. An id that matches nothing, or a file that is not under the server root, is an error naming it.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | What to read: a block id (with or without `#`), a `## Heading` line (its whole section), `=== type` for every block of a type, `=== code {lang=py}` or `{.warn}` for every block carrying those attributes, a `@<hex>` content address for a block with no id, or `L27`/`L27-58` for the smallest block holding those lines — the forms `geml_list` prints, plus the line numbers an editor or a diff hunk speaks | |
| file | Yes | Document path relative to the server's --root directory, e.g. notes/spec.geml | |
| part | No | How much of the block to return (default: whole). For a SECTION these cut it three ways: `head` is the heading line, `intro` everything under it up to its first subheading, `body` everything under it — so `body` always contains `intro`, and equals it when the section has no subheading. Reach for `intro` to read a section's opening without pulling its subsections into the conversation; a whole `#id` on a top-level heading is often the entire document. Only a heading has an intro. `body` is usually what you want together with `view`. | |
| view | No | Read THROUGH an `embed` block to the entity block it stands for, following a multi-layer chain to its end. An `embed` has no content of its own, so this is the only way to see what it points at; on any other block it changes nothing. Returns {from, content}: `from` names the document the content actually came from, and its references and relative paths resolve against THAT document, not this one. | |
| within | No | Optional: only look inside the blocks this selector names, e.g. `#install` for a section or `=== table` for every table. It takes the same selector forms as geml_get's `id`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false. The description adds useful behavioral context beyond that: the return is only the selected block, typically a small fraction of the file, and unmatched ids or files outside the server root produce named errors. It does not cover auth, rate limits, or output structure, so it stops short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, front-loaded with the core purpose, then id sourcing/alternative tool, then error behavior. Every sentence earns its place with no wasted wording.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a five-parameter read tool with no output schema, the description plus rich schema and annotations are mostly sufficient for selection and invocation. It covers purpose, alternatives, and error conditions, though it does not describe the returned block shape beyond saying the block comes back.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, and the schema already documents all five parameters in detail, including id selector forms and part/view/within semantics. The description mainly reinforces the id source from geml_list and an error condition, but adds little semantic detail beyond the schema for part, view, or within. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: read ONE block from a GEML document, not the whole file. It distinguishes itself from the whole-file read and names sibling tools (geml_list for addresses, geml_find for word search), so an agent can tell what it does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says to use this instead of reading the whole file, tells the agent to pass an address printed by geml_list as the id, and routes word-based lookup to geml_find first. These are clear when-to-use and when-to-use-an-alternative instructions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
geml_historyRead a document's historyARead-onlyInspect
Read a document's recorded history. WITHOUT rev: list every revision, newest first — each entry's offset is the selector geml_revert takes as rev (-1 is the revision before the current one), and an empty list means the document has no sidecar yet and nothing can be reverted. WITH rev: the full text of that one revision, for reading what the document looked like then without restoring it.
| Name | Required | Description | Default |
|---|---|---|---|
| rev | No | Revision selector — `0` for the current tip, `-N` for N revisions back, or a revision id from the list. Omit it to get the list instead of one revision's text. | |
| file | Yes | Document path relative to the server's --root directory, e.g. notes/spec.geml |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint=true and openWorldHint=false, but the description adds substantial context beyond them: it explains the empty-list sidecar condition ('nothing can be reverted'), the meaning of `offset` as a selector for `geml_revert`, and the exact return form in each mode. This is well beyond the safety profile already covered by annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded by mode, with caps-scanning labels ('WITHOUT `rev`' / 'WITH `rev`'). Every clause carries required information: mode behavior, selector semantics, and empty-list edge case.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description carries the return-shape burden, and it does: list mode returns revision entries with `offset` fields, single-revision mode returns full text. Annotations cover safety, and the description covers modes, edge cases, and the sibling-tool linkage, leaving no critical gap for a 2-param read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds cross-tool meaning: it tells the agent that each listed revision's `offset` is what `geml_revert` accepts as `rev`, and that `-1` is the revision before the current one. That goes beyond the schema's self-contained parameter docs, though the schema already covers most syntax details.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb and resource ('Read a document's recorded history') and immediately separates the two operating modes, list vs. single revision. It also names the sibling `geml_revert` to clarify the relationship, so an agent can distinguish this read-only inspection tool from its siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to omit `rev` (to list every revision newest-first) and when to supply it (to read one revision's full text). It further clarifies the boundary with `geml_revert` by noting this is 'for reading ... without restoring it,' giving a clear when/when-not signal.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
geml_listList the blocks of a documentARead-onlyInspect
List every addressable block in a GEML document — its address, kind and heading text — in one call, with no paging. Call this FIRST: what it returns is what every other tool here addresses, and it is cheaper and more reliable than reading the file to see what is in it. Rows marked anon have no #id; geml_get and geml_set take their address as id, while the other write tools need a real id, so give such a block one first. A file that is not under the server root is an error.
| Name | Required | Description | Default |
|---|---|---|---|
| file | Yes | Document path relative to the server's --root directory, e.g. notes/spec.geml | |
| within | No | Optional: only look inside the blocks this selector names, e.g. `#install` for a section or `=== table` for every table. It takes the same selector forms as geml_get's `id`. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and openWorldHint=false, and the description adds behavior the annotations cannot express: no paging, the meaning of `anon` rows (no #id), the id/aid asymmetry across the write tools, and the failure mode for files outside the server root. That is a rich, non-redundant behavioral disclosure.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core scoping sentence and the 'Call this FIRST' directive are front-loaded, and each subsequent sentence carries a distinct payload: no-paging, the anon/id caveat, and the root error. No filler sentences.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must describe the return shape, and it does (address, kind, heading text, anon flag). Combined with read-only annotations and full schema coverage, an agent has everything needed to call this correctly and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both `file` and `within` are already documented in the schema (including selector forms). The description adds nothing about `within` beyond what the schema says and only gestures at the address/id naming at the row level rather than the parameter level, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (list) and resource (every addressable block in a GEML document) plus the exact payload returned: address, kind and heading text. That level of specificity makes it immediately distinguishable from geml_get, geml_find and the write siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says 'Call this FIRST' and gives the reason (it is cheaper and more reliable than reading the file), then routes the agent onward: geml_get/geml_set take the address as id, other write tools need a real id so an anon block must be given one first. When-to-use plus alternatives are both covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
geml_renameRename a block idAIdempotentInspect
Rename a block id AND every reference to it in the same document, in one id-boundary-safe write. Use this rather than geml_set or a text search-and-replace, which would also hit ids that merely share a prefix. A Markdown heading's anchor is its text, so it is renamed by changing the heading with geml_set (part: head), not here. An old id that does not exist, or a new one already taken, is refused. Returns {ok, file, diagnostics, revision}, with notes when the write did something to say out loud (a block it dropped, an address it changed); a refusal is ok: false with a hint, and the file is unchanged.
| Name | Required | Description | Default |
|---|---|---|---|
| new | Yes | New id | |
| old | Yes | Current id | |
| file | Yes | Document path relative to the server's --root directory, e.g. notes/spec.geml |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the safety trio; the description adds refusal semantics (nonexistent `old`, taken `new`), the exact return shape including `notes` and `hint`, and the guarantee that a refused call leaves the file unchanged. Minor tension: `notes` mentions 'a block it dropped' while destructiveHint=false, which is worth noting but is a stated, surfaced side effect rather than a hidden one.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the operation and the differentiator, then routing exclusions, then the return/error contract. Dense but every sentence carries routing or behavioral information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description supplies the return contract, the error contract, and the no-side-effect-on-refusal guarantee, which is everything needed to call and interpret this mutation tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description genuinely adds semantics for `old`/`new`: `old` must exist and `new` must be free, and the schema's terse descriptions ('Current id', 'New id') gain real constraints.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb+resource (rename a block id) and its scope (every reference in the same document), and explicitly names the siblings it must not be confused with (geml_set, text search-and-replace). An agent can route to this tool without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit when-to-use with named alternatives and the reason they are wrong ('would also hit ids that merely share a prefix'), plus an explicit when-NOT-to-use case (Markdown heading anchors go through geml_set with `part: head`). Conditions for refusal are also given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
geml_revertRevert one blockADestructiveInspect
Undo ONE block, leaving every other block byte-for-byte unchanged — recover a single block after a bad edit without losing the good edits around it. rev defaults to undoing this block's LAST change (its previous distinct version), which holds even when other blocks were edited afterwards; or pass 0 for the tip, a -N offset, or a revision id from geml_history. Reverting across a revision where the block was deleted restores it; across one where it did not exist removes it. A rev that matches no revision, or a document with no history yet, is refused. Returns {ok, file, diagnostics, revision}, with notes when the write did something to say out loud (a block it dropped, an address it changed); a refusal is ok: false with a hint, and the file is unchanged.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Block id to revert | |
| rev | No | Revision selector: 0 (the tip) | -N (N revisions back) | id prefix. Omit to undo this block's last change (robust to edits of other blocks since). | |
| file | Yes | Document path relative to the server's --root directory, e.g. notes/spec.geml |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations disclose only destructive/not-idempotent; the description adds the edge-case semantics that matter — reverting across a deletion restores the block, across nonexistence removes it — plus the refusal behavior (ok:false with hint, file unchanged) and the return shape including `notes` for consequential side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense paragraph, front-loaded with the purpose and scope guarantee before the parameter and return details. Slightly long, but nearly every clause carries distinct semantic information (default rev, edge cases, refusal, return shape) rather than padding.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description fully documents the return contract ({ok, file, diagnostics, revision}, optional notes, refusal with hint) and the mutation's edge-case outcomes. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, but the description still adds value by spelling out the default-rev robustness semantics ('undo this block's LAST change... holds even when other blocks were edited afterwards') and the meaning of each selector form. It largely mirrors the schema text, so it earns an above-baseline but not maximal score.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (undo/revert) and resource (one block) plus a precise scope guarantee — 'leaving every other block byte-for-byte unchanged' — that immediately distinguishes it from geml_set, geml_delete, and geml_history. An agent can tell what this does and what it deliberately does not touch.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the motivating scenario (recover a single block after a bad edit without losing surrounding edits), explains the default `rev` behavior and why it is robust to other blocks being edited, and enumerates the alternative selectors (0 tip, -N, revision id from geml_history). It also names the two conditions under which the tool refuses.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
geml_setReplace one blockADestructiveIdempotentInspect
Replace ONE block and leave every other byte untouched — prefer this to rewriting a file. For content that does not exist yet use geml_add; to remove a block, geml_delete. The replacement is validated before it is written: if it would break the document, nothing is written and the diagnostics come back — fix the body rather than resending it. Removing content is not refused: if the replacement drops blocks, the write goes through and the result names each one, so check it after shortening a section; geml_revert puts one back. part replaces the whole block (default), its head line, a section's intro, or its body. In a Markdown file a heading's anchor is its text, as on GitHub: new heading text gives the heading a new address, and the document's links to the old one follow in the same write. GEML content written over a Markdown heading or prose is converted to Markdown, as in geml_add; a GEML block already in the file stays GEML. An id that matches no block, or several, is refused. Returns {ok, file, diagnostics, revision}, with notes when the write did something to say out loud (a block it dropped, an address it changed); a refusal is ok: false with a hint, and the file is unchanged.
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | Which block to replace: an id (with or without `#`), a `@<hex>` content address from `geml_list` for a block with no id, or `L27`/`L27-58` for the smallest block holding those lines. Must match exactly one block | |
| body | Yes | The replacement text | |
| file | Yes | Document path relative to the server's --root directory, e.g. notes/spec.geml | |
| part | No | What to replace (default: whole). `intro` replaces a section's opening — everything under the heading up to its first subheading — and leaves every subsection byte-identical, which is what makes a read-edit-write cycle on a long section safe. An empty intro (a subheading follows the heading immediately) is written into, so this also adds an opening where there was none. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare destructiveHint=true and non-read-only, but the description goes well beyond them: validation happens before the write, a breaking body leaves the file untouched and returns diagnostics, replacing-with-fewer-blocks is NOT refused and the result enumerates each dropped block, and an ambiguous or missing id is refused. It also discloses the return shape and the ok:false/hint refusal path.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core constraint and the sibling routing are front-loaded, and every sentence carries distinct information (validation, refusal, id matching, part variants, Markdown conversion, return shape). It is dense and lengthy, but not padded — the length is justified by the tool's branching behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, yet the description describes the return payload ({ok, file, diagnostics, revision}, optional notes) and the refusal form, plus the Markdown/GEML conversion rules and the dropped-block reporting. Nothing an agent needs to invoke this mutation correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description genuinely adds meaning: it explains what `part` values do behaviorally (intro leaves subsections byte-identical, making read-edit-write cycles safe, and an empty intro is written into). It also adds the Markdown anchor/heading-address semantics that the schema does not cover.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Replace ONE block') plus its defining scope constraint ('leave every other byte untouched'), and explicitly distinguishes itself from geml_add, geml_delete, and geml_revert. An agent can tell it apart from all siblings without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit routing rules: 'prefer this to rewriting a file,' 'For content that does not exist yet use geml_add,' 'to remove a block, geml_delete,' and 'geml_revert puts one back.' When-to-use, when-not-to-use, and the alternatives are all named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
geml_toConvert a whole documentARead-onlyInspect
Convert a WHOLE document and get the result back as text — the read half of the CLI's geml <file> --to <fmt>. to: "geml" on a Markdown file is the importer, the one thing the block tools cannot do; to: "md" projects a GEML document out (lossy); to: "json" returns the full document model, for when geml_list plus geml_get is not enough. Nothing is written — pass the result to geml_add or geml_set to land it. to: "html" also works but returns a whole self-contained page, usually tens of kilobytes this server cannot save: prefer the CLI (geml <file> --to html -o out.html) unless you want the markup in the conversation. A document with errors returns its diagnostics instead of a conversion, and a file that is not under the server root is an error.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Target format. Default is the CLI's: a GEML input becomes json, a Markdown input becomes geml. `html` is a whole page — large, and not writable from here. | |
| file | Yes | Document path relative to the server's --root directory, e.g. notes/spec.geml | |
| from | No | Override the input format, which is otherwise inferred from the extension (.md -> md, .json -> json, else geml). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond readOnlyHint=true: states nothing is written and tells the agent to pass results to geml_add/geml_set to persist, discloses that md output is lossy, that html is large and unwritable from the server, that erroneous documents return diagnostics not a conversion, and that out-of-root files error. This is exactly the extra operational context annotations cannot carry.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action, then layers format-specific guidance and error semantics. Dense but each clause adds a distinct fact. The single long paragraph is information-rich yet slightly cramped; minor formatting would help but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only conversion tool with no output schema, the description covers defaults, per-format tradeoffs, lossiness, error returns, root-scoping, and how to persist results. Nothing an agent needs to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the schema already documents each parameter, so baseline is 3. The description adds real value: it explains the per-enum behavior of `to` (json = full model, md = lossy projection, geml = importer), which the schema only sketches, plus defaulting behavior linking to the CLI.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a precise verb+resource: convert a WHOLE document to text. It explicitly frames itself as the read counterpart to the CLI write path and differentiates from sibling block tools ('the one thing the block tools cannot do'). An agent can distinguish it from geml_get/geml_list immediately.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use per target format, names alternatives (CLI for html; geml_list+geml_get for partial reads), and states a when-not ('prefer the CLI ... unless you want the markup in the conversation'). Routing guidance is concrete and actionable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.1.6- Changed
geml_add1 field changed- changed
Input schema / properties / anchor / descriptionPrevious value: -"Block id the insertion is relative to; required for before/after"New value: +"The block the insertion is relative to — an id, or any address geml_list prints; it must name one block. Required for before/after"
- Changed
geml_delete1 field changed- changed
Input schema / properties / ids / descriptionPrevious value: -"Block ids to remove"New value: +"The blocks to remove: ids or addresses"
11 tool updates
- First observed
geml_add - First observed
geml_check - First observed
geml_delete - First observed
geml_find - First observed
geml_get - First observed
geml_history - First observed
geml_list - First observed
geml_rename - First observed
geml_revert - First observed
geml_set - First observed
geml_to
TDQS
Scored across 11 tools
Each tool has a distinct role and the descriptions explicitly disambiguate the tricky pairs: geml_set vs geml_add (change existing vs insert new), geml_delete vs geml_revert (remove vs undo one change), and geml_rename vs geml_set (id-safe rename vs heading text change, which geml_rename explicitly defers to geml_set). Read tools are also cleanly separated: geml_list (what exists), geml_get (read one block), geml_find (which block holds words), geml_to (convert whole document). No two tools appear to do the same thing.
All tools share a uniform `geml_` snake_case prefix followed by a single token, which is highly predictable. Most are clear verbs (add, set, delete, rename, revert, list, find, get, check), with only minor deviations like the noun `history` and the preposition-ish `to`, both still readable in context.
11 tools is squarely in the well-scoped range for a document manipulation server, and each tool earns its place by covering a distinct operation (CRUD, search, validate, history/undo, format conversion). There are no redundant or filler tools.
The surface covers a full lifecycle: create (add), read (get/list/find), update (set), remove (delete), plus validation (check), history and single-block undo (history/revert), and format conversion (to) — richer than typical CRUD. Minor gaps remain, such as no explicit new-document creation or block-move operation, but these are largely workable via add/set.
Maintenance
Related MCP Connectors
MCP-native collaborative markdown editor with real-time AI document editing
MCP-native open-source Notion alternative: read & write pages, databases and kanban boards.
- ApricotOAuthtools.apricot
Manage SysML2 projects; check, evaluate, verify, query, document and diagram models.
- KorpusOAuthcloud.korpus
Shared memory for teams and their AI agents: Markdown concepts with typed links in shared bundles.
Related MCP Servers
- AlicenseAqualityDmaintenanceProvides powerful Markdown document editing capabilities with thread-safe operations, atomic transactions, and comprehensive validation.104MIT
- AlicenseAqualityDmaintenanceEnables efficient editing of RBT documents with structured operations that read and modify specific sections or blocks. Reduces LLM token consumption by 80-95% compared to full file operations through smart caching and partial document access.8MIT
- AlicenseCqualityNot gradedmaintenanceProvides semantic editing tools for Markdown files, allowing structured manipulation of document elements through hierarchical paths rather than raw text operations. Supports navigation, search, content replacement, element insertion/deletion, undo functionality, and YAML frontmatter management.152MIT
- AlicenseNot gradedqualityBmaintenanceProvides Markdown utilities: converts Markdown to plain text, extracts links and headings. Part of the Pipeworx MCP gateway.19 npmMIT