Skip to content

Codebase architecture ​

Use this map to find the code that owns a behavior before you change it. For setup, checks, and how to submit a change, see Contributing.

Library, binary, and crates ​

The mise package builds two targets. The library, src/lib.rs, holds everything except the command line: configuration, toolsets, backends, tasks, environments, and bootstrap. The binary, src/main.rs plus src/cli/, sits on top of it. src/main.rs imports the library's root with use mise::*, so code in src/cli/ still writes crate::config::…. A change confined to src/cli/ recompiles only the binary.

Library code must not refer to crate::cli. When core code needs command behavior, it calls a hook in src/frontend.rs, which the binary fills in at startup with cli::register_frontend. The hooks cover running mise lock after an install adds versions and listing subcommand names for "did you mean" suggestions. When cli needs a core item, make that item pub. The library denies unreachable_pub, so everything else stays pub(crate).

cfg(test) is set for the binary's tests but not for the library they call, so core code that behaves differently under tests checks mise_util::testing::in_tests() instead.

The workspace crates under crates/ cannot depend on the mise package. register_util_hooks in src/lib.rs gives them what they need from mise, such as the settings loader and the build identity used in cache keys, before anything else runs.

CrateContents
mise-utilEnvironment, directory, file, HTTP, cache, template, and EnvDiff/PathEnv helpers
mise-daemonsDaemon declarations, ports, presets, and the supervisor runtime (the toolset glue stays in src/daemons/)
mise-ociThe OCI registry client, layers, and image layout (the image builder stays in src/oci/)
mise-systemThe bootstrap, dotfiles, and history modules
mise-configThe mise.toml declaration types, so far for [bootstrap], [dotfiles], and [history]
mise-system-packagesSystem package manager drivers: apt, dnf, brew, brew-cask, and more
mise-uiProgress reports, prompts, and themes for the terminal
mise-settingsThe Settings types, generated from settings.toml, and the process-wide settings cache
vfoxThe embedded Lua runtime and the hook and module interfaces for vfox plugins
aqua-registryParsing, package lookup, and cache formats for aqua registries
mise-bootstrapBootstrap resource planning and dependency ordering
mise-lspThe language server behind mise lsp; mise passes it schema/mise.json and the mise fmt formatter
mise-cache-coreThe remote task cache protocol, content-addressed storage, authentication, and transport
mise-shimmise-shim.exe, the native executable that Windows shims use in the default exe mode
mise-sigstoreSigstore verification helpers
mise-tlsRoot certificate fallback for HTTPS clients when the system trust store is empty
mise-agent-envDetection of AI coding agents from the process environment
mise-interactive-configThe interactive TOML editor behind mise edit
mise-brew-metadataHomebrew formula metadata models
mise-brew-relocationHomebrew bottle placeholder and binary relocation
mise-dotenvA dotenv parser with explicit control over variable substitution

Where things live ​

BehaviorCodeUser docs
Commands, flags, and help textsrc/cli/; mod.rs dispatches, and each command has a file or directory such as use.rs, exec.rs, or tasks/CLI reference
What each command changessrc/cli/command_effects.rs
Config discovery, loading, and mergingsrc/config/; config_file/ holds MiseToml, ToolVersions, and IdiomaticVersionFilemise.toml
Settingssettings.toml, generated into crates/mise-settings; loading, trust, and CLI flags in src/config/settings.rsSettings
Config file schemaschema/mise.jsonmise.toml
Tool requests, resolution, install statesrc/toolset/Dev tools
Backendssrc/backend/; the Backend trait is in mod.rs and BackendType in backend_type.rsBackends
Core toolssrc/plugins/core/Core tools
Pluginssrc/plugins/ (asdf and vfox adapters) and crates/vfoxPlugins
Tool shorthandsregistry/*.toml, compiled in by build.rs; lookup in src/registry.rsRegistry
aqua registrycrates/aqua-registry; the bundled snapshot is vendor/aqua-registry/, baked in by build.rsaqua
Lockfilesrc/lockfile.rs and src/lockfile/Lockfile
Environment directivessrc/config/env_directive/; EnvDiff and PathEnv come from crates/mise-utilEnvironment variables
Shell activationsrc/shell/ (one file per shell), src/hook_env.rs, src/cli/activate.rsShell setup
Shimssrc/shims.rs and crates/mise-shimShims
Templatescrates/mise-util/src/tera.rs, re-exported as src/tera.rsTera templates
Taskssrc/task/Tasks
Remote task cachecrates/mise-cache-coreRemote task cache
Bootstrap and host packagessrc/cli/bootstrap.rs, crates/mise-system (packages in crates/mise-system-packages), crates/mise-bootstrapBootstrap
Dotfilessrc/cli/dotfiles/, crates/mise-system/src/managed_files.rs, crates/mise-system/src/history/Dotfiles
Daemonssrc/daemons/ (toolset glue), crates/mise-daemonsDaemons
Project dependenciessrc/deps/Project dependencies
Secretssrc/secrets/, src/sops.rs, src/agecrypt.rsSecrets
Cachescrates/mise-util/src/cache.rs: CacheManager<T>, MessagePack with zlib, written atomicallyCaches
packslip manifestssrc/packslip.rs, src/backend/packslip.rspackslip
OCI imagessrc/oci/ (builder), crates/mise-ociOCI images
OpenTelemetrysrc/otel/OpenTelemetry
Identity install layoutsrc/install_layout/Install layout
Sandboxingsrc/sandbox.rsSandboxing
Self-updatesrc/cli/self_update.rsPackaging mise

How a command runs ​

Most commands load the configuration, resolve the tools it requests, build an environment from them, and then run a child process or print shell code. Tasks and bootstrap start from the same configuration.

Configuration ​

src/config finds config files, loads them through the ConfigFile trait, and merges them. Which files are found, whether they are trusted, and how each field merges are separate decisions in the code. Settings, tools, environment directives, tasks, and bootstrap entries do not merge the same way, and write commands pick their target file separately.

Toolsets ​

src/toolset connects version requests to resolved versions and installation state:

TypeRole
ToolRequestA request such as node@24, a channel, or a ref, with its backend and options
ToolVersionA resolved version and its installation metadata
ToolsetThe requests and resolved versions for the current context
ToolsetBuilderCombines config, environment variable overrides, and command arguments, then resolves

Backends ​

The Backend trait splits shared policy from backend-specific work. Its public wrapper methods handle caching and resolution. A backend implements hooks such as _list_remote_versions, which returns VersionInfo entries, and install_version_. Core tools in src/plugins/core/ implement the same trait. For how mise picks a backend for a short name, see how backend selection works; to add one, see Adding a backend.

Plugins ​

src/plugins installs plugin sources and records their metadata. crates/vfox runs vfox plugins in its embedded Lua runtime. Tool plugins install one tool, backend plugins handle plugin:tool requests, environment plugins return variables and PATH entries, and package plugins manage batches of host packages. asdf adapters run legacy shell scripts. Installing or updating a plugin's source is separate from installing a tool version, and each keeps its own state. See Plugins.

Tasks ​

src/task discovers, schedules, and runs tasks. Task holds a definition, the providers in task_file_providers/ load local and remote task files, Deps is the dependency graph, and the executor and scheduler run ready tasks under the configured concurrency and output style. A node in the graph is a task with its arguments, environment variables, and run phase, so the same task with different arguments is a separate node. Read Dependencies and execution order before you change how the graph is built or how depends, depends_post, and wait_for behave.

Environment and shell activation ​

src/config/env_directive evaluates [env] directives. Directives marked tools = true run after tools are resolved, and the rest run before. mise activate emits a shell hook from src/shell/ that runs mise hook-env at each prompt. hook-env records an EnvDiff so the next run can undo the previous directory's changes before applying new ones. mise exec and mise run build the child environment directly and do not need activation.

Bootstrap and host state ​

src/cli/bootstrap.rs builds a plan and runs the selected phases. The code in crates/mise-system manages packages, files, edits, repositories, services, and platform-specific resources, which live outside any tool's install directory. Status, preview, apply, and prune are separate operations: a status check reads the host and changes nothing. A package batch can be a subset named on the command line, so never treat a package's absence from a batch as a request to remove it.

Rules to preserve ​

  • Treat versions as opaque strings. Resolve a request through the backend (Backend::latest_version, Backend::list_versions_matching, ToolRequest::resolve), never with a semver sort at a new call site.
  • Compare lockfile versions with ==, keep the backend and checksum of an entry, and never write latest, lts/*, or a prefix into the lockfile.
  • Do not add installs or network requests to a code path that only reports local state.
  • Build a subprocess's environment from the one mise computed, not the inherited process environment, which can miss earlier directives or select the wrong tool.
  • Include every input that changes a cached result in its cache key, such as options, environment variables, and source metadata. The environment cache (src/toolset/env_cache.rs) and the task caches (src/task/task_cache.rs) do not use CacheManager and have their own formats and invalidation rules.
  • Keep Windows PATH in native form inside mise and in child processes. Convert it only when emitting assignments into a running, positively identified MSYS2 or Cygwin shell; the agent guide has the full rules.
  • Classify every new command in src/cli/command_effects.rs; see Changing a CLI command.

Generated files ​

Edit the source, then regenerate. Commit the output with the change that produced it.

OutputSourceRegenerate with
mise.usage.kdl, docs/cli/Command definitions in src/cli/, src/assets/mise-extra.usage.kdl, and docs/.vitepress/cli-reference.tsmise run render:usage
tasks.mdThe project's tasks in tasks.toml, xtasks/, and mise.toml, through mise generate task-docsmise run render:usage
man/man1/mise.1mise.usage.kdlmise run render:mangen
completions/The usage spec, through mise completion <shell>mise run render:completions
docs/.vitepress/cli_commands.ts and the idiomatic version file tablesrc/cli/ and the idiomatic_files keys in registry/*.tomlmise run render:help
schema/mise.json, schema/mise-task.json, schema/miserc.jsonThe types and doc comments in crates/mise-config (MiseTomlDecl for the top level) and settings.toml, through mise-config's render-schema examplemise run render:schema
docs/public/llms.txtPage titles and leads, and docs/.vitepress/sidebar.tsmise run render:llms
Settings typessettings.tomlEvery build (crates/mise-settings/build.rs)
The registry compiled into miseregistry/*.tomlEvery build (build.rs)
The settings referencesettings.tomlEvery docs build

mise run render runs every render:* task. For the schemas, change the types and doc comments in crates/mise-config, not the JSON; a mise-config test fails while the committed files are stale.

Tests ​

Unit tests sit beside the code they test, E2E tests are Bash scripts under e2e/ run with mise run test:e2e, and the Windows E2E tests under e2e-win/ use Pester. See Testing for the commands and prerequisites.

MIT LicenseCopyright © 2026jdx.dev