runxmd 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- runxmd-1.0.0/LICENSE +21 -0
- runxmd-1.0.0/MANIFEST.in +6 -0
- runxmd-1.0.0/PKG-INFO +340 -0
- runxmd-1.0.0/README.md +313 -0
- runxmd-1.0.0/SPEC-v0.0.1.md +198 -0
- runxmd-1.0.0/SPEC-v0.0.2.md +166 -0
- runxmd-1.0.0/docs/README.md +14 -0
- runxmd-1.0.0/docs/architecture.md +508 -0
- runxmd-1.0.0/docs/discussion-2026-05-30.md +199 -0
- runxmd-1.0.0/docs/vision.md +481 -0
- runxmd-1.0.0/examples/AGENT.xmd +30 -0
- runxmd-1.0.0/examples/PROJECT.xmd +25 -0
- runxmd-1.0.0/pyproject.toml +43 -0
- runxmd-1.0.0/runxmd/__init__.py +7 -0
- runxmd-1.0.0/runxmd/agent.py +185 -0
- runxmd-1.0.0/runxmd/cli.py +102 -0
- runxmd-1.0.0/runxmd/executor.py +151 -0
- runxmd-1.0.0/runxmd/memory.py +22 -0
- runxmd-1.0.0/runxmd/parser.py +252 -0
- runxmd-1.0.0/runxmd/plugins/__init__.py +7 -0
- runxmd-1.0.0/runxmd/plugins/base.py +30 -0
- runxmd-1.0.0/runxmd/plugins/fs.py +45 -0
- runxmd-1.0.0/runxmd/plugins/http.py +51 -0
- runxmd-1.0.0/runxmd/plugins/lang.py +60 -0
- runxmd-1.0.0/runxmd/plugins/llm.py +78 -0
- runxmd-1.0.0/runxmd/plugins/shell.py +26 -0
- runxmd-1.0.0/runxmd.egg-info/PKG-INFO +340 -0
- runxmd-1.0.0/runxmd.egg-info/SOURCES.txt +31 -0
- runxmd-1.0.0/runxmd.egg-info/dependency_links.txt +1 -0
- runxmd-1.0.0/runxmd.egg-info/entry_points.txt +2 -0
- runxmd-1.0.0/runxmd.egg-info/top_level.txt +1 -0
- runxmd-1.0.0/setup.cfg +4 -0
- runxmd-1.0.0/setup.py +12 -0
runxmd-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Subham Divakar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
runxmd-1.0.0/MANIFEST.in
ADDED
runxmd-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: runxmd
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: runxmd — a runtime that turns Markdown-like .xmd documents into running systems.
|
|
5
|
+
Author-email: Subham Divakar <shubham.divakar@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/shubham10divakar/xmd
|
|
8
|
+
Project-URL: Repository, https://github.com/shubham10divakar/xmd
|
|
9
|
+
Project-URL: Issues, https://github.com/shubham10divakar/xmd/issues
|
|
10
|
+
Keywords: xmd,runtime,documents,agents,markdown,workflow,automation
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Environment :: Console
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Build Tools
|
|
22
|
+
Classifier: Topic :: Utilities
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
# XMD — a runtime that turns documents into running systems
|
|
29
|
+
|
|
30
|
+
> **HTML needed a browser to become useful. XMD needs a runtime to become a system.**
|
|
31
|
+
> Without the runtime, an `.xmd` file is just text. With it, the **document becomes
|
|
32
|
+
> the system** — documentation, configuration, workflow, and memory in one file
|
|
33
|
+
> that both **humans and AI agents** can read, write, and run.
|
|
34
|
+
|
|
35
|
+
[](./SPEC-v0.0.3.md)
|
|
36
|
+
[](#)
|
|
37
|
+
[](#)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## What is XMD?
|
|
42
|
+
|
|
43
|
+
XMD is a tiny runtime that **executes Markdown-like documents.** You write a plain
|
|
44
|
+
`.xmd` file describing a goal, some state, a checklist, and a workflow — and the
|
|
45
|
+
runtime *runs* it: executes the steps, remembers state across runs, and writes the
|
|
46
|
+
results back into the same file.
|
|
47
|
+
|
|
48
|
+
```text
|
|
49
|
+
# Project: Nightly Report
|
|
50
|
+
|
|
51
|
+
@goal
|
|
52
|
+
Pull yesterday's numbers and save a report.
|
|
53
|
+
|
|
54
|
+
@memory
|
|
55
|
+
last_run: "never"
|
|
56
|
+
|
|
57
|
+
@workflow nightly
|
|
58
|
+
- @http
|
|
59
|
+
url: https://api.example.com/metrics
|
|
60
|
+
- @write
|
|
61
|
+
path: reports/today.json
|
|
62
|
+
content: "{{ memory.last_run }} -> done"
|
|
63
|
+
|
|
64
|
+
@on_done
|
|
65
|
+
set: memory.runtime.status = "ok"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
runxmd run report.xmd # runs the workflow, then updates @memory in the file
|
|
70
|
+
runxmd watch report.xmd # re-runs automatically whenever you edit the file
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
That's the whole idea: **one document is the program, its config, its state, and
|
|
74
|
+
its documentation — all at once.**
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## What is it aimed at? (the why)
|
|
79
|
+
|
|
80
|
+
Today, a single automated task is scattered across many systems: a YAML config, a
|
|
81
|
+
shell script, a README that explains it, a database row that remembers state, a
|
|
82
|
+
cron entry that triggers it. They drift apart and only a developer can follow the
|
|
83
|
+
thread.
|
|
84
|
+
|
|
85
|
+
XMD collapses them into **one readable artifact.** The goal is not "Markdown that
|
|
86
|
+
runs code" — it's making the **document the primary unit of computation.**
|
|
87
|
+
|
|
88
|
+
And there's a specific reason that matters *now*: **AI agents already live in
|
|
89
|
+
documents.** They read instruction files, write notes to remember things, and
|
|
90
|
+
track tasks as Markdown — but they get nothing executable back. XMD is the missing
|
|
91
|
+
runtime beneath all of that.
|
|
92
|
+
|
|
93
|
+
- **Agents are the native user** — an `.xmd` file is just structured Markdown, so
|
|
94
|
+
an agent can author and maintain it correctly with no special training.
|
|
95
|
+
- **Humans are the adopter** — you install it, point it at a file, and trust it
|
|
96
|
+
with real work today.
|
|
97
|
+
- **The document is the contract between them** — both read, write, and run the
|
|
98
|
+
same file, safely (see [Field ownership](#memory--state-that-survives)).
|
|
99
|
+
|
|
100
|
+
If you've ever wanted a script you can *read like a doc* and an agent can *maintain
|
|
101
|
+
like a teammate*, that's what XMD is for.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Who is this for?
|
|
106
|
+
|
|
107
|
+
- **Automators / devops** who are tired of bash + YAML + cron sprawl and want one
|
|
108
|
+
legible file per task.
|
|
109
|
+
- **AI / agent builders** who want agents to own runnable, stateful documents
|
|
110
|
+
instead of inert notes.
|
|
111
|
+
- **Anyone** who wants a lightweight, dependency-free way to describe and run
|
|
112
|
+
small workflows that remember things between runs.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Install
|
|
117
|
+
|
|
118
|
+
Zero third-party dependencies — pure Python standard library (≥ 3.9).
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
git clone https://github.com/shubham10divakar/xmd.git
|
|
122
|
+
cd xmd
|
|
123
|
+
pip install -e .
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Now the `runxmd` command is available. Or run without installing:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
python -m runxmd.cli run examples/PROJECT.xmd
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## Quick start
|
|
135
|
+
|
|
136
|
+
Create `hello.xmd`:
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
# Hello XMD
|
|
140
|
+
|
|
141
|
+
@goal
|
|
142
|
+
Prove the runtime works.
|
|
143
|
+
|
|
144
|
+
@memory
|
|
145
|
+
name: "world"
|
|
146
|
+
|
|
147
|
+
@workflow hello
|
|
148
|
+
- @print
|
|
149
|
+
text: "hello {{ memory.name }}"
|
|
150
|
+
- @shell
|
|
151
|
+
run: echo "shell works too"
|
|
152
|
+
- @python
|
|
153
|
+
run: |
|
|
154
|
+
print("and so does python")
|
|
155
|
+
|
|
156
|
+
@on_done
|
|
157
|
+
set: memory.runtime.ran_at = "now"
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Run it:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
runxmd run hello.xmd
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```text
|
|
167
|
+
▶ workflow: hello
|
|
168
|
+
step 1 @print ✓
|
|
169
|
+
hello world
|
|
170
|
+
step 2 @shell ✓
|
|
171
|
+
shell works too
|
|
172
|
+
step 3 @python ✓
|
|
173
|
+
and so does python
|
|
174
|
+
|
|
175
|
+
· memory written back
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Open `hello.xmd` again — the runtime added `runtime.ran_at` to `@memory`. The
|
|
179
|
+
document changed itself.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## The `.xmd` format
|
|
184
|
+
|
|
185
|
+
A file is plain UTF-8 text. An optional title (`# ...`), then sections introduced
|
|
186
|
+
by `@directives`. Each section uses the grammar most natural to what it is:
|
|
187
|
+
|
|
188
|
+
| Section | What it is | Grammar |
|
|
189
|
+
|--------------------|-----------------------|---------|
|
|
190
|
+
| `@goal` | Human/agent intent | free prose |
|
|
191
|
+
| `@memory` | State that persists | `key: value` lines |
|
|
192
|
+
| `@tasks` | A checklist | `- [ ]` / `- [x]` |
|
|
193
|
+
| `@workflow <name>` | Ordered steps to run | `- @plugin` + indented `key: value` |
|
|
194
|
+
| `@on_done` | Hooks after the run | `set: memory.runtime.x = value` |
|
|
195
|
+
|
|
196
|
+
Workflow steps run top to bottom. A `key: |` line starts a multi-line block (handy
|
|
197
|
+
for code).
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Plugins (what steps can do)
|
|
202
|
+
|
|
203
|
+
A step is `- @<plugin>` plus params. Built in:
|
|
204
|
+
|
|
205
|
+
| Plugin | Does | Key params |
|
|
206
|
+
|-----------|------|-----------|
|
|
207
|
+
| `@print` | Echo text (after substitution) | `text` |
|
|
208
|
+
| `@shell` | Run a shell command | `run` |
|
|
209
|
+
| `@python` `@node` `@ruby` `@bash` | Run inline code in that language | `run` (block) |
|
|
210
|
+
| `@http` | HTTP request | `url`, `method`, `body`, `content_type` |
|
|
211
|
+
| `@write` | Write a file (creates dirs) | `path`, `content` |
|
|
212
|
+
| `@read` | Read a file into output | `path` |
|
|
213
|
+
| `@llm` | Ask an LLM (Anthropic; key from `ANTHROPIC_API_KEY`) | `prompt`, `model`, `max_tokens` |
|
|
214
|
+
|
|
215
|
+
**Any language, no bundling.** Language plugins just hand your code to the
|
|
216
|
+
interpreter already on your machine. If it's missing, the step fails with a clear
|
|
217
|
+
message *and the run continues* — XMD never installs anything for you.
|
|
218
|
+
|
|
219
|
+
```text
|
|
220
|
+
- @ruby
|
|
221
|
+
run: puts "only runs if ruby is installed"
|
|
222
|
+
```
|
|
223
|
+
```text
|
|
224
|
+
step 1 @ruby ✗ (exit 127)
|
|
225
|
+
'ruby' not found on this machine — install it to run @ruby steps, or skip this step.
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Memory — state that survives
|
|
231
|
+
|
|
232
|
+
`@memory` is what makes a document a *system* instead of a script. Three powers:
|
|
233
|
+
|
|
234
|
+
1. **Read-in** — loaded into a live store when the run starts.
|
|
235
|
+
2. **Substitution** — `{{ memory.key }}` anywhere in a step is replaced with the
|
|
236
|
+
value before it runs.
|
|
237
|
+
3. **Write-back** — changes are written back into the file, so the next run
|
|
238
|
+
remembers.
|
|
239
|
+
|
|
240
|
+
### Field ownership (safe co-editing)
|
|
241
|
+
|
|
242
|
+
Because both you/an agent *and* the runtime write to the file, ownership is split
|
|
243
|
+
so they can't clobber each other:
|
|
244
|
+
|
|
245
|
+
- **`runtime.*` keys belong to the runtime.** Only it writes them (via `@on_done`).
|
|
246
|
+
- **Every other key belongs to you/the agent.** The runtime reads and preserves
|
|
247
|
+
them but will **never** overwrite them. A hook that tries is refused with a
|
|
248
|
+
warning.
|
|
249
|
+
|
|
250
|
+
So `{{ memory.notes }}` (yours) is safe; `{{ memory.runtime.status }}` is the
|
|
251
|
+
runtime's to manage. Safe by design, not by luck.
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
## Reacting to changes — `runxmd watch`
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
runxmd watch report.xmd # re-run on every save
|
|
259
|
+
runxmd watch report.xmd --interval 0.5 # poll faster
|
|
260
|
+
runxmd watch report.xmd --max-runs 3 # stop after 3 runs (great for CI)
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
`watch` re-runs whenever the file changes. It will **not** loop on its own
|
|
264
|
+
write-back — only your edits trigger a re-run.
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## Agents — let a goal drive itself
|
|
269
|
+
|
|
270
|
+
`runxmd agent` turns the document from *a program you run* into *a goal that pursues
|
|
271
|
+
itself* (the vision's Layer 7):
|
|
272
|
+
|
|
273
|
+
```text
|
|
274
|
+
Read @goal → plan @tasks → execute each task → update @memory → write back
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
runxmd agent project.xmd # plan (if no tasks), then run linked workflows
|
|
279
|
+
runxmd agent project.xmd --replan # regenerate tasks from the goal
|
|
280
|
+
runxmd agent project.xmd --autonomous # let the LLM generate AND run steps for unlinked tasks
|
|
281
|
+
runxmd agent project.xmd --dry-run # show the plan without executing or writing
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
**Two ways a task gets done:**
|
|
285
|
+
1. **Explicit workflow link (safe, default):** annotate a task and the agent runs
|
|
286
|
+
that workflow — `- [ ] write the note -> write_note`.
|
|
287
|
+
2. **LLM-emitted steps (`--autonomous`):** for a task with no link, the LLM
|
|
288
|
+
generates the steps and the agent runs them. Opt-in, because it executes
|
|
289
|
+
model-generated commands.
|
|
290
|
+
|
|
291
|
+
Planning uses `@llm` (set `ANTHROPIC_API_KEY`). With no key, the agent skips
|
|
292
|
+
planning and still runs any pre-existing workflow-linked tasks. `runxmd agent` is the
|
|
293
|
+
one command allowed to author `@tasks`; mechanical write-back stays restricted to
|
|
294
|
+
`runtime.*` (see field ownership above). See [`examples/AGENT.xmd`](./examples/AGENT.xmd).
|
|
295
|
+
|
|
296
|
+
## Commands
|
|
297
|
+
|
|
298
|
+
```bash
|
|
299
|
+
runxmd run <file> [--workflow NAME] [--no-write] # execute; persist memory
|
|
300
|
+
runxmd watch <file> [--interval S] [--max-runs N] # re-run on change
|
|
301
|
+
runxmd agent <file> [--replan] [--autonomous] [--dry-run] # goal -> tasks -> run
|
|
302
|
+
[--model M] [--max-tokens N]
|
|
303
|
+
runxmd parse <file> # parsed structure as JSON
|
|
304
|
+
runxmd validate <file> # check it parses; list sections
|
|
305
|
+
runxmd --version
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Design principles
|
|
311
|
+
|
|
312
|
+
- **One file format.** Meaning lives in `@directives`, not in a zoo of extensions.
|
|
313
|
+
- **Inline-first.** The document carries the code; the runtime is a thin dispatcher.
|
|
314
|
+
- **Detect, don't install.** Use what's on the machine; fail clearly when it's not.
|
|
315
|
+
- **Stdlib only.** Zero dependencies, including `@http`.
|
|
316
|
+
- **The two-test rule for every feature:** *Could an agent write this with no
|
|
317
|
+
examples? Does it give a human a reason to trust it with real work today?*
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## Status & roadmap
|
|
322
|
+
|
|
323
|
+
**Current: v0.0.3** — see [`SPEC-v0.0.3.md`](./SPEC-v0.0.3.md) for the exact contract.
|
|
324
|
+
|
|
325
|
+
- ✅ Parser, executor, CLI (`run` / `watch` / `agent` / `parse` / `validate`)
|
|
326
|
+
- ✅ Plugins: shell, inline languages, http, filesystem, llm
|
|
327
|
+
- ✅ Memory: read / substitute / write-back, with field-ownership safety
|
|
328
|
+
- ✅ Reactive `runxmd watch`
|
|
329
|
+
- ✅ Agent engine (`@goal` → auto-generate `@tasks` → execute → update memory)
|
|
330
|
+
- ⏳ Declarative events (`@on_file_change`, `@daily`, `@on_commit`)
|
|
331
|
+
- ⏳ Portable `@task` abstraction (run the same intent via any language)
|
|
332
|
+
- ⏳ Multi-agent / distributed (XOS)
|
|
333
|
+
|
|
334
|
+
This is early software with a large vision. Contributions and ideas welcome.
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## License
|
|
339
|
+
|
|
340
|
+
MIT — see [LICENSE](./LICENSE).
|
runxmd-1.0.0/README.md
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
# XMD — a runtime that turns documents into running systems
|
|
2
|
+
|
|
3
|
+
> **HTML needed a browser to become useful. XMD needs a runtime to become a system.**
|
|
4
|
+
> Without the runtime, an `.xmd` file is just text. With it, the **document becomes
|
|
5
|
+
> the system** — documentation, configuration, workflow, and memory in one file
|
|
6
|
+
> that both **humans and AI agents** can read, write, and run.
|
|
7
|
+
|
|
8
|
+
[](./SPEC-v0.0.3.md)
|
|
9
|
+
[](#)
|
|
10
|
+
[](#)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## What is XMD?
|
|
15
|
+
|
|
16
|
+
XMD is a tiny runtime that **executes Markdown-like documents.** You write a plain
|
|
17
|
+
`.xmd` file describing a goal, some state, a checklist, and a workflow — and the
|
|
18
|
+
runtime *runs* it: executes the steps, remembers state across runs, and writes the
|
|
19
|
+
results back into the same file.
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
# Project: Nightly Report
|
|
23
|
+
|
|
24
|
+
@goal
|
|
25
|
+
Pull yesterday's numbers and save a report.
|
|
26
|
+
|
|
27
|
+
@memory
|
|
28
|
+
last_run: "never"
|
|
29
|
+
|
|
30
|
+
@workflow nightly
|
|
31
|
+
- @http
|
|
32
|
+
url: https://api.example.com/metrics
|
|
33
|
+
- @write
|
|
34
|
+
path: reports/today.json
|
|
35
|
+
content: "{{ memory.last_run }} -> done"
|
|
36
|
+
|
|
37
|
+
@on_done
|
|
38
|
+
set: memory.runtime.status = "ok"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
runxmd run report.xmd # runs the workflow, then updates @memory in the file
|
|
43
|
+
runxmd watch report.xmd # re-runs automatically whenever you edit the file
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
That's the whole idea: **one document is the program, its config, its state, and
|
|
47
|
+
its documentation — all at once.**
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## What is it aimed at? (the why)
|
|
52
|
+
|
|
53
|
+
Today, a single automated task is scattered across many systems: a YAML config, a
|
|
54
|
+
shell script, a README that explains it, a database row that remembers state, a
|
|
55
|
+
cron entry that triggers it. They drift apart and only a developer can follow the
|
|
56
|
+
thread.
|
|
57
|
+
|
|
58
|
+
XMD collapses them into **one readable artifact.** The goal is not "Markdown that
|
|
59
|
+
runs code" — it's making the **document the primary unit of computation.**
|
|
60
|
+
|
|
61
|
+
And there's a specific reason that matters *now*: **AI agents already live in
|
|
62
|
+
documents.** They read instruction files, write notes to remember things, and
|
|
63
|
+
track tasks as Markdown — but they get nothing executable back. XMD is the missing
|
|
64
|
+
runtime beneath all of that.
|
|
65
|
+
|
|
66
|
+
- **Agents are the native user** — an `.xmd` file is just structured Markdown, so
|
|
67
|
+
an agent can author and maintain it correctly with no special training.
|
|
68
|
+
- **Humans are the adopter** — you install it, point it at a file, and trust it
|
|
69
|
+
with real work today.
|
|
70
|
+
- **The document is the contract between them** — both read, write, and run the
|
|
71
|
+
same file, safely (see [Field ownership](#memory--state-that-survives)).
|
|
72
|
+
|
|
73
|
+
If you've ever wanted a script you can *read like a doc* and an agent can *maintain
|
|
74
|
+
like a teammate*, that's what XMD is for.
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Who is this for?
|
|
79
|
+
|
|
80
|
+
- **Automators / devops** who are tired of bash + YAML + cron sprawl and want one
|
|
81
|
+
legible file per task.
|
|
82
|
+
- **AI / agent builders** who want agents to own runnable, stateful documents
|
|
83
|
+
instead of inert notes.
|
|
84
|
+
- **Anyone** who wants a lightweight, dependency-free way to describe and run
|
|
85
|
+
small workflows that remember things between runs.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Install
|
|
90
|
+
|
|
91
|
+
Zero third-party dependencies — pure Python standard library (≥ 3.9).
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
git clone https://github.com/shubham10divakar/xmd.git
|
|
95
|
+
cd xmd
|
|
96
|
+
pip install -e .
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Now the `runxmd` command is available. Or run without installing:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
python -m runxmd.cli run examples/PROJECT.xmd
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Quick start
|
|
108
|
+
|
|
109
|
+
Create `hello.xmd`:
|
|
110
|
+
|
|
111
|
+
```text
|
|
112
|
+
# Hello XMD
|
|
113
|
+
|
|
114
|
+
@goal
|
|
115
|
+
Prove the runtime works.
|
|
116
|
+
|
|
117
|
+
@memory
|
|
118
|
+
name: "world"
|
|
119
|
+
|
|
120
|
+
@workflow hello
|
|
121
|
+
- @print
|
|
122
|
+
text: "hello {{ memory.name }}"
|
|
123
|
+
- @shell
|
|
124
|
+
run: echo "shell works too"
|
|
125
|
+
- @python
|
|
126
|
+
run: |
|
|
127
|
+
print("and so does python")
|
|
128
|
+
|
|
129
|
+
@on_done
|
|
130
|
+
set: memory.runtime.ran_at = "now"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Run it:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
runxmd run hello.xmd
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
```text
|
|
140
|
+
▶ workflow: hello
|
|
141
|
+
step 1 @print ✓
|
|
142
|
+
hello world
|
|
143
|
+
step 2 @shell ✓
|
|
144
|
+
shell works too
|
|
145
|
+
step 3 @python ✓
|
|
146
|
+
and so does python
|
|
147
|
+
|
|
148
|
+
· memory written back
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Open `hello.xmd` again — the runtime added `runtime.ran_at` to `@memory`. The
|
|
152
|
+
document changed itself.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
## The `.xmd` format
|
|
157
|
+
|
|
158
|
+
A file is plain UTF-8 text. An optional title (`# ...`), then sections introduced
|
|
159
|
+
by `@directives`. Each section uses the grammar most natural to what it is:
|
|
160
|
+
|
|
161
|
+
| Section | What it is | Grammar |
|
|
162
|
+
|--------------------|-----------------------|---------|
|
|
163
|
+
| `@goal` | Human/agent intent | free prose |
|
|
164
|
+
| `@memory` | State that persists | `key: value` lines |
|
|
165
|
+
| `@tasks` | A checklist | `- [ ]` / `- [x]` |
|
|
166
|
+
| `@workflow <name>` | Ordered steps to run | `- @plugin` + indented `key: value` |
|
|
167
|
+
| `@on_done` | Hooks after the run | `set: memory.runtime.x = value` |
|
|
168
|
+
|
|
169
|
+
Workflow steps run top to bottom. A `key: |` line starts a multi-line block (handy
|
|
170
|
+
for code).
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Plugins (what steps can do)
|
|
175
|
+
|
|
176
|
+
A step is `- @<plugin>` plus params. Built in:
|
|
177
|
+
|
|
178
|
+
| Plugin | Does | Key params |
|
|
179
|
+
|-----------|------|-----------|
|
|
180
|
+
| `@print` | Echo text (after substitution) | `text` |
|
|
181
|
+
| `@shell` | Run a shell command | `run` |
|
|
182
|
+
| `@python` `@node` `@ruby` `@bash` | Run inline code in that language | `run` (block) |
|
|
183
|
+
| `@http` | HTTP request | `url`, `method`, `body`, `content_type` |
|
|
184
|
+
| `@write` | Write a file (creates dirs) | `path`, `content` |
|
|
185
|
+
| `@read` | Read a file into output | `path` |
|
|
186
|
+
| `@llm` | Ask an LLM (Anthropic; key from `ANTHROPIC_API_KEY`) | `prompt`, `model`, `max_tokens` |
|
|
187
|
+
|
|
188
|
+
**Any language, no bundling.** Language plugins just hand your code to the
|
|
189
|
+
interpreter already on your machine. If it's missing, the step fails with a clear
|
|
190
|
+
message *and the run continues* — XMD never installs anything for you.
|
|
191
|
+
|
|
192
|
+
```text
|
|
193
|
+
- @ruby
|
|
194
|
+
run: puts "only runs if ruby is installed"
|
|
195
|
+
```
|
|
196
|
+
```text
|
|
197
|
+
step 1 @ruby ✗ (exit 127)
|
|
198
|
+
'ruby' not found on this machine — install it to run @ruby steps, or skip this step.
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Memory — state that survives
|
|
204
|
+
|
|
205
|
+
`@memory` is what makes a document a *system* instead of a script. Three powers:
|
|
206
|
+
|
|
207
|
+
1. **Read-in** — loaded into a live store when the run starts.
|
|
208
|
+
2. **Substitution** — `{{ memory.key }}` anywhere in a step is replaced with the
|
|
209
|
+
value before it runs.
|
|
210
|
+
3. **Write-back** — changes are written back into the file, so the next run
|
|
211
|
+
remembers.
|
|
212
|
+
|
|
213
|
+
### Field ownership (safe co-editing)
|
|
214
|
+
|
|
215
|
+
Because both you/an agent *and* the runtime write to the file, ownership is split
|
|
216
|
+
so they can't clobber each other:
|
|
217
|
+
|
|
218
|
+
- **`runtime.*` keys belong to the runtime.** Only it writes them (via `@on_done`).
|
|
219
|
+
- **Every other key belongs to you/the agent.** The runtime reads and preserves
|
|
220
|
+
them but will **never** overwrite them. A hook that tries is refused with a
|
|
221
|
+
warning.
|
|
222
|
+
|
|
223
|
+
So `{{ memory.notes }}` (yours) is safe; `{{ memory.runtime.status }}` is the
|
|
224
|
+
runtime's to manage. Safe by design, not by luck.
|
|
225
|
+
|
|
226
|
+
---
|
|
227
|
+
|
|
228
|
+
## Reacting to changes — `runxmd watch`
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
runxmd watch report.xmd # re-run on every save
|
|
232
|
+
runxmd watch report.xmd --interval 0.5 # poll faster
|
|
233
|
+
runxmd watch report.xmd --max-runs 3 # stop after 3 runs (great for CI)
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
`watch` re-runs whenever the file changes. It will **not** loop on its own
|
|
237
|
+
write-back — only your edits trigger a re-run.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Agents — let a goal drive itself
|
|
242
|
+
|
|
243
|
+
`runxmd agent` turns the document from *a program you run* into *a goal that pursues
|
|
244
|
+
itself* (the vision's Layer 7):
|
|
245
|
+
|
|
246
|
+
```text
|
|
247
|
+
Read @goal → plan @tasks → execute each task → update @memory → write back
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
runxmd agent project.xmd # plan (if no tasks), then run linked workflows
|
|
252
|
+
runxmd agent project.xmd --replan # regenerate tasks from the goal
|
|
253
|
+
runxmd agent project.xmd --autonomous # let the LLM generate AND run steps for unlinked tasks
|
|
254
|
+
runxmd agent project.xmd --dry-run # show the plan without executing or writing
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**Two ways a task gets done:**
|
|
258
|
+
1. **Explicit workflow link (safe, default):** annotate a task and the agent runs
|
|
259
|
+
that workflow — `- [ ] write the note -> write_note`.
|
|
260
|
+
2. **LLM-emitted steps (`--autonomous`):** for a task with no link, the LLM
|
|
261
|
+
generates the steps and the agent runs them. Opt-in, because it executes
|
|
262
|
+
model-generated commands.
|
|
263
|
+
|
|
264
|
+
Planning uses `@llm` (set `ANTHROPIC_API_KEY`). With no key, the agent skips
|
|
265
|
+
planning and still runs any pre-existing workflow-linked tasks. `runxmd agent` is the
|
|
266
|
+
one command allowed to author `@tasks`; mechanical write-back stays restricted to
|
|
267
|
+
`runtime.*` (see field ownership above). See [`examples/AGENT.xmd`](./examples/AGENT.xmd).
|
|
268
|
+
|
|
269
|
+
## Commands
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
runxmd run <file> [--workflow NAME] [--no-write] # execute; persist memory
|
|
273
|
+
runxmd watch <file> [--interval S] [--max-runs N] # re-run on change
|
|
274
|
+
runxmd agent <file> [--replan] [--autonomous] [--dry-run] # goal -> tasks -> run
|
|
275
|
+
[--model M] [--max-tokens N]
|
|
276
|
+
runxmd parse <file> # parsed structure as JSON
|
|
277
|
+
runxmd validate <file> # check it parses; list sections
|
|
278
|
+
runxmd --version
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
## Design principles
|
|
284
|
+
|
|
285
|
+
- **One file format.** Meaning lives in `@directives`, not in a zoo of extensions.
|
|
286
|
+
- **Inline-first.** The document carries the code; the runtime is a thin dispatcher.
|
|
287
|
+
- **Detect, don't install.** Use what's on the machine; fail clearly when it's not.
|
|
288
|
+
- **Stdlib only.** Zero dependencies, including `@http`.
|
|
289
|
+
- **The two-test rule for every feature:** *Could an agent write this with no
|
|
290
|
+
examples? Does it give a human a reason to trust it with real work today?*
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Status & roadmap
|
|
295
|
+
|
|
296
|
+
**Current: v0.0.3** — see [`SPEC-v0.0.3.md`](./SPEC-v0.0.3.md) for the exact contract.
|
|
297
|
+
|
|
298
|
+
- ✅ Parser, executor, CLI (`run` / `watch` / `agent` / `parse` / `validate`)
|
|
299
|
+
- ✅ Plugins: shell, inline languages, http, filesystem, llm
|
|
300
|
+
- ✅ Memory: read / substitute / write-back, with field-ownership safety
|
|
301
|
+
- ✅ Reactive `runxmd watch`
|
|
302
|
+
- ✅ Agent engine (`@goal` → auto-generate `@tasks` → execute → update memory)
|
|
303
|
+
- ⏳ Declarative events (`@on_file_change`, `@daily`, `@on_commit`)
|
|
304
|
+
- ⏳ Portable `@task` abstraction (run the same intent via any language)
|
|
305
|
+
- ⏳ Multi-agent / distributed (XOS)
|
|
306
|
+
|
|
307
|
+
This is early software with a large vision. Contributions and ideas welcome.
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## License
|
|
312
|
+
|
|
313
|
+
MIT — see [LICENSE](./LICENSE).
|