marxml
v0.1.2
Published
Fast markdown + XML query and mutation. Rust core with native Node bindings.
Maintainers
Readme
[!WARNING] Pre-1.0 · under active development.
marxmlis on0.X.Xand APIs, types, and selector grammar may still shift between minor versions. Not recommended for production yet — pin a specific version and read the changelog before bumping. Licensed MIT/Apache-2.0 (so it's always at your own risk anyway).
marxml lets you read and write XML-shaped tags embedded in markdown documents. Find them with CSS-style selectors, change them surgically, validate they're well-formed — without rewriting the prose around them. Native speed in Node via prebuilt binaries.
Features
- Find tags with selectors.
task[id^="4."],phase > task,note:not([archived])— the CSS subset you already know. - Edit surgically. Change an attribute or replace inner content. Every byte you didn't touch comes back identical: prose, whitespace, comments, ordering.
- Validate the shape. Required attributes, enum/regex constraints, child rules — declarative schema, structured errors with line numbers.
- Native speed. Prebuilt
.nodebinaries for macOS (arm64, x64) and Linux (x64-gnu, x64-musl, arm64-gnu). No build step. Windows support is pending — track the repo.
Why?
marxml started as plumbing for a workflow agent — plan and phase-planning documents (think GSD-style trackers) stored as markdown with task state inside XML tags. Agents needed to update those tags reliably: flip a status, append a note, mark a child done — without rewriting the surrounding prose or hallucinating new structure.
The general lesson: LLMs drift at the prose level but stay disciplined inside known XML tags. Scope the model's output to a tag, and the read/write boundary becomes deterministic again. marxml is the read/write layer for that boundary — selectors to find tags, byte-preserving mutation to change them, schema to verify what came back.
Install
pnpm add marxml
# or: npm install marxml
# or: yarn add marxml
# or: bun add marxmlNode >= 18. The right platform binary is pulled in as an optional dependency.
Quickstart
import { parse } from 'marxml'
const src = `
<phase id="1" status="todo">
<task id="1.1" status="todo">do this</task>
<task id="1.2" status="done">finished</task>
</phase>
`
const doc = parse(src)
for (const task of doc.select('task[status="todo"]')) {
console.log(task.attrs.id) // "1.1"
}
const updated = doc.updateAttrs('task[status="todo"]', [
{ name: 'status', value: 'done' },
])Docs
Full documentation lives in the repository:
- Node reference —
MarkdownDocshape, distribution, regex behavior. - DSL reference — selectors, validation schema, cookbook recipes, formal grammar.
- Architecture — tokenizer, mutation strategy, two-track API.
There's also a Rust crate of the same name — same API surface, shared source of truth.
License
Dual-licensed under either MIT or Apache 2.0 at your option.
