3行でいうと
- 公式の線引きは、CIや定期ジョブの自動化はSDK、認証・会話履歴・承認・ストリームまで自分のプロダクトの中に持ちたいときはapp-server、です。
codex mcp-serverは削除済みで、app-serverへの移行が案内されています。 - TypeScriptのSDK(
@openai/codex-sdk)はcodexのCLIを子プロセスとして起動します。PythonのSDK(openai-codex)はローカルのapp-serverをJSON-RPCで制御します。どちらも「ローカルのCodexを動かす」もので、サーバーに置くなら、そこにCodex本体と作業フォルダが要ります。 - app-serverのコマンドとWebSocket転送は、公式が「実験的で、本番向けには未対応」と書いています。さらに、app-serverの認証は商用やホスト型のサービスでは許されたことがない、という注意書きがあります。公式が勧めるSign in with ChatGPTは、読んだ範囲では選ばれた商用パートナー向けで、一般向けの手順は見つかりませんでした。
- 実験的の印がついた機能は、
initializeでcapabilities.experimentalApiをtrueにしないと使えません。モデル名や使える範囲は変わりやすいので、公式の表示と日付をそのまま確かめてください。
この記事は、実際に使って確かめた記録ではありません。運営者はCodexを入れていますが、使い心地はこの記事には書いていません。この記事は、2026年10月24日に公式ドキュメント(learn.chatgpt.com、developers.openai.com)と公式リポジトリ(openai/codex)を読んでまとめたものです。コードとJSONは公式の例を写したか、公式の記述からこの記事で並べ直したもので、実行していません。取得は要約の形で返るため、読み切れていない箇所は「読めていない」と書きました。契約や法律の助言ではありません。
先に結論
- まず「誰が動かすか」で決めます。 自分のパソコンやCIで、自分のアカウントかAPIキーで動かす自動化なら、SDKか
codex exec(前のガイド07)。自分のプロダクトの利用者に、会話・承認・ログインの画面を見せるなら、app-server。モデルだけ呼びたいなら、OpenAI APIのResponses APIです。 - SDKは「ローカルのCodexを遠隔操作する窓口」です。 最小の形は、TypeScriptが
startThread()とthread.run()、Pythonがthread_start()とthread.run()です。 - app-serverは、JSON-RPCで話す別のプロトコルです。
initialize、initialized、thread/start、turn/startの順に送り、通知を読みます。承認はサーバーからの「要求」で届き、クライアントが答えます。 - 認証は3つの層が混ざりやすいところです。 ①動かすCodexが誰としてOpenAIに入るか、②自分のクライアントとapp-serverの間、③自分のアプリの利用者をどう扱うか。商用・ホスト型で①のapp-server認証を使うことは、公式が許していません。
前提:用語をそろえる
- SDK:自分のコードからCodexを動かすライブラリ。公式はTypeScriptとPythonを挙げています。
- app-server:
codex app-serverというコマンドで、VS Code拡張のような「リッチなクライアント」を動かす窓口です。通信はJSON-RPC 2.0(公式は、"jsonrpc":"2.0"は通信では省略する、と書いています)。 - Thread / Turn / Item:Threadは会話、Turnはユーザーの1回の依頼とエージェントの作業、Itemはその中の入力や出力のひとつひとつ(メッセージ、コマンドの実行、ファイル変更、道具の呼び出しなど)です。
- Responses API:OpenAI APIの、モデルを呼ぶ窓口です。Codexの中身が裏でモデルに話しかけるときも、この形(
wire_api = "responses")が使われます。 - 実験的(experimental):公式がこの言葉をつけた機能は、変わったり消えたりしうる、という意味で読みます。
入口を選ぶ:どれを使うか
公式のSDKのページ、app-serverのページ、MCPサーバーのページ、モデルのページ、OpenAI APIのコード生成のガイドを並べ直しました。
| 入口 | 向いていること | 公式が書いている状態 | 認証とホスト型の扱い | 出典 |
|---|---|---|---|---|
codex exec |
1回きりの画面なしの実行、CI | 前のガイド(07)に詳しく書いた | CODEX_API_KEY が対象(環境変数のページ)。ホスト型の可否は読んだ範囲では見つからなかった |
Non-interactive mode |
TypeScript SDK(@openai/codex-sdk) |
サーバー側のNode.js(18以上)から、ローカルのCodexのスレッドを開始、継続、再開する | 公式のSDKのページに、実験的や非推奨の印は見つからなかった | CODEX_API_KEY が対象。既存のログインも使える。ホスト型の可否は読んだ範囲では見つからなかった |
Codex SDK |
Python SDK(openai-codex) |
ローカルのapp-serverをJSON-RPCで制御する。Python 3.10以上 | 「stable release」と書かれ、先行版は pip install --pre で選ぶ |
既存のログイン情報を自動で使い、login_chatgpt() などで始められる。ホスト型の可否は読んだ範囲では見つからなかった |
Codex SDK |
| app-server | 認証、会話履歴、承認、ストリームのイベントまで含めた、自前のクライアントを作る | コマンドとWebSocketは、実験的で本番向けには未対応と書かれている | 認証は商用・ホスト型では許されたことがない(app-serverのページ)。ローカルとオープンソースは継続可 | Codex app server |
| Responses API(OpenAI API) | Codexのエージェントの動きを使わず、モデルを直接呼ぶ | 通常のOpenAI API | OpenAI APIのキーで呼ぶ。Codexの認証の話とは別 | Code generation(OpenAI API) |
codex mcp-server |
(MCPサーバーとしてCodexをホストする) | 削除済み。app-serverへ移行 | 該当なし(削除済み) | Codex MCP server |
読み方のコツです。公式のapp-serverのページは、冒頭で「認証、会話履歴、承認、ストリームされるエージェントのイベントまで含む、プロダクトの中の深い統合」に向く、と書き、「ジョブの自動化やCIならSDKを使う」と書き分けています。SDKのページも、独自のクライアントを作るならapp-serverへ、と案内しています。また、PythonのSDKは中でapp-serverを使っているので、「SDKで足りるか、app-serverを直接叩くか」は、SDKの窓口で足りるかどうかの話です。
TypeScript SDK:最小の例
公式のSDKのページによると、TypeScriptの窓口は、アプリが「ローカルのCodexのスレッド」を開始、継続、再開できるライブラリです。サーバー側で使うこと、Node.js 18以上が必要なことが書かれています。
npm install @openai/codex-sdk
最小の使い方は、公式のページの例のとおり、次の形です。先頭のimportの行は、公式のREADMEにある1行を足しました。
import { Codex } from "@openai/codex-sdk";
const codex = new Codex();
const thread = codex.startThread();
const result = await thread.run(
"Make a plan to diagnose and fix the CI failures"
);
console.log(result.finalResponse);
同じスレッドで続けるには、もう一度 run() を呼びます。昔のスレッドに戻るには、スレッドのIDを resumeThread に渡します。
// running the same thread
const result = await thread.run("Implement the plan");
console.log(result.finalResponse);
// resuming past thread
const threadId = "<thread-id>";
const thread2 = codex.resumeThread(threadId);
const result2 = await thread2.run("Pick up where you left off");
console.log(result2.finalResponse);
中で何が起きているか(公式のREADMEより)
公式のSDKのREADMEによると、TypeScriptのSDKは、@openai/codex の codex のCLIを包み、子プロセスとして起動します。CLIとのやり取りは、標準入出力のJSONLです。ここで言えるのは次のことです。
- Codex本体が、動かす機械に必要です。 CLIが動く環境(作業フォルダ、権限、認証)が、そのままあなたのアプリの実行環境になります。
run()は、ターンが終わるまで返りません。 途中の経過を見たいときは、runStreamed()を使います。返ってくるeventsを、非同期のイテレーターで読む形で、item.completed(完了した項目)やturn.completed(使用量つき)といったイベントが挙がっています。イベントの全種類とフィールド名は、読めた範囲では確認できていません。- 返答の形を決められます。
run()にoutputSchema(JSON Schema)を渡すと、スキーマに合うJSONで返ります。結果はfinalResponseから読みます。ZodのスキーマからJSON Schemaを作る方法も、READMEに書かれています(zod-to-json-schemaをtargetに"openAi"を指定して使う)。 - 画像を渡せます。 文字列の代わりに配列を渡し、
"text"と"local_image"(pathつき)を並べます。画像はCLIの--imageとして渡されます。 - スレッドは保存されます。
~/.codex/sessionsに保存され、メモリ上のThreadを失っても、IDで再開できます。
途中経過を読む runStreamed()、返答の形を決める outputSchema
公式のREADMEの例は次の形です(抜粋で、switch の中の分岐は公式の例では先頭の item.completed までしか読めていません)。
const { events } = await thread.runStreamed(
"Diagnose the test failure and propose a fix"
);
for await (const event of events) {
switch (event.type) {
case "item.completed":
// 完了した項目(メッセージ、コマンド、ファイル変更など)を読む
break;
case "turn.completed":
// 使用量(event.usage)が入る
break;
}
}
outputSchema は、JSON Schemaを run() の2つ目の引数に渡します。READMEの例は次のとおりです。
const schema = {
type: "object",
properties: {
summary: { type: "string" },
status: { type: "string", enum: ["ok", "action_required"] },
},
required: ["summary", "status"],
additionalProperties: false,
} as const;
const turn = await thread.run("Summarize repository status", {
outputSchema: schema,
});
console.log(turn.finalResponse);
画像を渡す例も、READMEにあります。
const turn = await thread.run([
{ type: "text", text: "Describe these screenshots" },
{ type: "local_image", path: "./ui.png" },
{ type: "local_image", path: "./diagram.jpg" },
]);
(上の case 内のコメントは僕らの補足です。turn.completed の usage の細かい項目は読めていません。)
設定の渡し方と、よくつまずく点
| オプション | 渡す場所 | 公式の説明 |
|---|---|---|
workingDirectory |
startThread() |
Codexが動くフォルダ。既定は現在のフォルダ |
skipGitRepoCheck |
startThread()(README) |
Codexは既定でGitリポジトリを求める(取り返しのつかない失敗を避けるため)。true で確認を飛ばす |
env |
Codex のコンストラクタ |
既定ではCLIがNode.jsの環境を継承する。env を渡すと、CLIが受け取る変数を細かく決められる。CODEX_API_KEY のような必要な変数は、渡した環境の上にSDKが足す |
baseUrl |
Codex のコンストラクタ |
openai_base_url の設定として渡される |
config |
Codex のコンストラクタ |
設定のJSON。入れ子のキーは点でつないだ形にされ、値はTOMLの形で --config key=value として渡される |
configOverrides |
Codex のコンストラクタ |
点のつなぎでは書けないキー用に、TOMLの文字列をそのまま --config に渡す |
優先順位は、弱い順に、config、configOverrides、SDKが決める設定(baseUrl やスレッドごとの設定)と書かれています。これらはCodexの設定ファイルを書き換えません。公式の例は次の形です。
const codex = new Codex({
config: { default_permissions: "audit" },
configOverrides: [
'permissions.audit.filesystem={":root"="read","/path/to/project/.env"="deny"}',
],
});
これは、「audit という名前の権限プロファイルを選び、全体は読み取りだけ、.env は拒否」という設定を、SDKの呼び出しの側から与える例、と僕らは読みました。承認とサンドボックスの考え方は前のガイド(02)に書きました。
もうひとつ。env を指定すると、親のプロセスの環境変数は、指定したものだけになると読めます(READMEは「fully control(完全に決められる)」と書くだけで、「継承の代わり」とまでは明言していません)。公式の例は env: { PATH: "/usr/local/bin" } の形で、READMEはElectronアプリのようなサンドボックス化されたホストに便利、と添えています。PATHやHOMEを入れ忘れるとCLIが動かない、という事故がありうるので、最初は親の環境をコピーして必要なものを足す形から試すと安全に見えます(これは僕らの見立てです)。
認証
公式の環境変数のページによると、CODEX_API_KEY は、非対話の実行用のAPIキーで、exec、review、TypeScriptのSDK、遠隔の exec-server が対象です。信用できないリポジトリのコードを動かすときは、ジョブ全体ではなくコマンドごとに渡す、と書かれています。APIキーでは使えない機能(クラウド、GitHubのレビュー、Slackなど)があることは、前のガイド(06)に書いたとおりです。
Python SDK:最小の例
公式のPython SDKのREADMEとgetting-startedによると、インストールは次のとおりです。
pip install openai-codex
必要なのはPython 3.10以上です。SDKは、対応する openai-codex-cli-bin を依存として自動で入れます。「安定版のSDKは、対応する安定版のCodex CLIに合わせる」と書かれています。特定のローカルの実行ファイルを使いたいときだけ、CodexConfig(codex_bin=...) を渡します。先行版を試すなら、次のとおりです。
pip install --pre openai-codex
最小の例は、公式のREADMEのとおり次の形です。既存のCodexのログイン情報があれば、自動で使われます。
from openai_codex import Codex
with Codex() as codex:
thread = codex.thread_start()
result = thread.run("Explain this repository in three bullets.")
print(result.final_response)
thread.run(...) は TurnResult を返し、最終の返答、集めた項目、トークンの使用量が入る、と書かれています。サンドボックスは3つの既定の型で選びます。
| 型 | 公式の説明 |
|---|---|
Sandbox.read_only |
ファイルを読めるが書けない |
Sandbox.workspace_write |
読めて、ワークスペースと設定した書き込み可能な場所には書ける |
Sandbox.full_access |
ファイルシステムの制限なし |
sandbox= を省くと、app-serverの設定の既定になります。run(...) や turn(...) に渡したサンドボックスは、そのターンと、同じスレッドの以後のターンに効く、と書かれています。
公式の例は、thread_start(sandbox=Sandbox.workspace_write) で始め、thread.run("Review the diff only.", sandbox=Sandbox.read_only) のように、レビューのターンだけ読み取りにする形です。
続きの会話は、同じ thread で run を重ねます。保存済みのスレッドに戻るには codex.thread_resume("thr_123") です。非同期のアプリには、AsyncCodex(async with AsyncCodex() as codex:、await codex.thread_start(...))が用意されています。
ログインをコードから始める
PythonのSDKは、既存のログイン情報が使える場合はそれを使い、明示的にログインを始めることもできます。公式の例は3つです。
# ChatGPTのブラウザログイン
with Codex() as codex:
login = codex.login_chatgpt()
print(login.auth_url)
print(login.wait().success)
# ChatGPTのデバイスコード
with Codex() as codex:
login = codex.login_chatgpt_device_code()
print(login.verification_url, login.user_code)
login.wait()
# APIキー
with Codex() as codex:
codex.login_api_key("sk-...")
他のエージェントや道具の出力をSDKに渡すときは、ExternalMessage として渡す、と公式のgetting-startedにあります。道具としての権限は保つが、ユーザーが許可・承認した扱いにはならない、という説明です。細かい仕様はAPIリファレンス側にあり、読めていません。
公式のモデル名の例が、ページによって違う
SDKのページ(Pythonの例)とapp-serverのページの例は gpt-6.1-sol で、SDKのページは「そのアカウントで使えなければ model を省いて既定を使う」と書いています。app-serverのGitHubのREADMEの例は gpt-5.1-codex で、ページごとに例の更新時期が違うようです。公式のモデルのページ(確認日2026-10-24)は、Codexのモデルとして gpt-6-astra、gpt-6.1-sol、gpt-6-luna を挙げ、旧モデルの退役日も載せています(たとえば gpt-5.5 は2026年10月14日の退役と書かれ、ただしそれはChatGPTサインインのCodexの話で、APIキーとOpenAI APIは影響を受けない、とあります)。さらに、OpenAI APIのコード生成のガイドはCodexに合うモデルとして gpt-6-sol を挙げ(後の節)、モデルのページは gpt-6.1-sol を挙げていて、同じ公式の中でも名前がずれています。例のモデル名はそのままコピーせず、自分の環境で使える名前に置き換えてください。
app-server:自前のクライアントを作る
何であって、何でないか
公式のapp-serverのページは、これを「VS Code拡張のようなリッチなクライアントを動かすためのインターフェース」と説明し、オープンソースだ、と書いています。公式のオープンソースのページは、app-serverのソースを openai/codex の codex-rs/app-server にあると示しています。また、MCPのページは、app-serverは「MCPサーバーではなく、MCPクライアントの置き換えにもならない」と書いています。使っていた人は、MCPの道具の呼び出しを、app-serverのプロトコルの呼び出しに置き換える必要があります。
起動と転送方式
| 転送 | 起動の書き方 | 公式の説明 |
|---|---|---|
| stdio(既定) | --listen stdio://(--stdio) |
改行区切りのJSON(JSONL) |
| WebSocket | --listen ws://IP:PORT |
1つのテキストフレームに1つのJSON-RPCメッセージ。実験的で未対応 |
| Unixソケット | --listen unix:// または --listen unix://PATH |
WebSocketを、既定か指定のソケットの上で |
| なし | --listen off |
ローカルの転送を作らない |
WebSocketで待ち受けると、GET /readyz(待ち受けが始まれば 200 OK)と GET /healthz が使えます。Origin ヘッダーつきの要求は 403 で断られます。公式がWebSocketについて強く書いていることは、次のとおりです。
- 「app-serverのコマンドとWebSocket転送は、実験的で、本番では未対応」と書かれています。
- 平文のWebSocketは、ローカルホストかSSHのポート転送の中だけ。ローカル以外では、認証をかけ、TLS(
wss://)を使います。 - ループバック以外の待ち受けは、展開期間中、既定では認証なしの接続を許す、と書かれています。公開する前に認証を設定します。
- 認証は
--ws-auth capability-token(--ws-token-fileか--ws-token-sha256)か--ws-auth signed-bearer-token(--ws-shared-secret-fileなど)。クライアントはAuthorization: Bearer <トークン>を送り、認証はinitializeより前に行われます。(--ws-token-fileはファイルで渡す形で、生のトークンをコマンドラインに書かずに済みます。これを勧める文は、読めた範囲では確かめられませんでした。) - 負荷が高いと、JSON-RPCのエラー
-32001(「Server overloaded; retry later.」)が返り、指数バックオフとジッターつきで再試行する、と書かれています。
別の場所のapp-serverにCLIの画面をつなぐ例も、公式にあります。遠隔のときは、トークンを環境変数(CODEX_REMOTE_TOKEN)に置き、--remote-auth-token-env で渡す形が勧められています。
codex app-server --listen ws://127.0.0.1:4500
codex --remote ws://127.0.0.1:4500
流れ:initialize から turn/completed まで
公式の流れは、次のとおりです。
- app-serverを起動する(
codex app-server、またはオプションつき)。 - 接続して、
initializeを送り、そのあとinitializedという通知を送る。この手順の前にほかの要求を送ると、Not initializedのエラーになります。2回目のinitializeはAlready initializedになります。 - スレッドを始め(
thread/start)、続きならthread/resume、枝分かれならthread/fork。 turn/startでターンを始め、turn/steerで途中に入力を足し、turn/interruptで中断する。- 届く通知を読み、
turn/completedで最終の状態を受け取る。
公式の initialize の例(VS Code拡張のもの)は次の形です。
{
"method": "initialize",
"id": 0,
"params": {
"clientInfo": {
"name": "codex_vscode",
"title": "Codex VS Code Extension",
"version": "0.1.0"
}
}
}
公式は、clientInfo.name が、OpenAIのコンプライアンスログ基盤で、どのクライアントかを識別するために使われる、と書いています。企業のインテグレーションは、既知のクライアントの一覧に載せてもらうため、OpenAIに連絡する、とも書かれています。
thread/start の公式の例は次の形です(app-serverのページのもの。approvalPolicy の never は、承認の確認を出さない設定のはずです。前のガイド02で意味を確かめてから使ってください)。
{ "method": "thread/start", "id": 10, "params": {
"model": "gpt-6.1-sol",
"cwd": "/Users/me/project",
"approvalPolicy": "never",
"sandbox": "workspaceWrite",
"serviceName": "my_app_server_client"
} }
応答には thread.id などが入り、そのあと thread/started の通知が届きます。続けて turn/start の公式の例は次の形です。なお、この例の approvalPolicy: "unlessTrusted" は、app-serverのプロトコル側の値です。前のガイド02が書くCLI側の値(untrusted は廃止)とは別の面の表記なので、自分のCodexの版のスキーマで確かめてください。
{ "method": "turn/start", "id": 30, "params": {
"threadId": "thr_123",
"input": [ { "type": "text", "text": "Run tests" } ],
"cwd": "/Users/me/project",
"approvalPolicy": "unlessTrusted",
"sandboxPolicy": {
"type": "workspaceWrite",
"writableRoots": ["/Users/me/project"],
"networkAccess": true
},
"model": "gpt-6.1-sol",
"effort": "medium",
"summary": "concise"
} }
(公式の例には、ほかに personality と outputSchema も入っています。)
応答は、{ "id": 30, "result": { "turn": { "id": "turn_456", "status": "inProgress", "items": [], "error": null } } } の形です。input に入れられるのは、text、image、localImage(パス)などです。image は、learn.chatgpt.com のapp-serverのページでは { "type": "image", "url": "https://.../design.png" } の例ですが、GitHubのREADMEは、インラインのデータURLが要り、リモートのHTTP(S)の画像URLは拒否される、と書いていました(公式の2つの資料で食い違っています)。自分のCodexの版のスキーマと動きで確かめてください。モデル、effort、cwd、サンドボックスの方針、summary の上書きは、同じスレッドの以後のターンの既定になります。outputSchema だけは、そのターンだけです。
標準入出力で話す最小の組み立て(公式の例をこの記事で並べ直したもので、動作は確かめていません)は、次の順に1行ずつ送る形です。
{"method":"initialize","id":0,"params":{"clientInfo":{"name":"my_app","title":"My App","version":"0.1.0"}}}
{"method":"initialized","params":{}}
{"method":"thread/start","id":1,"params":{"cwd":"/path/to/project"}}
(応答の thread.id を使って)
{"method":"turn/start","id":2,"params":{"threadId":"<thread.id>","input":[{"type":"text","text":"Summarize this repo."}],"sandboxPolicy":{"type":"readOnly"}}}
initialized は、公式のNode.jsの例に send({ method: "initialized", params: {} }); とあるので、params を空で付けました。sandboxPolicy の readOnly は、公式のページに値として挙がっています。公式のNode.jsの例は、codex app-server を子プロセスで起動し、標準出力を1行ずつJSONとして読んで、この順で送る構成だと、取得した要約に書かれています。公式のNode.jsの例は、readline を取り込む行がなく、そのままでは動かない、と取得結果にありました。これを補って、承認の要求には必ず decline を返す骨組みにしたものが次です(この記事で公式の例と、承認の決定値の記述から並べ直したもので、この記事では動作を確かめていません)。
import { spawn } from "node:child_process";
import readline from "node:readline";
const proc = spawn("codex", ["app-server"], {
stdio: ["pipe", "pipe", "inherit"],
});
const rl = readline.createInterface({ input: proc.stdout });
const send = (message: unknown) => {
proc.stdin.write(`${JSON.stringify(message)}\n`);
};
rl.on("line", (line) => {
const msg = JSON.parse(line);
console.log(msg);
if (msg.id === 1 && msg.result?.thread?.id) {
send({
method: "turn/start",
id: 2,
params: {
threadId: msg.result.thread.id,
input: [{ type: "text", text: "Summarize this repo." }],
},
});
}
// サーバーからの「要求」: method と id の両方がある
if (msg.method?.endsWith("/requestApproval") && msg.id !== undefined) {
// result の中身の形は、公式のページでは確かめられていない
send({ id: msg.id, result: { decision: "decline" } });
}
});
send({ method: "initialize", id: 0, params: {
clientInfo: { name: "my_product", title: "My Product", version: "0.1.0" },
} });
send({ method: "initialized", params: {} });
send({ method: "thread/start", id: 1, params: { cwd: process.cwd() } });
最初の3つの send と、id が 0、1、2 と進む流れは、公式の例のとおりです。thread/start に付けた cwd は、公式の thread/start の例にある項目です。一方、承認への返事の形(result の中に decision を入れる書き方)は、公式のページに「決定値の payload で答える」とあるだけで、封筒の形は載っていませんでした。僕らの推測なので、次の generate-json-schema で作ったスキーマで必ず確かめてください。
版に合ったスキーマは、次のコマンドで作れます。
codex app-server generate-ts --out ./schemas
codex app-server generate-json-schema --out ./schemas
公式は、これらの出力は、生成したCodexの版に固有、と書いています。つまり、クライアントを書くときは、自分が動かすCodexの版からスキーマを作るのが、一番ずれにくいやり方です(これは僕らの見立てです)。
通知を読む:イベントの流れ
公式の「Event streaming」によると、スレッドを始めたあと、クライアントは thread/started、thread/status/changed、turn/*、item/*、serverRequest/resolved などの通知を読み続けます。
turn/started:statusがinProgress、itemsは空。- 各Itemは
item/started(idが差分のitemIdと対応)と、item/completed(最終の状態として信頼できるもの)を出します。 - 差分は、
item/agentMessage/delta、item/commandExecution/outputDelta、推論や計画の差分など。 - 不要な通知は、
initializeのcapabilities.optOutNotificationMethodsに、メソッド名そのもの(ワイルドカードなし)を並べて止められます。 - ターンの終わりは
turn/completedで、turn.statusはcompleted、interrupted、failedのどれかです。公式の例(SIWCのページ)は、成功はcompletedだけで、failedとinterruptedは成功ではない、と書いています。
失敗したターンは、error のイベントのあと turn/completed(status: "failed")で終わります。codexErrorInfo には ContextWindowExceeded、UsageLimitExceeded、Unauthorized、SandboxError などの値が入り、取得できた場合は上流のHTTPステータスが httpStatusCode に入ります。
承認:サーバーからの「要求」に、クライアントが答える
app-serverでは、コマンドの実行、ファイルの変更、権限の追加の許可が、サーバーからクライアントへの要求として届きます。クライアントが答えないと、ターンは先へ進みません。(これは僕らの見立てです。公式は、承認の応答がないときの挙動を、読めた範囲では書いていません。)
| 種類 | 届く要求 | 答えの選択肢 | 公式の補足 |
|---|---|---|---|
| コマンドの実行 | item/commandExecution/requestApproval(itemId、threadId、turnId、任意で reason、command、cwd、availableDecisions) |
accept、acceptForSession、decline、cancel、または acceptWithExecpolicyAmendment |
最後に item/completed で completed、failed、declined のどれか |
| ファイルの変更 | item/fileChange/requestApproval(reason、grantRoot など) |
accept、acceptForSession、decline、cancel |
同上 |
| 権限の追加 | item/permissions/requestApproval(要求する権限のネットワークやファイルを含む) |
許可した部分だけを permissions として返す |
scope を "session" にすると以後のターンも有効。省略か "turn" なら今のターンだけ。許可しなかった要求は無視される |
どの要求も、答えたあとに serverRequest/resolved が届きます。道具やアプリの副作用のある呼び出しは承認が要ることがあり、破壊的と注釈された呼び出しは、必ず承認が要る、と書かれています。承認の画面を自分で作るとは、この表の3種類に、自分のUIで人の判断を返すことです。
危険な窓口と、取り消せない操作
公式のページが、特に注意を書いているものです。
thread/shellCommandとprocess/*:サンドボックスの外で動きます(前者はフルアクセス、既定のタイムアウトは1時間)。ユーザーが明示的に出した命令のときだけ公開するよう、書かれています。process/*は実験的です。thread/delete:永続的に消し、スレッドの子孫も消します。thread/revert:ターンと以後の履歴を取り除きますが、ローカルのファイルの変更は元に戻しません。thread/rollback:削除済みで、呼ぶと「未知のメソッド」のエラーになります。
実験的の印と、そのスイッチ
initialize の capabilities.experimentalApi を省くか false にすると、安定した範囲だけです。true にすると実験的な項目が使え、使わずに呼ぶと「requires experimentalApi capability」のエラーになります。公式が実験的とするものの例は、process/*、environment/info、dynamicTools、historyMode、chatgptAuthTokens、tool/requestUserInput などです。permissions は、experimentalApi で開く「Beta」のクライアント向けと書かれています。plugin/* は「開発中で、本番のクライアント向けではない」と書かれています。experimentalFeature/list は、機能ごとの段階(beta、underDevelopment、stable、deprecated、removed)を返します。
認証:3つの層を分けて考える
層1:SDKやapp-serverが動かすCodexは、誰としてOpenAIに入るか
app-serverのページのアカウントの節(account/*)によると、認証のモードは、APIキー(apikey)、ChatGPT管理(chatgpt)、外部のChatGPTトークン(chatgptAuthTokens、実験的)です。Amazon Bedrockの認証にも触れた箇所がありましたが、細部は読めていません。
| 方法 | account/login/start の type |
公式の説明 |
|---|---|---|
| APIキー | apiKey |
apiKey を渡す |
| ChatGPTのブラウザログイン | chatgpt |
loginId と、ユーザーが開く authUrl が返る |
| ChatGPTのデバイスコード | chatgptDeviceCode |
verificationUrl と userCode が返り、クライアントが表示する |
| 外部のChatGPTトークン | chatgptAuthTokens |
ホストが accessToken、chatgptAccountId、任意で chatgptPlanType を渡す。initialize で experimentalApi が必要 |
ほかに、account/read(現在の認証状態)、account/login/completed の通知、account/login/cancel、account/logout、account/updated の通知、account/rateLimits/read(使用量の窓と、リセットの時刻)、account/usage/read が、メソッド一覧に挙がっています。外部トークンの場合、サーバーが401を受けると account/chatgptAuthTokens/refresh を要求し、ホストが新しいトークンを返す流れで、要求は約10秒でタイムアウトする、と書かれています。
使いすぎを見張りたいときは、account/rateLimits/read(使用量の窓と、リセットの時刻)を定期的に読み、残りが少ないときに自分のアプリ側で新しいターンを止める、という使い方が考えられます(これは僕らの見立てです)。なお、UsageLimitExceeded はターンの失敗の codexErrorInfo にも現れるので、失敗の通知側でも拾えます。APIキーとChatGPTのプランで、使える機能と数え方が違う点は、前のガイド(06)の表を先に見てください。
Pythonでは、同じことを login_chatgpt()、login_chatgpt_device_code()、login_api_key() として呼べます。SDKは、既存のログイン情報を自動で使います。ログイン情報の保存場所と扱い(auth.json はパスワードと同じ)は、前のガイド(06)にまとめました。
層2:自分のクライアントと、app-serverの間の認証
stdioなら親子のプロセスの間なので、問題になりません。WebSocketで外に出すときだけ、上の --ws-auth と Authorization: Bearer の話です。
層3:商用・ホスト型で、利用者に何を使わせるか
ここが、組み込みの一番大きな分かれ目です。公式のapp-serverのページの注意書きは、次の趣旨です。
- app-serverの認証は、商用やホスト型のサービスでは、許されたことがありません。すでにローカルやオープンソースのアプリで使っているものは、そのまま使い続けられると書かれています。
- 公式は、「利用者が自分の利用状況をよりよく管理し、見られるように」、Sign in with ChatGPTへの移行を勧めています。
Sign in with ChatGPTは、公式のヘルプ側では、参加しているアプリにChatGPTのアカウントでサインインする仕組みで、対象のPlusとPro利用者は、自分のプランをAIの要求に使うことも選べる、と書かれています。アプリの利用は既存のプランの上限に数えられ、ユーザーは設定でアプリごとの週の上限を決められます。
開発者向けのページ(developers.openai.com/siwc)は、ウェブサイトへのサインイン、ChatGPTのプラグイン、オープンソースのアプリへの組み込みを挙げています。「クライアントIDの申請」のページは、現時点では「選ばれた商用パートナー」への提供で、待ちリストに入るには関心のフォームを出す、と書いています。つまり、一般の開発者が今日すぐ使える手順は、読んだ範囲では見つかりませんでした。 有料やリモートでホストするアプリは、オープンソース向けのドキュメントではなく関心のフォームへ、と案内されています。
オープンソースのアプリの場合の流れ(公式のSIWCのページの要約)は、次のとおりです。
- クライアントの準備:
ext_agent_host_id(ホストごとに選んで保存する識別子)を用意し、ローカルの待ち受けとstate、nonce、PKCEを作る。 - ブラウザでOAuthに進み、ループバックにコードが返る。
- stateを確かめ、コードをPKCEつきで交換し、IDトークンと許可されたスコープを検証する。
- ベアラートークンで、Responses APIに
store: false、stream: trueで要求する。
ext_agent_host_id は、JWKサムプリントのURI(推奨)、urn:uuid:、did:key のいずれかの形式で、認証の資格情報としては扱えず、識別できる値(メールなど)も入れない、と公式は書いています。公開鍵由来のIDについて、秘密鍵の所持を、OpenAIは現時点では検証していない、とも書かれています。
この方式でapp-serverを使う場合、公式は、トークンを子プロセスの環境変数(ACCESS_TOKEN)に入れ、model_provider="openai_chatgpt_plan"、base_url を https://api.openai.com/v1、wire_api="responses"、requires_openai_auth=false、supports_websockets=false などの設定をつけて codex app-server --listen stdio:// を起動する、と書いています。トークンの更新はアプリが行い、更新したトークンでapp-serverを起動し直し、thread/resume で会話を続けます。model/list は、この設定では同梱のカタログを返すことがあり、「権利の確認ではなく一覧」として扱い、推論のターンが成功してはじめて使えると確かめられる、とあります。
この方式の制限(公式の「Preview limitations」)
- HTTPでは
store: falseとstream: trueが要ります。previous_response_idは使えず、必要な履歴はinputに入れます。system メッセージの項目は拒否されます。 - 使えない要求のフィールドの例:
background、conversation、max_output_tokens、temperature、top_p、user。 - ツールは関数とカスタムのツールが使えます。画像生成、ファイル検索、Code Interpreter、ホスト型のMCPとコネクタは使えません。音声と動画の入力も使えません。
- app-serverでは、自分のアプリが渡せるのはapp-serverのRPCの入力で、任意のResponsesのパラメーターは渡せません。
ページ名は「Preview limitations」で、本文にも「preview」という語(「Preview behavior and limitations」)が使われています。「beta」とは書かれていません。
APIを直接使う:Codexを使わずにモデルを呼ぶ
「Codexをアプリに入れたい」の中には、実は「コードを書くモデルを自分のアプリから呼びたい」だけの場合があります。その場合は、Codexのエージェントではなく、OpenAI APIのResponses APIが入口です。公式のコード生成のガイドの例は、次の形です(抜粋で、全文は取得できませんでした)。
curl https://api.openai.com/v1/responses \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d '{ "model": "gpt-6-astra", "reasoning": { "effort": "high" } }'
ガイドは、API経由のコード生成には gpt-6-astra を既定として勧め、Codex向けのモデルとして gpt-5.3-codex などがあるが、最新の汎用モデルのほうが普通は良い選択、と書いています。Codex自体は gpt-6-sol が最も合う、とも書かれています(確認日2026-10-24。モデルの名前と推奨は変わります)。上の例は抜粋で、入力の行が見えていません。完全な例は公式のページで確かめてください。
Codexを会社のLLMゲートウェイにつなぐ設定も、公式にあります(ゲートウェイのページ)。~/.codex/config.toml に model_provider = "enterprise-gateway" を決め、[model_providers.enterprise-gateway] の表に base_url(例:https://gateway.example.com/v1)、wire_api = "responses"、env_key = "CODEX_GATEWAY_API_KEY" を書く形です。ただし、このページが対象にしているのはCLIとmacOS・Windowsのアプリで、SDKとapp-serverがこの設定に従うかは、ページに書かれていません。自分のアプリで使うなら、実際に動かして確かめる必要があります。
非推奨・実験的・削除済みの区別
| 対象 | 公式の書き方 | 出典 |
|---|---|---|
codex mcp-server、codex-mcp-server |
削除済み。app-serverへ。アップグレード前に移行する | Codex MCP server、Codex SDK |
外部のMCPサーバーにCodexがつなぐ(codex mcp) |
引き続き対応 | Codex MCP server |
| app-serverのコマンド | 実験的。本番向けには未対応 | Codex app server、Codex MCP server |
| app-serverのWebSocket転送 | 実験的で未対応。ループバック以外は既定で認証なしの接続を許す(展開期間中) | Codex app server |
capabilities.experimentalApi で開くもの |
process/*、動的ツール、chatgptAuthTokens など |
Codex app server |
plugin/*(list、read、install、uninstall) |
開発中。本番のクライアント向けではない | Codex app server |
thread/rollback |
削除済み | Codex app server |
review/start の delivery: "detached"、thread/compacted、item/fileChange/outputDelta、thread/resume と thread/fork のフル履歴の応答(ページ分けされたスレッド) |
非推奨 | Codex app server |
| app-serverの認証 | 商用・ホスト型では許されたことがない | Codex app server |
| Python SDK | 安定版(stable release)。先行版は --pre |
Codex SDK |
| Sign in with ChatGPT(開発者向け) | 選ばれた商用パートナーへの提供、待ちリスト | siwc / request-client-id |
最初の10分でやること
公式に書かれている範囲で、読んだ人がすぐ動ける手順です。順番は僕らの整理です。
A. 自動化のため(SDK)
- 自分のパソコンのGitで管理している小さなフォルダを用意する(TypeScriptのSDKはGitリポジトリを求めるため)。
- TypeScriptなら
npm install @openai/codex-sdk(Node.js 18以上)、Pythonならpip install openai-codex(Python 3.10以上)。 - 上の最小の例を貼って、「このリポジトリを3行で説明して」のような読み取りだけの依頼を送る。Pythonなら
sandbox=Sandbox.read_onlyを付ける。 - 認証は、すでにCodexにログインしていればそれが使われる。していなければ、前のガイド(06)を見て、ログインか、
CODEX_API_KEYを1回の実行にだけ渡す。
B. 自前のクライアントのため(app-server)
codex app-server generate-json-schema --out ./schemasで、自分のCodexの版のスキーマを作る。codex app-server(stdio)を、自分のコードから子プロセスで起動する。initialize、initialized、thread/start、turn/startを送り、item/agentMessage/deltaとturn/completedを読む。読み取りだけにしたいときは、公式が値を挙げているturn/startのsandboxPolicy({"type":"readOnly"})を使う形から始める(thread/startのsandboxにreadOnlyを使えるかは、公式の例では確かめられませんでした)。- 承認の要求(
requestApproval)が来たら、最初は必ずdeclineを返すクライアントにして、流れを確かめてからacceptを作る(これは僕らの見立てです)。
C. 自分のサービスの利用者に使わせたい
app-serverの認証が商用・ホスト型で許されていないことを読み直し、Sign in with ChatGPTの開発者向けページ(developers.openai.com/siwc)と関心のフォームを確かめます。提供の条件は、OpenAIの規約と担当者に確かめてください。この記事は助言ではありません。
僕らの見立て
ここからは僕らの見立てです。公式が書いていることと分けて読んでください。
- SDKは入り口として軽い。ただし「動かす機械にCodexがいる」前提です。 ブラウザの中にそのまま入れる使い方は、読んだ範囲では想定されていません。作業フォルダと認証を設計する仕事は、Claude Codeを組み込むときと同じ形です。
- app-serverは「プロトコルの契約」を読む覚悟が要る。 実験的、スキーマは版ごと、削除されるメソッドもある、という状況では、自分のクライアントは、特定の版のCodexに合わせて固定し、更新のたびに
generate-json-schemaで差分を見る運用が、安全に見えます。 - 承認のUIは、手を抜けない。
thread/shellCommandやprocess/*のように、サンドボックスの外で動く窓口が同じプロトコルの中にあります。自分のアプリが、利用者に見せる窓口を、承認が必要なものだけに絞ることが、実質的な設計になります。 - 利用者のログインは、技術より先に契約の話です。 公式の注意書きから読む限り、ホスト型の自社サービスでCodexを動かすなら、利用者の認証は提供の条件に左右されます。
気をつけること
- この記事は、実際に使って確かめた記録ではありません。運営者はCodexを入れていますが、使い心地はこの記事には書いていません。コードは、公式の例を写したか、並べ直したもので、動作確認はしていません。
- 取得したのは要約です。app-serverのページは約10万字あり、末尾の約2千字と、
account/sendAddCreditsNudgeEmailの節の途中から後は、読めていません。TypeScript SDKのrunStreamed()の完全なコードと、イベントの全種類、Python SDKのAPIリファレンス、SIWCの「Registration and sign-in」「Accounts and sessions」などのページは、読めていません。 - GitHubのリポジトリのフォルダのページは、取得が拒否されました(robots)。READMEは、raw形式の別のURLで読みました。
- 公式の資料には日付が書かれていないものが多く、「確認日2026-10-24の内容」としてのみ書いています。モデル名、対応状況、実験的かどうかは、すぐ変わりえます。
- app-serverのページは、「コマンドは実験的で本番では未対応」と書き、前のガイド(04)が書いていた「開発・デバッグ向け」という言い方は、今回読んだページには見つかりませんでした。新しいほうの記述に合わせました。
- 公式のドキュメントの置き場所は、developers.openai.com から learn.chatgpt.com へ転送されます。出典は、実際に読んだURLを載せています。
- セキュリティ、契約、法律の助言ではありません。商用で使うときは、OpenAIの規約と、利用する各機能の条件を直接確かめてください。
出典
- Codex SDK(Codex Docs、OpenAI、日付の記載なし、確認日2026-10-24)
- Codex app server(Codex Docs、OpenAI、日付の記載なし、確認日2026-10-24)
- Codex MCP server(Codex Docs、OpenAI、日付の記載なし、確認日2026-10-24)
- Open source(Codex Docs、OpenAI、日付の記載なし、確認日2026-10-24)
- Models(Codex Docs、OpenAI、日付の記載なし、確認日2026-10-24)
- Environment variables(Codex Docs、OpenAI、日付の記載なし、確認日2026-10-24)
- Connect to a gateway(Codex Docs、OpenAI、日付の記載なし、確認日2026-10-24)
- Sign in with ChatGPT(ChatGPT Docs、OpenAI、日付の記載なし、確認日2026-10-24)
- Sign in with ChatGPT for developers(OpenAI Developers、日付の記載なし、確認日2026-10-24)
- Request a client ID(OpenAI Developers、日付の記載なし、確認日2026-10-24)
- ChatGPT plan usage in open-source apps(OpenAI Developers、日付の記載なし、確認日2026-10-24)
- Codex app-server with Sign in with ChatGPT(OpenAI Developers、日付の記載なし、確認日2026-10-24)
- Preview limitations(OpenAI Developers、日付の記載なし、確認日2026-10-24)
- Code generation(OpenAI API Docs、日付の記載なし、確認日2026-10-24)
- Codex SDK for TypeScript README(openai/codex、GitHub、mainの内容、確認日2026-10-24)
- Codex SDK for Python README(openai/codex、GitHub、mainの内容、確認日2026-10-24)
- Python SDK getting started(openai/codex、GitHub、mainの内容、確認日2026-10-24)
- app-server README(openai/codex、GitHub、mainの内容、確認日2026-10-24)