mise (mise-en-place) - Development Environment Tool
What is mise?
mise (pronounced "meez") is a development environment setup tool that manages:
- Dev Tools: Installing, pinning, and switching programming languages and tools
- Environments: Loading project-specific environment variables
- Tasks: Running project automation for build, test, lint, deploy, and everyday workflows
mise supports hundreds of development tools and can automatically switch between different versions based on your project directory.
Installation
Quick Install (Linux/macOS)
curl https://mise.run | shOther Methods
- Homebrew:
brew install mise - Windows:
winget install jdx.miseorscoop install mise - Debian/Ubuntu: Available via apt repository
- Fedora: Available via dnf repository
Core Configuration
mise.toml
The main configuration file for mise. Can be named:
mise.toml(project-specific)mise.local.toml(local, not committed to git)~/.config/mise/config.toml(global)
Example mise.toml:
[tools]
node = "20"
python = "3.11"
terraform = "1.0.0"
go = "latest"
[env]
NODE_ENV = "development"
DATABASE_URL = "postgresql://localhost/myapp"
[tasks.test]
run = "npm test"
description = "Run tests"
[tasks.build]
run = "npm run build"
deps = ["test"].tool-versions (asdf compatibility)
mise is compatible with asdf's .tool-versions format:
node 20.0.0
python 3.11.5
terraform 1.0.0Essential Commands
Tool Management
mise use node@20- Install and set node version (updates config)mise use -g node@20- Set global defaultmise install- Install all tools from configmise install node@20- Install specific versionmise ls- List installed toolsmise ls-remote node- List available versions
Execution
mise exec node@20 -- node script.js- Run command with specific tool versionmise x node@20 -- node script.js- Shorthand for execmise run test- Run defined taskmise test- Shorthand (if no command conflict)
Environment
mise activate bash- Activate mise in shell (add to .bashrc)mise activate zsh- Activate mise in zsh (add to .zshrc)mise activate fish- Activate mise in fishmise env- Show current environmentmise set KEY=value- Set environment variable
Information
mise doctor- Check mise setupmise config- Show loaded config filesmise current- Show active tool versionsmise which node- Show path to tool
Key Concepts
Activation vs Shims vs Exec
- Activation (
mise activate): Recommended for interactive shells. Updates PATH automatically when changing directories. - Shims: Symlinks that intercept tool calls. Good for CI/CD and IDEs.
- Exec (
mise exec): Run commands with mise environment without activation.
Tool Scopes
[email protected]- Exact versionnode@20- Latest 20.x versionnode@latest- Latest available versionnode@lts- Latest LTS versionref:master- Build from git refprefix:1.19- Latest matching prefixpath:/custom/path- Use custom installation
Configuration Hierarchy
Config files are loaded in order (later overrides earlier):
- Global:
~/.config/mise/config.toml - Parent directories:
mise.tomlfiles going up the tree - Current directory:
mise.toml - Local:
mise.local.toml
Tasks
TOML Tasks
[tasks.build]
run = "cargo build"
description = "Build the project"
depends = ["install"]
[tasks.test]
run = "cargo test"
depends = ["build"]File Tasks
Create executable scripts in mise-tasks/ directory:
#!/usr/bin/env bash
#MISE description="Run tests"
cargo testTask Features
- Parallel execution by default
- Dependency management
- File watching (
mise watch) - Environment variable passing
Environment Variables
Settings
MISE_DATA_DIR- Where tools are installed (~/.local/share/mise)MISE_CONFIG_DIR- Config directory (~/.config/mise)MISE_CACHE_DIR- Cache directoryMISE_GITHUB_TOKEN- GitHub token for API access
Tool-specific
MISE_NODE_VERSION=20- Override node versionMISE_PYTHON_VERSION=3.11- Override python version
Common Patterns
Project Setup
# Initialize project
cd my-project
mise use node@20 [email protected]
mise install
# Add environment variables
mise set NODE_ENV=development
mise set DATABASE_URL=postgresql://localhost/myappGlobal Tools
# Set global defaults
mise use -g node@lts [email protected] go@latestCI/CD
# Install mise and tools
curl https://mise.run | sh
export PATH="$HOME/.local/bin:$PATH"
mise install
mise run buildTroubleshooting
Common Issues
- Rate limiting: Set
MISE_GITHUB_TOKENfor GitHub API access - Tool not found: Run
mise doctorto check setup - Slow performance: Check
mise cache clearif stale - Permission errors: Ensure proper file permissions
Debugging
mise doctor- Comprehensive health checkmise config- Show config file loading ordermise env- Show current environmentmise which <tool>- Show tool path resolution
Plugin System
mise uses plugins to support different tools:
- Compatible with asdf plugins
- Automatic plugin installation
- Custom plugin repositories supported
- Plugin shortcuts in registry
Migration from asdf
mise is largely compatible with asdf:
- Reads
.tool-versionsfiles - Uses asdf plugins
- Similar commands (with improvements)
- Can run alongside asdf temporarily
Best Practices
- Use
mise.tomlfor committed project configuration - Use
mise.local.tomlfor local overrides - Activate mise in shell for interactive use
- Use shims for CI/CD and IDE integration
- Set
MISE_GITHUB_TOKENto avoid rate limits - Use
mise doctorregularly to check setup - Pin versions in production environments
- Use tasks for project automation
Advanced Features
Tool Options
[tools]
node = { version = "20", postinstall = "corepack enable" }
python = { version = "3.11", virtualenv = "myproject" }Hooks
[hooks]
enter = "mise install --quiet"
leave = "deactivate"Multiple Versions
[tools]
python = ["3.10", "3.11", "3.12"] # Install multiple versionsDevelopment & Contributing
Setting Up Development Environment
mise is written in Rust and uses itself for development tasks. To contribute to mise:
Prerequisites
- Rust (latest stable)
- Node.js
pipxoruv- Bash (newer than macOS default)
Getting Started
# Clone the repository
git clone https://github.com/jdx/mise.git
cd mise
# Install dependencies and build
mise run build
# Run sanity check
mise run buildDevelopment Setup
Create a development shim to easily run mise during development:
# Create ~/.local/bin/@mise
#!/bin/sh
exec cargo run -q --all-features --manifest-path ~/src/mise/Cargo.toml -- "$@"Then use @mise to run the development version:
@mise --help
eval "$(@mise activate zsh)"Testing
mise has a comprehensive test suite with multiple types of tests to ensure reliability and functionality across different platforms and scenarios.
Unit Tests
Unit tests are fast, focused tests for individual components and functions:
# Run all unit tests
cargo test --all-features
# Run specific unit tests
cargo test <test_name>
# Run tests with verbose output
cargo test --all-features -- --nocapture
# Run tests in series (not parallel)
RUST_TEST_THREADS=1 cargo test --all-featuresUnit test structure:
- Located in
src/directory alongside source code - Use Rust's built-in test framework
- Test individual functions and modules
- Fast execution (used for quick feedback during development)
E2E Tests
End-to-end tests validate the complete functionality of mise in realistic scenarios:
# Run all E2E tests
mise run test:e2e
# Run specific E2E test
./e2e/run_test test_name
# Run E2E tests matching pattern
./e2e/run_test task # runs tests matching *task*
# Run all tests including slow ones
TEST_ALL=1 mise run test:e2eE2E test structure:
- Located in
e2e/directory - Organized by functionality:
e2e/cli/- Command-line interface testse2e/core/- Core functionality testse2e/env/- Environment variable testse2e/tasks/- Task runner testse2e/config/- Configuration testse2e/tools/- Tool management testse2e/shell/- Shell integration testse2e/backend/- Backend testse2e/plugins/- Plugin tests
E2E test categories:
- Fast tests (
test_*): Run in normal test suites - Slow tests (
test_*_slow): Only run whenTEST_ALL=1is set - Isolated environment: Each test runs in a clean, isolated environment
Coverage Tests
Coverage tests measure how much of the codebase is covered by tests:
# Run coverage tests
mise run test:coverage
# Coverage tests run in parallel tranches for CI
TEST_TRANCHE=0 TEST_TRANCHE_COUNT=8 mise run test:coverageWindows E2E Tests
Windows has its own test suite written in PowerShell:
# Run all Windows E2E tests
pwsh e2e-win\run.ps1
# Run specific Windows tests
pwsh e2e-win\run.ps1 task # run tests matching *task*Plugin Tests
Test plugin functionality across different backends:
# Test specific plugin
mise test-tool ripgrep
# Test all plugins in registry
mise test-tool --all
# Test all plugins in config files
mise test-tool --all-config
# Test with parallel jobs
mise test-tool --all --jobs 4Test Environment Setup
Tests run in isolated environments to avoid conflicts:
# Disable mise during development testing
export MISE_DISABLE_TOOLS=1
# Run tests with specific environment
MISE_TRUSTED_CONFIG_PATHS=$PWD cargo testTest Assertions
The E2E tests use a custom assertion framework (e2e/assert.sh):
# Basic assertions
assert "command" "expected_output"
assert_contains "command" "substring"
assert_fail "command" "expected_error"
# JSON assertions
assert_json "command" '{"key": "value"}'
assert_json_partial_array "command" "fields" '[{...}]'
# File/directory assertions
assert_directory_exists "/path/to/dir"
assert_directory_not_exists "/path/to/dir"
assert_empty "command"Running Specific Test Categories
# Run all tests (unit + e2e)
mise run test
# Run only unit tests
mise run test:unit
# Run only e2e tests
mise run test:e2e
# Run tests with shuffle (for detecting order dependencies)
mise run test:shuffle
# Run nightly tests (with bleeding edge Rust)
rustup default nightly && mise run testRunning Single Tests
Unit Tests:
# Run a specific unit test by name
cargo test test_name
# Run tests matching a pattern
cargo test pattern
# Run tests in a specific module
cargo test module_name
# Run a single test with output
cargo test test_name -- --nocapture
# Run a single test file (if organized by file)
cargo test --test test_file_nameE2E Tests:
# Run a specific E2E test by name
./e2e/run_test test_name
# Run E2E tests matching a pattern
mise run test:e2e pattern
# Examples:
./e2e/run_test test_use # Run specific test
./e2e/run_test test_config_set # Run config-related test
mise run test:e2e task # Run all tests matching "task"Plugin Tests:
# Test a specific plugin
mise test-tool ripgrep
# Test a plugin with verbose output
mise test-tool ripgrep --raw
# Test multiple plugins
mise test-tool ripgrep jq terraformWindows Tests:
# Run a specific Windows test
pwsh e2e-win\run.ps1 -TestName "test_name"
# Run tests matching a pattern
pwsh e2e-win\run.ps1 taskTest Development Tips
- Test naming: Use descriptive names that explain what's being tested
- Test isolation: Each test should be independent and clean up after itself
- Use slow tests sparingly: Mark long-running tests as
_slowto avoid CI timeouts - Mock external dependencies: Use dummy plugins and mock data when possible
- Test edge cases: Include tests for error conditions and boundary cases
Performance Testing
# Run performance benchmarks
mise run test:perf
# Build performance test workspace
mise run test:build-perf-workspaceSnapshot Testing
Used for testing output consistency:
# Update test snapshots when output changes
mise run snapshots
# Use cargo-insta for snapshot testing
cargo insta test --accept --unreferenced deleteAvailable Development Tasks
Use mise tasks to see all available development tasks:
Common Tasks
mise run build- Build the projectmise run test- Run all tests (unit + E2E)mise run test:unit- Run unit tests onlymise run test:e2e- Run E2E tests onlymise run lint- Run lintingmise run lint:fix- Run linting with fixesmise run format- Format codemise run clean- Clean build artifactsmise run snapshots- Update test snapshotsmise run render- Generate documentation and completions
Documentation Tasks
mise run docs- Start documentation development servermise run docs:build- Build documentationmise run render:help- Generate help documentationmise run render:completions- Generate shell completions
Release Tasks
mise run ci- Run CI tasks (format, build, test)
Project Structure
mise/
โโโ src/ # Main Rust source code
โโโ e2e/ # End-to-end tests
โโโ docs/ # Documentation
โโโ tasks.toml # Development tasks
โโโ mise.toml # Project configuration
โโโ Cargo.toml # Rust project configuration
โโโ xtasks/ # Additional build scriptsPre-commit Hooks & Code Quality
mise uses multiple approaches for ensuring code quality and running pre-commit hooks:
hk (Modern Hook Manager)
mise uses hk (pronounced "hook") as its primary hook manager for linting and code quality checks. hk is a modern alternative to lefthook written by the same author as mise.
hk Configuration:
The project uses hk.pkl (written in the Pkl configuration language) to define linting rules:
# Run all linting checks
hk check --all
# Run linting with fixes
hk fix --all
# Run specific linter
hk check --step shellcheckAvailable Linters in hk:
- prettier: Code formatting for multiple languages
- clippy: Rust linting with
cargo clippy - shellcheck: Shell script linting
- shfmt: Shell script formatting
Using hk in Development:
# Install hk via mise
mise use hk
# Run linting (used in CI and pre-commit)
mise run lint # This runs hk check --all
# Run linting with fixes
hk fix --all
# Check specific file types
hk check --step prettier
hk check --step shellcheckTraditional Pre-commit Hooks (Alternative)
mise also supports traditional pre-commit hooks through multiple methods:
Option 1: Using lefthook (Legacy)
# Install lefthook
mise use lefthook
# Install the git hooks
lefthook install
# Run pre-commit manually
lefthook run pre-commitOption 2: Using standard pre-commit framework
# Install pre-commit
mise use pre-commit
# Install the git hooks
pre-commit install
# Run pre-commit manually
pre-commit run --all-filesOption 3: Using mise's built-in git hook generation
# Generate a git pre-commit hook that runs mise tasks
mise generate git-pre-commit --write --task=pre-commit
# This creates .git/hooks/pre-commit that runs:
# mise run pre-commitPre-commit Task Configuration
mise defines a pre-commit task that runs the main linting checks:
[pre-commit]
env = { PRE_COMMIT = 1 }
run = ["mise run lint"]This task:
- Sets
PRE_COMMIT=1environment variable - Runs
mise run lint, which executeshk check --all
Setting Up Pre-commit Hooks
Recommended approach using hk:
# Install hk
mise use hk
# Set up git hook to run mise's pre-commit task
mise generate git-pre-commit --write --task=pre-commit
# Or manually create .git/hooks/pre-commit:
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
exec mise run pre-commit
EOF
chmod +x .git/hooks/pre-commitAlternative approach using standard pre-commit:
# Install pre-commit
mise use pre-commit
# Install hooks defined in .pre-commit-config.yaml
pre-commit installRunning Pre-commit Checks Manually
# Run all pre-commit checks
mise run pre-commit
# Run specific linting checks
mise run lint
# Run linting with fixes
hk fix --all
# Run checks on specific files
hk check --files="src/**/*.rs"Environment Variables for Hooks
When hooks run, they have access to these environment variables:
PRE_COMMIT=1: Indicates the code is running in pre-commit contextSTAGED: Git staged files (when using mise's git hook generation)MISE_PRE_COMMIT=1: Set by mise's generated git hooks
Testing Configuration
- Unit tests: Fast tests for individual components
- E2E tests: Integration tests that test the full application
- Slow tests: Only run with
TEST_ALL=1environment variable - Windows tests: Separate PowerShell-based test suite
Development Tips
- Disable mise during development: If you use mise in your shell, disable it when running tests to avoid conflicts
- Use dev container: Docker setup available (currently needs fixing)
- Test specific features: Use
cargo test <test_name>for targeted testing - Update snapshots: Use
mise run snapshotswhen changing test outputs - Rate limiting: Set
MISE_GITHUB_TOKENto avoid GitHub API rate limits during development
Dependency Management
mise uses several tools to validate dependencies and code quality:
- cargo-deny: Validates licenses, security advisories, and dependency duplicates
- cargo-msrv: Verifies minimum supported Rust version compatibility
- cargo-machete: Detects unused dependencies in Cargo.toml
These checks run automatically in CI and can be run locally:
# Install tools
mise use cargo-deny cargo-msrv cargo-machete
# Run checks
cargo deny check
cargo msrv verify
cargo machete --with-metadataContributing Guidelines
- Before starting: File an issue or discuss in Discord for non-obvious changes
- Look for issues: Check "help wanted" and "good first issue" labels
- Test thoroughly: Ensure both unit and E2E tests pass
- Follow conventions: Use existing code style and patterns
- Update documentation: Add/update docs for new features
Pull Request Workflow
- PR titles: Must follow conventional commit format (validated automatically)
- Auto-formatting: Code will be automatically formatted by autofix.ci
- CI checks: All tests must pass across Linux, macOS, and Windows
- Coverage: New code should maintain or improve test coverage
- Dependencies: New dependencies are validated with cargo-deny
GitHub Actions Development
If modifying GitHub Actions workflows:
- Run
mise run lintfor the repository's configured checks - Self-hosted runners are configured for performance testing
- Run the zizmor workflow for security auditing
Conventional Commits
mise uses Conventional Commits for consistent commit messages and automated changelog generation. All commits should follow this format:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]Commit Types
- feat: New features (๐ Features)
- fix: Bug fixes (๐ Bug Fixes)
- refactor: Code refactoring (๐ Refactor)
- doc: Documentation changes (๐ Documentation)
- style: Code style changes (๐จ Styling)
- perf: Performance improvements (โก Performance)
- test: Testing changes (๐งช Testing)
- chore: Maintenance tasks, dependency updates
- revert: Reverting previous changes (โ๏ธ Revert)
Examples
feat(cli): add new command for listing plugins
fix(parser): handle edge case in version parsing
refactor(config): simplify configuration loading logic
doc(readme): update installation instructions
test(e2e): add tests for new plugin functionality
chore(deps): update dependencies to latest versionsScopes
Common scopes used in mise:
cli- Command line interface changesconfig- Configuration system changesparser- Parsing logic changesdeps- Dependency updatessecurity- Security-related changes
Breaking Changes
For breaking changes, add ! after the type or include BREAKING CHANGE: in the footer:
feat(api)!: remove deprecated configuration options
# OR
feat(api): remove deprecated configuration options
BREAKING CHANGE: The old configuration format is no longer supportedPackaging Testing
For testing package installation:
Ubuntu/Debian
# Test apt installation
docker run -ti --rm ubuntu
apt update -y && apt install -y curl
# ... installation stepsFedora
# Test dnf installation
docker run -ti --rm fedora
dnf install -y dnf-plugins-core
# ... installation stepsCI/CD & Pull Request Automation
mise uses several automated workflows to maintain code quality and streamline development:
Automated Code Formatting
- autofix.ci: Automatically formats code and fixes linting issues in PRs
- Runs
mise run renderandmise run lint-fixautomatically - Commits fixes directly to the PR branch
PR Title Validation
- semantic-pr-lint: Validates PR titles follow conventional commit format
- PR titles must match:
<type>[optional scope]: <description> - Example:
feat(cli): add new command for listing plugins
Continuous Integration
- Cross-platform testing: Ubuntu, macOS, and Windows
- Unit tests: Fast component-level tests
- E2E tests: Full integration testing with multiple test tranches
- Coverage testing: Code coverage across 8 parallel test runs
- Dependency validation:
cargo deny,cargo msrv,cargo machete
Release Automation
- release-plz: Automated release management based on conventional commits
- Automatically creates release PRs and publishes releases
- Runs daily via scheduled workflow
- Handles version bumping and changelog generation
mise Codebase Architecture
Overview
mise is a Rust-based tool with a modular architecture designed around three main concepts:
- Tool Version Management - Managing different versions of development tools
- Environment Management - Setting up environment variables and project contexts
- Task Running - Executing project tasks with dependency management
Core Architecture Components
1. **Main Entry Point** (`src/main.rs`)
- Asynchronous Tokio runtime with multi-threading
- Global error handling and panic hooks
- CLI argument parsing and routing
- Multi-progress reporting system
2. **CLI Layer** (`src/cli/`)
- Command Structure: Each command is a separate module (e.g.,
install.rs,use.rs,run.rs) - Argument Parsing: Uses
clapfor command-line argument handling - Command Execution: Async command execution with proper error handling
- Key Commands:
install- Install tool versionsuse- Add tools to configurationrun- Execute tasksenv- Environment managementshell- Shell integration
3. **Backend System** (`src/backend/`)
The backend system is the core abstraction for tool management:
Backend Trait: Common interface for all tool backends
pub trait Backend: Debug + Send + Sync {
async fn list_remote_versions(&self) -> Result<Vec<String>>;
async fn install_version(&self, ctx: &InstallContext, tv: &ToolVersion) -> Result<()>;
async fn uninstall_version(&self, tv: &ToolVersion) -> Result<()>;
// ... other methods
}Backend Types:
- Core Backends: Built-in support (Node.js, Python, etc.)
- ASDF Backends: External plugin system compatibility
- Aqua Backends: Package manager integration
- Language-specific: npm, cargo, pipx, gem, go, etc.
- Universal: ubi (GitHub releases)
4. **Configuration System** (`src/config/`)
Hierarchical Configuration:
Configstruct manages all configuration sourcesConfigFiletrait for different config formats:MiseToml- Main configuration formatToolVersions- ASDF compatibilityIdiomaticVersion- Language-specific files (.nvmrc,.python-version)
Configuration Hierarchy:
- System config (
/etc/mise/config.toml) - Global config (
~/.config/mise/config.toml) - Project configs (searched up directory tree)
- Environment-specific configs (
mise.dev.toml)
5. **Toolset Management** (`src/toolset/`)
Core Components:
Toolset- Collection of tools for a specific contextToolVersion- Represents a specific version of a toolToolRequest- User request for a tool (e.g.,node@18)ToolsetBuilder- Constructs toolsets from configuration
Tool Resolution Flow:
- Parse configuration files
- Resolve version specifications
- Build toolset with dependencies
- Install missing tools
- Set up environment
6. **Task System** (`src/task/`)
Task Components:
Taskstruct with metadata, dependencies, and execution infoDeps- Dependency graph management using petgraphTaskFileProvider- Discovers tasks from files and configuration- Parallel execution with dependency resolution
Task Types:
- TOML Tasks: Defined in
mise.toml - File Tasks: Executable scripts in task directories
- Command Tasks: Simple command execution
- Script Tasks: Inline script execution
7. **Plugin System** (`src/plugins/`)
Plugin Architecture:
Plugintrait for extensibilityAsdfPlugin- ASDF plugin compatibilityVfoxPlugin- Vfox plugin systemScriptManager- Manages plugin scripts
Plugin Types:
- Core Plugins: Built into mise
- External Plugins: Downloaded from repositories
- Local Plugins: Custom local implementations
8. **Shell Integration** (`src/shell/`)
Shell Support:
- Bash, Zsh, Fish, PowerShell support
Shelltrait for shell-specific behavior- Activation scripts for environment setup
- Hook system for directory changes
9. **Environment Management** (`src/env*.rs`)
Environment Components:
EnvDiff- Tracks environment changesEnvDirective- Configuration for environment variablesPathEnv- PATH management- Context-aware environment resolution
10. **Caching System** (`src/cache.rs`)
Cache Management:
CacheManager- Generic caching with TTL- File-based caching for versions, metadata
- Automatic cache invalidation
- Per-backend cache isolation
Key Design Patterns
1. **Trait-Based Architecture**
Backendtrait for tool managementConfigFiletrait for configuration formatsShelltrait for shell integrationPlugintrait for extensibility
2. **Async/Await Throughout**
- Tokio runtime for async operations
- Parallel tool installations
- Concurrent task execution
- Non-blocking I/O operations
3. **Error Handling**
eyrecrate for error management- Structured error types
- Context-aware error reporting
- Graceful fallback behavior
4. **Configuration Hierarchy**
- Multiple configuration sources
- Inheritance and overrides
- Environment-specific configurations
- Validation and trust system
5. **Dependency Management**
- Tool dependencies (e.g., Node.js for npm tools)
- Task dependencies with DAG resolution
- Parallel execution with proper ordering
- Circular dependency detection
Data Flow
- Initialization: Load configuration hierarchy
- Tool Discovery: Find available backends and versions
- Resolution: Resolve tool requests to specific versions
- Installation: Install missing tools in dependency order
- Environment Setup: Configure PATH and environment variables
- Execution: Run tasks or provide shell integration
Testing Architecture
Test Structure:
- Unit Tests: Component-level testing with mocks
- Integration Tests: End-to-end CLI testing
- E2E Tests: Real-world scenario testing
- Snapshot Tests: Output comparison testing
Test Organization:
src/- Unit tests alongside source codee2e/- End-to-end test scriptstest/- Test fixtures and utilitiessrc/snapshots/- Snapshot test data
This architecture provides a flexible, extensible foundation for managing development environments while maintaining compatibility with existing tools and workflows.
This covers the essential information about mise for LLMs to help users effectively use the tool for development environment management and contribute to its development.