# Runme: making the code blocks already in your Markdown actually runnable

> A Go CLI that turns named fenced code blocks in README files and docs into executable steps, plus what the repository reveals about the two generations of its runner.

**runmedev/runme** — DevOps Notebooks Built with Markdown

- Repository: https://github.com/runmedev/runme
- Website: https://runme.dev
- Stars: 2,199 · Forks: 91
- Language: Go
- License: Apache-2.0
- Published: 2026-10-08 · Updated: 2026-10-08 · Language: en
- Canonical page: https://hysenlabs.com/projects/runmedev-runme

## Three install paths that do not agree on what a version is

The README offers Homebrew first, then npm, then Go, and each one resolves to something different in practice:

```bash
$ brew install runme
```

```bash
$ npm install -g runme
```

```bash
$ go install github.com/runmedev/runme/v3@main
```

The third line is the interesting one. It asks for `@main`, not for a version tag, so what `go install` puts on your machine is whatever the tip of the default branch happens to be at that moment. Meanwhile the release feed is not built from GitHub tags at all. The three most recent releases carry no tag name in their metadata, and their bodies are download manifests rather than notes, pointing at archives on `downloads.runme.dev` such as `runme_darwin_arm64.tar.gz` under a version directory of 3.17.5. So there are two independent notions of a version here: a SemVer that lives in a downloads path, and a moving branch tip. Both are legitimate ways to run a tool, but they are not interchangeable, and a lockfile built from one says nothing about the other.

The README does note that binaries for other platforms can be downloaded from the releases page, which is the most predictable of the four routes if you want a fixed version. It also says, in the GitHub Actions badge at the top, nothing about release stability at all, so the CI signal you get is whether the build passes rather than whether a tagged artifact exists.

## Named cells are what separate a runbook from a code sample

Runme's claim is that it runs the fenced blocks that already exist in your Markdown, and that the block format is the mechanism. A plain fence is runnable but anonymous. A named one is addressable, which is what makes `runme run` possible:

```bash
$ runme run update-brew
```

The name comes from an attribute on the fence itself, which the README writes as `sh` with a `name` key. A file with two such blocks and no other convention is enough to demonstrate the whole idea, and the README keeps the example deliberately trivial by naming a cell after `brew update`.

What this buys you is a stable handle. Documentation tooling that rewrites a README can keep the cell name while changing the command inside it, and a script can invoke a documentation step by name without parsing prose. The project leans into this more than the README admits: the `command/` directory in the tree is where CLI verbs live, and there is a separate `document/` package plus `project/` and `notebook/` packages, which suggests the cell model is treated as a document concern rather than a text-parsing trick bolted onto the CLI.

The related claim in the README is about languages: Shell, Bash, Python, Ruby, JavaScript and TypeScript, Lua, PHP and Perl are said to work through a shebang feature. The tree supports the plausibility of that without showing it, since `runner/` is a real directory, but the README never shows a non-shell cell, so the multi-language story rests entirely on a sentence and an external documentation site.

## Four commands documented against a much larger internal surface

The commands section covers discovery and inspection and stops there. Three of the four examples are about looking rather than doing:

```bash
$ runme list
```

```bash
$ runme print hello-js
```

```bash
$ runme help
```

`runme list` enumerates the runnable cells in the current project, and `runme print` echoes the contents of one cell without executing it, which is the safer way to inspect something a document asks a human to run. Neither command is exotic, and both are the kind of thing you would want before trusting an automated runner with a repository you care about.

Against that, the tree is large. Beyond the four documented verbs there are `session/`, `runner/`, `runnerv2client/`, `runnerv2service/`, `integrations/`, `evals/`, `experimental/`, `telemetry/` and `web/`. There is also `api/`, `buf.gen.yaml` and `buf.work.yaml`, which are protobuf generation files, so at least part of this project speaks gRPC to something outside the binary. Whether those are all shipped in the CLI you install or are development scaffolding cannot be determined from the README, because it never mentions them.

One readable signal of that internal surface is the fence metadata in the README's own help example, which carries an explicit identifier field alongside the interactive flag. That shape, an ID that persists across renders, is the sort of detail that exists because something serializes cells rather than because a person types them.

## A repository that runs its own documentation workflow

The most telling files in the tree are the ones that have nothing to do with running code. There is a `.runme/` directory, an `AGENTS.md`, a `CLAUDE.md`, a `Makefile`, a `Brewfile`, `.envrc` and `.envspec`, and a `.dagger/` directory alongside a `dagger.json`. Dagger is a CI system that runs pipelines in containers, and `AGENTS.md` and `CLAUDE.md` are instruction files for coding agents, both of which are recent conventions rather than long-standing ones.

Put together, that says the project eats its own cooking in a fairly literal way. Its own contributor guide is meant to be executed by Runme, which is what the badge at the bottom of the README is for. It also means the repository is dogfooding several agent and pipeline conventions at once, which is a reasonable signal about how the maintainers expect documentation and automation to intersect, and a reason the `.envrc` and `.env.spec` pair exists at all. Runme is opinionated about environment variables being retained across cells, and a repo that keeps its own env files in the open is the natural place to enforce that.

The practical takeaway for a reader is that the README you are reading was assembled with the same tooling it describes. If a command in this README is wrong, that is a defect worth an issue, because the maintainers are the first audience for it.

## A contributing badge pointing at the previous organization name

The last section of the README tells you to click a badge titled Run with Runme to open `CONTRIBUTING.md`. The badge is not decoration. It points at a Runme API endpoint with a repository parameter, and that parameter is set to `github.com/stateful/runme.git`. The repository you are reading lives at `runmedev/runme`.

So the project's own call to action, the one link in the README that demonstrates the product, encodes an organization name from before the rename. What that does when you click it depends on how the Runme backend resolves that path, and the README offers no way to find out, because there is no troubleshooting section for it. Two facts sit side by side: the link is generated by a hosted service that may well keep an alias for the old path, and the repository metadata, the module path in the `go install` line, and the download URLs all use the current name. Whichever behaviour you get, the honest conclusion is that this is a stale string rather than a statement about which organization owns the project.

For anyone writing their own Runme badges, it is the one detail to check before shipping a docs link, since the same mistake is easy to make and hard to see.

## Where the README stops and the documentation site takes over

The split here is clean enough to state plainly. The README gives you installation, three inspection commands, one execution command, a link to a Discord, and a link to docs.runme.dev. Everything else is deferred: cell configuration is described only as a link, the multi-language claim has no example, telemetry has no mention, and the `experimental/` directory in the tree is never explained.

The repository itself fills in some of that. Star count is 2180 with 152 open issues, which is a normal ratio for a project with an active Discord and a large user base, and the last push was on 2026-09-17. Repository topics are `cloud`, `devops`, `markdown`, `notebooks` and `workflows`, which matches how the README positions the tool.

Where the README is genuinely good is the accuracy of its small claims. It says Runme persists runbooks in Markdown, which is true of any Markdown file and is the whole point, and it says environment variables are retained across execution much like a terminal session, which is the detail that decides whether a runbook can be split across cells at all. Check those two behaviours against your own setup first, because everything else in the tool is a convenience layer on top of them.

## Conclusion

Runme is at its best on the exact files most projects already have, a README full of fenced commands that drift out of date because nobody runs them. The named cell syntax is the part worth learning first, since it is what makes a block addressable by `runme run`, and the split between `runner/` and the two `runnerv2` directories is what you need to know before filing anything useful upstream. What the README does not settle is the configuration surface, the telemetry behavior, and the relationship between the current release channel and the `@main` install line. Start by running `runme list` in a repository of your own, then read the configuration page on docs.runme.dev before you rename any cell that a Makefile already depends on.

## FAQ

### How do I run a specific command block from a README with Runme?

Give the fenced block a name in its attributes, then invoke it by that name with `runme run update-brew`. The name, not the file path and not the command text, is the handle Runme uses, so renaming the command inside the fence does not break the reference.

### Does Runme replace my Makefile or task runner?

No. The README frames Runme as compatible with existing task definitions such as Makefile, Gradle, Grunt, NPM scripts and Deno tasks, meaning you keep the task runner and add Markdown as another place to invoke steps. Cells hold the commands; the task runner still holds the build graph.

### Which languages can a Runme cell actually run?

The README names Shell and Bash, Python, Ruby, JavaScript and TypeScript, Lua, PHP and Perl, and attributes the support to a shebang feature. It provides no non-shell example, so the multi-language claim is documented only on docs.runme.dev rather than demonstrated in the repository readme.

### Is it safe to point Runme at a README full of commands from other projects?

Inspect before you execute. `runme list` enumerates the cells in a project and `runme print` echoes one cell's contents without running it, which lets you read what a document asks you to do before letting it happen. Treat any command from an unfamiliar repository the way you would treat a shell script from one.

## Sources

- [License: Apache-2.0](https://github.com/runmedev/runme/blob/main/LICENSE)
- [Project website](https://runme.dev)
- [README](https://github.com/runmedev/runme/blob/main/README.md)
- [Releases](https://github.com/runmedev/runme/releases)
- [runmedev/runme on GitHub](https://github.com/runmedev/runme)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/runmedev-runme
