Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Coming from just or Task

mq-task covers what most justfiles and Taskfile.ymls do, but it is not a drop-in replacement: the task file is a Markdown document, and a few things work differently. This page maps the concepts and says plainly what is missing. There is no automatic converter; moving a file by hand takes a few minutes.

How mq-task thinks

  • A heading is a task and the code blocks under it are what runs. The prose is the description (mq-task list, --summary, shell completion).
  • A block is one script, not one command per line. In just every line runs in its own shell; here a bash block runs top to bottom in a single shell, so cd and variables carry over. Add set -e yourself if you want to stop at the first failure.
  • The block's language picks the interpreter (bash, python, node, ...), so what just calls a shebang recipe is simply a ```python block.
  • Values reach scripts as environment variables, whatever the language. There is no {{ }} text substitution into the script (see Variables).
  • mq-task does not echo commands. -v prints each block before it runs.
  • Without -f, the task file is searched for upwards from where you are (tasks.md first), and mq-task changes to its directory before running, like just. With -f, tasks run where you are.

From just

justmq-task
build: with indented lines## build with a ```bash block
test: build```meta with depends = ["build"]
deploy env="staging": and {{env}}params = ["env=staging"] and $MX_PARAM_ENV
*args / +argsthe rest of the command line: $MX_ARGS, $MX_ARG_0, ...
version := "1.0"vars = { version = "1.0" } (referenced as $version or ${version})
v := `git describe` vars = { v = { sh = "git describe" } }
set dotenv-loaddotenv = [".env"]
set shell := ["zsh", "-c"]runtimes in mq-task.toml, e.g. bash = "zsh"
shebang recipe #!/usr/bin/env python3a ```python block
[private] or a leading _a leading _ or private = true
[confirm("Sure?")]prompt = "Sure?" (--yes skips it)
[linux], [macos], [windows], [unix]if = 'os() == "linux"'
env_var("HOME"), os()${HOME} in vars; getenv("HOME") and os() in an if condition
alias b := buildalias = ["b"]
import "x.just" / mod ximports = ["x.md"], used as x:task
@recipe / set quietthe default: nothing is echoed
just --list, --summarymq-task, mq-task <task> --summary, mq-task list --json
just --choosemq-task tui
just --dry-runmq-task <task> --dry-run
first recipe is the defaultdefault_task = "build" in mq-task.toml
just --fmt, --evaluateno equivalent (mq-task check validates the file)

Not available: recipe groups ([group]), {{ }} interpolation of arguments or functions into the script text, invocation_directory() (a task always runs in the file's directory unless you set dir), and running a single line of a recipe.

From Task

Taskmq-task
tasks: map, desc/summaryheadings, with the prose as the description
cmdsthe lines of a code block
depsdepends. Task runs deps in parallel by default; mq-task runs them in order unless the task sets parallel = true
task: other with vars inside depsdepends = ["other name=value"]
vars, sh:vars = { A = "x", B = { sh = "cmd" } }
{{.VAR}} templates$VAR / ${VAR}; ${VAR} inside vars values is expanded by mq-task
env, dotenv, direnv, dotenv, dir
sources / generatessources / outputs (content checksums, like Task's default)
statusstatus (commands that exit 0 when the task is up to date)
preconditionsrequires for variables, if to skip, or a check in the script
for over a list, a matrix, sourcesfor = [..], { matrix = .. }, { glob = .. }; over a variable: { from = "task" }
deferdefer = ["cleanup"]
ignore_errorignore_error = true
promptprompt = "..."
run: onceonce = true
platformsif = 'os() == "linux"'
silentthe default (use -v to see the code)
internala leading _ or private = true
aliasesalias
includesimports, namespaced as file:task
requires: varsrequires
--watch, interval--watch, --interval
--parallel, --concurrency--parallel, -j
--force--no-cache
--list, --summarymq-task, --summary
--dry, --yes--dry-run, --yes

Not available: Go-template functions and conditionals, includes options (flatten, optional, per-include vars), method: timestamp, label, calling another task from the middle of a script (use depends, defer, or run mq-task other from the script), and set/shopt options.

A small example

A justfile:

default: test

build profile="debug":
    cargo build --profile {{profile}}

test: build
    cargo test

deploy env="staging": test
    @echo "deploying to {{env}}"

The same tasks in tasks.md:

## build

```meta
params = ["profile=debug"]
```

```bash
cargo build --profile "$MX_PARAM_PROFILE"
```

## test

```meta
depends = ["build"]
```

```bash
cargo test
```

## deploy

```meta
depends = ["test"]
params = ["env=staging"]
```

```bash
echo "deploying to $MX_PARAM_ENV"
```

and default_task = "test" in mq-task.toml. A Taskfile.yml converts the same way: each key under tasks: becomes a heading, cmds becomes the code block and deps, vars and the other keys move into the meta block as in the table above.

Checking the result

mq-task check          # finds typos, missing dependencies, cycles, missing runtimes
mq-task                # lists the tasks
mq-task <task> --dry-run