关于 GEML — a plain-text document format built to be edited in place, one section at a time
GEML 是面向人类和 Agent 协作的纯文本标记格式,配有按地址读取和修改内容的命令。它支持结构化校验与区块级回滚,适用于需要安全编辑 Markdown 或 GEML 文档的开发者和 Agent。
主要功能
- 01按区块地址读取与修改
- 02支持 Markdown 与 GEML
- 03语法和写入校验
- 04区块级历史记录与回滚
- 05跨文档引用与数据绑定
适用场景
- 01只读取文档中的目标区块
- 02修改表格单元格或数据字段
- 03回滚单个区块的编辑
- 04在多个文档间引用内容
配置
远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。
https://geml-mcp.supermarket.workers.dev/mcpclaude mcp add --transport http geml-spec-geml https://geml-mcp.supermarket.workers.dev/mcp{"mcpServers":{"geml-spec-geml":{"type":"http","url":"https://geml-mcp.supermarket.workers.dev/mcp"}}}在 Cursor 中打开{"servers":{"geml-spec-geml":{"type":"http","url":"https://geml-mcp.supermarket.workers.dev/mcp"}}}在 VS Code 中打开{"mcpServers":{"geml-spec-geml":{"type":"http","url":"https://geml-mcp.supermarket.workers.dev/mcp"}}}{"mcpServers":{"geml-spec-geml":{"serverUrl":"https://geml-mcp.supermarket.workers.dev/mcp"}}}命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。
工具
9| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| name | string | 否 | 文档的文件名,例如 notes/spec.geml 或 README.md——它决定文本是按 GEML 还是 Markdown(`.md` 名称)读取,也决定文档在消息中的称呼。默认值:document.geml。 |
| source | string | 是 | 文档的全文。此服务器不保存文件:你发送的内容就是文档。 |
| within | string | 否 | 可选:仅在此选择器指定的块内查找,例如用 `#install` 指定一个章节,或用 `=== table` 指定所有表格。它接受与 geml_get 的 `id` 相同的选择器形式。 |
详细介绍
GEML — 通用表达式标记语言
English | 中文
GEML 是一种轻量级标记语言,具有统一、可寻址的块和标准动词。
易于人类阅读,也能让 Agent 安全修改。
在 Agent 驱动的开发和知识工作中,纯文本和 Markdown 没有确定的块边界:程序和模型只能输入整个文件,再输出整个文件——最多也就是用行窗口探查内容;而要改写时,还得原样重述原文。文档越长,Token 成本越高,操作也越臃肿。改写几轮后,摘录到其他地方的副本就会开始偏离原文。
无需任何改动即可开始使用。 geml list、geml find 和 geml get 可以寻址你已有的 Markdown——无需转换,也不会创建新文件,你的 .md 仍是 .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 file
只有指定的部分会进入 Agent 的上下文——只有几 KB,而不是整个文件,无论文档增长到多长。每次保存都是一个版本,你可以读回或回滚一个块,也可以回滚整个文件。
▶ 在 Playground 中试用——无需安装,也无需预先阅读任何内容。
想要比一个章节更细——比如一个块、一张图表或一张表格?让 .geml 处于两者之间:按这个粒度编辑,而你交付的 --to md 永远不会与它偏离。
**块有名称;块内的内容有坐标。**表格中的单元格、data 块中的叶节点、meta 中的键——每个值都有结构本身提供的坐标,get 和 set 都能准确定位到该值。
geml get doc.geml '#fy[2]["Q1"]' # one cell
geml set doc.geml '#intake["fields"][1]["name"]' # one leaf in the JSON
对人来说,它是易读的纯文本;对 Agent 来说,它是可寻址、可验证、可追踪、可回滚的 "文档即基础"。
GEML 极简。 它是纯文本——即使没有渲染器也依然清晰易读; 整个语言只有一种块语法; 原生支持可寻址、可验证、可引用的结构。
GEML 不为每种内容单独设计一套小语法,而是用同一种容器承载所有内容:带类型的块。代码是一个块,表格、图表、数学公式、提示框,甚至元数据也都是块——你也可以把一段文字作为一个块(=== text),让它可以被寻址。以后扩展也同样简单。每次结构都相同,因此语言足够容易学习,也不容易出错。
=== code {#hello lang=python}
print("hi")
===
geml get doc.geml '#hello' # by name, just this block
块都有名称,因此动词有明确的操作对象——完整语法请见 一分钟了解格式。
目录:它解决的问题 · 为什么是现在 · 有何不同 · 一分钟了解格式 · 配置档案 · 动手试试 · 与大模型一起使用 · 成熟度与版本 · 设计理念 · 路线图 · 参与其中 · 许可证
它解决的问题
解决的问题
-
上下文负载和令牌膨胀
- 现状:JSON/XML 等数据格式带有大量包装标签和语法符号;Markdown 缺少严格的结构元数据和引用机制。
- 方案:优化标记密度和语法开销,只读写目标块——上下文成本不再随文档长度增长,让 Agent 读写更轻量。
-
AST 级精度和解析确定性
- 现状:非结构化文本经过多轮大模型读写后会逐渐退化——格式损坏、语义偏移、解析幻觉。
- 方案:采用可直接映射到抽象语法树(AST)的确定性语法,让程序和大模型执行原子级块的创建、读取、更新和删除。
-
文档副本碎片化
- 现状:多 Agent 协作和共享流水线通过复制粘贴传递内容,导致多个彼此断开的副本。
- 方案:从设计上实现 单一事实来源——通过标准化模块引用和数据绑定,消除冗余副本和版本分歧。
主要特性
1. AST 级结构化操作
- 统一的节点定义;文档可直接解析为类型化文档树(AST)。
- Agent 可精准定位目标章节、属性或组件;使用局部补丁和幂等更新取代整文件重写。写入以字节拼接的方式落盘,并对整篇文档重新验证——树用于读取和验证,且保证每个未触及的字节都保持不变。
2. 低令牌消耗的读写
- 节省的不是标记字符,而是永远不会被读取的部分:
#id可定位一个语义完整的块,其余内容不会进入上下文。 - 在语义相同的情况下,提示词令牌成本显著更低:模型吞吐量更高,推理成本更低。
3. 单一事实来源与模块化引用
- 原生支持跨文档、跨片段的组件引用。
- 只需更改一次源节点,所有引用都会同步更新——不会出现版本偏差。
4. 稳健的双向读写
- 全语言使用统一的块结构——易于生成且不易出错,非常适合主流大模型的输出分布。
- 严格的验证器可精确指出错误位置,并提供可执行的修复反馈。
5. 基于配置档案的领域扩展能力
- 避免方言混乱:通过声明式
profile元数据扩展领域词汇表(例如设计风格、交互式表单、代码图谱、媒体时间线),无需发明新语法或破坏解析器。 - 在未知环境中进行静态类型和约束检查,并安全回退到标准块。
对比
| 维度 | Markdown | JSON / YAML | GEML |
|---|---|---|---|
| 上下文成本(按块读写) | 高(整份文件读入和写出) | 高(整份文件 + 语法噪声) | 极低(仅处理目标块) |
| 精准 AST 操作 | 弱(没有严格的语义节点) | 强 | 强(专为 Agent 读写打造) |
| 人类可读性 | 高 | 中 | 高 |
| 单一来源引用 | 不支持 | 需要协议扩展 | 原生支持(模块化嵌入) |
| 领域扩展能力 | 碎片化(专有语法变通方案) | 取决于 Schema | 原生 Profile(无需新增语法 + 可验证) |
| 写入安全性 | 弱 | 中 | 强(错误写入会在落盘前被拒绝 + 支持单块回滚) |
为什么大模型时代需要一种全新的文本格式
因为文档的生产者和使用者都变了。
在传统软件工程中,文档要么是供人阅读的静态说明,要么是供程序使用的序列化数据文件。
如今,人和 AI Agent 会以很高的频率协作处理同一份文档。当 Agent 成为文档的“第二位读者和共同作者”时,旧有的平衡便彻底被打破:
- 上下文是稀缺的算力资源:每次读取或写入整份文档,都会消耗 Agent 有限的注意力窗口和推理预算;
- 人机协作需要同构的载体:人需要一眼就能看懂,Agent 则需要能够逐块精确读写;
- 知识必须有唯一的事实来源:分散的提示词和复制粘贴的 Markdown 注定会在每次迭代中逐渐失真。
然而,我们现有的文本基础设施都不是为这种场景设计的:
- Markdown(为人排版):没有稳定的结构化区块,也没有机器键。要修改一个参数,Agent 就必须读写整份文本——在多轮循环中浪费上下文预算,还容易导致格式和含义偏移。
- JSON / XML(为机器序列化):充斥着包装语法和结构噪声,妨碍人们自然阅读,同时也会在较长的上下文中悄悄消耗昂贵的 token。
- 临时记忆和分散的文件(没有唯一的事实来源):上下文散落在聊天记录和各处的 Markdown 副本中;副本一经创建便开始偏离原文,随后还会出现版本不一致和幻觉式失真。
这三种失败的根源,恰恰是每种工具自身的优点:Markdown“永不报错,什么都能写”的特性赋予了人们自由书写的空间——也正因如此,机器无法信任它读回的结构;JSON/XML 的严格架构赋予了机器确定性——也正因如此,没人会用它写散文。优点即缺陷,因此打补丁无法解决问题:给 Markdown 加上“无效引用必须导致构建失败”的规则,违背了它的设计初衷;从 JSON 中移除包装语法,则否定了它的本质。当人和 Agent 开始以很高的频率共同编写同一份文本时,我们需要的不是在两极之间折中,而是一种从第一天起就将“人类可读”和“机器可操作”视为同一项设计约束的格式。
答案:「文档即基座」(Doc-as-a-Base)
GEML 不会发明笨重的新运行时。它借鉴了 Roy Fielding 博士在其博士论文中提出的 REST 架构风格,为纯文本文档赋予一套标准的操作语义:
| 旧问题 | 对应能力(四条定律) | 为开发者和 Agent 带来的好处 |
|---|---|---|
| 修改一处就意味着要重写整篇文本 | 寻址定律 | 每个块都带有一个 #id;get/set 只读取和写入该块。从未加载的内容就不会被破坏——上下文窗口仍由你掌控。 |
| 副本到处都是,而且各自逐渐偏离 | 投影定律 | === embed 会动态求值,而不是复制粘贴;在源头定义一次,就不必再费力同步副本。 |
| 错误格式/失效引用污染下游 | 验证定律 | 构建时检查引用和语法;错误写入会在落地前被拦截,无需等待人工审核。 |
| 一次错误编辑就得回滚整个文件 | 回滚定律 | 配套的 .gemlhistory 可原子地还原单个块——无需拆掉整页;为 Agent 提供轻量级的版本安全网。 |
文档不再只需要一种格式——它还需要一组动词。 GEML 保留了纯文本的可读性,并增加了确定性的块级操作。
💡 深入阅读: 如果你对大模型时代文档工程的困境,以及为何我们需要从头重新设计纯文本格式感兴趣,请阅读我们在博客上发表的完整文章:《大模型时代,我们为何需要一种新的文本格式?》
GEML 有何不同
GEML 有意保持精简——设计背后的思考、它所拒绝的内容,以及仍未解决的问题,都记录在我们的设计思路中。
四项能力已在上一章确立——寻址、投影、验证、回滚。本章将逐一说明各格式如何实现这些能力,以及 GEML 如何划定自身边界。
与其他格式的比较
这四种格式各自在所属领域都有成熟的解决方案;不寻常的是,能在一种纯文本格式中兼具这四种特性:
| 家族 | 状态的实际形态 | 可寻址/可引用 | 可投影/可嵌入 | 可验证 | 历史/可追溯性 |
|---|---|---|---|---|---|
| Word / Docs | 不透明状态 | ❌ 没有块级键;通过平台 API 访问 | ❌ 只能复制粘贴 | ❌ 完全无法检查 | ⚠️ 在平台服务器端,不在文件中 |
| Markdown / AsciiDoc | 字符流 | ⚠️ 标题锚点或方言 ID;没有读写动词 | ⚠️ 方言嵌入(Obsidian ![[…]]、include::)——失效时不会提示 | ❌ 失效的链接不会提示 | ❌ 格式内没有——需要外部 git |
| JSON / XML | 数据序列化 | ✔️(id / schema) | ⚠️ 仅 XML(XInclude,外部) | ✔️ 通过外部工具链 | ❌ 格式内没有——需要外部 git |
| GEML | 纯文本 + 块结构 | ✔️ 每个块都有唯一的 #id(可原生引用) | ✔️ === embed:引用即查找(原生支持) | ✔️ 构建时错误 | ✔️ 文件旁的 .gemlhistory(原生支持追溯) |
逐项对比:与 CommonMark 对比 · 与 XML 和 JSON 对比 · 7 种格式的能力矩阵 · awesome-markdown 中的 Markdown 变体与工具(中文,HTML 页面)。
与 Markdown 共存:GEML 是编辑时的事实来源,Markdown 是交付产物。使用 geml <file> --to md|html 单向投影,照常交付 .md 或 .html。协作,而非锁定。(投影会有损:块 ID 和表格绑定的图表无法保留。)
**别只信表格中的说法——重新运行验证。**我向模型提出了这个问题:
根据你刚才编辑 README 的实际经验,描述一下你在文档上执行的命令步骤(我看到你用了 grep 之类的工具),以及你是否会缓存文档以节省 token——我们来比较一下,看看 GEML 的哪些部分真正值得保留。
得到的回答:一次编辑的成本和真实一天的操作回放。把这个问题发给你自己的模型,看看它会怎么说。
附言:我还在尝试弄清楚,codemap 生成的上游调用链(调用它的内容)和下游调用链(它调用的内容),能否像定位函数和调用点那样定位它们,并以相同方式修改项目代码。有结果后我会发布报告。
1 分钟了解这种格式
类型化块
**一种结构,适用于所有类型。**块的基本语法是 === type [attributes] … ===(其中 {#id .class key=val} 这样的属性为可选)——只有 type(以及块体的读取方式)会变化:
=== code {lang=python}
print("hi")
===
=== note {.intro}
Parsed prose with *emphasis* and a [[#budget]] reference.
===
=== meta
title = "Budget plan"
===
三个或更多连续的 = 会打开一个块;相同长度的连续 = 会关闭它;更长的围栏可以嵌套在更短的围栏内。带有 #id 的块也可以用带标签的围栏 === #id 关闭——无需计算围栏长度,长块也就不容易出错得多(嵌套仍然需要更长的外层围栏:块体中任何相同长度的裸 === 都会提前关闭块,无论是否使用带标签的围栏)。类型决定了块体的读取方式——raw(原样呈现:code、diagram、math、table)、flow(解析带行内标记的文本:note、text)或 data(每行一个 key=val:meta);embed 完全没有块体——它的 src= 指明其代表的块;每个块都可以带有属性对象 {#id .class key=val},其中 .class 是语义标签,绝不是样式钩子。完整的行内语法(强调、链接、[[#id]] 自动引用、媒体、脚注、行内 $math$)请参阅规范。
表格——两种形式,同一个模型
以可视化方式编写表格:
=== table {#budget caption="Annual cost"}
| Plan | Months | Rate |
|-------|-------:|-----:|
| Basic | 1 | 30 |
| Pro | 2 | 30 |
===
……也可以将其作为数据编写。表格保存事实;其上的 view 可派生出计算列和汇总行:
=== 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)"}
===
两种表格形式描述的是同一个模型。FY 列和 Total 行由视图在构建时计算得出:
| 业务板块 | Q1 | Q2 | Q3 | Q4 | FY | n |
|---|---|---|---|---|---|---|
| 云 | 8 | 10 | 12 | 14 | 44.0 | 1 |
| 平台 | 5 | 6 | 7 | 9 | 27.0 | 1 |
| 服务 | 3 | 4 | 4 | 5 | 16.0 | 1 |
| 总计 | 87.0 | 3 |
compute 会在每行中对列执行 + - * / ( ) 运算;summary 会根据 sum / avg / min / max / count 聚合结果添加底部行(也可对这些结果进行运算,例如计算加权比率);末尾的 [printf] 用于设置数字显示格式。上例中的 n 是一种计算行数的惯用写法——count 会统计某一列中的非空单元格,因此对常量列求和就能得到行数。
表格也可以通过 src="regions.csv" 从外部 CSV 文件中读取数据。
数学
=== math {#gauss caption="Gaussian integral"}
\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}
===
$$\int_{-\infty}^{\infty} e^{-x^2} dx = \sqrt{\pi}$$
图表与图示——承载 DSL,或将表格绘制成图表
GEML 不会解释图示内容;它会将其交给可插拔的渲染器处理(未知的 format 会触发警告,但内容会保留):
=== 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]
图示也可以将表格绘制成图表——单一事实来源,列引用会在构建时进行检查,且无需复制数据:
=== diagram {format=geml-chart data=#fy25-report type=bar x=Segment y=FY}
===
图表基于上方的 #fy25-report 视图绘制——FY 是计算列,因此图表绑定的是派生出该列的视图,而不是基础表格:
xychart-beta
title "FY by segment"
x-axis [Cloud, Platform, Services]
y-axis "FY"
bar [44, 27, 16]
数据——一种值,而不只是文本
每种块类型都说明了它所承载的内容:code 是一段代码,table 是一个网格,math 是一个公式。data 承载的是数据值,数据格式也在此定义——json(默认格式)、jsonl,以及适用于已声明子集的 yaml;toml 则保留待用。类型化意味着系统会读取内容,而不只是将其显示出来:缺少逗号会导致构建失败,geml get --json 会返回值本身,图表也可以直接读取它。
=== data {#log format=jsonl}
{"ts":"09:00","p95":41}
{"ts":"09:10","p95":58}
===
jsonl 内容每行包含一条记录,程序可以直接在文件末尾追加记录。记录也可以保存在独立文件中:src=ops/latency.jsonl#L900-999 用于指定文件,并可选指定行范围——日志仍可像以前一样持续追加和截取,而文档则是它经过验证、可寻址且可绘制成图表的视图。
嵌入——动态引用,而非副本
一个块可以代表另一个块:在同一文档中使用 src=#id,跨文档则使用 src=other.geml#id。嵌入会在渲染时动态查找源内容——只需修改一次源内容,所有嵌入都会同步更新;删除源内容,则 geml check 会立即使构建失败。
=== embed {src=#fy25}
===
内容保持为空;目标位于 src= 中。
Markdown 无法展示投影效果。要实时查看:安装浏览器扩展,打开 sample.geml 的原始链接,并向下滚动到 Transclusion 部分——同一文档内的投影(src=#roadmap)、跨文档投影,甚至链式解析(一个嵌入引用图表,而该图表又绑定到另一个文件中的表格)都会直接渲染在原处:这里不会写入任何内容,但只需修改一次源内容,投影就会随之更新。
配置文件——像乐高积木一样组合的领域词汇
想要编写交互式表单、定义设计令牌系统,或在文档中映射整个代码库的调用图?
在传统 Markdown 中,这需要使用专有插件(:::note、自定义 JSX 标签),最终不可避免地分裂成互不兼容的方言孤岛。
GEML 通过 Profiles(应用层词汇,规范 §8.6) 解决了这个问题:只需一行声明,即可按需解锁领域专属的结构化强大功能。
=== 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"}
===
无碎片化扩展
• 🧩 像乐高积木一样自由组合
核心语法保持精简且固定,而领域能力可以无限扩展。调用图、设计令牌、表单验证、版本历史……只需一行 profile = "...",即可组合多种领域词汇。
• ⚡ 零插件开销,工具支持即刻可用
添加新的领域块 无需分叉解析器,也无需自定义插件。自定义块可即刻继承完整基础设施:确定性 #id 寻址、geml get/set 块级修改、CLI 动词、MCP 协议以及自主 AI Agent 控制。
• 🛡️ 天然可移植,绝不受限于单一工具 扩展能力而不破坏互操作性。在任何第三方或陌生处理器中,文档都能保持 100% 的结构完整性和块级可寻址性,彻底摆脱切换工具时格式错乱的噩梦。
标准已发布配置文件
| 配置文件(指南) | 状态 | 用途 | 允许使用的超能力 | CLI | 在线演示 / 示例 |
|---|---|---|---|---|---|
geml-codemap/v1 | 稳定 | 将代码库的调用图生成为 GEML 文档:每个方法对应一个代码块,让你能看到哪些代码会调用它,以及它会调用什么;前端和后端合并为一张图 | code 代码块:anchor、name、entry-via | geml codemap build|verify|serve | 交互式调用图 · sample.geml |
geml-media/v1 | 草案 | 在一份文档中描述视频时间线:素材、剪辑、字幕和语音轨道;可将其导出为网页播放器,或使用 ffmpeg 渲染为 MP4 | media、media-asset、media-clip、media-text | geml media build|export|lay|todo | 文档转视频(通过 ffmpeg 将文档转为 MP4) |
geml-style/v1 | 草案 | 颜色、间距和布局存放在单独的样式表文档中,其中的规则会应用于内容;内容文档本身保持不变 | style-rule、style-state、style-screen、style-frame | geml style check | GitHub Blob 页面 1:1 复刻 |
geml-history/v1 | 稳定 | 在文档旁的 .gemlhistory 文件中保存历史版本:读取任意旧版本、恢复单个代码块,或回滚整个文件 | history-revision、history-keyframe、history-blob | geml history save|get|restore | 原子代码块回滚工作流 |
geml-form/v1 | 草案 | 在文档中描述表单:其字段、字段类型、必填项和允许范围;浏览器扩展和 Playground 会绘制预览 | form、form-field、form-group、form-options、form-note;form-field 上的约束属性 pattern、min、max…… | — | 交互式复杂表单示例 |
geml-translator/v1 | 草案 | 翻译文档不包含任何译文:它嵌入源文并指定目标语言,浏览器扩展会在打开时通过机器翻译生成译文,因此译文会跟随源文的每次更改 | embed 和 meta 属性 translate-to | — | — |
💡 想看看配置文件的实际效果吗? •
geml-media在线演示:一份剪辑文档和一条命令(geml media build ep01-cut.geml --out ep01.mp4 --burn-subs)即可调用 ffmpeg,对齐音视频、混合轨道,并将字幕烧录到成片中(查看)。 •geml-style在线演示:page.geml中的内容保持纯文本,样式和布局则存放在github.style.geml中,无需受 CSS 限制,即可渲染出与 GitHub Blob 页面像素级 1:1 精确复刻的页面(查看)。 • 表格中的每个配置文件名称都链接到一页式指南——介绍其用途、第一条命令和日常用法。如果你编写代码,请从geml-codemap开始。你也可以轻松创建自己的自定义领域配置文件。
接下来 — 立即动手体验
▶ 在 Playground 中试写 GEML — 在左侧编辑,右侧实时渲染;一旦引用失效,构建判定就会立刻变红。无需安装,也无需预先阅读。
接下来,按适合你的顺序体验:
- 在浏览器中查看渲染效果。 安装**扩展程序,并打开一个原始
.geml链接 (原始文件,而不是 GitHub blob 页面——后者是 HTML):GEML 规范本身(自我验证——规范本身就是一份 GEML 文档,以完整规模渲染)、展示示例**(计算表格、四个图表、一个 Mermaid 流程图和数学公式),或用于交互式代码图谱的 playground/sample.geml。 - 查看如何用文档排出一个完整的页面。 样式演示是 GitHub blob 页面的 1:1 复刻——包含顶部栏、文件树、面包屑导航、Preview/Code/Blame 和下拉菜单;其中
page.geml包含所有文本,github.style.geml包含所有颜色和长度,而查看器对两者都一无所知。它可在任何浏览器中打开——页面由查看器自身的代码绘制——对应的 GEML 就在下方。 - 在本地运行。 执行
npm i -g @geml/geml(Node 22+),然后用geml check检查文档,或用geml codemap build对自己的代码库运行。 - 设置 Claude Code——只需一条命令。
npx -y @geml/geml skill install会为所有项目在用户全局范围内安装创作技能、CLI 和 MCP 服务。不会编辑任何设置,也不会安装钩子。详情。 - 阅读语法。 完整规范(EN / 中文)具有规范性,篇幅也足以一次读完。
- 或者逐条查看规则的实际示例。 图解 GEML(EN 和 中文)——共十一页独立内容,涵盖每种块类型、每种配置文件以及 CLI:左侧是 GEML,右侧是处理器实际执行的操作(
geml check诊断信息、geml list地址、--to html标记),每条规则都标注了来源和状态。
将 GEML 与大模型搭配使用
目标只有一个:让模型一次编辑一个块,并进行验证—— 而不是为了修改一个段落就重新读取并重新输出整个文件。只需一步即可实现,具体步骤取决于你使用的工具。
使用 Claude Code、Gemini 或 Qwen——运行此命令
npx -y @geml/geml skill install
它会为所有项目在用户全局范围内安装创作技能、geml CLI 和 MCP 服务。无需编辑 settings.json,也无需钩子;升级后重新运行即可。
(更喜欢使用插件?运行 claude plugin marketplace add geml-spec/geml,然后运行
/plugin install geml@geml——技能相同,并附带 MCP 服务。)
使用 DeepSeek Harness——添加此套件
相同的设置,打包为 dsh 套件——包含 geml MCP 服务、创作技能和代码图谱技能:
dsh plugin --profile web add @geml/dsh-plugin # web = the profile dsh boots by default; use your own profile name if you run another
可在 dshmarket 和 awesome-dsh-plugin 上找到;源代码位于 integrations/dsh-plugin/。
使用 Codex — 安装插件
同一套内容再次打包供 Codex 使用:两个技能、MCP 服务,以及一个
SessionStart 钩子。在此仓库的检出目录中启动 Codex,它就会显示在
/plugins 中(市场源已提交至
.agents/plugins/marketplace.json);若不克隆仓库也要添加,可使用
integrations/codex-plugin/ 中的 git-subdir 条目。
然后在会话中说一次,项目就会切换为:
此项目使用 GEML 作为基础文档格式;需要时可从中生成其他格式。
使用其他工具 — 粘贴这段内容,然后检查输出
没有可读取的技能的模型需要了解一次规则。粘贴下面的提示词,并将
geml check 作为对其写回内容的检查关卡 — CLI 安装命令为
npm i -g @geml/geml(Node 22+)。
将文档写为 GEML:每个区块的格式都是
=== type [attributes]…===(1 分钟了解此格式列出了各类型)。有四条规则是模型容易弄错的:闭合围栏必须是长度与精确的起始围栏相同的一串=,且正文包含===时需要更长的外层围栏;标题只能使用 ATX#,不能使用---frontmatter(元数据使用=== meta);每个#id都必须唯一,且每个引用([[#id]]、[text](#id)、[^id]、data=#id)都必须能解析;不能使用原始 HTML。规范性说明见GEML-spec.md。
它会如何处理文档
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 code
任何章节都可通过 get 和 set 按三种方式切分:--head 是标题行,
--intro 是首个子标题之前的内容,--body 是章节下的全部内容 — 因此 --body 始终包含 --intro,若没有子标题,则与其相同。编辑章节开头时,无需将其子章节也纳入上下文。
每次修改都会在写入前重新解析;如果会破坏文档,就会拒绝写入 — 这让无人值守编辑也能安全进行。其余动词(delete、rename、history、--to md|html|geml 转换、按类型或内容哈希定位区块)见
解析器 README。
MCP 服务
软件包附带标准的 Model Context Protocol 服务,因此你的 Agent
每次只编辑一个区块,而不是重写整个文件——Markdown 和
GEML 文件均如此。它可在 Windows、macOS 和 Linux 上本地运行;--root 是服务
的访问范围限制目录(使用 . 或 ${workspaceFolder} 绑定到
当前项目)。
无需安装——相同的工具也可在 Cloudflare 上运行,地址为
https://geml-mcp.supermarket.workers.dev/mcp。在 Cloudflare 上,文档会随每次调用传输,写入结果以文本形式返回;请参阅
Worker 的 README。
Claude Code——一条命令即可完成设置(安装技能、CLI 和 MCP 服务):
npx -y @geml/geml skill install
(也可通过 CLI 手动注册:claude mcp add --scope user geml -- npx -y @geml/geml mcp --root .)
Cursor——在项目中添加 .cursor/mcp.json:
{
"mcpServers": {
"geml": {
"command": "npx",
"args": ["-y", "@geml/geml", "mcp", "--root", "${workspaceFolder}"]
}
}
}
(也可在 Cursor Settings → Features → MCP 中设置:名称为 geml,命令为 npx -y @geml/geml mcp --root .)
VS Code——无需配置:
GEML 扩展会向聊天功能提供两个服务:托管服务,以及针对每个工作区文件夹运行的 geml mcp --root .。编辑器询问时,选择你需要的服务即可。
Claude Desktop——添加到 claude_desktop_config.json:
{
"mcpServers": {
"geml": {
"command": "npx",
"args": [
"-y",
"@geml/geml",
"mcp",
"--root",
"/absolute/path/to/your/docs"
]
}
}
}
然后只需提出你想要的修改——例如“修复 FY26 表格中的 Q3 行”——Agent 就会处理对应的区块。你无需记住工具名称:每个工具都对应一个 CLI 动词(geml set → geml_set),因此终端和 Agent 使用的是同一套词汇。
两项保障让这种方式优于让模型重写文件:写入内容会先经过解析,再写入磁盘;如果会破坏文档,系统就会拒绝写入并提供诊断信息。每次写入前还会先记录一个 .gemlhistory 修订版本——因此,错误编辑既能被阻止,也能被撤销(geml_revert 会还原一个区块,文件其余部分的字节保持不变)。路径始终限制在 --root 范围内,客户端无法扩大此范围。
将 --root 指向包含代码图谱的仓库(geml codemap build),同一服务还可以回答“谁调用了这个?”——通过四个只读的 geml_codemap_* 工具,只需一个客户端条目,无需两个。所有工具和选项见:
docs/mcp-guide.md。
生态与成熟度
GEML 是一项小型且年轻的规范,但它已经稳定:1.0 已发布,可用于实际文档(本仓库自身的规范就是一个实例),并配有严格的一致性测试套件、通过该套件的参考实现**(版本独立于规范)**,以及开放的提案流程。
规范只有一份,并提供双语版本。.gemlhistory 伴随文件由 geml-history/v1 配置文件定义——这是规范之上的应用层,而非规范本身的一部分。这也是它采用 MIT 许可、而规范采用 CC-BY 许可的原因(LICENSE-spec.md 说明了原因):
| 文档 | 英文 | 中文 |
|---|---|---|
| 规范 | GEML-spec.md | GEML-spec_CN.md |
geml-history/v1 配置文件 | geml-history-profile.md | geml-history-profile_CN.md |
本项目发布的所有配置文件:spec/profiles/。
版本与兼容性
- 自托管 —
GEML-spec.geml是用 GEML 编写的规范,每次测试运行都必须能对其进行无错误解析。 - 一致性测试套件 用于确保不同实现之间的兼容性。
- 解析器参考实现。 目前已有 1,700+ 项单元测试,以及一致性语料库、往返序列化和端到端 CLI 运行;覆盖率由 CI 门控,行 / 语句 / 函数 / 分支覆盖率均须达到 ≥95%。
- 语法支持向前兼容。 处理器必须能够对其不认识的结构优雅降级(规范 §8.2),因此,添加块类型或图表格式不属于破坏性变更。类型注册表是开放的:未注册的类型名称应包含连字符(
acme-invoice),不含连字符的名称留给规范的后续版本使用(§8.5)。 - 声明符合规范。 实现逐项通过一致性测试套件后,即可称其为符合 GEML 1.0(§8.5)。无需获得许可,也无需本仓库批准。
- 线上格式。 扩展名
.geml(版本附属文件.gemlhistory),媒体类型text/vnd.geml— 已于 2026-10-26 在 IANA 注册为厂商树媒体类型;如果该规范将来通过 IETF 发布,则可申请标准树媒体类型text/geml。 .gemlURL 上的片段标识符用于指定具有该 id 的块(§0.6)——这与 HTML 页面上#tag的含义不同。
我们如何思考设计
设计遵循的原则
-
人类与 Agent 同构,而非妥协 GEML 不在适合人类阅读的 Markdown 与适合机器读取的 JSON 之间折中,而是将人类可读性与机器确定性视为一个不可妥协的约束。人类看到的是清晰、无干扰的文本;Agent 获取的是强类型 AST——消除两种独立格式之间的转换损耗。
-
文档即基底,而非字符流 传统文档是脆弱的字符流,编辑一句话往往就需要重写整个文件。GEML 将文档视为可寻址的结构化记录数据库,每条记录都具有稳定的主键(
#id)。每个区块都有独立的生命周期、空间坐标和原子化的 CRUD 接口,适合 Agent 以 O(1) 复杂度进行读写。 -
一种语法基元,无限领域词汇 拒绝为每种新内容发明语法补丁。GEML 使用单一的类型化区块基元(
=== type)来承载代码、数据、表格、数学公式和布局。领域能力通过 Profiles(profile = "...")无限扩展:语法保持 100% 冻结,而词汇表持续开放——从根源上消除方言碎片化。 -
转置而非复制:消除复制的动机 传统超链接只是指向其他位置的路标,容易促使人们复制粘贴,最终导致副本不同步。GEML 引用是动态视口(
=== embed):在源位置定义一次,即可在各处实时投影。消除复制的动机,从而维护唯一真实来源。 -
编译器级完整性:像对待代码一样对待文档 Markdown 的理念是“永不失败,尽量渲染内容”——这是 Agent 产生幻觉和文档悄然衰退的主要温床。GEML 强制执行严格的构建时静态验证。失效的
#id、无效属性和循环引用都会导致构建失败并返回非零退出码。在错误污染下游系统之前将其捕获。 -
本地优先的历史记录,而非云锁定或 Git 开销 数据属于本地文件系统,版本控制应细化到区块级别。GEML 拒绝将版本历史锁定在专有云平台(如 Notion 或 Google Docs)中,同时避免 Git 对微小编辑进行整个仓库提交所带来的高昂开销。配套的
.gemlhistory提供纯文本的本地优先原子快照和精准回滚(geml revert doc.geml '#id'),确保真正的数据自主权与安全性。
因此,它拒绝
| 拒绝的内容 | 原因 |
|---|---|
| 自有的图表语言 | 外部 DSL 由外部托管(Mermaid、Graphviz、D2、……);该格式仅定义承载协议 |
| 原始 HTML 逃生通道 | 语义保持可移植,不绑定任何后端或渲染器 |
Setext 标题 / --- frontmatter | 仅使用 ATX #,因此不会与主题分隔线冲突 |
| 完整的电子表格引擎 | 按行公式和汇总聚合已足够;无需单元格寻址、查找或宏 |
路线图
- GEML
1.0规范,提供英文版和中文版,并附带一致性测试套件 — 以及定义.gemlhistory旁车文件的geml-history/v1配置文件 - 媒体类型
text/vnd.geml已在 IANA 注册(2026-10-26),其已发布规范为本项目规范,变更控制方为本项目 - 参考实现
@geml/geml:解析器、CLI、块级.gemlhistory跟踪 - 官方 MCP 服务(
geml mcp),适用于 Claude Code、Cursor、Codex 和其他 MCP 宿主 - codemap — 以 GEML 编写的整个代码库调用图
- VS Code 扩展已发布到 Visual Studio Marketplace(发布者
geml) - 生态集成:VS Code 高亮和引用检查、tree-sitter、Obsidian、Logseq(与实时数据库图谱双向同步)、浏览器查看器、GitHub Action、LangChain / LlamaIndex,以及 Agent 框架插件 — Claude Code、Codex、Grok、DeepSeek Harness,另有 Gemini CLI 和 Kimi Code 的根清单
- Logseq 插件列入 Logseq marketplace(PR #893),Grok 插件列入
xai-org/plugin-marketplace - 第二个实现
geml-parser-rs/— Rust 编写,编译为 WebAssembly,仅依据规范和一致性测试套件编写,未阅读参考解析器 - 由其他人编写的实现 — Python,或你选择的任何语言;规范和一致性测试套件均已公开,我们很乐意协助让它们保持一致
参与其中
GEML 已达到 1.0,但“稳定”意味着现有规则不会突然改变,
而不是设计已经定型。目前有两个实现,但作者只有一位 —
因此规范背后仍然只有一套观点。你的想法仍有可能改变规范本身。
如果你想参与其中:
来讨论这些仍处于草案阶段的提案:
有其他想法?发起讨论。
| 缺口 | 当前进展 | 所需工作 |
|---|---|---|
| 为更多 Agent 工具安装技能 | Gemini CLI、Qwen Code 和 AGENTS.md 已可通过检测安装;MCP 服务适用于任何客户端 | 以相同方式添加其余工具:Cursor、GitHub Copilot、Cline — 它们的规则文件约定变化很快,编写前请查阅最新文档 |
| 入门指南在其他模型上的效果 | 目前仅在 Claude 上测试过 | 让 GPT / Gemini / 本地模型各自依据入门指南编写一批 GEML,统计首次通过 geml check 的数量,并报告它们反复出错的规则 — 这些规则正是入门指南应该明确说明的 |
| 更深入的 Obsidian 集成 | 可以渲染,但尚未进入社区商店 | 在 CodeMirror 层进行编辑并实现无缝双向渲染,以及完成商店提交。需要熟悉 Obsidian API 的人。 |
| 查看器在其他浏览器上的表现 | Chrome 可用 | 移植到 Firefox / Safari。 |
| 打包 RAG 集成 | LangChain / LlamaIndex 是参考实现 | 发布到 PyPI;并接入其他框架(Haystack、DSPy,等等)。 |
- 用你的语言实现规范 — 仅依据规范编写新的 GEML 解析器(如何编写解析器);
geml-parser-rs/就是以这种方式编写的,可作为完整示例进行对照 - 找出规范中含糊不清之处本身就是贡献,无论该解析器最终是否会发布。
或者提出新想法:
- 一个 GEP:提案、规范修改和一致性测试用例一并提交(流程)
或者立即使用:
| 场景 | 位置 | 状态 |
|---|---|---|
| 在命令行中使用 — 一条命令即可完成验证、转换、按块编辑和版本历史管理 | @geml/geml(源代码位于 geml-parser/) | 可用 |
在浏览器中阅读 — 打开任意 .geml 原始链接,即可就地渲染:计算表格、图表、Mermaid、数学公式,诊断信息以横幅形式显示 | Chrome 网上应用店 · 源代码 | 可用 |
| 让 Agent 按块编辑 — MCP 服务让 Agent 修改单个块,而不是重写整个文件;每次写入都会先经过验证,再写入磁盘 | docs/mcp-guide.md | 可用 |
| 在 DeepSeek Harness 中使用 — geml MCP 服务加上创作和代码图谱技能,组成一个可安装的捆绑包 | @geml/dsh-plugin · dshmarket · 源代码 | 可用 |
在 Codex 中使用 — 同一套内容:两项技能、MCP 服务和一个 SessionStart 钩子,可从 /plugins 安装 | integrations/codex-plugin/ | 可从此仓库获取;尚未上架公共插件目录 |
| 在 Grok 中使用 — 再次提供同一套内容:两项技能和 MCP 服务 | integrations/grok-plugin/ | 可从此仓库获取;尚未提交 xai-org/plugin-marketplace PR |
将 Logseq 图谱同步为纯文本 — 将 Logseq 2.0 DB 图谱持续同步为 GEML 文件,便于寻址和使用 git;可通过 restore 还原 | @geml/logseq-sync · 源代码 | 监视器已发布到 npm;插件通过发布版 zip 安装——市场列表(PR #893)尚未合并 |
| 将代码库转换为文档 — 将整个调用图构建为可浏览的 GEML 文档树 | geml codemap build(指南 · 设计文档) | 可用 |
| 在编辑器中编写 — 语法高亮 + 构建时引用检查 | Visual Studio Marketplace · 源代码 | 可用 |
在 Android Studio / IntelliJ 中编写 — 语法高亮、输入时诊断、预览、结构视图,以及从 .gemlhistory 恢复块 | integrations/intellij+androidstudio-plugin/ | 已构建;需安装自行构建的 zip(从磁盘安装插件),尚未上架 JetBrains Marketplace |
| 在 Obsidian 中渲染 — 使用参考解析器和查看器渲染器,与网页采用相同的代码路径 | integrations/obsidian/ | 已构建,尚未上架社区商店 |
为 RAG / Agent 框架提供数据 — 块级加载器(每块一个分块,并携带 block_id)+ Agent 编辑工具 | integrations/langchain+llamaindex/ | 参考实现 |
| 无需安装即可试用 — 左侧编辑,右侧实时渲染 | Playground | 可用 |
建议先阅读这三个文件:GOVERNANCE.md 了解决策如何制定,CONTRIBUTING.md 了解如何提交贡献,以及 CODE_OF_CONDUCT.md 了解关于如何对待他人的唯一规则——你可以尖锐地反对设计,但不要针对个人。
仓库结构
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.
许可与治理
代码采用 MIT 许可(LICENSE):本仓库中的所有内容——
geml-parser/、geml-parser-rs/、整个 integrations/、.claude/skills/、docs/、
spec/profiles/ 中的配置文件、spec/proposals/ 中的 GEP——规格文档除外。
规格文档采用 CC-BY-4.0 许可(LICENSE-spec.md
准确列出了这些文档):spec/GEML-spec* 和 spec/in_geml_format/*。规格只有一份;
spec/profiles/ 下的配置文件属于应用层,采用 MIT 许可。
规格不是软件,因此任何人都可以在未经许可的情况下构建符合规范的实现——通过
一致性测试套件 后,即可称其为 符合 GEML 1.0 规范。
名称的使用。 实现 GEML、使用格式名称为实现命名(如 geml-rs、pygeml,或在你的
语言的软件包注册表中发布名为 geml 的软件包),或声明你的工具能够读写 GEML,都无需许可。我们只有两项请求,均不构成法律限制:只有通过一致性测试套件后,才将实现称为符合 GEML 1.0 规范;并且不要暗示本项目编写、认可或维护了该实现。CC-BY-4.0 已要求对规格文本本身进行署名。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。