How to Add a New Language Plugin to mise: A Complete Guide

To add a new language plugin to mise, create a directory with a metadata.lua file and hooks under ~/.local/share/mise/plugins/<name>, then register it using mise plugins add <source>.

The mise tool manager (jdx/mise) supports extensible language plugins that allow you to manage versions of programming languages and tools. Whether you're adapting an existing asdf plugin or building a custom vfox-based integration, understanding how to add a new language plugin to mise requires familiarity with its plugin detection system and directory structure.

Understanding mise Plugin Architecture

Mise stores plugins in the directory defined by dirs::PLUGINS (typically ~/.local/share/mise/plugins/). According to the source code in src/plugins/mod.rs, each plugin is classified by a specific PluginType—which can be Asdf, Vfox, VfoxBackend, or Package—determined by the files present in the plugin directory.

Plugin Type Detection

Mise detects the plugin type using PluginType::from_plugin_path (lines 00222-00238 in src/plugins/mod.rs). This function inspects directory contents to distinguish between:

  • Vfox plugins: Contain a metadata.lua file
  • Asdf plugins: Contain executable scripts like bin/list-all
  • Package plugins: Special configuration-based definitions

For custom language plugins, you'll typically create a Vfox-style plugin by including the metadata.lua marker file.

The Core Plugin Files

The source code defines how plugins are instantiated via the PluginType::plugin method (lines 00441-00451), which constructs a concrete PluginEnum variant wrapping either AsdfPlugin (from src/plugins/asdf_plugin.rs) or VfoxPlugin (from src/plugins/vfox_plugin.rs).

Step-by-Step: Creating a Language Plugin

To add a new language plugin to mise manually, prepare the plugin directory structure before registration.

Step 1: Initialize the Plugin Directory

Create a named directory under the plugins root. The name becomes your plugin identifier:

PLUGIN_NAME=my-lang
mkdir -p ~/.local/share/mise/plugins/$PLUGIN_NAME/hooks

Step 2: Create the metadata.lua File

Add a metadata.lua file to mark this as a Vfox-style plugin:

touch ~/.local/share/mise/plugins/$PLUGIN_NAME/metadata.lua

This file serves as the type marker that PluginType::from_plugin_path checks when scanning the directory.

Step 3: Implement Required Hooks

At minimum, create an available.lua hook that tells mise when the tool can be used:

-- ~/.local/share/mise/plugins/my-lang/hooks/available.lua
return os.execute("command -v my-lang >/dev/null") == 0

Place this in the hooks/ subdirectory. This script should return a truthy value when the language runtime is installed on the host system.

Step 4: Add Installer Scripts (Optional)

If your plugin needs custom installation logic, add additional hook scripts:

cat > ~/.local/share/mise/plugins/$PLUGIN_NAME/hooks/backend_install.lua <<'EOF'
#!/usr/bin/env bash

# Download and install logic here

# Place binaries under $MISE_ROOT/tools/my-lang/<version>

EOF
chmod +x ~/.local/share/mise/plugins/$PLUGIN_NAME/hooks/backend_install.lua

Other optional hooks include install.lua and uninstall.lua, which the Vfox backend executes during tool lifecycle operations.

Registering and Installing Your Plugin

Once your directory structure is ready, register the plugin with mise using the PluginSource::parse logic (lines 00404-00433 in src/plugins/mod.rs).

From a Git Repository

mise plugins add git::https://github.com/you/my-lang-plugin.git

The PluginSource::parse function detects Git URLs and triggers install_git_plugin_source (lines 00776-00816), which clones the repository, checks out the requested ref, and symlinks the final directory into dirs::PLUGINS.

From a Local Path

For local development, use a file path:

mise plugins add /path/to/my-lang-plugin

This invokes install_local_plugin_source (lines 00709-00784), which creates a symlink to your local directory.

From a ZIP Archive

You can also distribute plugins as ZIP files. If the source URL ends with .zip (detected at lines 00420-00425), mise extracts the archive instead of cloning:

mise plugins add https://github.com/you/my-lang-plugin/releases/latest/download/plugin.zip

How mise Resolves Plugin Types

When you run mise plugins ls or reference a tool, mise determines the backend implementation using two key methods:

  1. PluginType::from_plugin_config (lines 00207-00216): Handles plugins declared in mise.toml configuration files
  2. PluginType::from_plugin_path (lines 00222-00238): Scans the filesystem for metadata.lua and hook directories to classify existing plugins

The src/toolset/install_state.rs module maintains a map of installed plugins (list_plugins) that is consulted when resolving plugin:tool specifications.

Using Your New Plugin

After installation, verify the plugin is recognized:

mise plugins ls | grep my-lang

Reference tools from your plugin using the plugin:tool syntax:

mise use my-lang:my-tool@latest

The Vfox backend (implemented in src/plugins/vfox_plugin.rs) handles version resolution and installation, while the Asdf backend (src/plugins/asdf_plugin.rs) supports legacy plugins that expose bin/list-all executables.

Summary

  • Create the structure: Build a directory under ~/.local/share/mise/plugins/<name> containing metadata.lua and required hooks
  • Mark the type: The presence of metadata.lua triggers PluginType::from_plugin_path (lines 00222-00238) to classify it as a Vfox plugin
  • Register via source: Use mise plugins add with a Git URL, local path, or ZIP file; PluginSource::parse (lines 00404-00433) handles the source detection
  • Install logic: Git sources use install_git_plugin_source (lines 00776-00816) while local paths use install_local_plugin_source (lines 00709-00784)
  • Integrate seamlessly: Once installed, plugins work with mise use and version management through the PluginEnum abstraction defined in src/plugins/mod.rs

Frequently Asked Questions

What is the difference between Asdf and Vfox plugins in mise?

Asdf plugins rely on executable scripts in a bin/ directory (such as list-all and install), while Vfox plugins use Lua-based hooks in a hooks/ directory and require a metadata.lua marker file. Mise detects the type automatically via PluginType::from_plugin_path based on which files are present.

Can I add a plugin directly in mise.toml without using mise plugins add?

Yes. The configuration parser in src/config/mod.rs supports a [plugins] section where you can declare plugins inline. When parsing mise.toml, mise calls PluginType::from_plugin_config (lines 00207-00216) to resolve these declarations without requiring a separate installation step.

How does mise handle plugin updates?

When you run mise plugins update, mise re-invokes the installation logic for Git-based plugins. The install_git_plugin_source function (lines 00776-00816) fetches the latest changes from the remote repository and updates the local checkout in dirs::PLUGINS.

Why does my plugin need an available.lua hook?

The available.lua hook tells mise whether the underlying tool is already installed on the host system. This allows mise to skip unnecessary installations when the language runtime exists outside of mise's management, optimizing the tool resolution pipeline.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →