追記(2026.03.18):TouchID, Apple Watch対応にした。
もう.envにAPIキーを平文で置くのはやめた — macOS Keychain管理CLI「LLM Key Ring」を読んで、過去に一度、.envrcがGitHubにpushしてしまってから、.envrcを自前スクリプトで管理してきたが、ちゃんとした仕組みを作りたい欲が出てしまったので書いた。
envrcctlという、何の工夫もないネーミングだけれど。
なんで書いたの?
素直にlkrを使わせていただけば良いのだけれど、環境変数もまとめて管理したいとか、親ディレクトリの.envrcの値も継承したいとか、諸々理由がある。
例えば、.envrcには、そのディレクトリ(プロジェクト)固有の環境変数、自分の場合は$BREW_FORMULA等が設定される。
git add hoge.rbじゃなく、
git add $BREW_FORMULAでOK。どのディレクトリでも同じコマンドで良くなる。
あるいは、複数のプロジェクトで同じOPENAI_API_KEYを使う、ということもあるので、source_upを使う。
インストール
macOSならHomebrewでインストールできる。
brew install rioriost/tap/envrcctldirenvを使っていることが前提なので、もし無ければ追加でインストール。
brew install direnv使い方
既に.envrcが存在するディレクトリで、doctorサブコマンドを実行すると分かりやすい。
envrcctl doctor
WARN: Managed block not found in .envrc. Run `envrcctl init`.
WARN: unmanaged exports outside block: BREW_FORMULA, UV_PUBLISH_TOKEN. Run `envrcctl migrate` to move them.
WARN: possible plaintext secrets in exports: UV_PUBLISH_TOKEN. Consider `envrcctl secret set` for these values.BREW_FORMULAがenvrcctlで管理されてないよ、と、UV_PUBLISH_TOKENはシークレットなのに平文だよと教えてくれる。
envrcctl migrate
Migrate unmanaged exports into the managed block? [y/N]: y
direnv: error /Users/rifujita/ownCloud/bin/test_envrcctl/.envrc is blocked. Run `direnv allow` to approve its contentmigrateしてenvrcctlの管理下に。
envrcctl secret set --account 'uv_token_test_envrcctl' UV_PUBLISH_TOKEN
Secret value:
Confirm secret value:
direnv: loading ~/ownCloud/bin/test_envrcctl/.envrc
direnv: export +BREW_FORMULA +ENVRCCTL_SECRET_UV_PUBLISH_TOKENsecret setで、Keychainに放り込む。これで、.envrcからUV_PUBLISH_TOKENを消してもOK。
envrcctl unset UV_PUBLISH_TOKENsecretではないので、単純にunsetすれば良い。
direnv allow
direnv: loading ~/ownCloud/bin/test_envrcctl/.envrc
direnv: export +BREW_FORMULA +ENVRCCTL_SECRET_UV_PUBLISH_TOKENdirenv allowすれば、実際にexportされるものが分かる。ENVRCCTL_SECRET_UV_PUBLISH_TOKENは、UV_PUBLISH_TOKENに展開される。
envrcctl exec -- python3 -c 'import os; print(os.environ.get("UV_PUBLISH_TOKEN")); print(os.environ.get("BREW_FORMULA"))'
py-hogehoge
agentops_mcp_server.rbUV_PUBLISH_TOKENとBREW_FORMULAが取得できている。
実際の.envrcの中身は以下のようになっているので、間違ってGitHubで公開しても問題は無し。
cat .envrc
# >>> envrcctl:begin
# managed: true
export BREW_FORMULA=agentops_mcp_server.rb
export ENVRCCTL_SECRET_UV_PUBLISH_TOKEN=kc:st.rio.envrcctl:uv_token_test_envrcctl:runtime
# <<< envrcctl:endexecでいちいち呼ぶのは面倒臭い場合、–injectを付けてinitサブコマンドを使う。
envrcctl init --injectこれで対面式、つまりTTYからであれば環境変数を参照できる。
cat .envrc
# >>> envrcctl:begin
# managed: true
export BREW_FORMULA=agentops_mcp_server.rb
export ENVRCCTL_SECRET_UV_PUBLISH_TOKEN=kc:st.rio.envrcctl:uv_token_test_envrcctl:runtime
eval "$(envrcctl inject)"
# <<< envrcctl:endその他の使い方は、READMEかhelpを。
envrcctl --help
Usage: envrcctl [OPTIONS] COMMAND [ARGS]...
Manage .envrc with managed blocks.
╭─ Options ──────────────────────────────────────────────────────────────────────╮
│ --install-completion Install completion for the current shell. │
│ --show-completion Show completion for the current shell, to copy │
│ it or customize the installation. │
│ --help Show this message and exit. │
╰────────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ─────────────────────────────────────────────────────────────────────╮
│ init Create .envrc if missing and insert managed block. │
│ inherit Toggle source_up inheritance in the managed block. │
│ set Set a non-secret export in the managed block. │
│ unset Unset a non-secret export in the managed block. │
│ get Get a non-secret export value from the managed block. │
│ list List non-secret exports in the managed block. │
│ inject Emit export statements for all secret references. │
│ exec Execute a command with managed secrets injected into the environment. │
│ eval Show the effective environment (masked secrets). │
│ doctor Run security and consistency checks for .envrc. │
│ migrate Move unmanaged exports into the managed block. │
│ secret Manage secret references. │
╰────────────────────────────────────────────────────────────────────────────────╯なお、Linux用のコードは実装してあるけれど、未テストです。

