
Company News
AWS Security Hub Adds Socket for Supply Chain Security
Socket is now in the AWS Security Hub Extended plan. Adopt it through AWS, apply committed spend, and block malicious open source packages.
@geml/geml
Advanced tools
GEML(General Expressive Markup Language) — one format, two readers. People and AI agents co-write the same document: plain text that stays legible for people, and addressable, verifiable, and versioned for machines. Reference parser, validator, renderer &
The reference parser, validator, renderer, and CLI for GEML (General Expressive Markup Language) — one format, two readers. People and AI agents co-write the same document: plain text that stays legible for people, and addressable, verifiable, and versioned for machines.
Every kind of structured content — code, tables, diagrams, math, callouts, metadata — rides on one primitive, the typed block:
=== code {#hello lang=python}
print("hi")
===
#id; geml get / geml set '#id'
read or patch one section without re-emitting the whole file (on this repo's
own spec, ~31× less context than shipping the whole document).#id is an
error, not a silent dead link), and the parser emits a document-model JSON
with a diagnostics array, so agents and CI get a structured pass/fail signal.geml history and geml revert snapshot and rewind
revisions over a plain-text .gemlhistory sidecar.Try the format in the playground — no install. Full pitch, spec, and format comparison live in the repository.
npm install -g @geml/geml # global CLI — installs the `geml` command
# or, per project:
npm install @geml/geml # library + local bin
Requires Node ≥ 22.
The CLI is built around one question: can a single agent author and maintain an
entire .geml file from the command line — create, add, edit, delete, and copy
blocks in from other files? Three tests keep the command set honest:
#id and
the content adopts it, every write is guarded, a file is edited in place while
- streams to stdout.Every command reads a file path, or - for stdin. Exit codes: 0 ok ·
1 document/operation error · 2 usage error.
geml doc.geml # document-model JSON (default --to json)
geml doc.geml --to md|html|geml # convert; geml notes.md -> GEML
geml get doc.geml ['#id'] # list addressable ids, or print one block (heading id = its section)
geml set doc.geml '#id' [--head|--body] [--in F[#src]] # replace a block's content (id kept)
geml add doc.geml (--append|--before #id|--after #id) [--in F[#src]] # insert a fragment
geml delete doc.geml '#id' ['#id2' …] # remove one or more blocks
geml rename doc.geml '#old' '#new' # rename an id + every reference to it
geml revert doc.geml '#id' [--rev -1] # undo a block: splice / resurrect / remove
geml check doc.geml [--root <dir>] # validate only: diagnostics + exit code (--json for the array)
geml history <commit|verify|show|restore|log> doc.geml [...] # .gemlhistory version sidecar
geml codemap <build|verify|render|serve|refresh|find|mcp> # your codebase's call graph as GEML docs
geml --help | --version # --version --json prints {"parser","spec"}
The agent loop: geml get a block → set/add/delete/rename it →
geml check → geml history commit — small, precise, verifiable edits.
Conversion is one entry — geml <file> [--to json|html|md|geml]; the input
format is inferred (--from overrides > extension > GEML), the target is --to
(default: GEML → JSON, Markdown → GEML), and -o names the output path.
set and add take their content from --in F (F's block whose id equals the
target), --in F#src (F's block #src), or stdin (raw bytes). set replaces
a whole block and normalizes the content's id to the target — so you can fork
any block into this slot without hand-editing its id (--head swaps just the
head line, --body just the body). add inserts a fragment (one or more
blocks, or bare prose) at --append / --before #id / --after #id, keeping
the content's own ids (a collision is refused). delete removes one or more
ids; rename rewrites an id's declaration and every reference to it.
Mutations (set/add/delete/rename) write the whole updated document:
in place when the input is a file, or to stdout when the input is -; -o
redirects the write (-o - forces stdout), so edits pipe cleanly. Every write
is guarded — re-parsed and refused if it would break the document or drop an id
(a reference left dangling by delete is a warning, not a refusal; geml check
flags it later).
Undo is revert, which reconciles one block to a past revision (--rev, default
-1): it splices back changed content, resurrects a deleted block (placed
by its old neighbours, or --append/--before/--after), or removes a block
that did not exist then. So each forward edit has an inverse:
| forward edit | undo |
|---|---|
set #id | revert #id (splice) |
delete #id | revert #id (resurrect) |
add #id | revert #id (remove) — or delete #id |
rename #old #new | rename #new #old (self-inverse) |
revert reads the .gemlhistory sidecar, so set/delete/add undo needs a
prior geml history commit; rename is its own inverse and needs no history.
A heading's #id addresses its whole section — the heading line through
the line before the next heading of the same-or-higher level — so the prose
under a heading is block-editable with no extra syntax.
Spans overlap: blocks nested in the section keep their own ids, and a set on
the section that drops one of them is refused by the guard. get --json on a
heading covers the same content as the raw span: a section envelope
{kind:"section", id, level, blocks:[heading, …its section's blocks]} (a
block/footnote id still prints its single model node). --head narrows
get/set/revert to ANY id's head line — a heading's line, or a typed
block's opening fence line, so an agent renames a heading or edits a block's
attributes (caption, compute, …) without touching the body. Convention: keep
the document title in === meta (title = "…"), not an H1 — a lone top-level
# section is the whole document, the telltale that it is really a title.
import { parse, serialize, renderHtml, gemlToMd, mdToGeml } from "@geml/geml";
const doc = parse(src); // { kind:"document", children, ids, diagnostics }
const ok = !doc.diagnostics.some(d => d.severity === "error");
const html = renderHtml(doc); // one self-contained HTML string
const md = gemlToMd(doc).md; // GitHub-Flavored Markdown (lossy)
const geml = mdToGeml(markdown).geml; // the inverse
const canonical = serialize(doc); // GEML text; parse(serialize(parse(x))) is stable
parse(src, { resolveDoc }) enables cross-document reference checking — pass a
function that returns another file's source by path (or null).
Full normative spec, history-sidecar spec, and format comparison live in the
repository. The spec is itself
written in GEML (GEML-spec.geml) and parsed clean on every test run.
MIT.
FAQs
CLI and parser for GEML, a plain-text document format where every block has an id — so an AI patches one block instead of rewriting the file; edits, reference checks and rollbacks are all per block. Ships an MCP server.
The npm package @geml/geml receives a total of 752 weekly downloads. As such, @geml/geml popularity was classified as not popular.
We found that @geml/geml demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Company News
Socket is now in the AWS Security Hub Extended plan. Adopt it through AWS, apply committed spend, and block malicious open source packages.

Research
/Security News
Popular npm packages keyv and cacheable compromised.

Security News
A misconfiguration gave three Anthropic models internet access, and one, believing it was in a simulation, shipped a credential-stealing package to PyPI.