Codex CLIの非対話実行を試す|JSONL・終了状態・失敗の見分け方

Codex CLIの非対話実行を試す|JSONL・終了状態・失敗の見分け方

codex execをスクリプトから呼んだものの、最終メッセージに「完了」と書かれているだけで成功扱いしてよいのか。途中のコマンドが失敗したとき、どこを見ればよいのか。自動処理へ進むほど、この判断に迷いやすくなります。

結論から言うと、最終メッセージだけでは足りません。少なくとも次の3点を別々に確認します。

  1. Codex CLIプロセスの終了コード
  2. JSONLに記録されたイベントと、途中のコマンド終了状態
  3. 期待した成果物の内容と、対象外ファイルに変更がないこと

この記事では、記事専用の架空Markdownを1ファイルだけ整形した実測をもとに、成功、空入力、不正なJSONL、CLI起動失敗、エージェント内コマンド失敗の切り分け方を紹介します。Web公開や外部サービス更新までは扱いません。

繰り返し使う対象範囲や確認コマンドは、AGENTS.mdでCodexの作業ルールを整理する方法でまとめています。今回だけの依頼と共通ルールを分けてから、非対話実行を試すと確認項目をそろえやすくなります。

今回の検証条件

実在する業務資料やリポジトリは使わず、隔離した一時ディレクトリに架空の会議メモだけを置きました。

項目 条件
検証日時 2026年10月9日 06:02 UTC
OS Linux 4.18.0、x86_64
Codex CLI codex-cli 0.162.0
モデル gpt-5.6-sol
対象 meeting-note.md 1ファイル
サンドボックス workspace-write
セッション --ephemeral
出力 --jsonによるJSONL

APIキーや保存済み認証の内容は、fixture、プロンプト、出力、検証記録へ含めていません。workspace-writeは書込みを許可する設定なので、作業ディレクトリには記事用fixture以外を置かない構成にしています。

入力は次の短いメモです。

依頼内容は、見出しと箇条書きを加え、意味、名前、日時、期限を変えないこと。変更対象はこの1ファイルだけとしました。

codex execの出力を3つに分ける

OpenAI公式資料によると、通常のcodex execは進捗を標準エラーへ、最後のエージェントメッセージを標準出力へ出します。--jsonを付けると、標準出力は1行に1つのJSONオブジェクトを置くJSON Lines(JSONL)になります。

今回の最小呼び出しは、次の形です。WORK_DIRは架空Markdownだけを置いた一時ディレクトリ、ログはその外側へ保存します。

この検証では、成功時に次の順でイベントが記録されました。

プロセス終了コードは0で、変更後のMarkdownは期待値とバイト単位で一致しました。作業ディレクトリには対象ファイル以外を置いていないため、対象外のファイル変更もありませんでした。

一方、標準エラーには、途中で失敗したファイル変更操作の記録が1件残りました。その後に別の操作で期待した変更が完了しています。この例からも、標準エラーが空かどうか、最終文が成功を名乗っているか、という1点だけで判定しないほうが安全です。

無地の確認用紙とノートPCを見比べ、処理結果を照合する架空の開発担当者

JSONLは1行ずつ解析する

JSONL全体を1つのJSONとして読み込むのではなく、空でない各行を順にjson.loads()へ渡します。次の判定器は、プロセス非ゼロ、JSONLの構文エラー、ターン失敗、途中コマンドの非ゼロ、成果物不一致を別の終了コードで返します。

この判定器を保存済みの実測データとfixtureへ適用した結果は次のとおりです。

ケース Codexプロセス JSONLまたは成果物 判定器の終了コード
成功 0 turn.completed、期待値と一致 0
エージェント内コマンド失敗 0 command_executionが終了7 6
CLI引数エラー 2 JSONLなし、成果物無変更 7
壊れたJSONL fixture 0として検査 3行目で構文エラー 2
成果物不一致 0 JSONL完了、期待値と不一致 8

ここで重要なのは、「turn.completedがある」と「成果物が正しい」を別条件にしたことです。未知のイベントが現れた場合も、黙って既知イベントへ読み替えず、記録したうえで判定器の更新要否を確認します。

空入力はCodexを起動する前にも止める

対象ファイルが空なら、モデルを呼ぶ前に止められます。

空のempty.mdに対して実行すると、標準エラーはEMPTY_INPUT: empty.md、終了コードは10となり、Codexは起動しませんでした。

別に、codex execへ標準入力からプロンプトを渡さないケースも確認しました。この場合は標準エラーにNo prompt provided via stdin.と出て、Codex CLIは終了コード1、JSONLなし、対象ファイル無変更でした。入力ファイルが空なのか、CLIへ依頼文が渡っていないのかを分けて記録できます。

CLI失敗と、エージェント内コマンド失敗は別物

安全なCLI失敗例として、存在しないオプション--article-invalid-optionを指定しました。CLIは使用方法を標準エラーへ出し、終了コード2で終了しました。モデル処理は始まらず、JSONLは空、対象ファイルも無変更です。

一方、エージェントへ無害なsh -c 'exit 7'を1回だけ実行させたケースでは、JSONLのcommand_executionに終了コード7とstatus: failedが記録されましたが、Codex CLIプロセス自体は終了コード0で、ターンもturn.completedでした。

つまり、CLIの終了コード0だけでは、途中のコマンド成功までは保証できません。JSONL内のcommand_executionも調べ、1件でも非ゼロなら成果物を採用しないルールにします。

--output-schemaと--jsonを混同しない

--jsonは実行中のイベント列をJSONLで出すための指定です。--output-schemaは、最終応答を指定したJSON Schemaへ合わせるために使います。同じ「JSON」という言葉が出ますが、検査対象が異なります。

今回の実測では--output-schemaを使っていません。導入する場合は、少なくとも次を追加で確認します。

  • schema全文を検証記録へ残す
  • 最終応答をJSON Schema検証器へ通す
  • schema準拠と内容の正しさを別々に判定する
  • JSONLイベント列と最終応答を別ファイルとして扱う

また、--output-last-messageとの比較、--ephemeral有無による保存物の差、別OS、別言語のwrapperは未確認です。これらは今回の成功表へ含めず、採用環境ごとの事前チェック項目とします。

WordPressの変更へ応用する場合は、CodexでWordPressを変更する前の確認項目も参照してください。こちらは検証未完了の計画テンプレートとして、バックアップ、表示確認、復元の条件を整理しています。

採用前に人が見るポイント

自動判定が通っても、そのまま公開や外部更新へつなげません。変更前後を並べて、次を確認します。

  • 名前、日時、期限、否定表現など、元の意味が変わっていないか
  • 入力にあった内容が欠けていないか
  • 入力にない事実や説明が増えていないか
  • 対象外ファイルが増減・変更されていないか
  • 標準出力、標準エラー、JSONLへ秘密情報が入っていないか
  • 同じ失敗を無制限に再実行していないか

失敗時は、入力不備、CLI起動失敗、ターン失敗、コマンド失敗、JSONL構文エラー、成果物不一致のどこで止まったかを記録します。原因または方式を変えない同条件の反復は避けます。

ノートPCと無地のチェック用紙を見比べ、採用前に変更内容を確認する架空の開発担当者

まとめ

codex execをバッチ処理へ組み込むときは、最終メッセージだけで成功を決めず、JSONL、Codex CLIプロセスの終了コード、成果物差分を別々に確認します。特に、エージェント内コマンドが終了コード7でも、Codex CLI自体は0でturn.completedになる実測結果には注意が必要です。

最初は架空データ1ファイルだけの隔離環境で試し、空入力、CLI失敗、壊れたJSONL、コマンド失敗、差分不一致をそれぞれ不採用にできることを確認します。最後は人が意味の変化と対象外変更を見てから採用してください。

資料確認日:2026年10月9日。参照:OpenAI「Non-interactive mode」。Codex CLIの仕様やイベント形式は変わる可能性があるため、導入時と公開直前に公式資料と採用CLI版を再確認してください。

運営者情報

著者・監修者:タケナカ

タイトルとURLをコピーしました