Skip to content

harehare/mq-task

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

196 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mq-task logo

mq-task

ci release license

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.

demo

Warning

mq-task is currently under active development.

Features

  • 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/--dir overrides, plus meta-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

Installation

Quick Install

curl -sSL https://raw.githubusercontent.com/harehare/mq-task/refs/heads/main/bin/install.sh | bash

The 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

$ cargo install --git https://github.com/harehare/mq-task.git

Usage

Run a task (shorthand)

# Run from README.md (default)
mq-task "Task Name"

# Run from a specific file
mq-task -f tasks.md "Task Name"

Run a task (explicit)

mq-task run "Task Name"
mq-task run --file tasks.md "Task Name"

Pass arguments to a task

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 arg2

Arguments 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"
```

Environment variables and working directory

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=prod

A 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 instead

Task dependencies

You 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

Named parameters

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  # named

Parameters are exposed as MX_PARAM_<NAME> environment variables. A required parameter with no value bound is an error.

Aliases and the default task

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"

Private tasks

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 available tasks

# 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 --all

Initialize configuration

mq-task init

This creates an mq-task.toml file with default runtime settings.

Configuration

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 argument

Use 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 Build

default_task (top-level, outside [runtimes]) sets which task runs when mq-task is invoked with no task name — see Aliases and the default task.

Exit codes

mq-task exits with the same code the task's process exited with, so it composes correctly with &&, CI, and git hooks.

License

MIT

About

A task runner that executes code blocks in Markdown files based on section titles.

Topics

Resources

Stars

11 stars

Watchers

0 watching

Forks

Contributors