miseの1Passwordの環境変数読み込みのたびに数秒待たされるのを、fnoxのdaemonで解消してみた

miseの1Passwordの環境変数読み込みのたびに数秒待たされるのを、fnoxのdaemonで解消してみた

miseの[env]で1Passwordから読み込んでいたトークンが、miseのアップデート後はEnterのたびに読み直されるようになりました。原因を調べて、hook_env.chpwd_onlyとfnoxのdaemonで0.01秒前後まで戻した記録です。
2026.10.30

データ事業本部の横山です。

わたしは普段、開発環境のツールや環境変数をmiseで管理しています。
作業ディレクトリごとにツールや環境変数を自動で設定してくれるため大変便利なのですが、miseはターミナルで操作をするたびに環境変数を評価し直します。

ある日から、ターミナルでEnterを押すたびにプロンプトが戻ってくるまでに3秒程度待たされるようになりました。
調べてみると、miseのアップデートで「redact = trueの値はキャッシュしない」仕様に変わったのが原因でした。

そこで、miseの作者が作っている秘密値管理ツール「fnox」のdaemonを挟んで遅さを解消してみたので、その手順を共有します。

結論

  • mise v2026.10.3から、redact = trueを付けた値を含む環境変数は、env_cache([env]の計算結果のキャッシュ)に保存されなくなった
    • その結果、プロンプトのたびにop readが呼ばれ、1回あたり3秒程度待たされていた
  • hook_env.chpwd_only = trueで、miseが環境変数を計算し直すのをcdしたときだけにした
  • op readをfnox getに置き換え、fnoxのdaemonに値をメモリで持たせた
    • 2回目以降の取得は約0.01秒で返るようになった

計測してみると、こんな感じに変わりました。

処理 変更前 変更後
Enterからプロンプトが戻るまで 3秒程度 0.01秒前後
作業ディレクトリにcdしたとき 3秒程度 0.07〜0.08秒
PCを起動して最初に値を取るとき 3秒程度 3秒程度

最終的な設定は次の3つです。
各設定内容はあくまで例ですが詳細は後述します。

~/.config/mise/config.toml(ユーザールートでの設定)

[settings]
# hook-envをcdしたときだけ実行し、Enterごとの再計算を止める
hook_env.chpwd_only = true

[tools]
# daemonからの読み取りには1.43.0以上が必要
fnox = "1.43.0"

[env]
# exec()はmiseが有効になる前のPATHで動くので、fnoxは絶対パスで呼ぶ
CLIENT_ID     = { value = "{{ exec(command='~/.local/share/mise/installs/fnox/latest/fnox get CLIENT_ID') }}", redact = true }
CLIENT_SECRET = { value = "{{ exec(command='~/.local/share/mise/installs/fnox/latest/fnox get CLIENT_SECRET') }}", redact = true }

~/.config/fnox/config.toml(ユーザールートでの設定)

[daemon]
enabled = true

[providers.op]
type = "1password"
vault = "Private"

[providers.keychain]
type = "keychain"
service = "my-oauth"

[secrets]
# 値そのものではなく、取得元での名前だけを書く
# 1Passwordは「item名/フィールド名」
API_TOKEN = { provider = "op", value = "API Token/token" }
# キーチェーンはアカウント名
CLIENT_ID = { provider = "keychain", value = "client-id" }
CLIENT_SECRET = { provider = "keychain", value = "client-secret" }

~/{project名}/.mise.toml(各作業ディレクトリでの設定)

[env]
API_TOKEN = { value = "{{ exec(command='~/.local/share/mise/installs/fnox/latest/fnox get API_TOKEN') }}", redact = true }

以降、何が起きていたのかと、実際にどう直したのかを順に見ていきます。

fnoxとは

項目 内容
リポジトリ jdx/fnox
作者 jdx(miseの作者)
ライセンス MIT
バージョン 1.43.0(2026年10月時点)
公式ドキュメント fnox.jdx.dev

fnoxは、秘密値の「取得元」を設定ファイルにまとめておき、fnox getやfnox execで取り出すCLIです。
取得元には1Password、macOSのキーチェーン、AWS Secrets Managerなどが使えます。

今回使うのはdaemonの機能です。
[daemon] enabled = trueにしておくと、fnox getしたときにdaemonがバックグラウンドで立ち上がり、解決した値をメモリに保持してくれます。
ディスクには書かないので、平文の値がファイルに残らないのは嬉しいポイントです。

前提条件

わたしが動作確認した環境は以下の通りです。
fnoxはmiseのグローバル設定の[tools]で入れるので、個別のインストールは不要です。

項目 バージョン
macOS 26.6.2
mise 2026.10.18
fnox 1.43.0
1Password CLI(op) 2.30.3
zsh 5.9

1Password CLIは、1Passwordのデスクトップアプリと連携(設定の「開発者」→「1Password CLIと連携」)している前提です。

何が起きていたのか

もともとの構成

変更前は、.mise.tomlの[env]に次のように書いていました。

~/{project名}/.mise.toml(各作業ディレクトリでの設定、変更前)

[env]
API_TOKEN = { value = "{{ exec(command='op read \"op://Private/API Token/token\"') }}", redact = true }

exec()はmiseのテンプレート関数で、コマンドの出力を環境変数の値にできます。
redact = trueは、mise envなどの出力で値を伏せるための指定です。

op readは1回呼ぶと数秒かかるので、miseのenv_cacheを有効にしていました。

~/.config/mise/config.toml(ユーザールートでの設定、変更前)

[settings]
# [env]の計算結果を暗号化してディスクにキャッシュする
env_cache = true

これで、op readが呼ばれるのはキャッシュが切れたとき(何も指定しなければ1時間ごと)だけになり、普段は待たされることはありませんでした。

Enterのたびに待たされるようになった

miseの更新を行ったところEnterを押すたびに3秒程度待たされるようになりました。

mise hook-envの時間を測ってみると、API_TOKENがある作業ディレクトリだけ毎回3秒程度かかっていました。
miseはzshのプロンプトを出す前(precmd)に毎回mise hook-envを呼ぶので、ここが遅いとEnterのたびに待たされることになります。

env_cacheのキャッシュファイルを見てみると、最終更新がmiseを更新したタイミングから止まっていました。
キャッシュが書かれていないので、毎回op readが呼ばれていたようです。

原因と対応策

miseのリリースを遡ってみると、v2026.10.3(2026年10月5日公開)のPR #13950で、次の変更が入っていました。

  • redact = trueの値を1つでも含む環境変数は、env_cacheに保存しない
  • シェルの状態を持つ__MISE_DIFFなどにも、秘密値の平文ではなくハッシュを持たせる

この対応策としては、次のようなものを考えました。

案 結果
hook_env.chpwd_only = true Enterごとの再計算は止まるが、cdのたびに3秒程度待たされるのは残る
exec()の中身をfnox getにしてdaemonに持たせる 2回目以降は0.01秒で返る

ということで、hook_env.chpwd_onlyとfnoxのdaemonの2つを組み合わせることにしました。

手順

1. hook_env.chpwd_onlyを有効にする

まずはEnterごとの再計算を止めます。
miseのグローバル設定の[settings]に1行足します。

~/.config/mise/config.toml(ユーザールートでの設定)

[settings]
hook_env.chpwd_only = true

これでmise hook-envはcdしたときだけ実行されるようになり、precmdの処理は0.01秒前後になりました。

ただし、.mise.tomlを編集した内容は、次にcdするまで反映されません。
編集したあとはcd .しておくと確実です。

この時点でEnterの待ちはなくなりましたが、作業ディレクトリにcdするたびに3秒程度待たされるのはそのままです。
残りはfnoxで解消します。

2. fnoxをインストールする

fnoxをmiseのグローバル設定の[tools]に追加します。

~/.config/mise/config.toml(ユーザールートでの設定)

[tools]
fnox = "1.43.0"

daemonからの読み取りには1.43.0以上が必要です。

mise install

3. fnoxの設定ファイルを作る

fnoxのグローバル設定(~/.config/fnox/config.toml)に、daemonの設定と秘密値の取得元を書きます。

~/.config/fnox/config.toml(ユーザールートでの設定)

[daemon]
enabled = true

[providers.op]
type = "1password"
vault = "Private"

[secrets]
API_TOKEN = { provider = "op", value = "API Token/token" }

[secrets]のvalueは、1Passwordの「item名/フィールド名」です。
値そのものは書かないので、このファイルはdotfilesとして管理しても問題ありません。

設定できたら、値が取れるか確かめてみます。
値を画面に出さないように、文字数だけ確認しています。

fnox get API_TOKEN | wc -c
# 初回は1Passwordの指紋認証が出て、数秒かかる
fnox daemon status
# fnox daemon running
# pid: 1238
# cached_entries: 1

fnoxはキーチェーンからも読めます。
キーチェーンに入れてある値を使う場合は、[providers]にキーチェーンを足して、次のように書きます。

~/.config/fnox/config.toml(ユーザールートでの設定)

[providers.keychain]
type = "keychain"
# キーチェーンのサービス名(securityコマンドの-sに当たる)
service = "my-oauth"

[secrets]
# valueはアカウント名(securityコマンドの-aに当たる)
CLIENT_ID = { provider = "keychain", value = "client-id" }
CLIENT_SECRET = { provider = "keychain", value = "client-secret" }

4. .mise.tomlのop readをfnox getに置き換える

.mise.tomlのexec()の中身を、op readからfnox getに置き換えます。

~/{project名}/.mise.toml(各作業ディレクトリでの設定)

 [env]
-API_TOKEN = { value = "{{ exec(command='op read \"op://Private/API Token/token\"') }}", redact = true }
+API_TOKEN = { value = "{{ exec(command='~/.local/share/mise/installs/fnox/latest/fnox get API_TOKEN') }}", redact = true }

ここで少しハマりました。
最初はfnox get API_TOKENと書いたのですが、fnox: command not foundになってしまいました。
exec()はmiseが環境を組み立てる途中で動くので、miseが入れたツールにPATHが通る前に実行されるみたいです。
なので、インストール先のlatestのリンクを絶対パスで呼んでいます。

redact = trueはそのまま残しています。
env_cacheには相変わらず載りませんが、毎回の取得がdaemonから0.01秒で返るので、気にならなくなりました。

トラブルシューティング

exec()の中でfnox: command not foundになる

exec()は、miseが入れたツールにPATHが通る前に実行されます。
fnoxだけでは見つからないので、~/.local/share/mise/installs/fnox/latest/fnoxのように絶対パスで呼んでください。

1Passwordで値を変えたのに古い値のまま

daemonは1Password側の変更を検知しません。
値を変えたら、次のどちらかで取り直してください。

# 1つだけ取り直す
fnox get --refresh API_TOKEN
# daemonのキャッシュをまるごと消す
fnox daemon clear

daemonはlaunchd配下で動いていて、ターミナルを閉じても止まりません。
なので、ターミナルを開き直すだけでは古い値のままになります。

.mise.tomlを編集しても反映されない

hook_env.chpwd_only = trueにしたので、cdするまで[env]は計算し直されません。
cd .すると反映されます。

さいごに

miseの1Passwordの環境変数読み込みのたびに数秒待たされる問題を、hook_env.chpwd_onlyとfnoxのdaemonで解消してみました。

原因がmiseの「redact = trueの値はキャッシュしない」という意図した仕様変更だったので、mise側の設定だけで元に戻す方法はなさそうでした。
fnoxのdaemonはメモリにだけ値を持つので、平文をディスクに残さない形で対応できるため対応策としてはちょうどよかったかなと思います。

副次的によかったのは、認証のダイアログが何度も出なくなったことです。
私がそうなのですが、普段作業する際にターミナルマルチプレクサなどでターミナルをいくつも立ち上げて作業している方も多いかと思います。
exec()から直接取りに行っていたときは、ターミナルごとにキーチェーンや1Passwordに問い合わせるので、認証のダイアログがターミナルの数だけ出ていました。
fnoxのdaemonを挟むことで、最初の1回で取得した値をあとから開いたターミナルもdaemonから受け取れるようになります。
一度認証すれば、あとから開いたターミナルでは求められなくなり、ターミナルを一気に開くときの手間がだいぶ減りました。

この記事がどなたかの参考になれば幸いです。

参考資料

この記事をシェアする

関連記事