mdt
v0.9.8 markdown templates for humans and agents

Write it once.
Sync it everywhere.

mdt keeps the same words in your README, your doc comments, and your docs site. Write a block once with {@name}, drop {=name} wherever it belongs, and let mdt update do the copying.

Start in two minutes →
.templates/install.t.mdprovider
<!-- {@install} -->
<!-- {/install} -->

Edit the provider. Watch the copies drift.

readme.mdconsumer
<!-- {=install} -->

<!-- {/install} -->
src/lib.rsconsumer
//! <!-- {=install|trim|linePrefix:"//! ":true} -->

//! <!-- {/install} -->
docs/setup.mdconsumer
<!-- {=install|trim|codeBlock:"text"} -->

<!-- {/install} -->

$ mdt checkCheck passed: all consumer blocks are up to date.

The whole language

Four tags.
That's it.

mdt tags are HTML comments, so they vanish when markdown renders. No build step in your docs, no new file format, nothing to learn past this row of cards.

{@name}

Provider

Defines a block once, in a *.t.md template file.

{=name}

Consumer

Marks a spot that should hold a copy. Markdown or code comments.

{~name:""}

Inline

A one-line value, like a version number in the middle of a sentence.

{/name}

Close

Ends any block. Everything between the tags belongs to mdt.

Where it works

Docs that live
in your code.

Consumers work inside source comments, so your doc comments, your README, and your docs site can all quote the same paragraph. A transformer adds the comment marker to every line.

//! <!-- {=clientDocs|trim|linePrefix:"//! ":true} -->
//! A fast HTTP client.
//!
//! Supports async and blocking modes.
//! <!-- {/clientDocs} -->
pub struct Client;

Also JavaScript, Java, Kotlin, Swift, C, C++, and C#, plus any extension you add. Source file support →

Small, sharp tools

More than
copy and paste.

Pull values from your manifests, reshape a block for each place it lands, and fail the build the moment two copies disagree.

Data in, docs out

Point mdt at package.json, Cargo.toml, or any data file. The version in your docs is the version you ship.

# mdt.toml
[data]
pkg = "package.json"

<!-- {@install} -->
npm i my-lib@{{ pkg.version }}
<!-- {/install} -->

Transformers

One block, many shapes. Trim it, fence it, indent it, prefix every line, or replace text on the way out.

<!-- {=install|trim
  |codeBlock:"sh"} -->
```sh
npm i my-lib@0.9.7
```
<!-- {/install} -->

Drift fails CI

mdt check exits non-zero when any copy is stale and tells you exactly which block, in which file. Add one line to your workflow.

# .github/workflows/ci.yml
- run: npx -y @m-d-t/cli check

Check failed.
  block `install` at readme.md:3:1
Run `mdt update`.

Built for agents

Your agent writes it once.
mdt puts it everywhere.

Agents are great at editing docs and terrible at remembering the four other places the same sentence lives. mdt gives them one place to write and a command that proves nothing drifted.

  • An agent skill built into the binary: mdt skill --install .claude/skills
  • An MCP server with tools to list, preview, check, and update blocks
  • A language server for go-to-provider, hovers, and diagnostics in your editor
$ mdt check
Check failed.
  stale consumers: 2

Stale consumers:
  block `install` at readme.md:3:1
  block `install` at src/lib.rs:1:5

$ mdt update
Updated 2 block(s) in 2 file(s).

$ mdt check
Check passed: all consumer blocks are up to date.

Get started

Stop updating docs
in five places.

Read the docs →