mq-task is a task runner that executes code blocks in Markdown files based on section titles.
It is implemented using mq, a jq-like command-line tool for Markdown processing, to parse and extract sections from Markdown documents.
Warning
mq-task is currently under active development.
- Execute code blocks from specific sections in Markdown files
- Task dependencies with automatic execution ordering
- Named task parameters with defaults, plus positional args
- Per-run
--env/--diroverrides, plusmeta-declared defaults for environment variables and working directory - Default task, aliases, and private (hidden) tasks
- Configurable runtimes for different programming languages, with real exit codes and interactive stdin
- Support for custom heading levels
- TOML-based configuration
- Built on top of the mq query language
curl -sSL https://raw.githubusercontent.com/harehare/mq-task/refs/heads/main/bin/install.sh | bashThe installer will:
- Download the latest mq binary for your platform
- Install it to
~/.local/bin/ - Update your shell profile to add mq to your PATH
$ cargo install --git https://github.com/harehare/mq-task.git# Run from README.md (default)
mq-task "Task Name"
# Run from a specific file
mq-task -f tasks.md "Task Name"mq-task run "Task Name"
mq-task run --file tasks.md "Task Name"You can pass arguments to your task using -- separator:
# Pass arguments to a task
mq-task "Task Name" -- arg1 arg2 arg3
# With explicit run command
mq-task run "Task Name" -- arg1 arg2 arg3
# From a specific file
mq-task -f tasks.md "Task Name" -- arg1 arg2Arguments are accessible via environment variables:
MX_ARGS: All arguments joined by space (e.g., "arg1 arg2 arg3")MX_ARG_0,MX_ARG_1, ...: Individual arguments
Example in a Markdown task:
## My Task
```bash
echo "All args: $MX_ARGS"
echo "First arg: $MX_ARG_0"
echo "Second arg: $MX_ARG_1"
```Like just, you can set environment variables and a working directory for a task at invocation time — no declaration needed in the Markdown file:
# Set one or more environment variables (repeatable)
mq-task deploy --env REGION=eu --env DEBUG=1
# Run the task's commands in a specific working directory
mq-task deploy --dir ../other-project
# Combine both
mq-task run deploy --env REGION=eu --dir ../other-project--env KEY=VALUE variables are available in the task's shell alongside MX_ARGS/MX_PARAM_*. --dir applies to every command in the task (and its dependencies) for that run. Both flags are available on the shorthand form, run, and tui.
You can also declare default environment variables directly in a task's meta block:
## deploy
```meta
env = ["REGION=staging", "LOG_LEVEL=info"]
```
```bash
echo "deploying to $REGION ($LOG_LEVEL)"
```A CLI --env flag of the same name overrides the meta default for that run:
mq-task deploy # REGION=staging
mq-task deploy --env REGION=prod # REGION=prodA working directory can be declared the same way with dir (relative paths resolve against the directory mq-task was invoked from):
## deploy
```meta
dir = "services/api"
```
```bash
pwd # services/api
```The CLI --dir flag overrides a meta-declared dir for that run:
mq-task deploy # runs in services/api
mq-task deploy --dir services/worker # runs in services/worker insteadYou can declare dependencies between tasks using a meta code block (TOML format). When a task is run, its dependencies are automatically executed first in the correct order.
## format
```bash
cargo fmt
```
## lint
```meta
depends = ["format"]
```
```bash
cargo clippy
```
## test
```meta
depends = ["lint"]
```
```bash
cargo test
```Running mq-task test will automatically execute format → lint → test in order:
Running task: test
Running dependency: format
...
Running dependency: lint
...
(test output)
- Multiple dependencies are supported:
depends = ["format", "lint"] - Shared dependencies are executed only once even if multiple tasks depend on them
- Circular dependencies are detected and reported as an error
Declare parameters in the meta block. A bare name is required; name=value sets a default.
## deploy
```meta
params = ["env=staging", "region"]
```
```bash
echo "deploying to $MX_PARAM_ENV / $MX_PARAM_REGION"
```mq-task deploy -- region=eu # env falls back to "staging"
mq-task deploy -- prod eu # positional, filled in declaration order
mq-task deploy -- env=prod region=eu # namedParameters are exposed as MX_PARAM_<NAME> environment variables. A required parameter with no value bound is an error.
Give a task alternate names with alias in its meta block:
## build
```meta
alias = ["b"]
```
```bash
cargo build
```mq-task b now runs build. Set default_task in mq-task.toml to run a task when mq-task is invoked with no task name:
default_task = "build"A task whose title starts with _, or whose meta block has private = true, is hidden from list/tui output but can still be run directly or used as a dependency:
## _cleanup
```bash
rm -rf tmp/
```# List tasks from README.md (default)
mq-task
# List tasks from a specific file
mq-task -f tasks.md
mq-task list --file tasks.md
# Include private tasks
mq-task list --allmq-task initThis creates an mq-task.toml file with default runtime settings.
Create an mq-task.toml file to customize runtime behavior:
# Runtimes configuration
# Simple format: language = "command", execution mode defaults to "file"
[runtimes]
bash = "bash"
sh = "sh"
python = "python3"
ruby = "ruby"
node = "node"
javascript = "node"
js = "node"
php = "php"
perl = "perl"
# Detailed format with execution mode
# Execution modes: "file" (default), "stdin", or "arg"
# - file: write code to a temp file and run it as an argument (keeps stdin interactive)
# - stdin: pipe code into the command's standard input (stdin unavailable to the script itself)
# - arg: pass code as a command-line argument
[runtimes.go]
command = "go run"
execution_mode = "file"
[runtimes.jq]
command = "jq"
execution_mode = "arg" # jq's filter is a CLI argument, not read from stdin
[runtimes.mq]
command = "mq"
execution_mode = "arg" # mq uses query as argumentUse execution_mode = "stdin" only when a command needs the code piped in literally (e.g. psql, redis-cli) — the task script then can't also read from the terminal.
You can also mix both formats:
[runtimes]
python = "python3" # Simple format, uses default file mode
[runtimes.go] # Detailed format with custom execution mode
command = "go run"
execution_mode = "file"# Using shorthand (from tasks.md by default)
mq-task Build
# From a specific file
mq-task -f tasks.md Build
# Using explicit run command
mq-task run Build
mq-task run --file tasks.md Builddefault_task (top-level, outside [runtimes]) sets which task runs when mq-task is invoked with no task name — see Aliases and the default task.
mq-task exits with the same code the task's process exited with, so it composes correctly with &&, CI, and git hooks.
MIT
