executable.md treats markdown documents as executable workflows. A document can expand markdown components, execute annotated code blocks, and evaluate in-process Effection operations while staying a valid, readable markdown file in any viewer.
The command-line tool is called xmd (eXecutable MarkDown).
This project is an implementation of the draft spec in specs/executable-mdx-spec.md.
- Expands JSX-style component invocations like
<Greeting name="world" />from markdown files. - Executes fenced code blocks marked with
execoreval. - Optionally journals component imports and command results to a diagnostic JSONL trace.
- Shares bindings across
evalblocks inside a component. - Supports long-lived background processes with
daemonand provider-style components for LLM-backed workflows.
README.md
---
title: My Project
---
# {meta.title}
<Greeting name="world" />
```bash exec
ls ./src
```components/Greeting.md
---
emoji: Hello
inputs:
name:
type: string
required: true
---
{meta.emoji}, {props.name}!Rendered output:
# My Project
Hello, world!
main.ts
utils.tsInstall the xmd binary (macOS/Linux):
curl -fsSL https://executable.md/install.sh | shPrebuilt binaries for each platform are published on the releases page. The binary is self-contained — no Node or Deno required to run it.
- Size: binaries are self-contained and fairly large (roughly 90–125 MB depending on platform) — the embedded Deno runtime dominates. Trimming this further is tracked in #66.
- Alpine / musl: no musl build is published. On Alpine, run via
denoor use the glibc binary undergcompat. - macOS: binaries are currently unsigned. The install script clears the Gatekeeper quarantine automatically; if you download a binary manually, run
xattr -d com.apple.quarantine ./xmdbefore first use. Signing/notarization is tracked in #68. - Windows: the binary runs, but
execblocks that invoke shell commands need a shell (e.g. Git Bash or WSL) onPATH. Provider andevaldocuments work without one.
xmd run core/examples/hello-world.mdWrite a diagnostic trace for one run:
xmd run core/examples/hello-world.md --journal .xmd/events.jsonlUseful flags:
--journal,-j- write current-run journal entries to a new JSONL file for debugging. The path must not exist and is never replayed.--verbose,-V- print durable journal entries to stderr while running.--component-dir- add component search directories. Defaults tocomponentsand..
executable.md treats the root document like a component:
- Frontmatter becomes
meta. - JSX tags with capitalized names become component invocations.
<Content />acts as a slot for child content.- Text segments support
{meta.key}and{props.key}interpolation. - Markdown is healed at execution boundaries with
remendso formatting does not bleed across components or executable blocks.
The first word in a fence info string is the language. The remaining words form a modifier chain. Standard renderers only read the first word, so the modifiers stay invisible everywhere else.
```bash silent timeout=30s exec
git diff --stat
```Built-in modifiers:
exec- run the block as a subprocess and render stdout.eval- run JavaScript/TypeScript in-process as an Effection operation.silent- execute but suppress rendered output.persist- keep resources created by an eval block alive for the component lifetime.timeout=30s- cancel a long-running block.daemon- start a long-running subprocess tied to the component scope.
LLM sampling is not a fence modifier — it happens through the <Sample> component installed by provider middleware (see Provider components).
eval blocks run in a shared VM context and binding environment for the current component.
```ts eval
const port = yield* findFreePort();
const baseUrl = `http://127.0.0.1:${port}`;
```
```bash daemon exec
./server --port {port}
```Highlights:
- Top-level bindings are exported automatically for later blocks.
- Bare
{name}interpolation inside executable block content reads from eval bindings. output("...")lets an eval block render text into the document.renderChildren()andrender(markdown)let eval blocks render nested content intentionally.
The repo includes reusable markdown components (in core/components/) that demonstrate the provider pattern:
AnthropicProvider.mdOllamaProvider.mdLlamafileProvider.mdSample.mdInstruction.md
These components combine eval, daemon, readiness checks, and Sample middleware so a document can talk to a cloud or local model server without custom runtime wiring.
core/examples/hello-world.md shows the pattern combining a cloud model (Claude) and a local model (Ollama). Provider docs currently need the built-in components on the search path:
xmd run core/examples/hello-world.md --component-dir core/components--journal writes internal workflow journal entries for troubleshooting. A trace can include component source, command output, evaluated values, and errors, so treat it as potentially sensitive data.
Each invocation requires a new path. If the path already exists, xmd exits without executing the document or modifying the file. An interrupted process may leave a partial trace; the CLI preserves it for inspection and does not use it as recovery input.
core/src/run-document.ts- document entrypoint and durable import pipeline.core/src/scanner.ts- boundary scanner for components and executable fences.core/src/- component expansion, eval/exec handling, modifiers, and sampling helpers.core/components/- reusable provider and demo components.cli/src/cli.ts- thexmdcommand.core/examples/hello-world.md- end-to-end example.specs/executable-mdx-spec.md- design and behavior spec.
This is a Deno-first project. Run the tool from source and the checks with deno:
deno task xmd run core/examples/hello-world.md # run a document from source
deno task build # compile the standalone xmd binary
deno task lint # oxlint + oxfmt
deno check core/mod.ts # typecheck
deno task test # run the test suiteThis is an early, first public release and a draft spec, optimized for experimentation around executable markdown workflows, Effection-based evaluation, and provider-driven AI documents. Feedback, issues, and contributions are very welcome — please open an issue.