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.luafile - 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:
PluginType::from_plugin_config(lines 00207-00216): Handles plugins declared inmise.tomlconfiguration filesPluginType::from_plugin_path(lines 00222-00238): Scans the filesystem formetadata.luaand 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>containingmetadata.luaand required hooks - Mark the type: The presence of
metadata.luatriggersPluginType::from_plugin_path(lines 00222-00238) to classify it as a Vfox plugin - Register via source: Use
mise plugins addwith 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 useinstall_local_plugin_source(lines 00709-00784) - Integrate seamlessly: Once installed, plugins work with
mise useand version management through thePluginEnumabstraction defined insrc/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →