xeq 2.3.0

xeq is a cross-platform CLI tool that runs sequences of commands from a single TOML file, making repetitive tasks fast and consistent.
xeq-2.3.0 is not a library.

xeq

Crates.io Downloads License Build Rust

xeq is a cross-platform CLI tool that runs sequences of commands from a single TOML file, making repetitive tasks fast and consistent.

Every project has a setup ritual. Ten commands, always in the same order, run every time. Write them once in a xeq.toml, commit it, and anyone on any OS runs the exact same steps with one command.


Table of Contents


Installation

macOS / Linux

curl -sSf https://raw.githubusercontent.com/opmr0/xeq/main/install.sh | sh

Windows (PowerShell)

iwr https://raw.githubusercontent.com/opmr0/xeq/main/install.ps1 -UseBasicParsing | iex

Via cargo (Rust package manager)

cargo install xeq


Quick Start

1. Create a xeq.toml in your project root:

[setup]

run = [

    "npm install",

    "npm run build"

]



[dev]

run = ["npm run dev"]

2. Run any script by name:

xeq run setup

xeq run dev

xeq finds xeq.toml in the current directory automatically. No extra setup needed.

Use xeq init to create a xeq.toml file, and xeq will generate one for you.


Comparison with other tools

Feature xeq Makefile npm scripts just
File type TOML Makefile package.json Justfile
Works on all OS Yes Mostly Linux/macOS Yes Yes
Validation command Yes (xeq validate) No No No
Variables Yes Yes Limited Yes
Args support Yes Limited Limited Yes
Nested scripts Yes (xeq://) Yes No Yes
Parallel run Yes Yes (-j) No No
.env support Yes (auto) No No Yes (opt-in)

Commands

xeq init

Creates a starter xeq.toml in the current directory. Will not overwrite an existing file.

xeq init [template]

You can chose a template to start with

Available templates

android, ansible, astro, aws, bun, deno, django, docker, dotnet, elixir, expo, fastapi, flutter, git, go,hugo ,java-gradle,java-maven, kubernetes, laravel, monorepo, nestjs, nextjs, node, python, rails,react, rust, svelte, tauri


xeq run <script> [flags]

Runs a script by name. Commands execute one at a time in order. If any command fails, xeq stops, unless you pass --continue-on-err.

xeq run setup

xeq run build --continue-on-err

xeq run dev --quiet

xeq run test --parallel

xeq run create --args my-app

xeq run deploy --args env=prod

Flag Short Description
--continue-on-err -C Keep going even if a command fails
--quiet -q Hide xeq's own log messages
--clear -c Clear the terminal before each command
--parallel [threads_num] -p Run all commands at the same time with certain number of threads (default: your PC's logical processors(threads))
--args <values...> -a Pass arguments into the script, positional or key=value
--global -g Use the globally saved path instead of the local xeq.toml
--summary -s Print a summary table of commands and execution times after the script finishes
--dry-run -d Preview commands without executing them
--allow-empty-args -A Remove the restrictions on arguments and variables
--no-env Skip loading the .env file
--allow-recursion Let a script call itself

xeq list

Shows all scripts in your TOML file, their names, descriptions, and commands.

xeq list

xeq list --global


xeq toml

Shows how the TOML format should be

xeq toml format
───────────────────────────────────────────────────────

File level fields
  shell = "bash"         optional - shell to run commands with
                         supported: sh, zsh, fish, bash, cmd, powershell
                         default: sh (linux/macos), cmd (windows)

[vars]                   optional - file level variables
  var_name = "value"

Script fields
  [script-name]
  run = ["cmd1", "cmd2"] required - commands to run in order
  description = "..."    optional - shown in xeq list
  dir = "./path"         optional - working directory for commands
  options = ["..."]      optional - baked in flags
  parallel_threads = 4   optional - enables parallel execution
  on_success = "script"  optional - script to run on success
  on_error = "script"    optional - script to run on error
  vars.var_name = "value"    optional - script level variable

Available options
  quiet                suppress xeq log messages
  clear                clear terminal before each command
  continue_on_err      keep running if a command fails
  allow_recursion      allow a script to call itself
  summary              print execution summary after run
  allow_empty_vars     skip errors for undefined variables

Variable types
  {{@var}}               user defined variable
  {{$ENV_VAR}}           environment variable
  {{1}} {{2}}            positional arguments
  {{snippets.name}}      snippet output

───────────────────────────────────────────────────────
run `xeq init` to create a starter xeq.toml

xeq validate

Checks all scripts in your TOML file for errors without running anything.

xeq validate

xeq validate --global

Catches:

  • Nested xeq:// calls pointing to scripts that don't exist. see Nested Scripts
  • parallel is enabled and there is a cd or xeq:// in the commands. see Parallel Execution
  • Undefined {{@vars}} not defined in vars. see Variables
  • Circular dependencies between scripts
  • events and continue_on_err set on the same script. see Events
  • events and parallel_treads field (events will be ignored)
  • events and summary option (the summary won't be printed)
  • unsupported shells in the shell value. see Custom Shells
  • dir paths that don't exist
  • parallel_thread field equals 0 or 1

xeq config [path]

Saves a TOML file path globally. See Global Configuration.

xeq config ~/my-scripts/xeq.toml   # save the path

xeq config                          # open the saved file in your default editor

Commands aliases

xeq supports command aliases so xeq run is the same as xeq r

command alias
xeq run xeq r
xeq config xeq c
xeq init xeq i
xeq validate xeq v

TOML Format

A xeq.toml file contains named scripts. Each script needs at least a run array:

[my-script]

description = "What this script does"

parallel_threads = 6

dir = "./my_app"

options = ["quiet"]

run = [

    "command one",

    "command two"

]

  • Script names are case-sensitive, Build and build are different scripts
  • run required, contains all commands to run
  • description optional, only shows in xeq list
  • parallel_threads optional, enables parallel execution and set a number of threads for the execution. see Parallel Execution
  • dir optional, is the path where the script will run, it can be an absolute or a relative path
  • options optional. see Script Options

Features

1. Script Options

Bake default behavior into a script so you don't have to pass flags every time:

[build]

options = ["quiet"]

run = ["cargo build", "cargo test"]

Now xeq run build always runs quietly and in parallel, no flags needed.

Available options: quiet, clear, continue_on_err, allow_recursion, summary, allow_empty_vars

Toggling: CLI flags toggle script options. If a script has quiet baked in and you pass --quiet, it turns quiet off for that run.

xeq run build          # quiet ON  (from TOML)

xeq run build --quiet  # quiet OFF (toggled by CLI flag)


2. Variables

Use a [vars] block to define reusable values. Reference them in commands with {{@varname}}:

[vars]

image = "myapp:latest"

env = "development"



[build]

run = ["docker build -t {{@image}} ."]



[start]

run = ["APP_ENV={{@env}} npm start"]

Local variables let a specific script override a global value:

[vars]

image = "myapp:latest"



[build]

vars.image = "myapp:build"

run = ["docker build -t {{@image}} ."]   # uses "myapp:build"



[push]

run = ["docker push {{@image}}"]          # uses "myapp:latest"

Override at runtime using --args:

xeq run build --args image=myapp:hotfix

Resolution order, most specific win:

--args (runtime)  ->  local vars (per script)  ->  global vars (file-level)

an error will happen if the vars isn't defined, you can prevent this by using --allow-empty-vars / -A flag or allow_empty_flag option and the raw {{@varname}} will be passed if no variables was passed


3. Arguments

For values that change every run, use positional placeholders {{1}}, {{2}}, etc.:

[create]

run = [

    "npm create vite@latest {{1}} -- --template {{2}}",

    "cd {{1}}",

    "npm install"

]

xeq run create --args my-app react

# {{1}} = my-app

# {{2}} = react

Mix named and positional args in a single call:

xeq run deploy --args env=production my-app

an error will happen if the argument isn't passed, you can prevent this from happening using --allow-empty-vars / -A flag or allow_empty_flag option and the raw {{n}} will be passed if no arguments was provided


4. Environment Variables

Reference system environment variables in commands using {{$VARNAME}}:

[deploy]

run = ["deploy --token {{$API_TOKEN}} --env {{$DEPLOY_ENV}}"]

xeq automatically loads a .env file from the current directory if one exists:

# .env

API_TOKEN=abc123
DEPLOY_ENV=production
xeq run deploy   # API_TOKEN and DEPLOY_ENV loaded automatically

Pass --no-env to skip loading the .env file.

an error will happen if the environment variable doesn't exists


5. Nested Scripts

A script can call other scripts using the xeq:// prefix:

[install]

run = ["npm install"]



[build]

run = ["npm run build"]



[deploy]

run = [

    "xeq://install",

    "xeq://build",

    "npm run deploy"

]

Running xeq run deploy automatically runs install and build first, in order.

Circular dependency protection: xeq detects and exits on circular calls. Add allow_recursion to options or pass the --allow-recursion flag if you intentionally need this.


6. Parallel Execution

Run all commands in a script at the same time:

[check]

parallel_threads = 4

run = [

    "cargo test",

    "cargo clippy",

    "cargo fmt --check"

]

parallel_threads field enables parallel execution and set a number of threads for the execution

use -p to enable parallel execution and set the number of threads to your PC's threads or disable it if it's enable in the config file

use -p <threads> to enable parallel execution or override the parallel_threads value on a single run

xeq run check      # all three run at the same time

xeq run check -p 4   # same using CLI flag

Scripts with cd commands or xeq:// calls cannot run in parallel. Use xeq validate to catch this before running.


7. Global Configuration

xeq finds xeq.toml in your current directory automatically, no setup needed for project-level scripts.

For scripts you use across all your projects save a global file once and run it from anywhere:

xeq config ~/my-scripts/xeq.toml   # save once

xeq run git-cleanup --global        # run from any directory

xeq list --global                   # see all global scripts

8. Run Summary

Pass --summary to see every command and how long it took:

xeq run build --summary

command                        time   status
--------------------------------------------------
cargo test                     1.39s  succeeded
cargo clippy                   0.80s  succeeded
cargo fmt                      0.26s  succeeded

9. Events

Events allow you to trigger additional commands based on whether a script succeeds or fails.


on_error

Runs when the script fails.

[build]

run = ["cargo test", "cargo build"]

on_error = ["echo failed"]

If any command in run fails, the commands in on_error will be executed.


on_success

Runs when the script completes successfully.

[build]

run = ["cargo test", "cargo build"]

on_success = ["echo done"]

If all commands in run succeed, the commands in on_success will be executed.


Rules & Limitations

  • Events are ignored during parallel execution
  • Using events will disable the execution summary
  • Events cannot be combined with continue_on_err

10. Custom shells

Set a shell to run your command with per file

shell = "zsh"



[build]

run = [

    "cargo build",

    "cargo test",

]

Available shells: sh,bash,zsh,cmd,powershell,fish

When the shell value isn't supported xeq will return an error

Examples

The examples/ folder has ready-to-use TOML files for common workflows.

File Description Key Features Used
react-tailwind.toml Scaffold and run a React + Tailwind project variables, cd operators
nextjs.toml Next.js project setup and pipeline nested scripts, variables
rust-project.toml Rust checks, build and publish parallel, nested scripts
docker.toml Docker image and container management variables, nested scripts
git-workflow.toml Common git operations variables, arguments
nested-scripts.toml CI pipeline from reusable pieces nested scripts
env-vars.toml Deploy and notify using env vars {{$VAR}}, nested scripts
python-project.toml Virtualenv, checks and PyPI publish parallel, nested scripts, variables
database.toml Migrations, seed, dump and restore env vars, arguments, nested scripts
monorepo.toml Multi-package frontend workspace parallel, variables, nested scripts
aws-deploy.toml ECR push and ECS deploy pipeline env vars, nested scripts
go-project.toml Go build, test and cross-compile parallel, nested scripts, variables
arguments.toml Positional and named arg patterns arguments, variables
script-options.toml Flag toggle mechanic demonstrations options, parallel, quiet, continue_on_err

How It Works

  • xeq stores your TOML file path using the system config directory
  • Commands run through sh -c on Linux/macOS and cmd /C on Windows
  • cd commands update the working directory for all subsequent commands in that script
  • Variables resolve in order: --args -> local vars -> global vars
  • Environment variables are loaded from .env automatically before any script runs
  • Script names are case-sensitive: Build and build are different scripts

License

MIT - LICENSE