geml

GEML

GEML — General Expressive Markup Language(通用表达型标记语言)

*English 中文*

一种格式,两类读者。
AI 智能体可共同书写同一篇章。
对人,清晰可读;对机器,可寻址、可校验、可带版本。

GEML 是纯文本——由一种类型块承载一切,由一个 .gemlhistory 伴生文件记忆。

npm CI GEML check code: MIT spec: CC BY 4.0

到 Playground 试写 GEML——左边编辑、右边实时渲染,引用一断,构建判定当场翻红。无需安装。


GEML 是一种面向结构化文档的标记语言。.geml 文件本身就是纯文本,读它不需要任何渲染器。它也不为每种内容单独设一套迷你语法,而是把所有内容都放在一个构造上:类型块(typed block)

=== code {#hello lang=python}
print("hi")
===

代码是块,表格、图形、公式、提示框、乃至文档元数据,也都是块。形态每次都一样,所以这门格式好学,也难写错。

为什么现在需要一种新格式

Markdown 是为人类手写、人类阅读的文档设计的。而今天,同一批文档还要由 AI 智能体和 CI 流水线来书写、编辑、评审与查询——这一转变,对格式提出了三件 Markdown 从未需要提供的事:

GEML 就是围绕这三点做出来的。目标不是给某种文档格式”加上 AI 功能”,而是选一种对人更简单、对机器也更可靠的格式。

GEML 有什么不同

很多格式能做到其中一两件。GEML 的特别之处在于,一种纯文本格式三点都满足:

  1. 单一原语承载一切结构化块。 代码、表格、图形、公式、提示框、元数据——全是同一个 === type {…} 类型块。一套语法要学、一套语法去正确生成:没有按特性各设的语法,也没有 HTML 兜底。
  2. 引用在构建期被校验。 给任意块标 #id、在任何地方引用它;悬空引用或断掉的跨文档链接是构建错误,而非静默的 404。自动编辑不会悄悄腐烂。
  3. 自包含的版本历史。 一个同名 .gemlhistory 伴生文件即可重建任意历史修订、把文档回滚——离线、无需 git、无需服务——而且它是纯文本,智能体能读懂文档的演变。

Markdown、HTML、CommonMark、AsciiDoc、Org-mode 的完整对照,见格式比较

五分钟看懂这个格式

类型块

一种形态,通吃所有类型。 每个块永远是 === type {#id .class key=val}===——变的只有 type(以及正文怎么读):

=== code {lang=python}
print("hi")
===

=== note {.intro}
解析过的散文,可用 *强调* 与 [[#budget]] 引用。
===

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

连续的 =(≥3 个)开块,等长的一串闭块;更长的围栏可嵌套更短的。带 #id 的块还可以用带标签围栏 === #id 闭合——不必数围栏长度,长块、嵌套块因此更难写错。类型决定正文如何解读——raw(原样:codediagrammathtable)、flow(带内联标记的散文:note)、或 data(每行一个 key=valmeta);每个块都可携带属性对象 {#id .class key=val},其中 .class语义标签,绝不作样式钩子。完整的内联语法(强调、链接、[[#id]] 自动引用、媒体、脚注、行内 $公式$)见规范

表格 —— 两种正文,一个模型

可视化写法:

=== table {#budget caption="年度成本"}
| Plan  | Months | Rate |
|-------|-------:|-----:|
| Basic |      1 |   30 |
| Pro   |      2 |   30 |
===

……或写成数据,带计算列汇总行

=== table {#fy25 format=csv header=1 compute="FY [%.1f] = Q1 + Q2 + Q3 + Q4" summary="Segment = 'Total'; FY [%.1f] = sum(FY)"}
Segment,  Q1, Q2, Q3, Q4
Cloud,     8, 10, 12, 14
Platform,  5,  6,  7,  9
Services,  3,  4,  4,  5
===

两种形态描述同一个模型。FY 列与 Total 行在构建期算出:

Segment Q1 Q2 Q3 Q4 FY
Cloud 8 10 12 14 44.0
Platform 5 6 7 9 27.0
Services 3 4 4 5 16.0
Total         87.0

compute 对各列逐行做 + - * / ( ) 运算;summary 用聚合 sum / avg / min / max / count(并可对聚合结果再做算术,如加权比率)生成表尾一行;列名后的 [printf] 控制数字显示。

表格还支持用 src="regions.csv" 引入外部 CSV。

公式

=== math {#gauss caption="高斯积分"}
\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="评审流程"}
graph LR
  A[Draft] --> B{Review} -->|ok| C[Publish]
===
graph LR
  A[Draft] --> B{Review} -->|ok| C[Publish]

图形还能为一张表作图——单一真相,列引用在构建期受校验,数据零拷贝:

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

取自上面的 #fy25 表:

xychart-beta
  title "FY by segment"
  x-axis [Cloud, Platform, Services]
  y-axis "FY"
  bar [44, 27, 16]

一份给程序员的礼物:geml-code-graph

为了更好地体会 GEML 格式的强大与灵活,我们拿程序员最熟悉、也最有挑战性的场景之一——代码图——来试一试。 把整个代码库的调用图,写成 GEML。 geml codemap build 把调用图落成一棵 GEML 文档树——每个方法一个 #id 块,#calls / #called-by 正反向边。正向调用的下游链做问题排查、反向被调用的上游链查看影响面,全都秒速得见; geml-parser/render.ts 的方法图:悬停 RenderCtx.inline,整条调用链高亮、其余变暗;点击节点,该方法源码就显示在图旁边

npm i -g @geml/geml             # 需要 Node 22+
geml codemap build              # --root 默认当前目录:识别语言 → 索引 → 合并成一张图,落在 ./.geml-code-graph/
geml codemap serve              # 自动打开浏览器看图

[!TIP] TS/JS——零前置,build 会自己拉取 scip 索引器。 Java / C / Python / Go / Kotlin——多下载一个 Joern:release 包解压后把目录传给 build,例如 --joern C:\joern\joern-cli(放进 PATH 也行,可省掉这个参数)。 前端 + 后端混合仓库——会并进同一张图

geml-code-graph 本身就是一个 diagram 格式——一行就能把它嵌进任何 GEML 文档(=== diagram {format=geml-code-graph src=.geml-code-graph/index.geml} ===),且每次代码变更都会自动触发重建,代码图永不脱节。规模不是问题:图是纯文本数据表——上万源文件、几十万条边仍秒开秒查(去感受下全局密如蛛网的对称美感带来的震撼吧),随意搜方法名可以定位调用链路。

下一步——快点上手用一下:

  1. 装上浏览器扩展,打开任一 raw .geml 链接看它渲染——GEML 规范本身(dogfood——规范本身就是一份 GEML,规模化渲染)、showcase(计算表、四张图、一条 Mermaid 流程、公式),或把 playground/sample.geml 打开看交互式代码图。
  2. 或现在就到 ▶ Playground 自己当场试着编辑下——无需安装。
  3. 想了解完整语法,读完整规范(中 / English)。

为什么它对人和 AI 都好使

让 GEML 肉眼读起来舒服的那套形态,也正是它在自动化下可靠的原因:

在大模型里使用 GEML

GEML 的设计目标是让模型来写、也来改——而且改得精确。要改一处,agent 不必重读、 重发整篇文档,而是按 id 定位到单个块,改完再校验。命令集只对着一条标尺打磨—— 一个 agent 能否单靠命令行跑完一篇文档的全生命周期?——所以动词力求够全(每个 环节都有对应动词)、够顺手(参数少、默认合理、I/O 可管道化)、够一致(指定 目标 #id,内容便归到它名下,每次写入都有守卫):

npm i -g @geml/geml                 # 安装 geml 命令
geml doc.geml                       # 文档模型 JSON(默认 --to json)
geml doc.geml --to md|html|geml     # 转换(geml notes.md -> GEML;-o 写文件)
geml get    doc.geml ['#id']        # 列出全部 id,或打印单个块(标题 id = 整节)
geml set    doc.geml '#license' --in template.geml#mit   # 替换一个块,fork 另一文件(id 归一到 #license)
geml add    doc.geml --after '#intro' --in snippet.geml  # 在某位置插入片段(保留其自身 id)
geml delete doc.geml '#draft' '#tmp'           # 删除一个或多个块
geml rename doc.geml '#old' '#new'             # 重命名一个 id 及其全部引用
geml revert doc.geml '#plan' --rev -1          # 把单个块回退到某历史修订

转换只有一个入口 geml <file> [--to <fmt>]:输入格式自动判定(--from 覆盖 > 扩展名 > GEML),目标由 --to 决定(默认:GEML 输入 → JSON、Markdown 输入 → GEML)。编辑则由四个动词覆盖整块生命周期:set 替换一个块(从文件或 stdin fork 内容,并把 id 归一到目标)、add 在某位置插入片段、delete 删除一个或多个块、 rename 改写一个 id 及其全部引用。每个变更都写出整篇更新后的文档——输入是文件 就地改、输入是 - 走 stdout、-o 重定向——因此编辑天然可管道化,且都有守卫: 写前重新解析,若会破坏文档则拒写。按 id 读取与修补,让每次编辑又小又准——只花整篇 文档零头的 token。

GEML primer。 把文档写成 GEML。每个块都是 === type {#id .class key=val}===;闭合围栏是与开围栏等长的一串 =,更长的围栏可嵌套更短的——块若带 #id,也可以用带标签围栏 === #id 闭合(不必数长度,长块或嵌套块优先用它)。 块类型:code/diagram/math/table(原样正文)、note(带内联标记的散文)、 meta(每行一个 key=val)。标题只用 ATX #——没有 --- frontmatter(用 === meta)。每个 #id 唯一,且每个引用([[#id]][text](#id)[^id]、 图表 data=#id)都必须能解析。不允许 raw HTML。内联:*强调***加粗**`代码`$公式$[文本](url)。规范见 GEML-spec_CN.md

生态

状态、边界与贡献

GEML 已发布 1.0——稳定,可用来写真实文档(本仓库的规范本身就是一例)。

成熟度信号。 完整的核心规范(§1–§8)外加历史扩展规范,均有中英两版;可用的参考实现、渲染器 + CLI;一套一致性测试集输入 → 投影出的文档模型),还要由第二个、独立编写的解析器逐用例复刻出完全相同的结果——两个各自独立的实现在每个用例上都一致,才能保证强调、列表这类微妙规则不会各写各的、跑偏——另有 600+ 项单元与一致性检查兜底(参考实现约 99% 行覆盖,CI 门槛:行/语句/函数/分支均 ≥95%);以及自举——GEML-spec.geml 是用 GEML 写成的规范本身,每次测试都被干净解析。

设计边界(非目标)。 GEML 刻意保持小:

贡献。 各种贡献都欢迎——报 bug、工具与集成、更广的一致性覆盖,以及规范本身讨论。GEML 已是 1.0,但仍可演进:实质性的规范改动通过 GEP 讨论并落地,每项都附带对应的一致性用例。参考实现的测试套件就是契约——代码改动应保持 npm test 通过、且 dogfood 规范解析无误。最有价值的贡献是用另一种语言写一个独立实现——可移植的一致性测试集让它成为一个周末的活儿,见 docs/WRITING-A-PARSER.md

文档 English 中文
核心规范 GEML-spec.md GEML-spec_CN.md
历史扩展 GEML-history-spec.md GEML-history-spec_CN.md

仓库结构

spec/                  核心规范 + .gemlhistory 扩展(英 / 中)、dogfood 的
                       GEML-spec.geml、CC-BY 规范许可证、proposals/(GEP)
geml-parser/           参考实现、渲染器、CLI + codemap 工具集(TypeScript, Node 22)
integrations/          GEML 接入的所有地方:geml-viewer(浏览器扩展)、
                       geml-check-action(CI)、vscode、obsidian、tree-sitter(简报)
playground/            浏览器内 playground(含本仓库的实时 geml-code-graph)
docs/                  指南、设计笔记、格式 COMPARISON(英 / 中)、图片资产,
                       以及一个可自行渲染的示例 .geml 文档

许可与治理

代码(geml-parser/integrations/geml-viewer/integrations/geml-check-action/)为 MITLICENSE)。规范文档为 CC-BY-4.0LICENSE-spec.md)——规范不是软件,任何人都可以构建一个兼容实现。决策方式见 GOVERNANCE.md,参与方式见 CONTRIBUTING.md