runxmd — a runtime that turns Markdown-like .xmd documents into running systems.
Project description
XMD — a runtime that turns documents into running systems
HTML needed a browser to become useful. XMD needs a runtime to become a system. Without the runtime, an
.xmdfile is just text. With it, the document becomes the system — documentation, configuration, workflow, and memory in one file that both humans and AI agents can read, write, and run.
What is XMD?
XMD is a tiny runtime that executes Markdown-like documents. You write a plain
.xmd file describing a goal, some state, a checklist, and a workflow — and the
runtime runs it: executes the steps, remembers state across runs, and writes the
results back into the same file.
# Project: Nightly Report
@goal
Pull yesterday's numbers and save a report.
@memory
last_run: "never"
@workflow nightly
- @http
url: https://api.example.com/metrics
- @write
path: reports/today.json
content: "{{ memory.last_run }} -> done"
@on_done
set: memory.runtime.status = "ok"
runxmd run report.xmd # runs the workflow, then updates @memory in the file
runxmd watch report.xmd # re-runs automatically whenever you edit the file
That's the whole idea: one document is the program, its config, its state, and its documentation — all at once.
What is it aimed at? (the why)
Today, a single automated task is scattered across many systems: a YAML config, a shell script, a README that explains it, a database row that remembers state, a cron entry that triggers it. They drift apart and only a developer can follow the thread.
XMD collapses them into one readable artifact. The goal is not "Markdown that runs code" — it's making the document the primary unit of computation.
And there's a specific reason that matters now: AI agents already live in documents. They read instruction files, write notes to remember things, and track tasks as Markdown — but they get nothing executable back. XMD is the missing runtime beneath all of that.
- Agents are the native user — an
.xmdfile is just structured Markdown, so an agent can author and maintain it correctly with no special training. - Humans are the adopter — you install it, point it at a file, and trust it with real work today.
- The document is the contract between them — both read, write, and run the same file, safely (see Field ownership).
If you've ever wanted a script you can read like a doc and an agent can maintain like a teammate, that's what XMD is for.
Who is this for?
- Automators / devops who are tired of bash + YAML + cron sprawl and want one legible file per task.
- AI / agent builders who want agents to own runnable, stateful documents instead of inert notes.
- Anyone who wants a lightweight, dependency-free way to describe and run small workflows that remember things between runs.
Install
Zero third-party dependencies — pure Python standard library (≥ 3.9).
git clone https://github.com/shubham10divakar/xmd.git
cd xmd
pip install -e .
Now the runxmd command is available. Or run without installing:
python -m runxmd.cli run examples/PROJECT.xmd
Quick start
Create hello.xmd:
# Hello XMD
@goal
Prove the runtime works.
@memory
name: "world"
@workflow hello
- @print
text: "hello {{ memory.name }}"
- @shell
run: echo "shell works too"
- @python
run: |
print("and so does python")
@on_done
set: memory.runtime.ran_at = "now"
Run it:
runxmd run hello.xmd
▶ workflow: hello
step 1 @print ✓
hello world
step 2 @shell ✓
shell works too
step 3 @python ✓
and so does python
· memory written back
Open hello.xmd again — the runtime added runtime.ran_at to @memory. The
document changed itself.
The .xmd format
A file is plain UTF-8 text. An optional title (# ...), then sections introduced
by @directives. Each section uses the grammar most natural to what it is:
| Section | What it is | Grammar |
|---|---|---|
@goal |
Human/agent intent | free prose |
@memory |
State that persists | key: value lines |
@tasks |
A checklist | - [ ] / - [x] |
@workflow <name> |
Ordered steps to run | - @plugin + indented key: value |
@on_done |
Hooks after the run | set: memory.runtime.x = value |
Workflow steps run top to bottom. A key: | line starts a multi-line block (handy
for code).
Plugins (what steps can do)
A step is - @<plugin> plus params. Built in:
| Plugin | Does | Key params |
|---|---|---|
@print |
Echo text (after substitution) | text |
@shell |
Run a shell command | run |
@python @node @ruby @bash |
Run inline code in that language | run (block) |
@http |
HTTP request | url, method, body, content_type |
@write |
Write a file (creates dirs) | path, content |
@read |
Read a file into output | path |
@llm |
Ask an LLM (Anthropic; key from ANTHROPIC_API_KEY) |
prompt, model, max_tokens |
Any language, no bundling. Language plugins just hand your code to the interpreter already on your machine. If it's missing, the step fails with a clear message and the run continues — XMD never installs anything for you.
- @ruby
run: puts "only runs if ruby is installed"
step 1 @ruby ✗ (exit 127)
'ruby' not found on this machine — install it to run @ruby steps, or skip this step.
Memory — state that survives
@memory is what makes a document a system instead of a script. Three powers:
- Read-in — loaded into a live store when the run starts.
- Substitution —
{{ memory.key }}anywhere in a step is replaced with the value before it runs. - Write-back — changes are written back into the file, so the next run remembers.
Field ownership (safe co-editing)
Because both you/an agent and the runtime write to the file, ownership is split so they can't clobber each other:
runtime.*keys belong to the runtime. Only it writes them (via@on_done).- Every other key belongs to you/the agent. The runtime reads and preserves them but will never overwrite them. A hook that tries is refused with a warning.
So {{ memory.notes }} (yours) is safe; {{ memory.runtime.status }} is the
runtime's to manage. Safe by design, not by luck.
Reacting to changes — runxmd watch
runxmd watch report.xmd # re-run on every save
runxmd watch report.xmd --interval 0.5 # poll faster
runxmd watch report.xmd --max-runs 3 # stop after 3 runs (great for CI)
watch re-runs whenever the file changes. It will not loop on its own
write-back — only your edits trigger a re-run.
Agents — let a goal drive itself
runxmd agent turns the document from a program you run into a goal that pursues
itself (the vision's Layer 7):
Read @goal → plan @tasks → execute each task → update @memory → write back
runxmd agent project.xmd # plan (if no tasks), then run linked workflows
runxmd agent project.xmd --replan # regenerate tasks from the goal
runxmd agent project.xmd --autonomous # let the LLM generate AND run steps for unlinked tasks
runxmd agent project.xmd --dry-run # show the plan without executing or writing
Two ways a task gets done:
- Explicit workflow link (safe, default): annotate a task and the agent runs
that workflow —
- [ ] write the note -> write_note. - LLM-emitted steps (
--autonomous): for a task with no link, the LLM generates the steps and the agent runs them. Opt-in, because it executes model-generated commands.
Planning uses @llm (set ANTHROPIC_API_KEY). With no key, the agent skips
planning and still runs any pre-existing workflow-linked tasks. runxmd agent is the
one command allowed to author @tasks; mechanical write-back stays restricted to
runtime.* (see field ownership above). See examples/AGENT.xmd.
Commands
runxmd run <file> [--workflow NAME] [--no-write] # execute; persist memory
runxmd watch <file> [--interval S] [--max-runs N] # re-run on change
runxmd agent <file> [--replan] [--autonomous] [--dry-run] # goal -> tasks -> run
[--model M] [--max-tokens N]
runxmd parse <file> # parsed structure as JSON
runxmd validate <file> # check it parses; list sections
runxmd --version
Design principles
- One file format. Meaning lives in
@directives, not in a zoo of extensions. - Inline-first. The document carries the code; the runtime is a thin dispatcher.
- Detect, don't install. Use what's on the machine; fail clearly when it's not.
- Stdlib only. Zero dependencies, including
@http. - The two-test rule for every feature: Could an agent write this with no examples? Does it give a human a reason to trust it with real work today?
Status & roadmap
Current: v0.0.3 — see SPEC-v0.0.3.md for the exact contract.
- ✅ Parser, executor, CLI (
run/watch/agent/parse/validate) - ✅ Plugins: shell, inline languages, http, filesystem, llm
- ✅ Memory: read / substitute / write-back, with field-ownership safety
- ✅ Reactive
runxmd watch - ✅ Agent engine (
@goal→ auto-generate@tasks→ execute → update memory) - ⏳ Declarative events (
@on_file_change,@daily,@on_commit) - ⏳ Portable
@taskabstraction (run the same intent via any language) - ⏳ Multi-agent / distributed (XOS)
This is early software with a large vision. Contributions and ideas welcome.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file runxmd-1.0.0.tar.gz.
File metadata
- Download URL: runxmd-1.0.0.tar.gz
- Upload date:
- Size: 36.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
48fb4d54d6dea21d6495714a97efea798ba1dbb3a4ba53a7464eccb25600220f
|
|
| MD5 |
2e8697fa44888f607e453853039e6b51
|
|
| BLAKE2b-256 |
4cd85ad3b6405cb1e8179996a48d5b93c79e8578c8958c35bb91582a7d3e99f7
|
File details
Details for the file runxmd-1.0.0-py3-none-any.whl.
File metadata
- Download URL: runxmd-1.0.0-py3-none-any.whl
- Upload date:
- Size: 21.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
09bf2d881bd2fcbb76ef76bed7db250efc60de7c577e03f8f1faf48dea682898
|
|
| MD5 |
3c694ce41fb42aa58367dbd2d2f8ab6d
|
|
| BLAKE2b-256 |
d5e60ac24a743500b70b2d08e2d85d3802191efadce364ce691f9f19fa1da049
|