Skip to content

Codex CLI の接続

OpenAI の Codex CLI を shunt へ向け、ChatGPT/Codex OAuth アカウントプールで負荷分散する。

Updated View as Markdown

他の接続ガイドはすべて Claude Code をバックエンドへルーティングします。このページは逆方向です。OpenAI の Codex CLI を shunt へ向け、shunt が ChatGPT/Codex OAuth アカウントのプールで負荷分散します。shunt は Codex CLI の OpenAI Responses トラフィックをそのまま中継します — Anthropic への変換はありません。そのため CLI は、chatgpt.com へ直接話すのと同じワイヤプロトコルで shunt と話します。

これは インバウンド Codex エンドポイントの実践編です。あちらのページが挙動の仕様 (フェイルオーバーの表、枯渇時のセマンティクス、リロードのルール)で、以下の手順はエンドツーエンドの接続ウォークスルーです。ここで引用している Codex CLI の設定キーは、OpenAI の設定リファレンス認証のドキュメントに基づいています。

1. shunt でエンドポイントを有効にする

インバウンドエンドポイントはオプトインです。テーブルを追加し、chatgpt_oauth プロバイダーへ向けます (デフォルトのプロバイダー名は codex です)。

# shunt config.toml
[server.codex_endpoint]
provider = "codex"        # must be a chatgpt_oauth provider; "codex" is the built-in default

codex は組み込みの chatgpt_oauth プロバイダーなので、エンドポイントを有効にするために [providers.codex] ブロックは不要です。別名のプロバイダーへ向けるには、[providers.<name>] テーブルとして宣言し (設定リファレンスを参照)、上記の provider = "<name>" を設定します。

shunt check                # validates the endpoint's provider exists + is chatgpt_oauth
shunt run

[server.codex_endpoint] がない場合、いずれのルートも登録されず、shunt のデフォルトの HTTP サーフェスは変わりません。存在する場合、起動時の検証は未知の providerauthchatgpt_oauth でないプロバイダーを拒否します — このエンドポイントはオペレーターの Codex ベアラーを注入するため、chatgpt_oauth プロバイダーだけが要件を満たします。すべてのキーについては 設定リファレンスを参照してください。

2. Codex CLI を shunt へ向ける

Codex CLI は、使用する base URL が何であれ /responses を末尾に付けます(Codex は OpenAI Responses のワイヤプロトコルを話します — wire_api = "responses" が唯一サポートされる値です)。そのため shunt は 3 つのルートを登録し、以下のどのクライアント形状もそのいずれかに着地します。

Codex CLI の ~/.codex/config.toml 到達する shunt のルート
カスタムプロバイダー base_url = ".../v1" POST /v1/responses
openai_base_url = ".../v1" POST /v1/responses
chatgpt_base_url = ".../backend-api/codex" POST /backend-api/codex/responses

推奨 — カスタムモデルプロバイダー。 requires_openai_auth = false にすると CLI から見て未認証になるため、ローカルの codex loginまったく不要で(アカウントは shunt が供給します)、shunt トークンの提示方法もどちらの形式でも動作します(ステップ 3)。

# ~/.codex/config.toml
model_provider = "shunt"          # select it as the active provider
model = "gpt-5.6-sol"             # an entitled slug — see step 5

[model_providers.shunt]
name = "shunt"
base_url = "http://127.0.0.1:3001/v1"
wire_api = "responses"            # the only supported value; also the default
requires_openai_auth = false      # shunt handles auth; the CLI needs no ChatGPT/API login here

より簡単 — base URL を上書きする(プロバイダーブロックなし):

# ~/.codex/config.toml — pick one
openai_base_url  = "http://127.0.0.1:3001/v1"                 # + OPENAI_API_KEY = your shunt token
chatgpt_base_url = "http://127.0.0.1:3001/backend-api/codex"  # loopback only (ChatGPT login mode)

openai_base_url + OPENAI_API_KEY=<shunt-token> は LiteLLM/llmgateway の作法です — CLI はトークンを Authorization: Bearer として送り、shunt はそれを受け付けます(ステップ 3)。したがってこの形状は [server.auth] があっても動作します。chatgpt_base_url は CLI を ChatGPT ログインモードのままにし、自身の ChatGPT トークンを送るため、shunt はそれをクライアントトークンとして受け付けられません — ゲートされていない(ループバックの) shunt でのみ使ってください。どちらも CLI を自身の OpenAI/ChatGPT 認証モードで動かすため、いずれもローカルの codex login が必要です。上記のカスタムプロバイダーなら、それすら不要になります。

CLI 自身のローカルな ~/.codex/auth.json のログインは、どのアカウントが応答するかとは無関係です — すべてのリクエストは shunt のプールからアカウントを引きます。ループバックの base_url は素の http:// のままで構いません。リモートには https:// を使ってください。shunt プロバイダーには supports_websockets = true を設定しないでください — このエンドポイントは HTTP/SSE 専用です(後述)。

3. shunt クライアントトークンを提示する([server.auth] 設定時)

shunt に [server.auth] が設定されている場合 — ループバックを超えるものには推奨です — shunt のクライアントトークンを 2 通りのいずれかで提示します。shunt はどちらも受け付けます。

A. OpenAI 形式の Bearer キーとして — LiteLLM/llmgateway の作法です。shunt トークンを API キーとして設定すると、CLI はそれを Authorization: Bearer <shunt-token> として送ります。

# ~/.codex/config.toml — built-in openai provider (no provider block needed).
# Set the base URL here, NOT via the OPENAI_BASE_URL env var (see the caution in step 2).
openai_base_url = "http://127.0.0.1:3001/v1"
# then present only the token via env — the CLI sends it as Authorization: Bearer
export OPENAI_API_KEY="<shunt-token>"
# or a custom provider — env_key becomes the Bearer
[model_providers.shunt]
base_url = "http://127.0.0.1:3001/v1"
wire_api = "responses"
env_key = "SHUNT_TOKEN"      # reads $SHUNT_TOKEN, sent as Authorization: Bearer

B. x-shunt-token ヘッダーとして(あるいは [server.auth].header が指定する名前で)。ヘッダーを付けられるのはカスタムプロバイダーだけです。env_http_headers でシークレットを config.toml の外に保ってください。

[model_providers.shunt]
name = "shunt"
base_url = "http://127.0.0.1:3001/v1"
wire_api = "responses"
requires_openai_auth = false
env_http_headers = { "x-shunt-token" = "SHUNT_TOKEN" }   # reads $SHUNT_TOKEN
export SHUNT_TOKEN="<token>"

(あるいは http_headers = { "x-shunt-token" = "<token>" } とハードコードします。)いずれの場合もトークンは [server.auth] のリストと照合され、欠落や誤りがあれば 401 authentication_error を返します。[server.auth] がまったくない場合、エンドポイントはそこへ到達できる誰にでも開かれています — ループバックなら問題ありませんが、共有ゲートウェイでは不可です。クライアントのベアラー/ヘッダーは shunt への認証にのみ使われ、取り除かれて Codex バックエンドへ転送されることはありません。

4. shunt でアカウントプールをプロビジョニングする

このエンドポイントは Codex マルチアカウントのプールをそのまま再利用します — アカウントは CLI 側ではなく shunt のホストでプロビジョニングしてください。

codex login                       # sign in to a ChatGPT account (browser flow)
shunt login codex --name main     # capture it into shunt's store
# Each additional pool account needs its own login + capture (a separate ChatGPT
# account): `codex login` then `shunt login codex --name backup`, and so on.
# shunt config.toml
[[providers.codex.accounts]]
name = "main"

[[providers.codex.accounts]]
name = "backup"     # each declared name must be provisioned above; an unprovisioned
                    # account is skipped on failover (its credential fails to resolve)

選択はセッションスティッキーです。Codex CLI 自身の session-id リクエストヘッダーがアカウントのキーになるため、1 つの会話は健全なかぎり 1 つのアカウントに留まり、その後フェイルオーバーします(429 → ローテーション、401 → リフレッシュ + リトライ、5xx → クールダウン + ローテーション)。プール経由の成功レスポンスには x-shunt-account: <name> ヘッダーが付きます。[server.auth] を有効にした共有ゲートウェイでは、スティッキーキーが認証済みクライアントごとにスコープされるため、たまたま同じ session-id を送る別々のクライアントは別々のスティッキーキーを使います — クライアント間でのスティッキーキーの衝突を防ぐためです。(キーは別個ですが、別個の 2 つのキーが同じアカウントにハッシュされることはあり得ます。)

[[providers.codex.accounts]]まったく設定されておらず、ストアも空の場合、エンドポイントはデフォルトの ~/.codex/auth.json 認証情報 1 つへフォールバックします — プールもフェイルオーバーもありません。そのため [server.codex_endpoint] を設定した時点で、Codex ログイン 1 つで動作します。

5. entitle されたモデルを選ぶ

6. 検証する

3 つのルートのいずれかに対する生の Responses リクエストは、そのまま中継され、(プールされている場合は) x-shunt-account ヘッダーを返すはずです。

curl -N -i -X POST http://127.0.0.1:3001/v1/responses \
  -H "content-type: application/json" \
  -H "x-shunt-token: <token>" \
  -d '{"model":"gpt-5.6-sol","input":"say hi","stream":true}'
  • content-type: text/event-streamx-shunt-account: ヘッダーを伴う 200 ⇒ プールがリクエストを処理し、SSE がそのまま中継されています。
  • 401 authentication_errorx-shunt-token が欠落しているか無効です(ステップ 3)。
  • モデル名を挙げた 400 ⇒ そのアカウントがそのスラッグに entitle されていません(ステップ 5)。

続いて実際の Codex CLI で 1 ターン走らせてみてください — base URL 以外に CLI 側のコード変更なしで、プールを往復します。/v1/messages 経路との違いは インバウンド Codex エンドポイントを、登録されるルートは HTTP エンドポイントを参照してください。

HTTP/SSE のみ

対象のプロバイダーが websocket = true であっても、このエンドポイントは常に HTTP トランスポートを使います。そのため Codex CLI の shunt プロバイダーでは supports_websockets をオフ(デフォルト)のままにしてください。実験的な Codex WebSocket v2 トランスポート はこのエンドポイントのスコープ外で、フォローアップとして追跡されています。

Navigation

Type to search…

↑↓ navigate↵ selectEsc close