Claude
Skills
Sign in
Back

mise

Included with Lifetime
$97 forever

Mise configuration patterns, task definitions, hooks, presets, and language-specific setup guidance for dev environment management and project tooling.

Productivity

What this skill does


# mise

mise is a polyglot tool version manager and task runner. A single `mise.toml` replaces Makefiles, shell scripts, and language-specific version managers (nvm, pyenv, rustup). It manages tool versions, defines project tasks, and sets environment variables from one configuration file.

## Config File Structure

Order sections canonically for consistency:

```toml
min_version = "2024.9.5"

[env]
DATABASE_URL = "postgres://localhost/myapp_dev"

[tools]
python = "3.12"

[tasks]
test.run = "pytest"

[settings]
auto_install = true
not_found_auto_install = true
task_run_auto_install = true
```

Use `min_version` to enforce a minimum mise version. Recognized top-level sections: `[env]`, `[tools]`, `[tasks]`, `[settings]`, `[plugins]`, `[tool_alias]`, `[task_config]`, `[vars]`.

## Tool Version Management

Pin every tool to a concrete semver (`"0.15.16"`), never `"latest"` or `"lts"`. Where a repo extends `basher83/renovate-config`, the mise preset auto-merges tool bumps — but only for semver-pinned entries. `"latest"` is invisible to renovate's mise manager, so it silently strands a tool at whatever version installed first; a semver pin gets the same currency plus renovate visibility and rollback. (`"latest"` once froze hk at 1.36.0, three minors past the 1.40.0 fix for its config-cache round-trip bug.) Produce pins by **resolve-then-pin**: `mise use --pin <tool>` resolves the current version and writes it exactly, and global `MISE_PIN=1` makes that the default; bare `mise use <tool>` writes the unpinnable `"latest"` under mise's fuzzy default. Do not phrase this guidance as "resolve live" or "never hardcode" — agents read that as "use `latest`"; name the `--pin` mechanism explicitly. The format table below catalogs what mise accepts; this policy governs what to write.

Specify tools in the `[tools]` section. mise installs and activates them automatically.

```toml
[tools]
node = "22"                   # Major version prefix
python = "3.12.2"             # Exact version
go = "latest"                 # Latest stable
erlang = "lts"                # LTS channel
```

Multiple versions install side-by-side (first is default):

```toml
[tools]
python = ["3.11", "3.12"]
```

### Version formats

| Format | Example | Behavior |
|--------|---------|----------|
| Exact | `"3.12.2"` | Specific version |
| Prefix | `"3.12"` | Latest matching 3.12.x |
| Channel | `"latest"`, `"lts"` | Resolved at install time |
| Reference | `"ref:main"` | Git ref, compiled from source |
| Subtraction | `"sub-1:latest"` | One major behind latest |

### Table form with options

```toml
[tools]
node = { version = "22", postinstall = "corepack enable" }
rust = { version = "stable", components = "clippy,rustfmt", profile = "default" }
```

### Backend syntax for non-core tools

```toml
[tools]
"ubi:astral-sh/ruff" = "0.15.16"     # GitHub binary releases
"cargo:cargo-watch" = "8.5.3"        # Cargo crate
"npm:prettier" = "3.4.2"             # npm package
"pipx:ansible-lint" = "25.1.3"       # Python CLI tools via pipx
```

### Custom plugins

Register custom tool plugins in `[plugins]`:

```toml
[plugins]
fnox-env = "https://github.com/jdx/mise-env-fnox"
```

## Task Definitions

Tasks are defined in `[tasks]` or as executable files in `.mise/tasks/`.

### Inline tasks

```toml
tasks.test = "pytest"
tasks.lint = "ruff check ."
tasks.format = "ruff format ."
```

### Table tasks

```toml
[tasks.build]
description = "Build the project"
depends = ["lint"]
run = "cargo build --release"
dir = "{{config_root}}/backend"
env = { RUST_LOG = "info" }
sources = ["src/**/*.rs", "Cargo.toml"]
outputs = ["target/release/myapp"]
```

### Task-level options

Pin tool versions per-task, set aliases for shortcuts, or override the shell:

```toml
[tasks."lint:shellcheck"]
description = "Lint shell scripts"
run = "shellcheck scripts/*.sh"
tools = { "shellcheck" = "0.11.0" }    # Pin tool version for this task
alias = "sc"                            # Short alias for mise run sc
shell = "bash -c"                       # Override default shell
```

### Task directory scoping

Use `dir` to run a task in a specific subdirectory. Essential for monorepos and infrastructure projects where different tasks target different paths:

```toml
[tasks.prod-validate]
description = "Validate production Terraform"
dir = "infrastructure/environments/production"
run = "terraform init -backend=false -input=false >/dev/null && terraform validate"

[tasks.prod-plan]
description = "Plan production changes"
dir = "infrastructure/environments/production"
run = "terraform plan"
```

Relative paths resolve from the config file's directory. Use `{{config_root}}` for explicit anchoring. When multiple tasks share a base directory, the pattern of environment-scoped tasks (same command, different `dir`) keeps configs DRY while remaining explicit about scope.

### Multi-line scripts

```toml
[tasks.setup]
run = [
  "pip install -e '.[dev]'",
  "pre-commit install"
]
```

### File-based tasks

Place executable scripts in `.mise/tasks/`. Subdirectories create namespaces — `.mise/tasks/db/migrate` becomes task `db:migrate`.

```bash
#!/usr/bin/env bash
#MISE description="Run database migrations"
#MISE depends=["db:check"]

alembic upgrade head
```

Mark file tasks executable (`chmod +x`). Any language works via shebang.

### Task arguments

```toml
[tasks.deploy]
usage = '''
arg "<environment>" help="Target environment" default="staging"
flag "-v --verbose" help="Verbose output"
'''
run = "deploy.sh ${usage_environment}"
```

## Namespace Taxonomy

Name tasks as `namespace:verb`. The namespace is a domain noun, the verb is an action. This groups related tasks alphabetically in `mise tasks` output.

```toml
# Per-project namespaces use the project's domain
tasks."vault:triage" = "claude --print /inbox-process"
tasks."cluster:deploy" = "talosctl apply-config"

# Cross-project namespaces for shared concerns
tasks."cc:prime" = "claude --print /vault-prime"
tasks."git:clean" = "git branch --merged | grep -v main | xargs git branch -d"
```

Use the project's primary domain noun as the namespace. Avoid generic names like `run:` or `do:`.

## Environment Variables

```toml
[env]
NODE_ENV = "development"
PROJECT_ROOT = "{{config_root}}"

# Load from dotenv
_.file = ".env"

# Python virtual environment
_.python.venv = { path = ".venv", create = true }
```

Template variables: `{{config_root}}` (directory containing mise.toml), `{{env.VAR}}` (existing env vars).

## Layered Configuration

mise resolves configuration from multiple levels, with closer files taking precedence:

```text
~/.config/mise/config.toml       # Global: cross-cutting tools and tasks
./mise.toml                      # Project: local tools and tasks
./mise.local.toml                # Local overrides (gitignored)
```

Global config handles cross-cutting concerns (shared tools, repo orchestration tasks). Project config handles repo-specific tools and tasks. Global tasks never assume a specific repo structure — use environment variables or auto-detection.

Use `mise.local.toml` (gitignored) for environment-specific overrides. Tasks can generate this file to switch environments:

```toml
[tasks."env:local"]
description = "Switch to local LAN environment"
run = '''
cat > .mise.local.toml << 'EOF'
[env]
NOMAD_ADDR = "http://192.168.11.11:4646"
CONSUL_HTTP_ADDR = "http://192.168.11.11:8500"
EOF
echo "Switched to local. Run 'mise trust' to apply."
'''
```

## Task Dependencies

```toml
[tasks.check]
description = "Full quality gate"
depends = ["format:check", "lint", "test"]

[tasks.deploy]
depends = ["check"]
depends_post = ["notify"]           # Runs after this task completes
wait_for = ["build"]                # Waits without forcing execution
```

Independent dependencies run in parallel by default. Control parallelism with `[settings] jobs = 4`.

## Version Resolution

Never hardcode tool versions from training data — they will be wrong. Always resolve versions at runtime through mi

Related in Productivity