anyenv から mise への移行ガイド — 仕組みの違いから移行手順まで
はじめに
anyenv はシェル初期化に依存したシム方式でランタイムを管理する。この設計が bubblewrap sandbox のようなシェル初期化を行わない環境と相性が悪く、node や npm が見つからずに大量の回避策が走る問題に直面した。
根本解決として mise への移行を検討した際に生じた疑問と、移行手順をまとめる。
anyenv と mise それぞれの仕組み
anyenv(シム方式)
anyenv は nodenv・pyenv・goenv などの「env 系ツールマネージャ」をまとめて管理するツール。各 env ツール自体もシム方式を採用している。
シムとは何か
シム(shim)はコマンドの横取り役スクリプト。たとえば node コマンドを実行すると、実際には以下のファイルが動く:
~/.anyenv/envs/nodenv/shims/nodeこのシムスクリプトの中身は、おおまかに以下の動作をする:
nodenvコマンドを探す(PATHに入っている必要がある)nodenvがカレントディレクトリの.node-versionやグローバル設定を読む- 対応する実バイナリ(
~/.anyenv/envs/nodenv/versions/25.2.1/bin/node)に処理を委譲する
つまりシムが動くには nodenv 自体が PATH に存在すること が前提で、これは .zshrc の eval "$(anyenv init -)" によって設定される。シェル初期化なしではシムは機能しない。
mise(単一バイナリ方式)
mise は Node・Python・Go・Ruby など 200 以上のランタイムを一元管理できる Rust 製のツールマネージャ。~/.local/bin/mise という 単一バイナリ として動作する。
mise のシムは動作が異なる
mise もシムを持つが、呼び出し先が違う:
~/.local/share/mise/shims/node ← mise のシムこのシムが呼ぶのは mise exec -- node。mise バイナリ1個さえ PATH にあれば、シェル初期化なしで動作する。
sandbox で "node" 実行
→ ~/.local/share/mise/shims/node(シム)
→ mise exec -- node(mise バイナリが処理)
→ ~/.local/share/mise/installs/node/25.2.1/bin/node(実ランタイム)ファイル構成の比較
| 役割 | anyenv/nodenv | mise |
|---|---|---|
| マネージャ本体 | ~/.anyenv/envs/nodenv/bin/nodenv(シェル依存) | ~/.local/bin/mise(単一バイナリ) |
| シム | ~/.anyenv/envs/nodenv/shims/node | ~/.local/share/mise/shims/node |
| 実ランタイム | ~/.anyenv/envs/nodenv/versions/25.2.1/bin/node | ~/.local/share/mise/installs/node/25.2.1/bin/node |
| シェル初期化が必要か | 必要 | 不要(バイナリだけあればOK) |
なぜ mise への移行を検討したか — bubblewrap sandbox との相性問題
bubblewrap は Linux の namespace を使ったサンドボックスで、Claude Code のエージェントが使うケースがある。このサンドボックスはシェル(.zshrc 等)を初期化しない。
anyenv のシムはシェル初期化なしでは動かないため、sandbox 内で node を実行しようとすると:
nodenvが PATH にない → シムが失敗- Claude が nvm・volta・asdf・mise・corepack など複数のツールマネージャを順番に探索
registry.npmjs.orgから npm をダウンロードして bootstrap- 28 分の大半がこの探索・bootstrap に費やされ、30 分タイムアウトの主因になった
mise であれば、sandbox の PATH に ~/.local/bin(mise バイナリ)と ~/.local/share/mise/shims/ を追加するだけで全言語対応できる:
// bwrap の引数に追加するだけで全言語をカバー
misePath := filepath.Join(home, ".local/share/mise")
if _, err := os.Stat(misePath); err == nil {
args = append(args,
"--bind", misePath, misePath,
"--bind", localBin, localBin,
)
newPath = shimPath + ":" + localBin + ":" + originalPath
}anyenv の場合は言語ごと(nodenv・pyenv・goenv…)に個別処理が必要だった。
よくある疑問
Q1. anyenv と mise は共生できるか
技術的には可能。PATH の優先順位で制御できる。.zshrc で anyenv の初期化(eval "$(anyenv init -)")を書かなければ anyenv のシムは PATH に入らず、事実上 mise が優先される。
ただし 同一言語(Node など)を両方で管理すると混乱の原因 になるため、実際には言語ごとに担当を分けるか、mise に一本化するかが現実的。
anyenv の ~/.anyenv/ ディレクトリはディスクに残しておいて問題ない(シェルから見えなくなるだけ)。容量が気になれば後で削除する。
Q2. mise はプロジェクトごとに都度インストールが必要か
No。mise もグローバルバージョンをサポートする。
mise use -g node@25 # グローバル設定
mise use -g python@3.12.mise.toml や .node-version のないプロジェクトは自動的にグローバルバージョンを使う。オーバーヘッドは nodenv と同等で、同一バージョンは ~/.local/share/mise/installs/ にキャッシュされ再インストール不要。
MISE_MISSING_RUNTIME_BEHAVIOR=autoinstall を設定すれば自動インストールも可能。
Q3. 既存リポジトリに .mise.toml を追加する必要があるか
mise は既存のバージョンファイルを自動で読む:
| ファイル | 自動読み込み |
|---|---|
.node-version | ✅ |
.nvmrc | ✅ |
.python-version | ✅ |
.mise.toml | ✅ |
- バージョンファイルが ない プロジェクト → グローバルバージョンを使用(追加作業不要)
- バージョンファイルが ある プロジェクト → そのまま mise が読む(
.mise.toml不要)
既存リポジトリはほぼ何も変えなくてOK。
Q4. mise のシムは anyenv のシムと何が違うのか
anyenv のシムは nodenv を呼ぶ(シェル初期化で nodenv が PATH に入っていること前提)のに対し、mise のシムは mise exec を呼ぶ(mise バイナリ1個だけあればOK)。この差がシェル初期化なし環境での動作可否を分ける。
移行手順
ステップ 1: mise をインストール
curl https://mise.run | sh
# ~/.local/bin/mise に配置されるステップ 2: .zshrc を切り替え
# 削除(anyenv の行)
eval "$(anyenv init -)"
# 追加(mise の行)
eval "$(mise activate zsh)"新しいシェルを開くか source ~/.zshrc で反映する。
ステップ 3: 現在のバージョンを mise でインストール
anyenv で入れているバージョンを確認してから移植する:
# anyenv 側で確認
nodenv versions # 例: * 25.2.1
pyenv versions # 例: * 3.12.0
# mise でインストール
mise install node@25.2.1
mise install python@3.12.0
# グローバルに設定
mise use -g node@25.2.1
mise use -g python@3.12.0ステップ 4: 動作確認
node --version
npm --version
python --versionステップ 5(任意): anyenv を無効化・削除
.zshrc から anyenv init を消した時点でシムは無効になる。~/.anyenv/ 自体は残しておいて問題ないが、不要なら削除できる:
rm -rf ~/.anyenvdotfiles で anyenv を管理している場合は、インストールスクリプトやシンボリックリンクの設定も削除する。
mise を使う上でのポイント
シェル初期化なし環境での直接実行
mise activate なしでも mise exec で実行できる:
mise exec -- node --version
mise exec -- python --versionバッチスクリプトや cron、sandbox などシェルを初期化しない環境ではこの形式が有効。
プロジェクトごとのバージョン指定
# .mise.toml を作成
mise use node@20
mise use python@3.11.mise.toml の内容:
[tools]
node = "20"
python = "3.11"mise が管理できる主なランタイム
mise ls-remote node # 利用可能な Node.js バージョン一覧
mise ls-remote python
mise ls-remote go
mise ls-remote ruby
mise ls-remote rustまとめ
| 観点 | anyenv | mise |
|---|---|---|
| 仕組み | env 系ツール群 + シム(シェル依存) | 単一バイナリ + シム(シェル不要) |
| sandbox との相性 | ❌ シェル初期化が必要 | ✅ バイナリだけあればOK |
| グローバルバージョン | ✅ | ✅ |
| プロジェクトごとのバージョン | ✅(.node-version 等) | ✅(.mise.toml または既存ファイル) |
| 既存バージョンファイルの読み込み | ✅ | ✅ |
| 対応言語数 | nodenv・pyenv 等を個別インストール | 200 以上を一元管理 |
anyenv 特有の問題(sandbox との相性・言語ごとの個別セットアップ)に課題を感じているなら、mise への移行はシンプルで恩恵が大きい。既存のバージョンファイルはそのまま使えるため、リポジトリ側の変更もほぼ不要。