メインコンテンツへスキップ

Codex の experimental な Hooks を有効化して活用する

目次

TL;DR


はじめに

本記事の内容は Codex v0.115.0(2026年3月時点)で検証しています。開発中の機能のため、今後のバージョンで仕様が変更される可能性があります。

Codex には公式にはまだ Hooks 機能がありません。公式ドキュメントにも記載はなく、Changelog に「experimental hooks engine」という一行が載っている程度です。

ところが、実は「under development」ステータスで すでに動く Hooks が実装されていますcodex features list を実行してみたところ codex_hooks というフィーチャーフラグが見つかり、有効化すると実際にフックが発火することを確認しました。

ただし設定の JSON 構造や対応イベントの詳細はどこにも書かれていないため、OSS として公開されている openai/codex リポジトリ(Apache License 2.0)の Rust ソースコード(codex-rs/hooks/)を読んで仕様を特定しました。本記事ではその調査結果をまとめます。


1. 発見と有効化

フィーチャーフラグの確認

Codex には codex features list というフィーチャーフラグの一覧を表示するコマンドがあります。Hooks の存在を知ったのもこのコマンドがきっかけで、実行してみたところ codex_hooks が「under development」として表示されました。

$ codex features list
codex_hooks    under development  false

デフォルトは無効です。

有効化

# config.toml に永続化される
codex features enable codex_hooks

有効化すると起動時に以下の警告が表示されます。

⚠ Under-development features enabled: codex_hooks. Under-development features are incomplete
  and may behave unpredictably.

2. 設定ファイル

ファイルパスと形式

項目
グローバル設定~/.codex/hooks.json
プロジェクト設定<project>/.codex/hooks.json
形式JSON

Codex の一般設定は ~/.codex/config.toml(TOML 形式)ですが、Hooks 設定は hooks.json(JSON 形式) という別ファイルです。config.toml に hooks を書いても読まれません。

~/.codex/
├── config.toml      ← 一般設定・feature flags
└── hooks.json       ← hooks 設定(JSON)

JSON 構造

構造がやや独特で、イベント名の配列にハンドラを直接並べるのではなく、一段ラッパーを挟む必要があります。ソースコード(codex-rs/hooks/src/engine/config.rs)では MatcherGroup という構造体で定義されており、matcher(正規表現フィルタ)と hooks(ハンドラ配列)を持ちます。

hooks.<EventName>[].matcher  → フィルタ条件(省略可)
hooks.<EventName>[].hooks[]  → 実行するハンドラの配列

具体的な JSON は以下のようになります。

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo 'session started'",
            "timeout": 10
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo 'session stopped'",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

timeout はオプションで、デフォルトは600秒です。

動かない書き方

この入れ子構造を知らずに、イベント配列に直接ハンドラを並べる書き方をすると動きません。

{
  "hooks": {
    "SessionStart": [
      {
        "type": "command",
        "command": "echo 'session started'"
      }
    ]
  }
}

実際にこの書き方で動かず、ソースコードを読んで入れ子が必要なことに気づきました。公式ドキュメントがないため、ソースコードが唯一の正確な情報源です。


3. 対応イベント

サポートされている3イベント

イベント発火タイミング
SessionStartセッション開始・再開時
UserPromptSubmitユーザーがプロンプトを送信した時
Stopエージェント応答完了時

ツール実行やサブエージェント関連のイベントは未実装です。

ハンドラタイプ

ハンドラタイプは「フックが発火したときに何を実行するか」の種類です。ソースコード(codex-rs/hooks/src/engine/config.rs)上は commandpromptagent の3タイプが定義されていますが、現時点で実際に動作するのは command(シェルコマンド実行)のみです。

タイプ内容状態
commandシェルコマンドを実行する動作する
promptエージェントのコンテキストにプロンプトを注入する未実装("skipping prompt hook" とログに表示される)
agent別のエージェントを起動して処理させる未実装

async: true(非同期実行)も定義はありますが未実装です。prompt が使えるようになれば「プロンプト送信時に毎回追加の指示を注入する」、agent なら「応答完了後に別のエージェントでレビューを走らせる」といった使い方が考えられますが、現状は「イベント発火 → シェルコマンド実行」の一択です。

stdin に渡される JSON ペイロード

hook コマンドは $SHELL -l -c "<command>" で実行され、stdin に JSON ペイロード が渡されます。

{
  "session_id": "019d07b0-...",
  "cwd": "/Users/user/project",
  "hook_event_name": "SessionStart",
  "model": "o3-pro",
  "permission_mode": "default",
  "source": "startup",
  "transcript_path": null
}
フィールド説明
session_idセッションID(UUID v7)
cwd作業ディレクトリ
hook_event_nameイベント名
model使用中のモデル
permission_mode承認ポリシー
source開始種別(SessionStart のみ)
transcript_path会話履歴ファイルのパス(現状 null)

イベントごとに追加されるフィールドがあります。

フィールドイベント説明
sourceSessionStartstartup / resume / clear
promptUserPromptSubmitユーザー入力テキスト
turn_idUserPromptSubmit / Stop会話ターンの識別子
last_assistant_messageStop最後のアシスタント応答
stop_hook_activeStopStop フックがアクティブか

session_idcwdhook_event_namemodelpermission_mode は全イベント共通です。


4. 活用事例: 複数エージェントセッションの一元管理

自作のデスクトップアプリで、AI コーディングエージェントの Hooks を利用して複数セッションの状態を一元管理しています。SessionStart / Stop イベントを受け取ってセッション一覧を更新する仕組みです。

Codex でもこの Hooks が使えることがわかったので、同じアプリで Codex のセッションも管理できるように拡張しました。

hooks.json で何を設定しているか

hooks.json にイベントとコマンドを書いておくと、そのイベントが発火したときにコマンドが実行されます。逆に言うと、hooks.json が空だったり存在しなければ、フィーチャーフラグを有効にしても何も起きません。

以下の設定例では、全イベントで同じことをしています。stdin に渡される JSON ペイロードを $(cat) で読み取り、curl で自作アプリの API にそのまま転送するだけです。

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "curl -s -X POST http://localhost:3000/api/hook -H 'Content-Type: application/json' -d \"$(cat)\"",
            "timeout": 10
          }
        ]
      }
    ],
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "curl -s -X POST http://localhost:3000/api/hook -H 'Content-Type: application/json' -d \"$(cat)\"",
            "timeout": 10
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "curl -s -X POST http://localhost:3000/api/hook -H 'Content-Type: application/json' -d \"$(cat)\"",
            "timeout": 10
          }
        ]
      }
    ]
  }
}

受け取る側のアプリは、JSON 内の session_idhook_event_name を見てセッションの状態を更新します。この仕組みは他のツールの Hooks とも共通なので、同じ API エンドポイントで複数のエージェントツールを一元管理できています。


5. 制限事項と今後の展望

現時点の制限

OSS ならではの利点

制限が多い一方で、Codex は Apache License 2.0 の OSS であるため、Hooks の実装を直接ソースコードで確認できます。本記事の内容も codex-rs/hooks/src/ のソースを読んで特定したものです。仕様が不明な場合にソースコードが読めるのは大きな安心感があります。

今後の可能性

GitHub の Discussion #2150 では、Hooks 機能のリクエストスレッドに多数のコメントが寄せられており、コミュニティの関心の高さがうかがえます。今後ツールイベントの追加やハンドラタイプの拡充が期待されます。


まとめ

Codex の Hooks はまだ開発中で機能も限定的ですが、フィーチャーフラグを有効にすれば今すぐ使えます。セッションの開始・終了を検知してコマンドを実行する程度の用途であれば、十分活用できそうです。


参考

ZSL
ZSL

AIエンジニア

生成AIを活用した開発ワークフローの研究・実践をしています。