Sota411 ← Back
← Back to Articles

2026-06-01

Codexの選択UIを自分用にforkしてcodex-customにした

きっかけ

Codex の Plan Mode では, 確認用の選択肢が「3つ + 自由記述」で出る.

これが地味に足りなかった. 実装方針を選ぶときに, 「推奨案」「保守的な案」「速い案」だけで終わらせると, もう一つの現実的な案が自由記述に流れがちだった. 逆に, 毎回20個も候補がほしいわけではない.

最初はプロンプトに「4択で出して」と書けば済むと思っていた. ただ, 選択肢数は tool schema と実行時バリデーションにも出てくる. ここをモデルへのお願いだけで合わせると, 失敗したときにどこが悪いのか分かりにくい.

それで Codex CLI を fork して, request_user_input 周りを自分用に変えた.

変えたこと

まず既定を 4択 + Custom answer にした.

自由記述欄は, モデルが isOther のような特別な選択肢を出す方式にはしなかった. クライアント側で最後に足す. その方が, モデル出力の揺れに引っ張られない.

選択肢数は config で変えられる.

toml[tools.experimental_request_user_input]
default_options_count = 4
max_questions = 3

default_options_count は通常の選択肢数. max_questions は1回の確認UIに出せる質問数の上限.

候補を多めに並べたいなら, 次のようにもできる.

toml[tools.experimental_request_user_input]
default_options_count = 20
max_questions = 3

0 はエラーにした. 選択肢数や質問数上限が0だと UI として成立しないので, schema と実行時バリデーションの両方で落とす.

通常版を置き換えなかった理由

最初は, build したバイナリをそのまま codex として置き換える案も考えた.

やめた理由は切り分けのしやすさ. fork 版は実験用なので, 公式版と設定, 履歴, 認証情報を混ぜたくなかった. 普段使いの ~/.codex/config.toml を壊すと, Codex 全体の作業に影響する.

fork 版は codex-custom という別名にした.

ここでは fork した repository の場所を $CODEX_FORK_DIR と書く.

bashln -sf "$CODEX_FORK_DIR/codex-rs/target/debug/codex" "$HOME/.local/bin/codex-custom"

CODEX_HOME も分ける.

bashCODEX_HOME="$HOME/.codex-custom" codex-custom

通常版は ~/.codex, fork 版は ~/.codex-custom を見る. これなら, fork 版がおかしくなっても通常版へ戻れる.

alias ではなく function にした

普段は cdxyolo という zsh のショートカットで Codex を起動していた.

もともとの cdxyolo は alias だった. alias だと, -f が付いたときだけ fork 版に切り替えるような分岐を書きにくい.

そのため, cdxyolo を shell function に変えた.

zshcdxyolo() {
  if [ "$1" = "-f" ]; then
    shift
    CODEX_HOME="$HOME/.codex-custom" codex-custom "$@"
  else
    codex "$@"
  fi
}

これで, いつもの作業は cdxyolo, fork 版を使うときだけ cdxyolo -f にできる.

完全に別コマンドへ分ける案もあった. ただ, 使い分けの粒度は「この作業だけ fork 版で試す」くらいなので, 入口は cdxyolo のままにした.

symlink が古い作業ディレクトリを見ていた

途中で, codex-custom の symlink が古い checkout を見ていることに気づいた.

text~/.local/bin/codex-custom
-> <old-checkout>/codex-rs/target/debug/codex

この状態では, GitHub 側の fork を更新しても手元の codex-custom は変わらない. コードは新しいのに, 起動しているバイナリは古いままになる.

今後は fork した repository を正にして, symlink もその build 成果物を見るようにした.

bashln -sf "$CODEX_FORK_DIR/codex-rs/target/debug/codex" "$HOME/.local/bin/codex-custom"

公式版の更新に追従する

fork すると, 公式 Codex の更新をどう取り込むかが残る.

手でやるなら, openai/codex を fetch して merge し, conflict を直して build すればよい. ただ, これは忘れる.

なので GitHub Actions で upstream 追従用の PR を作るようにした.

workflow がやることは次の通り.

  • openai/codexmain を fetch する
  • fork 側の main に merge する
  • request_user_input 周りのテストを実行する
  • cargo build --bin codex を実行する
  • 通れば bot/upstream-sync から PR を作る

GitHub-hosted Actions は自分のPCではないので, 手元の codex-custom バイナリまでは更新できない.

PR を merge したら, 手元では build と symlink 更新だけをやる.

bashgit pull
cd codex-rs
cargo build --bin codex
ln -sf "$CODEX_FORK_DIR/codex-rs/target/debug/codex" "$HOME/.local/bin/codex-custom"
codex-custom --version

PR 作成とテストまでは自動化する. 自分のPCへ反映する最後のところだけ手でやる.

作ってみて

やったこと自体は小さい. 3択を4択にし, 必要なら config で変えられるようにしただけとも言える.

ただ, 通常版と分けて cdxyolo -f で起動できるようにしたので, 普段の Codex を壊さずに試せる. ここを分けたのが一番効いている.

fork はすぐ便利になる一方で, 公式更新に追いつく手間も増える. 今回はその手間を GitHub Actions の PR 作成まで寄せて, 最後の build だけを手元に残した.

← トップページに戻る