mise
Mise Comprehensive Skill
Table of Contents
- STRICT ENFORCEMENT: Usage Field Required
- Overview
- Task Definition Methods
- Task Arguments - Usage Spec Reference
- Task Configuration Reference
- Running Tasks (CLI)
- Task Dependencies and Caching
- Dev Tools Management
- Environment Configuration
- Hooks and Watchers
- Configuration and Settings
- Prepare Feature (Experimental)
- Monorepo Tasks (Experimental)
- Best Practices
STRICT ENFORCEMENT: Usage Field Required
This skill WILL NOT generate tasks with shell-native argument handling.
All task arguments MUST be defined using the usage field. This is non-negotiable.
REQUIRED Pattern
[tasks.deploy]
description = "Deploy to environment"
usage = 'arg "<env>" help="Target environment" choices "dev" "staging" "prod"'
run = 'deploy.sh ${usage_env?}'
#!/usr/bin/env bash
#MISE description="Process files"
#USAGE arg "<input>" help="Input file"
#USAGE arg "[output]" default="out.txt" help="Output file"
echo "Processing ${usage_input?} -> ${usage_output:-out.txt}"
BLOCKED Patterns
# BLOCKED: Bash positional arguments
[tasks.bad]
run = 'deploy.sh $1 $2'
# BLOCKED: Bash special variables
[tasks.also_bad]
run = 'process.sh "$@"'
# BLOCKED: Inline Tera templates (deprecated, removed 2026.11)
[tasks.deprecated]
run = 'echo {{arg(name="x")}}'
Why This is Enforced
| Benefit | Description |
|---|---|
| Type Safety | Arguments validated before execution |
| Auto-completion | Shell completions generated automatically |
| Cross-platform | Works on bash, zsh, fish, PowerShell |
| Self-documenting | mise run --help shows all options |
| No Parsing Bugs | Eliminates shell quoting/escaping issues |
| Choices Validation | Invalid values rejected immediately |
Overview
mise is an all-in-one developer environment tool that manages:
- Dev tools - install and manage language runtimes, CLIs, and build tools (18 backends)
- Tasks - project-specific commands with argument handling, dependencies, caching
- Environments - manage env vars, profiles, dotenv files, secrets
- Hooks - run commands on directory changes, project enter/leave, tool install
Key Features:
- Parallel dependency building (concurrent by default)
- Last-modified and content-hash checking (avoid unnecessary rebuilds)
- File watching (
mise watchrebuilds on changes) - Cross-platform argument handling via
usagespec - Hierarchical configuration with profile support
- 18 tool backends (aqua, github, npm, cargo, pipx, go, etc.)
Task Definition Methods
TOML-Based Tasks (in mise.toml)
Simple Tasks
[tasks]
build = "cargo build"
test = "cargo test"
lint = "cargo clippy"
Detailed Tasks
[tasks.build]
description = "Build the CLI"
run = "cargo build"
[tasks.test]
description = "Run tests"
depends = ["build"]
run = "cargo test"
File-Based Tasks (executable scripts)
Place in mise-tasks/ or .mise/tasks/ directory. Files must be executable (chmod +x).
#!/usr/bin/env bash
#MISE description="Build the CLI"
#MISE depends=["lint"]
cargo build
Supported directories:
mise-tasks/.mise-tasks/mise/tasks/.mise/tasks/.config/mise/tasks/
File tasks use #MISE or #USAGE comment headers for configuration.
Alternative header syntax (if formatters modify #MISE):
# [MISE] description="Build"
# [MISE] depends=["lint"]
Task Grouping (Namespaces)
Subdirectories create namespaced tasks:
mise-tasks/
├── test/
│ ├── unit → test:unit
│ ├── integration → test:integration
│ └── e2e → test:e2e
└── lint/
├── eslint → lint:eslint
└── prettier → lint:prettier
Remote Tasks
Fetch tasks from external sources:
[tasks.build]
file = "https://example.com/build.sh"
[tasks.release]
file = "git::https://github.com/org/repo.git//scripts/release.sh?ref=v1.0.0"
Remote files are cached in MISE_CACHE_DIR.
Task Arguments - Usage Spec Reference
REMINDER: Always use the usage field. Never use $1, $@, or shell-native argument handling.
The usage field uses KDL-inspired syntax to define arguments, flags, and completions.
Positional Arguments (arg)
| Attribute | Type | Default | Description |
|---|---|---|---|
| (name) | string | required | "<name>" = required, "[name]" = optional. "<file>" triggers file completion, "<dir>" triggers dir completion. |
help |
string | none | Short help text shown with -h |
long_help |
string | none | Extended help text shown with --help |
default |
string | none | Default value if not provided. default="" sets to empty string (different from unset). |
env |
string | none | Environment variable that can provide this arg's value. Priority: CLI > env > default. |
var |
boolean | #false |
Variadic mode (accept multiple values). "<name>" requires 1+, "[name]" accepts 0+. |
var_min |
integer | none | Minimum values when variadic |
var_max |
integer | none | Maximum values when variadic |
choices |
values | none | Restrict to enumerated set |
double_dash |
string | none | "required", "optional", "automatic", "preserve" |
hide |
boolean | #false |
Exclude from help output |
Examples:
arg "<file>" help="Input file to process"
arg "[output]" default="out.txt" help="Output file"
arg "<files>" var=#true var_min=1 help="One or more files"
arg "<env>" choices "dev" "staging" "prod" help="Target environment"
arg "<args>..." double_dash="automatic" help="Pass-through arguments"
Variadic args in bash:
# Values are shell-escaped string in usage_files
eval "files=($usage_files)"
for f in "${files[@]}"; do
echo "Processing: $f"
done
Flags (flag)
| Attribute | Type | Default | Description |
|---|---|---|---|
| (definition) | string | required | "-s --long" (boolean) or "-s --long <value>" (with value). Short flag optional. |
help |
string | none | Short help text |
long_help |
string | none | Extended help for --help |
default |
string/bool | none | Default value. Boolean flags use #true/#false. |
env |
string | none | Environment variable backing the flag |
global |
boolean | #false |
Available on all subcommands |
count |
boolean | #false |
Value = number of times used (e.g., -vvv = 3) |
var |
boolean | #false |
Flag repeatable, collecting values |
var_min |
integer | none | Min values when var=#true |
var_max |
integer | none | Max values when var=#true |
negate |
string | none | Negative form (e.g., "--no-color"). Sets env var to false. |
choices |
block | none | Restrict values to enumerated set |
hide |
boolean | #false |
Exclude from docs/completions |
required_if |
string | none | Required if named flag is set |
required_unless |
string | none | Required unless named flag is present |
overrides |
string | none | If set, named flag's value is ignored |
Examples:
flag "-v --verbose" help="Enable verbose output"
flag "-f --force" help="Skip confirmation prompts"
flag "--port <port>" default="8080" help="Server port"
flag "--color" negate="--no-color" default=#true help="Enable colors"
flag "-d --debug" count=#true help="Debug level (-ddd for max)"
flag "--include <pattern>" var=#true help="Include patterns (repeatable)"
flag "--shell <shell>" { choices "bash" "zsh" "fish" }
flag "--file <file>" required_if="--dir" help="Required if --dir is set"
Count flags: -vvv sets $usage_verbose to 3. Short flags chain: -abc = -a -b -c.
Negate flags: flag "--color" negate="--no-color" default=#true — --no-color sets $usage_color to false.
Custom Completions (complete)
Provide dynamic tab-completion for arguments. Preferred over choices when values change.
complete "<arg_name>" run="<shell command outputting one value per line>"
Key rules:
- Must appear after the
argit applies to - Names must match exactly
- Do not combine with
choiceson the samearg
Examples:
usage = '''
arg "<service>" help="Service name"
complete "service" run="ls -d infrastructure/*/application 2>/dev/null | sed 's|infrastructure/||;s|/application||'"
arg "<environment>" help="Target environment"
complete "environment" run="ls infrastructure/${usage_service}/application/env/ 2>/dev/null | sed 's/.tfvars//'"
'''
With descriptions:
complete "plugin" run="mise plugins ls" descriptions=#true
Output format: value:description per line.
choices vs complete:
| Feature | choices |
complete |
|---|---|---|
| Values | Hardcoded in spec | Dynamic from command |
| Validation | Rejects invalid input | Tab-completion only |
| Maintenance | Must edit to add options | Auto-discovers new options |
| Best for | Stable enums (yes/no, log levels) | File/directory-derived values |
Accessing Arguments in Scripts
Environment variables (prefixed with usage_):
| Definition | Environment Variable |
|---|---|
arg "<file>" |
$usage_file |
arg "[output]" |
$usage_output |
flag "-v --verbose" |
$usage_verbose |
flag "--dry-run" |
$usage_dry_run |
flag "-o --output <file>" |
$usage_output |
Naming rules: usage_ prefix, hyphens to underscores, lowercase, long name used.
Bash variable expansion patterns:
| Pattern | Use Case |
|---|---|
${var?} |
Required args - fail if missing |
${var:-default} |
Optional with fallback |
${var:?msg} |
Required with custom error |
${var:+value} |
Conditional (if set, use value) |
Values by type:
| Type | Present | Absent |
|---|---|---|
| Boolean flag | "true" |
unset (or "false" with default=#false) |
| Count flag | "1", "2", etc. |
"0" |
| Value flag/arg | the string value | unset or default |
| Variadic | shell-escaped space-separated | unset or empty |
Critical distinction: default="" makes variable SET to empty string. No default + not provided = UNSET.
# Required arg - error if not provided
echo "Deploying to ${usage_environment?}"
# Optional with default
clean="${usage_clean:-false}"
# Conditional flag forwarding
docker build ${usage_verbose:+--verbose} .
# Boolean flag check
if [ -n "${usage_dry_run:-}" ]; then
echo "Dry run mode"
fi
# Variadic to array
eval "files=($usage_files)"
File Task Headers
#!/usr/bin/env bash
#MISE description="Deploy application"
#USAGE arg "<environment>" help="Environment" {
#USAGE choices "dev" "prod"
#USAGE }
#USAGE flag "-f --force" help="Skip confirmation"
echo "Deploying to ${usage_environment?}"
Supported shebangs: bash, node, python, deno, pwsh, fish, zsh.
Task Configuration Reference
All Task Fields
Core Execution
| Field | Type | Default | Description |
|---|---|---|---|
run |
string | string[] | object[] |
— | Command(s) to execute. Supports structured array (see below). |
run_windows |
same as run |
— | Windows-specific override |
file |
string |
— | External script path (local, HTTP, or Git URL) |
shell |
string |
— | Interpreter (e.g., "bash -c", "node -e") |
usage |
string |
— | Usage spec for arguments/flags |
Metadata
| Field | Type | Default | Description |
|---|---|---|---|
description |
string |
— | Task help text |
alias |
string | string[] |
— | Alternative name(s) |
hide |
bool |
false |
Exclude from listings |
Dependencies
| Field | Type | Default | Description |
|---|---|---|---|
depends |
string | string[] | object[] |
— | Tasks to run BEFORE (supports structured objects) |
depends_post |
string | string[] | object[] |
— | Tasks to run AFTER |
wait_for |
string | string[] | object[] |
— | Wait for tasks without adding as deps |
Environment & Tools
| Field | Type | Default | Description |
|---|---|---|---|
env |
table |
— | Task-specific env vars (NOT passed to depends). Supports age-encrypted values. |
tools |
table |
— | Tools to install before running |
Execution Context
| Field | Type | Default | Description |
|---|---|---|---|
dir |
string |
{{config_root}} |
Working directory. Use {{cwd}} for user's cwd. |
raw |
bool |
false |
Direct stdin/stdout connection (disables parallel execution) |
Output Control
| Field | Type | Default | Description |
|---|---|---|---|
quiet |
bool |
false |
Suppress mise output |
silent |
bool | "stdout" | "stderr" |
false |
Suppress all/specific output |
Caching
| Field | Type | Default | Description |
|---|---|---|---|
sources |
string | string[] |
— | Input files (glob patterns) |
outputs |
string | string[] | {auto: true} |
— | Generated files. Use {auto = true} for implicit tracking. |
Safety
| Field | Type | Default | Description |
|---|---|---|---|
confirm |
string |
— | Prompt before running. Supports Tera templates with usage.*. |
Timeout & Inheritance
| Field | Type | Default | Description |
|---|---|---|---|
timeout |
string |
— | Max execution duration (e.g., "30s", "5m"). Overrides global task_timeout. |
extends |
string |
— | Template task to inherit configuration from. |
Structured run Array
Mix inline scripts with task references, including parallel sub-task execution:
[tasks.pipeline]
run = [
{ task = "lint" }, # run lint (with its dependencies)
{ tasks = ["test", "typecheck"] }, # run test and typecheck in parallel
"echo 'All checks passed!'", # then run a script
]
Structured depends with Args/Env
Pass arguments and environment variables to dependencies:
[tasks.deploy]
depends = [
{ task = "build", args = ["--release"], env = { RUSTFLAGS = "-C opt-level=3" } }
]
run = "./deploy.sh"
Env vars passed to dependencies are scoped to that dependency only.
Task Inheritance (extends)
A task can inherit configuration from another task:
[tasks._base_deploy]
hide = true
depends = ["build", "test"]
env = { DEPLOY_TIMESTAMP = "{{now()}}" }
tools = { node = "22" }
[tasks.deploy-staging]
extends = "_base_deploy"
env = { DEPLOY_ENV = "staging" }
run = "./scripts/deploy.sh staging"
[tasks.deploy-prod]
extends = "_base_deploy"
confirm = "Deploy to production?"
env = { DEPLOY_ENV = "production" }
run = "./scripts/deploy.sh production"
Global Task Configuration
[task_config] Section
[task_config]
dir = "{{cwd}}" # Default working directory for all tasks
includes = [
"tasks/*.toml", # Local task files
".mise/tasks/", # Task directory
"git::https://github.com/org/tasks?ref=v1" # Remote tasks
]
[vars] Section
Shared variables between tasks (NOT environment variables):
[vars]
project_name = "myapp"
version = "1.0.0"
registry = "ghcr.io/myorg"
[vars._.file]
path = "vars.toml" # Load vars from external file
[tasks.build]
run = "echo Building {{vars.project_name}} v{{vars.version}}"
Vars are accessed via {{vars.key_name}} Tera templates. They are not passed as environment variables.
Global Task Settings
| Setting | Type | Default | Description |
|---|---|---|---|
task_output |
string | "prefix" |
Output mode: prefix, interleave, keep-order, replacing, timed, quiet, silent |
task_timeout |
string | none | Default timeout (e.g., "30m") |
task_timings |
bool | false |
Show elapsed time per task |
task_skip |
string[] | [] |
Tasks to skip by default |
task_skip_depends |
bool | false |
Skip dependencies |
task_run_auto_install |
bool | true |
Auto-install missing tools |
task_show_full_cmd |
bool | false |
Disable command truncation in output |
task_disable_paths |
string[] | [] |
Paths to exclude from task discovery |
task_remote_no_cache |
bool | false | Always fetch latest remote tasks |
task.source_freshness_hash_contents |
bool | false |
Use blake3 content hashing instead of mtime |
task.source_freshness_equal_mtime_is_fresh |
bool | false |
Equal mtime = fresh |
jobs |
int | 8 |
Max concurrent task execution |
Running Tasks (CLI)
Commands
| Command | Description |
|---|---|
mise run <task> / mise r <task> |
Execute task |
mise <task> |
Shorthand (if no command conflict) |
mise tasks / mise tasks ls |
List all tasks |
mise tasks --hidden |
Include hidden tasks |
mise tasks deps |
Show dependency tree |
mise tasks deps --dot |
DOT format for Graphviz |
mise tasks info <task> |
Show task details |
mise tasks add <name> -- <cmd> |
Create task via CLI |
mise watch <task> / mise w <task> |
Watch and re-run on file changes |
Execution Flags
| Flag | Description |
|---|---|
-j, --jobs N |
Parallel job limit (default: 4) |
-f, --force |
Ignore source/output caching |
-n, --dry-run |
Preview without executing |
-o, --output MODE |
prefix, interleave, keep-order, replacing, timed, quiet, silent |
-r, --raw |
Direct stdin/stdout/stderr |
-c, --continue-on-error |
Continue running tasks even if one fails |
-s, --shell SHELL |
Shell spec (default: sh -c -o errexit -o pipefail) |
-t, --tool TOOL@VERSION |
Additional tools beyond mise.toml |
--timings |
Show elapsed time per task |
--timeout DURATION |
Task timeout (e.g., 30s, 5m) |
--fresh-env |
Bypass environment cache |
--skip-deps |
Run only specified tasks, skip dependencies |
--no-cache |
Skip cache on remote tasks |
--no-prepare |
Skip automatic dependency preparation |
Parallel Tasks and Wildcards
mise run test:* # All test:* tasks
mise run lint:** # All nested lint tasks
mise run {build,test} # Multiple specific tasks
mise run lint ::: test ::: check # Parallel task groups with :::
mise run cmd1 arg1 ::: cmd2 arg2 # Parallel with separate args
Default Task
[tasks.default]
depends = ["build", "test"]
run = "echo 'Ready!'"
Task Dependencies and Caching
Dependencies
[tasks.deploy]
depends = ["build", "test", "lint"] # Run before (parallel by default)
depends_post = ["notify"] # Run after
wait_for = ["db:migrate"] # Wait if running, don't add
Caching with sources/outputs
[tasks.build]
sources = ["Cargo.toml", "src/**/*.rs"]
outputs = ["target/release/myapp"]
run = "cargo build --release"
# Skips if sources unchanged and outputs exist
Auto outputs:
[tasks.build]
sources = ["src/**/*.rs"]
outputs = { auto = true } # Implicit tracking via task hash
run = "cargo build"
Redactions (Experimental)
Hide sensitive values from task output:
redactions = ["API_KEY", "PASSWORD", "SECRETS_*"]
Dev Tools Management
Backends Overview
mise supports 18 backend types. Recommended priority order:
| Priority | Backend | Description |
|---|---|---|
| 1 | aqua | Most features, best security (cosign/SLSA/attestation). No plugins needed. |
| 2 | github | GitHub releases with auto OS/arch detection |
| 3 | gitlab | GitLab releases |
| 4 | forgejo | Forgejo/Codeberg releases |
| 5 | http | Direct HTTP/HTTPS downloads with URL templating |
| 6 | s3 | S3/MinIO (experimental) |
| 7 | pipx | Python CLIs in isolated environments |
| 8 | npm | Node packages |
| 9 | go | Go packages (requires compilation) |
| 10 | cargo | Rust packages (requires compilation) |
| 11 | gem | Ruby gems |
| 12 | dotnet | .NET tools (experimental) |
| 13 | conda | Conda packages (experimental) |
| 14 | spm | Swift packages (experimental) |
| 15 | vfox | vfox plugins (cross-platform, Windows) |
| 16 | asdf | asdf plugins (legacy, no Windows) |
TOML Syntax for Tools
[tools]
# Simple version
node = "22"
python = "3.12"
ruby = "latest"
# Multiple versions
python = ["3.12", "3.11"]
# With options
node = { version = "22", postinstall = "corepack enable" }
python = { version = "3.11", os = ["linux", "macos"] }
ripgrep = { version = "latest", os = ["linux", "macos"] }
# Explicit backend
"aqua:BurntSushi/ripgrep" = "latest"
"github:cli/cli" = "latest"
"npm:prettier" = "latest"
"pipx:psf/black" = "latest"
"cargo:eza" = "latest"
"go:github.com/DarthSim/hivemind" = "latest"
Version formats:
| Format | Example | Description |
|---|---|---|
| Exact | "20.0.0" |
Specific version |
| Prefix | "20" |
Latest matching prefix |
| Latest | "latest" |
Most recent stable |
ref:<SHA> |
"ref:abc123" |
Compile from git ref |
path:<PATH> |
"path:/opt/node" |
Use custom binary |
sub-<N>:<BASE> |
"sub-1:latest" |
N versions behind base |
Per-Tool Options
Every tool supports these options regardless of backend:
| Option | Type | Description |
|---|---|---|
version |
string | Tool version |
os |
string[] | Restrict to OS: "linux", "macos", "windows" |
install_env |
table | Environment variables during installation |
postinstall |
string | Command after installation. MISE_TOOL_INSTALL_PATH available. |
Backend-Specific Configuration
GitHub Backend Options
[tools."github:cli/cli"]
version = "latest"
asset_pattern = "gh_*_linux_x64.tar.gz" # Match specific release asset
bin = "gh" # Rename binary
filter_bins = "gh" # Only expose specific bins
no_app = true # Skip macOS .app bundles
HTTP Backend
[tools."http:my-tool"]
version = "1.0.0"
[tools."http:my-tool".platforms]
macos-x64 = { url = "https://example.com/tool-macos-x64.tar.gz", checksum = "sha256:..." }
linux-x64 = { url = "https://example.com/tool-linux-x64.tar.gz", checksum = "sha256:..." }
URL template variables: {{ version }}, {{ os() }}, {{ arch() }}, {{ os_family() }}
OS/arch remapping: {{ os(macos="darwin") }}, {{ arch(x64="amd64") }}
Cargo Backend
[tools]
"cargo:eza" = "latest"
"cargo:cargo-edit" = { version = "latest", features = "add" }
Settings: cargo.binstall = true (use precompiled binaries, default), cargo.binstall_only = false.
Pipx Backend
[tools]
"pipx:black" = "latest"
"pipx:harlequin" = { version = "latest", extras = "postgres,s3" }
"pipx:ansible" = { version = "latest", uvx = false } # Disable uv
Shims and Aliases
Shims location: ~/.local/share/mise/shims
# Shim mode (non-interactive shells)
eval "$(mise activate zsh --shims)" # in ~/.zprofile
# PATH mode (interactive shells)
eval "$(mise activate zsh)" # in ~/.zshrc
Best practice: Use both — shims in profile for non-interactive, PATH activation in rc for interactive.
Tool aliases (remap to different backend):
[tool_alias]
node = 'asdf:company/our-custom-node'
[tool_alias.node.versions]
lts = '22'
Shell aliases:
[shell_alias]
ll = "ls -la"
gs = "git status"
CLI Commands for Tools
mise use node@22 # Install + activate + write to mise.toml
mise use -g node@22 # Write to global config
mise install node@20 # Install without activation
mise install # Install all configured tools
mise ls # List installed
mise ls-remote node # List available versions
mise which node # Show real binary path
mise x python@3.12 -- script.py # Run with specific tool
mise reshim # Rebuild shims
mise registry # List all available tools
Environment Configuration
Basic Variables
[env]
NODE_ENV = 'production'
DEBUG = 'app:*'
PORT = 3000
# Unset a variable
UNWANTED_VAR = false
mise set NODE_ENV=development # Set via CLI
mise set # View all
mise unset NODE_ENV # Remove
mise env # Export all
mise env --json # Export as JSON
mise env --dotenv # Export as dotenv
Special Directives (env._)
_.path — Prepend to PATH
[env]
_.path = ["tools/bin", "{{config_root}}/scripts"]
_.path = { path = ["{{env.GEM_HOME}}/bin"], tools = true } # Lazy eval
_.file — Load from .env/json/yaml files
[env]
_.file = '.env'
_.file = ['.env', '.env.local', '.env.{{env.MISE_ENV}}']
_.file = { path = ".secrets.yaml", redact = true }
_.source — Source shell scripts
[env]
_.source = "./setup-env.sh"
_.source = { path = "my/env.sh", tools = true }
Profiles (MISE_ENV)
Profiles enable environment-specific config files:
MISE_ENV=staging mise run deploy
This loads mise.staging.toml in addition to mise.toml. Config file order:
mise.toml(base)mise.staging.toml(profile overlay)mise.staging.local.toml(local overrides, gitignored)
Important: MISE_ENV cannot be set in mise.toml — it must be in .miserc.toml, an env var, or CLI flag because it determines which config files to load.
Required and Redacted Variables
[env]
# Required — error if not set
DATABASE_URL = { required = "Set postgres connection string" }
# Redacted — hidden from output
API_KEY = { value = "secret_key_here", redact = true }
redactions = ["*_TOKEN", "SECRET_*", "API_*"]
Templates (Tera)
mise.toml values support Tera templates:
[env]
PROJECT_DIR = "{{config_root}}"
LOG_FILE = "{{config_root}}/logs/{{now() | date(format='%Y-%m-%d')}}.log"
NODE_PATH = "{{env.npm_config_prefix}}/lib/node_modules"
Available template variables:
| Variable | Description |
|---|---|
env.* |
Current environment variables |
config_root |
Directory containing mise.toml |
cwd |
Current working directory |
mise_bin |
Path to mise binary |
mise_pid |
Process ID |
xdg_cache_home |
XDG cache directory |
xdg_config_home |
XDG config directory |
xdg_data_home |
XDG data directory |
xdg_state_home |
XDG state directory |
Key Tera functions:
| Function | Description |
|---|---|
exec(command="cmd") |
Execute shell command, return stdout |
arch() |
System architecture |
os() |
Operating system |
os_family() |
OS family (unix/windows) |
num_cpus() |
CPU count |
now() |
Current datetime |
get_env(name, default) |
Get env var with fallback |
chomp(str) |
Remove trailing newline |
Key Tera filters:
| Filter | Description |
|---|---|
lower, upper, capitalize |
Case transforms |
trim, replace(from, to) |
String manipulation |
split(pat), join(sep) |
Array operations |
basename, dirname, extname |
Path operations |
hash, hash_file |
SHA256/BLAKE3 hashing |
absolute, canonicalize |
Path resolution |
kebabcase, snakecase, uppercamelcase |
Case conversion |
Shell-style variable expansion (requires env_shell_expand = true):
[settings]
env_shell_expand = true
[env]
LD_LIBRARY_PATH = "$MY_LIB:$LD_LIBRARY_PATH"
Hooks and Watchers
Hook Types
| Hook | Trigger | Requires mise activate? |
|---|---|---|
cd |
Directory changes | Yes |
enter |
Enter a project (once) | Yes |
leave |
Leave a project (once) | Yes |
preinstall |
Before tool installation | No |
postinstall |
After tool installation | No |
Syntax
[hooks]
cd = "echo 'changed directory'"
enter = "echo 'entered project'"
leave = "echo 'left project'"
preinstall = "echo 'about to install'"
postinstall = "echo 'installed'"
# Multiple hooks
enter = ["echo 'first'", "echo 'second'"]
# Shell hooks (execute in current shell context)
[hooks.enter]
shell = "bash"
script = "source completions.sh"
Watch Files
[[watch_files]]
patterns = ["src/**/*.rs"]
run = "cargo fmt"
Sets MISE_WATCH_FILES_MODIFIED env var. Requires watchexec.
Hook Environment Variables
All hooks receive: MISE_ORIGINAL_CWD, MISE_PROJECT_ROOT, MISE_PREVIOUS_DIR (cd hooks).
Postinstall receives: MISE_INSTALLED_TOOLS (JSON array), MISE_TOOL_NAME, MISE_TOOL_VERSION, MISE_TOOL_INSTALL_PATH.
Configuration and Settings
File Hierarchy
Config files in precedence order (highest first):
mise.local.tomlmise.tomlmise/config.toml.mise/config.toml.config/mise.toml.config/mise/config.toml.config/mise/conf.d/*.toml(alphabetical)
Global: ~/.config/mise/config.toml
System: /etc/mise/config.toml
Legacy: .tool-versions (asdf-compatible)
mise searches upward from cwd to root (or MISE_CEILING_PATHS). Merge behavior:
- Tools: Additive with overrides
- Env vars: Additive with overrides
- Tasks: Completely replaced per task name
- Settings: Additive with overrides
Key Settings Reference
[settings]
# Execution
jobs = 8 # Concurrent jobs
experimental = false # Enable experimental features
# Task defaults
task_output = "prefix" # prefix|interleave|keep-order|replacing|timed|quiet|silent
task_timeout = "10m" # Default task timeout
task_timings = true # Show elapsed time
task_skip = ["slow-task"] # Tasks to skip
task_skip_depends = false # Skip dependencies
# Environment
env_shell_expand = true # Enable $VAR expansion
env_cache = false # Cache computed environment
env_cache_ttl = "1h" # Cache TTL
# Tool management
auto_install = true # Auto-install missing tools
disable_backends = ["asdf"] # Disable backends
pin = false # Default --pin for mise use
lockfile = true # Read/update lockfiles
# Security
paranoid = false # Extra-secure behavior
gpg_verify = false # Verify GPG signatures
# Performance
fetch_remote_versions_cache = "1h" # Version cache
http_timeout = "30s" # HTTP timeout
# Node-specific
[settings.node]
corepack = false # Enable corepack
compile = false # Compile from source
# Python-specific
[settings.python]
uv_venv_auto = false # Auto-create venv with uv
compile = false # Compile from source
# Aqua security
[settings.aqua]
cosign = true # Verify Cosign signatures
slsa = true # Verify SLSA provenance
Minimum Version
min_version = '2024.11.1' # Hard (errors)
min_version = { soft = '2024.11.1' } # Soft (warns)
min_version = { hard = '2024.11.1', soft = '2024.9.0' } # Both
Automatic Environment Variables
Tasks automatically receive:
| Variable | Description |
|---|---|
MISE_ORIGINAL_CWD |
Original working directory |
MISE_CONFIG_ROOT |
Directory containing mise.toml |
MISE_PROJECT_ROOT |
Project root directory |
MISE_TASK_NAME |
Current task name |
MISE_TASK_DIR |
Task script directory |
MISE_TASK_FILE |
Full path to task script |
Prepare Feature (Experimental)
Ensures dependencies are installed before task execution.
export MISE_EXPERIMENTAL=1
mise prepare
[prepare.npm]
auto = true
[prepare.custom]
sources = ["schema/*.graphql"]
outputs = ["src/generated/"]
run = "npm run codegen"
Built-in providers: npm, yarn, pnpm, bun, go, pip, poetry, uv, bundler, composer.
Monorepo Tasks (Experimental)
# Root mise.toml
experimental_monorepo_root = true
Requires MISE_EXPERIMENTAL=1.
mise //projects/frontend:build # Absolute path from root
mise :build # Task in current config_root
mise '//projects/frontend:*' # All tasks in frontend
mise //...:test # Test task in all projects
Settings:
[settings.task]
monorepo_depth = 5
monorepo_exclude_dirs = ["dist", "node_modules"]
monorepo_respect_gitignore = true
Best Practices
DO
- Always use
usagefield for task arguments - Use
${var?}for required args to fail early - Set
descriptionfor discoverability - Use
sources/outputsfor cacheable tasks - Use
dependsfor task ordering - Use
confirmfor destructive operations - Use
choicesfor stable enums,completefor dynamic/filesystem-derived values - Group related tasks with namespaces (e.g.,
test:unit,test:e2e) - Use
mise.local.tomlfor personal overrides (gitignored) - Prefer aqua backend for security (cosign/SLSA verification)
- Use
env._.filefor dotenv loading instead ofMISE_ENV_FILE - Redact sensitive values with
redact = true - Use templates for dynamic values instead of hardcoding paths
- Use
extendsto share config between similar tasks
DON'T
- Use
$1,$2,$@,$*for arguments - Use
$argsin PowerShell - Use inline
{{arg(name="x")}}syntax (deprecated, removed 2026.11) - Forget to quote glob patterns in sources
- Set env vars in
envthat deps need (they don't inherit — use structureddependswithenv) - Use
raw = trueunless interactive input needed - Set
MISE_ENVinmise.toml(it determines which files to load) - Manually add executables to shims directory (
mise reshimremoves them) - Use
MISE_RAW=1without knowing it setsMISE_JOBS=1
Complete Task Example
[tasks.deploy]
description = "Deploy application to environment"
alias = "d"
depends = ["build", "test"]
usage = '''
arg "<env>" choices "dev" "staging" "prod" help="Target environment"
flag "-f --force" help="Skip confirmation"
flag "--dry-run" help="Preview only"
'''
env = { DEPLOY_TIMESTAMP = "{{now()}}" }
tools = { node = "22" }
sources = ["dist/**/*"]
timeout = "5m"
confirm = "Deploy to {{usage.env}}?"
run = '''
#!/usr/bin/env bash
set -euo pipefail
if [ -n "${usage_dry_run:-}" ]; then
echo "DRY RUN: Would deploy to ${usage_env?}"
exit 0
fi
./scripts/deploy.sh "${usage_env?}"
'''
Complete File Task Example
#!/usr/bin/env bash
#MISE description="Run database migrations"
#MISE alias="migrate"
#MISE depends=["db:check"]
#MISE tools={postgresql="16"}
#USAGE arg "<direction>" choices "up" "down" help="Migration direction"
#USAGE flag "-n --count <n>" default="1" help="Number of migrations"
#USAGE flag "--dry-run" help="Preview SQL only"
set -euo pipefail
direction="${usage_direction?}"
count="${usage_count:-1}"
if [ -n "${usage_dry_run:-}" ]; then
echo "Would run $count migration(s) $direction"
exit 0
fi
migrate "$direction" -n "$count"
Complete Dev Tools + Env Example
min_version = "2024.11.1"
[settings]
jobs = 8
task_output = "interleave"
task_timings = true
env_shell_expand = true
[tools]
node = "22"
python = { version = "3.12", postinstall = "pip install -r requirements.txt" }
"aqua:BurntSushi/ripgrep" = "latest"
"npm:prettier" = "latest"
[env]
NODE_ENV = "development"
DATABASE_URL = { required = "Set postgres connection string" }
API_KEY = { value = "{{env.API_KEY}}", redact = true }
_.path = ["./node_modules/.bin", "{{config_root}}/scripts"]
_.file = [".env", ".env.local"]
[hooks]
enter = "echo 'Welcome to {{vars.project_name}}'"
[vars]
project_name = "myapp"
[tasks.dev]
description = "Start development server"
depends = ["build"]
tools = { node = "22" }
run = "npm run dev"
[tasks.build]
description = "Build project"
sources = ["src/**/*.ts", "tsconfig.json"]
outputs = ["dist/**/*"]
run = "tsc --build"
[tasks.test]
description = "Run tests"
depends = ["build"]
run = "vitest run"