codex-app-server
λ codex app-server
プログラムなどから実行するためのインターフェイスが用意されている
Claude Code Maxプランを別のクライアントから使うのは規約違反なのと対称的ではある
docs
λ codex app-server generate-ts
ts型生成
gpt-5.icon
codex app-server は、Codex を IDE拡張などから操作するためのローカル/近接サーバです。
CLI のように単に「1回質問して1回返す」だけでなく、
会話(スレッド)を保存/再開する
1ターン中のストリーミング(途中経過)を逐次UIに反映する
コマンド実行やファイル編集などの“副作用”を 承認フロー付きで扱う
といった「エージェント的な体験」を支えるのが目的です。
2. 通信方式(Protocol)
JSON-RPC 2.0 風(ただし wire 上は "jsonrpc":"2.0" ヘッダ省略)
双方向通信(リクエスト/レスポンス+サーバ通知)
トランスポート:
stdio://(デフォルト): JSONL(1行1JSON)
ws://(実験・非推奨): WebSocket の text frame 1つに1メッセージ
バックプレッシャ(過負荷)重要点
内部キューが詰まると新規リクエストを JSON-RPC error -32001("Server overloaded; retry later.")で拒否。
クライアント側は リトライ可能扱い(指数バックオフ+ジッター)にする想定です。
3. 3つの基本概念:Thread / Turn / Item
この3階層がUI実装の核です。
Thread(スレッド)
会話そのもの。保存・一覧・再開・アーカイブができる。
Turn(ターン)
ユーザー入力 → エージェント応答までの「1往復」。
ターン中はストリーミングで進捗が流れる。
Item(アイテム)
ターンの中の“出来事”の単位。例:
userMessage(入力)
agentMessage(最終回答)
reasoning(要約された推論/または生ログ)
commandExecution(コマンド実行)
fileChange(ファイル変更提案・適用)
webSearch(Web検索要求)
など
UIは実質「Item のライフサイクル」を描画する作りになります。
4. 接続のライフサイクル(最重要フロー)
4.1 初期化ハンドシェイク(initialize)
接続直後に必ず:
1. initialize リクエスト
2. initialized 通知(クライアント→サーバ)
これより前に他メソッドを呼ぶと "Not initialized" で拒否。
同一接続で2回 initialize すると "Already initialized"。
通知を抑制できる(opt-out)
initialize.params.capabilities.optOutNotificationMethods に通知メソッド名を列挙すると、その接続では該当通知を止められます。例: item/agentMessage/delta を止めると“文字の逐次ストリーミング”を抑制できる。
4.2 Thread を開始/再開
thread/start 新規
thread/resume 既存IDを再開
thread/fork 履歴をコピーして枝分かれ
戻りの thread.ephemeral が true のときは「メモリ上のみ」運用で thread.path=null。
4.3 Turn を開始
turn/start でユーザー入力を送る。ここからストリーミングが始まる。
4.4 通知を読んでUI更新
stdout(stdioの場合)にサーバから JSON-RPC notification が流れ続けるので、クライアントは読みながらUIを更新します。
turn/started
item/started
item/*/delta(ストリーム)
item/completed
turn/completed
5. “イベント駆動UI”としての見方(実装のコツ)
Item の共通ライフサイクル
基本は常にこれです:
1. item/started(UIにプレースホルダを出す)
2. 0回以上の delta 通知(進捗・増分)
3. item/completed(確定状態)
例:agentMessage
item/started(空のメッセージ枠)
item/agentMessage/delta が複数回(文字列をappend)
item/completed(最終テキストで確定)
例:commandExecution
item/started(実行予定コマンドが見える)
承認が必要なら item/commandExecution/requestApproval(サーバ→クライアントの“リクエスト”)
承認後、item/commandExecution/outputDelta が流れる
item/completed(exitCode等を含む確定情報)
UIは「アイテムごとに状態機械を持つ」と分かりやすいです。
6. 承認(Approvals):副作用を安全に扱う仕組み
コマンド実行やファイル変更は、設定次第で 必ずユーザー承認が必要になります。
ここが “ただのストリーミングチャット” と違う部分。
6.1 コマンド承認フロー
サーバがクライアントに JSON-RPC request(id付き) を投げてきます:
item/commandExecution/requestApproval
クライアントは {"decision": ...} を返す必要がある。代表:
accept
acceptForSession
decline
cancel
-(その他実験的な policy amendment)
承認が解決されると serverRequest/resolved が来て、最終的に item/completed で結果確定。
6.2 ファイル変更承認フロー
item/started(diffを提示)
item/fileChange/requestApproval
クライアント accept / decline
item/completed(適用成功/失敗/拒否)
ポイント: UIは承認ダイアログを「ターン内にインライン表示」するのが想定。
7. API全体の地図(何があるか)
大別すると:
会話管理(Thread)
start/resume/fork/list/read/archive/unarchive
thread/unsubscribe(購読解除。最後の購読者が抜けると thread が unload され thread/closed)
会話実行(Turn)
turn/start(新規ターン)
turn/steer(同じターンに追加入力:in-flight の方向修正)
turn/interrupt(キャンセル)
ユーティリティ
command/exec(スレッド無しで単発実行)
モデル/機能
model/list
experimentalFeature/list
collaborationMode/list(実験)
skills/list / skills/config/write
app/list(コネクタ一覧)
認証
account/read
account/login/start(apiKey / chatgpt)
account/logout
rate limit 取得など
8. Skills / Apps の使い方(UIから“明示的に呼ぶ”)
Skills
テキストに $skill-name を含める。
さらに input に {"type":"skill", ...} を入れると、曖昧解決が不要で速い(推奨)。
Apps(コネクタ)
テキストに $demo-app のような slug を入れる。
mention アイテムで app://<connector-id> を渡すと確実。
9. “実験API”の意味(互換性が壊れる領域)
initialize.params.capabilities.experimentalApi = true を付けると、
実験メソッド
実験フィールド
dynamicTools(クライアント側ツール呼び出し)など
が使えるようになる一方、後方互換性は保証されません。
スキーマ生成も --experimental を付けると実験領域込みになります。
10. 最小構成でのクライアント実装イメージ(設計レベル)
クライアントは最低限、次を実装すれば “VS Code拡張っぽい体験” が作れます。
1. JSONL(stdio)でメッセージ送受信
2. 初期化: initialize → initialized
3. スレッド: thread/start(or resume)
4. ターン: turn/start
5. 通知ループ:
turn/started でターン枠を作る
item/started でアイテム枠を作る
delta 系でアイテムを更新
requestApproval が来たらUIでユーザーに選ばせて response を返す
item/completed で確定
turn/completed でターン確定