{"id":24058222,"url":"https://github.com/ctsrc/mdrun","last_synced_at":"2025-08-02T09:05:30.407Z","repository":{"id":57637613,"uuid":"412404610","full_name":"ctsrc/mdrun","owner":"ctsrc","description":"Runs command-line pipelines embedded in Markdown and CommonMark documents. Keeps your authored docs up to date. Even usable as an alternative to IPython notebooks.","archived":false,"fork":false,"pushed_at":"2021-10-01T10:52:47.000Z","size":34,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-25T15:07:28.345Z","etag":null,"topics":["abstract-syntax-tree","ast","commonmark","computer-science","data-science","devops","iac","infrastructure-as-code","markdown","qa","quality-assurance","software-development","software-engineering","sre","technical-writing","writing-tool"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ctsrc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-10-01T09:25:49.000Z","updated_at":"2024-04-07T12:02:57.000Z","dependencies_parsed_at":"2022-09-02T02:13:04.801Z","dependency_job_id":null,"html_url":"https://github.com/ctsrc/mdrun","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/ctsrc/mdrun","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctsrc%2Fmdrun","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctsrc%2Fmdrun/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctsrc%2Fmdrun/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctsrc%2Fmdrun/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ctsrc","download_url":"https://codeload.github.com/ctsrc/mdrun/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ctsrc%2Fmdrun/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267464522,"owners_count":24091505,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-28T02:00:09.689Z","response_time":68,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["abstract-syntax-tree","ast","commonmark","computer-science","data-science","devops","iac","infrastructure-as-code","markdown","qa","quality-assurance","software-development","software-engineering","sre","technical-writing","writing-tool"],"created_at":"2025-01-09T05:56:26.495Z","updated_at":"2025-08-02T09:05:30.346Z","avatar_url":"https://github.com/ctsrc.png","language":"Shell","readme":"# mdrun\n\n[![Crates.io](https://img.shields.io/crates/v/mdrun.svg)](https://crates.io/crates/mdrun) [![Docs.rs](https://docs.rs/mdrun/badge.svg)](https://docs.rs/mdrun/)\n\nRuns command-line pipelines embedded in Markdown and CommonMark documents.\n\nKeeps the output of shell commands in your README.md\nand other documents up to date.\n\nAutomatically rewrites the table of contents for your README.md.\n\nUsable as an alternative to IPython notebooks.\n\nVaguely reminiscient of Knuth's computer programming system \"Web\"\nwith its programs TANGLE and WEAVE, but at the same time not.\n\n## Work in progress\n\nThis tool is not yet ready for use, as at present time\nno code for it has yet been written.\n\n## Table of contents\n\nTable of contents will be added as soon as `mdrun` is able to generate it.\n\n## Introduction\n\n`mdrun` is a tool that reads Markdown and CommonMark documents and:\n\n  - Runs shell commands from one or more specified sections of your document.\n  - Captures the output of said shell commands.\n  - Inserts the output of the shell commands into the document.\n  - Updates the output of the shell commands in the document.\n\nAdditionally, it performs the following tasks:\n\n  - Generates a table of contents for your document.\n  - Updates the table of contents in your document.\n\n## Dogfooding\n\nWe wrote this tool to scratch an itch, and we use it ourselves.\nBoth in other projects, and on the very README you are presently reading.\n\n(Also, when I say \"we\" I actually mean \"I\", because there is only me working\non this as of yet. Contributions are welcome though, as long as they stick to\nthe essence of the project. So perhaps one day it really will be \"we\".)\n\n## Use cases\n\nThe foremost usecase for `mdrun` lies in keeping documentation up to date,\nby capturing and updating the output of shell commands that your docmuents\ncontain.\n\nAside from this, one of many other possible use cases include using `mdrun`\nwith a Markdown or CommonMark document in the style of what IPython provides\nwhen you choose to \"Run all cells\" on an IPython notebook. Albeit more simple\nand less interactive compared to IPython of course. Simpler and less\ninteractive for the time being, at least.\n\n## Usage\n\nSince one might not want to execute all commands in any given document,\nthe tool requires that you specify which section(s) of the document\nto run shell commands from. By default, no commands will be executed\nunless sections are specified, and furthermore, only the commands\nthat belong to the section itself, and not any commands inside of\nany subsections will be executed.\n\nAdditionally, for safety and convenience, `mdrun` will only execute\nfenced commands that satisfy the following conditions:\n\n  1. The code block containing the command is fenced and has an info string\n     indicating which shell the command is to be run in.\n  2. The aforementioned info string has a value corresponding to either\n     of the following: `zsh`, `fish`, `bash`, `sh`, `ksh`, `tcsh` or `csh`.\n  3. The code block containing the command is immediatelly followed\n     by a code block that has an info string with a value of `text`.\n\nAs such, assuming `mdrun` has been installed to a directory that is\nin your `$PATH`, and you were to run the following command in this\ndirectory, specifying that `mdrun` run on the section titled \"Usage\"\nof this README:\n\n```zsh\nmdrun -s Usage README.md\n```\n\nAnd further assuming that you have `zsh` installed on your system,\nthen you will find that the following commands will execute and\nthe output will be updated correspondingly.\n\n```zsh\ndate +%s\n```\n\n```text\n\n```\n\n```zsh\nuname -a\n```\n\n```text\n\n```\n\nWhereas the following command will not be executed, because there is no\ncorresponding fenced code block with info string `text` immediatelly\nfollowing it.\n\n```zsh\necho This command is not executed.\n```\n\nLikewise, the following command will not be executed either, because\nthe info string for the command code block has a value that is different\nfrom the set of accepted values for the info string of a command code block:\n\n```python3\nprint(\"Hello from Python 3.\")\n```\n\n```text\n\n```\n\nAlthough... Python may eventually be considered to be in scope. So in that case\nwe'll have to come up with another example instead.\n\nThis one may be a safer bet for something that will probably remain\nconsidered out of scope:\n\n```sql\nselect current_date;\n```\n\n```text\n\n```\n\nSince in order for that command to really make sense, we'd at the very least\nneed to know which sql client to use (PostgreSQL here), and usually we'd need\nto know which database to run the sql command on etc.\n\nEither way, in both the case of Python 3 and any command-line capable sql client,\nif you wanted to run commands and capture output you could specify a shell command\nthat invokes the tool in question.\n\nSo for example Python 3:\n\n```zsh\npython3 -c \"print('Hello from Python 3.')\"\n```\n\n```text\n\n```\n\nand a multi-line Python 3 example:\n\n```zsh\npython3 \u003c\u003cEOF\nfor i in range(2):\n  print(i)\nEOF\n```\n\n```text\n\n```\n\nand SQLite:\n\n```zsh\nsqlite3 \u003c\u003cEOF\nselect date('now');\nEOF\n```\n\n```text\n\n```\n\netc, etc.\n\nThat being said, and given that we mentioned PostgreSQL I might also note that\nyou'd probably usually *not* want to connect to a persistent database in the\ncontext of sections of documents that you run `mdrun`. But even that will\nsometimes be appropriate. It all depends on what you are trying to do with\n`mdrun` and your Markdown or CommonMark documents.\n\n### Another couple of examples\n\nLikewise to the above, when you run:\n\n```zsh\nmdrun -s Usage README.md\n```\n\nyou will find that the following is *NOT* updated, because it belongs\nto a subsection of the \"Usage\" section rather than belonging directly\nto the \"Usage\" section itself:\n\n```zsh\necho $SHELL\n```\n\n```text\n\n```\n\nWhereas if we instead run:\n\n```zsh\nmdrun -s \"Another couple of examples\" README.md\n```\n\nthen we will find that both the output for the preceeding `echo $SHELL`\ncommand and the following command will be executed, because now we are\ntargeting this specific section.\n\n```zsh\ngit describe --always --dirty=+\n```\n\n```text\n\n```\n\n### We can do it recursively too, if you'd like (as long as you're careful)\n\nTODO: Describe\n\n### Handling of multiple sections which share the same name\n\nBelow we have two sections which are both named \"What happens if you try to\nrun `mdrun` on a section that does not have a unique name?\"\n\nWe then attempt to run `mdrun` specifying that we want it to run on a section\nwith this name.\n\n```zsh\nmdrun -s \"What happens if you try to run `mdrun` on a section that does not have a unique name?\" README.md\n```\n\nIn this case, `mdrun` will report that the section name is ambiguous because\nmultiple sections share the same name. Therefore, the commands will not be executed,\nthe output will remain unmodified, and `mdrun` will exit with a non-zero exit code.\n\n#### What happens if you try to run `mdrun` on a section that does not have a unique name?\n\nThis is an example of a section that does not have a unique name.\nThe section that follows this one shares the same name.\n\n```zsh\necho hello\n```\n\n```text\n\n```\n\n#### What happens if you try to run `mdrun` on a section that does not have a unique name?\n\nThis is an example of a section that does not have a unique name.\nThe section that precedes this one shares the same name.\n\n```zsh\necho world\n```\n\n```text\n\n```\n\n### A config-file for use in projects?\n\nI am debating making it so that `mdrun` will look for a file named `.mdrunconf`\nor some-such in the current working directory, but I am leaning towards leaving\nit up to each project to create a short shell script that invokes `mdrun` with\nthe sections it should run instead of doing that.\n\n### Handling of multiple sections which share the same name (cont.)\n\nThe above applies also even when the sections in questions are not direct\nsiblings. `mdrun` was made to behave this way for safety, to ensure that one\ndoes not accidentally run the commands belonging to the wrong section.\n\nFor this same reason, `mdrun` does not provide numeric indexing as a way of\ndisambiguating, because additional sections sharing the same name could have\nbeen inserted into the document between.\n\n(Of course, sections could also have been renamed, but this is less likely\nto happen by accident/without noticing in our opinion, so we take it as a\nprerequisite for use of the tool to assume that the specificed section names\ncorrespond to what the user intended as long as we deny running commands\non specified sections where the section name is non-unique.)\n\nThe primary and recommended way of dealing with multiple sections that\nshare the same name is to give unique names to each section in your document.\n\nThe secondary and non-recommended way of dealing with multiple sections\nthat share the same name is to run `mdrun` recursively on a common ancestor,\nor on the nearest non-ambigous ancestor of each of the sections in question.\n\n### Running on multiple sections\n\n#### Some section\n\n```zsh\nping -c4 1.1.1.1\n```\n\n```text\n\n```\n\n#### Another section\n\n```zsh\nping -c4 8.8.8.8\n```\n\n```text\n\n```\n\n#### Now then\n\nLet's say that we want to run the commands for both of the above sections;\n\"Some section\" and \"Another section\". The way that we do this is simply by\nsupplying the section argument multiple times; one for each section we want\nto execute the commands of and capturing the corresponding output for and\nso on:\n\n```zsh\nmdrun -s \"Some section\" -s \"Another section\" README.md\n```\n\n### Clearing all outputs\n\nClearing all outputs is simple and sometimes a desirable thing to do:\n\n```zsh\nmdrun --clear-all-outputs README.md\n```\n\nIf you then subsequently run `mdrun` again on all of the desired sections\nthen you can easily spot if there are any sections that you have forgotten\nto cover.\n\n### Table of contents and depth\n\nIf you only want to update the table of contents, and not run any commands,\nyou can use the `--toc-only` flag:\n\n```zsh\nmdrun --toc-only README.md\n```\n\nBy default table of contents is generated for level 2 and level 3 headings.\nThis range can be adjusted by making use of the `--toc-depth-min \u003cm\u003e` and\n`--toc-depth-max \u003cn\u003e` arguments.\n\nFor example:\n\n```zsh\nmdrun --toc-depth-min 1 --toc-depth-max 6 --toc-only README.md\n```\n\n### Verbosity\n\nBy default, `mdrun` runs with a verbosity level of \"info\", which causes it\nto print out the commands that are currently being executed.\n\nYou can reduce the verbosity level to \"warn\" which will only print warnings and errors\nby supplying the `--silent` flag once or its alias `-s` once.\n\nYou can reduce the verbosity level to \"errors\" which will only print errors\nby supplying the `-s` flag twice; `-ss`.\n\nYou can silence `mdrun` completely by supplying the `-s` flag thrice; `-sss`.\nIn this mode nothing is printed by the tool, aside from panics that may be printed\nby the Rust runtime. This verbosity level -- or rather perhaps, quietness level --\nmay be useful in certain scripting settings. The `mdrun` command will of course\nstill exit with an appropiate exit status indicating whether it was able to\nsuccessfully complete its tasks or not.\n\n### Synopsis (quick help) and version\n\nA synopsis of how to invoke `mdrun` is available by running the `mdrun` command\nwith the `--help` flag or its alias `-h`:\n\n```zsh\nmdrun -h\n```\n\n```text\n\n```\n\nYou can retrieve version information by running the `mdrun` command with\nthe `--version` flag.\n\n```zsh\nmdrun --version\n```\n\n```text\n\n```\n\n## Installation\n\n### Option 1: Via the package manager for your operating system\n\nThis option is not yet available, but we hope to see this tool available\nin the following package managers eventually:\n\n- Homebrew for macOS\n- Official apt repositories for Ubuntu, KDE Neon and Debian\n- Arch Linux AUR\n- FreeBSD ports\n- and more...\n\n### Option 2: Download precompiled binaries via the GitHub releases page\n\nNot yet available but will be soonish.\n\n### Option 3: Via crates.io using the Rust development environment tool `cargo`\n\n1. Install the Rust development environment, if you haven't done so already:\n\n   ```zsh\n   curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\n   ```\n\n2. Install mdrun:\n\n   ```zsh\n   cargo install mdrun\n   ```\n\n## Acknowledgements\n\nThis tool would not be possible without the awesome CommonMark Markdown parser\n[comrak](https://github.com/kivikakk/comrak).\n\n## Contributing\n\nIf you have a feature that you'd like to implement, or a bug that you would\nlike to fix, please file an issue so that we can discuss it and if what you\nhave in mind is in line with the goals and scope of this project then I will\ngive you the go-ahead signal and you can then code it up and submit a\npull-request that we can discuss further.\n\n## ⭐ Star, share, like, subscribe ;) ⭐\n\nIf you enjoy this project please remember to star it on GitHub.\n\nAnd feel free to tell some friends, colleagues or your family about it too :)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fctsrc%2Fmdrun","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fctsrc%2Fmdrun","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fctsrc%2Fmdrun/lists"}