mise

repository·main·Indexed 12 days ago

https://github.com/jdx/mise

A tool manager that prepares development environments by managing dev tools, environment variables, and tasks through a single mise.toml configuration file. Written in Rust, it provides tool management for runtimes like Node.js, Go, and Python, as well as a task runner and environment variable management.

Tokens
313.5K
Snippets
1.2K
Records
1.5K
Agent score
96%

What's inside mise

  1. Overview of mise Plugin Lua Modules

    main
    mise plugins can access a set of built-in Lua modules to perform common operations. These modules are available in both backend plugins and tool plugins. They allow you to handle tasks like HTTP requests, JSON parsing, file system operations, and semantic versioning directly within your plugin logic.
  2. What is mise and how does it work?

    main

    Overview

    mise (pronounced "meez") is a development environment setup tool designed to provide a consistent way to set up and interact with projects regardless of the programming language used. It uses a mise.toml configuration file to manage project environments.

    Core Functionality

    mise provides three main categories of functionality:

    1. Tool Management: Installs and manages development tools and runtimes (e.g., node, python, terraform). It allows you to specify different versions of these tools for different projects and supports hundreds of available tools via plugins.
    2. Environment Variable Management: Manages environment variables (e.g., AWS_ACCESS_KEY_ID) that may vary between projects. It can also automatically activate tools like Python virtualenvs when you enter a project directory.
    3. Task Running: Acts as a task runner to share common tasks within a project among developers and can execute tasks based on file changes.
  3. Overview of mise oci commands

    main

    The mise oci suite allows you to turn a mise.toml into a container image with one OCI layer per installed tool. This architecture ensures that updating a single tool only invalidates its specific layer, maximizing cache reuse.

    CommandDescription
    mise oci buildProduces an OCI image layout on disk.
    mise oci runBuilds (or reuses) an image and runs a command inside it via podman/docker.
    mise oci pushBuilds (or reuses) an image and pushes it to a registry.
  4. Protect against SSH lockout during bootstrap

    main

    When running mise bootstrap over SSH with an incoming policy of deny or reject, mise performs safety checks to prevent locking you out:

    1. It checks the SSH_CONNECTION environment variable.
    2. It verifies that at least one existing incoming tcp allow rule covers both the connected peer address and the server port.
    3. If these conditions aren't met, the application fails before applying changes.

    Escape Hatch: If you are performing a deliberately out-of-band deployment and need to bypass this check, set allow_lockout = true in your configuration.

    allow_lockout = true # Use to bypass SSH safety checks during deployment
  5. How mise manages development tools

    main

    mise is a tool manager that automates the installation, version management, and environment setup for programming language runtimes (like Node.js, Python, Ruby, Go) and other development tools.

    Tool Resolution Flow

    When you enter a directory or run a command, mise follows these steps:

    1. Configuration Discovery: Walks up the directory tree to find and merge configuration files (mise.toml, .tool-versions, etc.).
    2. Tool Resolution: Resolves version specs (e.g., node@latest) using registries.
    3. Backend Selection: Chooses a backend (core, asdf, aqua, etc.) to handle the tool.
    4. Installation Check: Verifies if required versions are installed; installs missing ones automatically.
    5. Environment Setup: Configures PATH and environment variables.

    Configuration Hierarchy

    Settings cascade from broad to specific:

    • ~/.config/mise/config.toml (Global defaults)
    • ~/work/mise.toml (Work-specific)
    • ~/work/project/mise.toml (Project-specific overrides)
    • ~/work/project/.tool-versions (Legacy asdf compatibility)
  6. Control task execution order

    main

    You can manage the sequence and concurrency of tasks using depends, wait_for, and depends_post.

    Dependency Types

    • depends: Ensures the specified tasks run before the current task.
    • wait_for: Does not add a dependency, but if the specified task is already running, the current task will wait for it to finish.
    • depends_post: (Implicitly used for post-execution logic).

    Complex Execution Flows

    You can define a task that orchestrates other tasks in series or parallel using an array of task objects:

    [tasks.one_by_one]
    run = [
        { task = "example1" },      # Runs example1, waits for it to finish
        { tasks = ["example2", "example3"] }, # Runs example2 and example3 in parallel
    ]
    [tasks.build]
    run = "echo 'build'"
    
    [tasks.test]
    run = "echo 'test'"
    depends = ["build"]
  7. Use `matching` and `matching_regex` for precise asset selection

    main

    If a GitLab release contains multiple assets that autodetection cannot distinguish, use matching or matching_regex to narrow the selection.

    Important: matching and matching_regex refine the list of candidates after autodetection has already selected the correct OS and architecture. If asset_pattern is also provided, it takes precedence and matching/matching_regex are ignored.

    To install two different binaries from the same release, you must use distinct tool_alias entries so they reside in different install directories. Reusing the same gitlab:owner/repo string with different matching options will cause the second installation to overwrite the first.

    # Using matching to pick a specific binary from a multi-binary release
    "gitlab:owner/repo" = { version = "latest", matching = "mytool-cli" }
    
    # Using matching_regex for precise selection
    "gitlab:owner/repo" = { version = "latest", matching_regex = "^mytool-cli-" }
  8. Group file tasks into sub-directories

    main

    Tasks placed in sub-directories of the default task folders are automatically prefixed with the directory name. This allows for logical grouping of related tasks.

    Example structure:

    mise-tasks
    ├── build
    └── test
        ├── _default
        ├── integration
        └── units

    Resulting task names:

    • build
    • test (from test/_default)
    • test:integration
    • test:units
  9. Manage file snippets with Edit entries

    main

    Edit entries allow you to manage specific parts of a file without owning the whole file. They are keyed by target_path/id.

    Blocks

    A block is a multi-line snippet delimited by marker comments in the target file. The markers are named after the entry's id.

    • Markers: The prefix is inferred from the file extension (e.g., # for shell, -- for Lua, // for C-like). You can override this with comment = "...".
    • Behavior: Applying a block replaces only the content between the markers or appends it if absent. Everything else in the file is untouched.

    Lines

    A line ensures an exact single line exists in the file. It appends the line to the end if it is missing. It is idempotent and never modifies or removes other lines.

    Templates for Edits

    To use a template for an edit entry, pair source with template = "tera".

    [dotfiles]
    # A block in .zshrc
    "~/.zshrc/activate" = { block = 'eval "$(mise activate zsh)"' }
    
    # A multi-line block
    "~/.zshrc/aliases" = { block = '''
    alias ll='ls -l'
    alias la='ls -la'
    ''' }
    
    # A single line in /etc/hosts
    "/etc/hosts/dev" = { line = "127.0.0.1 dev.local" }
    
    # A templated edit
    "~/.gitconfig/identity" = { source = "snippets/git-identity.tmpl", template = "tera" }
  10. How Env Plugins declare cacheability

    main

    When developing environment plugins (vfox modules), you can control caching behavior by returning a configuration object from the MiseEnv hook. To make a plugin cacheable and specify which files trigger an invalidation, return:

    {cacheable = true, watch_files = [...]}

  11. Create custom presets using mise tasks

    main

    You can reduce boilerplate and automate project scaffolding by creating custom presets. Presets are implemented using mise tasks. By placing task scripts in ~/.config/mise/tasks/, you can define complex setup workflows that can be invoked from any directory.

    To create a preset, write a shell script and use special #MISE directives to control the execution environment, such as setting the working directory (#MISE dir="{{cwd}}") or defining dependencies (#MISE depends=["preset:name"]).

    # Example of a preset task script
    #!/usr/bin/env bash
    #MISE dir="{{cwd}}"
    
    mise use python@latest
    mise config set env._.python.venv.path .venv
  12. Understand HTTP Backend caching behavior

    main

    The HTTP backend uses an intelligent caching system to optimize disk usage and installation speed. Instead of storing files separately for every tool, mise downloads and extracts files into a central cache directory. Tool installations are then created as symlinks to this cached content.

    Cache Location

    Downloaded and extracted files are stored in $MISE_CACHE_DIR/http-tarballs/. Default locations are:

    • Linux: ~/.cache/mise/http-tarballs/
    • macOS: ~/Library/Caches/mise/http-tarballs/

    Cache Key Generation

    To ensure identical downloads are shared across different tools, cache keys are generated using:

    1. Blake3 hash of file content: Used when no checksum is provided.
    2. Extraction options: The strip_components option is included in the key because it changes the resulting directory structure.

    Symlinked Installations

    When a tool is installed via the HTTP backend, the installation directory is a symlink to the cached extracted content:

    ~/.local/share/mise/installs/http-my-tool/1.0.0 → ~/.cache/mise/http-tarballs/71f774.../extracted

    Cache Metadata

    Each cache entry contains a metadata.json file describing the content:

    {
      "url": "https://example.com/releases/my-tool-v1.0.0.tar.gz",
      "checksum": "sha256:a1b2c3d4e5f6789...",
      "size": 1024000,
      "extracted_at": 1703001234,
      "platform": "macos-arm64"
    }