投稿

anyenv から mise への移行ガイド — 仕組みの違いから移行手順まで

anyenv から mise への移行ガイド — 仕組みの違いから移行手順まで

はじめに

anyenv はシェル初期化に依存したシム方式でランタイムを管理する。この設計が bubblewrap sandbox のようなシェル初期化を行わない環境と相性が悪く、nodenpm が見つからずに大量の回避策が走る問題に直面した。

根本解決として mise への移行を検討した際に生じた疑問と、移行手順をまとめる。


anyenv と mise それぞれの仕組み

anyenv(シム方式)

anyenv は nodenv・pyenv・goenv などの「env 系ツールマネージャ」をまとめて管理するツール。各 env ツール自体もシム方式を採用している。

シムとは何か

シム(shim)はコマンドの横取り役スクリプト。たとえば node コマンドを実行すると、実際には以下のファイルが動く:

~/.anyenv/envs/nodenv/shims/node

このシムスクリプトの中身は、おおまかに以下の動作をする:

  1. nodenv コマンドを探す(PATH に入っている必要がある)
  2. nodenv がカレントディレクトリの .node-version やグローバル設定を読む
  3. 対応する実バイナリ(~/.anyenv/envs/nodenv/versions/25.2.1/bin/node)に処理を委譲する

つまりシムが動くには nodenv 自体が PATH に存在すること が前提で、これは .zshrceval "$(anyenv init -)" によって設定される。シェル初期化なしではシムは機能しない。

mise(単一バイナリ方式)

mise は Node・Python・Go・Ruby など 200 以上のランタイムを一元管理できる Rust 製のツールマネージャ。~/.local/bin/mise という 単一バイナリ として動作する。

mise のシムは動作が異なる

mise もシムを持つが、呼び出し先が違う:

~/.local/share/mise/shims/node  ← mise のシム

このシムが呼ぶのは mise exec -- nodemise バイナリ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 ~/.anyenv

dotfiles で 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 への移行はシンプルで恩恵が大きい。既存のバージョンファイルはそのまま使えるため、リポジトリ側の変更もほぼ不要。

トレンドのタグ