TL;DR
- Codex CLIのUIや操作感を変えずに、OpenAI / DeepSeekを切り替えて利用できるようにした
- やり方は、
CODEX_HOMEをOpenAI用 / DeepSeek用に分離し、それぞれの設定・認証情報を独立して管理すること
背景・目的
- Codexの利用制限に達したときの代替としてDeepSeekを使えるようにしたい。ただ、別のCLIへ乗り換えるのではなく、CodexのUIや操作感はそのまま使いたかったため、切り替える方法がないか調べてみた。
- 調べた結果、
CODEX_HOMEを切り替えることで、Codexの設定や認証情報を接続先ごとに分離できることが分かったため、OpenAI用とDeepSeek用の環境を分け、Taskfileから簡単に切り替えられるように実装した。 - この方法や具体的な実装例については、調べてもまとまった情報があまり見つからず、試行錯誤する中でCodexのトークンもかなり消費したため、同じことをもう一度調べ直さなくて済むよう、今回の構成と実装手順をメモとして残しておく。
前提
今回使用した環境は以下。
使用環境
- Codex CLI v0.148.0
- DeepSeek API
- Python 3.x
- uv
- Task
- Linux / WSL
ディレクトリ構成
<PROJECT_ROOT>/
├── .codex-home/
│ ├── main/
│ │ └── config.toml
│ └── deepseek/
│ ├── config.toml
│ └── models.json
└── scripts/
└── switch_codex_profile.py
手順
1 OpenAI用 / DeepSeek用のCODEX_HOMEを作成
OpenAI用 / DeepSeek用にそれぞれ CODEX_HOME を作成し、配下に必要な設定ファイルを配置する。
OpenAI用config.tomlを作成
通常利用しているCodexの設定ファイルをOpenAI用の CODEX_HOME にコピーする。
mkdir -p .codex-home/main
cp ~/.codex/config.toml .codex-home/main/config.toml
DeepSeek用config.toml / models.jsonを作成
まずDeepSeek用の CODEX_HOME を作成する。
mkdir -p .codex-home/deepseek
.codex-home/deepseek/config.toml を作成し、DeepSeek用の設定を記載する。
model = "deepseek-v4-pro"
model_provider = "deepseek"
preferred_auth_method = "apikey"
forced_login_method = "api"
model_reasoning_effort = "high"
model_catalog_json = "<DeepSeek用CODEX_HOME>/models.json"
[model_providers.deepseek]
name = "deepseek"
base_url = "https://api.deepseek.com/"
wire_api = "responses"
experimental_bearer_token = "<DEEPSEEK_API_KEY>"
-
<DeepSeek用CODEX_HOME>と<DEEPSEEK_API_KEY>は、それぞれ実際のパスとDeepSeek APIキーに置き換える。 -
models.jsonはDeepSeek公式ドキュメントで公開されているモデルカタログを配置する。 - ※APIキーを含むため、
.codex-home/はGitの管理対象から除外することを推奨。
2 CODEX_HOMEを切り替えるスクリプトを作成
# scripts/switch_codex_profile.py
import argparse
import shutil
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parents[1]
CODEX_HOME_ROOT = PROJECT_ROOT / ".codex-home"
def get_codex_home(profile: str) -> Path:
return CODEX_HOME_ROOT / profile
def set_profile(profile: str) -> None:
codex_home = get_codex_home(profile)
codex_home.mkdir(parents=True, exist_ok=True)
if profile == "main":
source = Path.home() / ".codex" / "config.toml"
target = codex_home / "config.toml"
if not source.exists():
raise FileNotFoundError(f"OpenAI Codex config not found: {source}")
shutil.copyfile(source, target)
elif profile == "deepseek":
config = codex_home / "config.toml"
models = codex_home / "models.json"
if not config.exists():
raise FileNotFoundError(
f"DeepSeek config not found: {config}\n"
"Create the DeepSeek config.toml before switching."
)
if not models.exists():
raise FileNotFoundError(
f"DeepSeek models.json not found: {models}\n"
"Create models.json from the DeepSeek Codex documentation."
)
def main() -> None:
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest="command", required=True)
set_parser = subparsers.add_parser("set")
set_parser.add_argument("profile", choices=["main", "deepseek"])
path_parser = subparsers.add_parser("path")
path_parser.add_argument("profile", choices=["main", "deepseek"])
args = parser.parse_args()
if args.command == "set":
set_profile(args.profile)
elif args.command == "path":
print(get_codex_home(args.profile))
if __name__ == "__main__":
main()
OpenAI側へ切り替える場合。
uv run python scripts/switch_codex_profile.py set main
export CODEX_HOME="$(uv run python scripts/switch_codex_profile.py path main)"
codex
DeepSeek側へ切り替える場合。
uv run python scripts/switch_codex_profile.py set deepseek
export CODEX_HOME="$(uv run python scripts/switch_codex_profile.py path deepseek)"
codex
3 (Optional) Taskfileに起動コマンドを追加
毎回コマンドを入力するのが面倒なので、Taskfileから起動できるようにする。
version: "3"
env:
UV_CACHE_DIR: "{{.TASKFILE_DIR}}/tmp/uv-cache"
PLAYWRIGHT_BROWSERS_PATH: "{{.TASKFILE_DIR}}/tmp/playwright-browsers"
tasks:
codex:codex:
desc: Run Codex with OpenAI profile.
cmds:
- |
uv run python scripts/switch_codex_profile.py set main
export CODEX_HOME="$(uv run python scripts/switch_codex_profile.py path main)"
codex {{.CLI_ARGS}}
codex:deepseek:
desc: Run Codex with DeepSeek profile.
cmds:
- |
uv run python scripts/switch_codex_profile.py set deepseek
export CODEX_HOME="$(uv run python scripts/switch_codex_profile.py path deepseek)"
codex {{.CLI_ARGS}}
以下のように起動できる。
task codex:codex
task codex:deepseek
ハマったポイント
DeepSeekを指定してもOpenAIのモデルで起動する
最初はDeepSeek用の CODEX_HOME を指定しても、OpenAIのモデルで起動していた。
task codex:deepseek
# > model: gpt-5.6-sol
CODEX_HOME をDeepSeek用のディレクトリに切り替えるだけではなく、その配下にDeepSeek用の config.toml と models.json を事前に配置しておく必要がある。
そのため、DeepSeek用の設定ファイルを用意した上で、その CODEX_HOME を指定してCodexを起動することで解決した。
API key login is required で起動できない
DeepSeek用の設定を読み込めるようにしたところ、次のエラーが発生した。
API key login is required, but ChatGPT is currently being used. Logging out.
原因としては、DeepSeek用の CODEX_HOME にChatGPTの認証状態が残っていたことだった。
DeepSeek用の CODEX_HOME を指定してログアウトすることで解決した。
export CODEX_HOME="<DeepSeek用CODEX_HOME>"
codex logout
OpenAI側ではなく、DeepSeek側の CODEX_HOME を指定してログアウトする点に注意。
参考
-
DeepSeek API Docs - Integrate with Codex
- DeepSeekをCodex CLIから利用するための公式手順。
config.toml/models.jsonの設定を参照。
- DeepSeekをCodex CLIから利用するための公式手順。
-
DeepSeek × Codex セットアップ
- DeepSeek用の
config.tomlを作成する際に参考にした記事。
- DeepSeek用の
-
OpenAI Codex - Configuration Reference
-
CODEX_HOMEやconfig.toml、Model ProviderなどCodex側の設定項目を確認する際に参照。
-