[!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.
Features
- Find tags with selectors.
task[id^="4."],phase > task,note:not([archived])— the CSS subset you already know. Compiled once viaSelector::parse, reused many. - Edit surgically. Mutators take
&strand returnStringby splicing into the source. 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.
- No
unsafe. Workspace-wideunsafe_code = "forbid". Hand-rolled state-machine tokenizer, stack-based tree assembler,thiserrorerror types.
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
MSRV: 1.75.
Quickstart
use ;
let src = r#"
<phase id="1" status="todo">
<task id="1.1" status="todo">do this</task>
<task id="1.2" status="done">finished</task>
</phase>
"#;
let doc = parse?;
let sel = parse?;
for task in doc.select
let updated = doc.update;
println!;
# Ok::
Docs
API reference on docs.rs. Long-form documentation lives in the repository:
- Rust reference — API surface, design notes, lints, MSRV.
- DSL reference — selectors, validation schema, cookbook recipes, formal grammar.
- Architecture — tokenizer state machine, mutation strategy, two-track API.
There's also an npm package of the same name — same API surface via napi-rs bindings, prebuilt binaries per platform.
License
Dual-licensed under either MIT or Apache 2.0 at your option.