CodexとTemporalで自動リファクタリングを回し放題にする話

最近、CodeXが熱いらしいですね。

普段はClaudeのMaxプラン(5倍枠)を愛用しているのですが、これがまあ、すぐに6時間の制限に引っかかる。しかもループを回して精度を上げようとしているのか、応答が意外と遅かったりします。

そこで、久々にCodexに切り替えてウェブ上でタスクを回してみたのですが、制限にかかるまでの「粘り」がすごい。モデルは分かりませんが、Claudeよりは失敗も目立つものの、ガシガシ回すには今のところ最適解な気がしています。

しかも、サブスクリプションプランでもCIとかで使って良いらしい! ということで、これはアプリケーションと統合してワークフローを回し放題にするしかないな、と。

おうちk8sにTemporalを載せて、自動リファクタリングを爆速で回してみることにしました。

GitHub - temporalio/temporal: Temporal service

Temporal service. Contribute to temporalio/temporal development by creating an account on GitHub.

github.com

Codexサブスクリプションで自動化を回す「裏口」?

端的に言うと、公式ドキュメントにやり方が書いてあります。

Authentication – Codex | OpenAI Developers

Sign-in methods for Codex

developers.openai.com
Maintain Codex account auth in CI/CD (advanced) | OpenAI Developers

Use Codex's built-in refresh flow to keep auth.json working on trusted CI/CD runners

developers.openai.com

具体的には、Codex CLIなどでブラウザログインした際に生成される auth.json を使う方法です。

裏口的な感じもしますが、公式で紹介されている以上、正規のルートということで良いのでしょう。ただ、中身には refresh_token が入っており、定期的にローテーションされるので注意が必要です。切れたら手動で再生成が必要ですが、そこは自動化の対価として飲み込むことにします。

ただドキュメントに記載がある通り、以下は守る必要がありそうです。k8sの分散を考えると2個目がネックでしょうか。同時に複数のワークフローが実行されると、危なくなってきそうです。同時に一つになるように制御しておいた方が良いかもしれません。

Operational rules that matter

  • Use one auth.json per runner or per serialized workflow stream.
  • Do not share the same file across concurrent jobs or multiple machines.
  • Do not overwrite a persistent runner’s refreshed file from the original seed on every run.
  • Do not store auth.json in the repository, logs, or public artifact storage.
  • Reseed from a trusted machine if built-in refresh stops working. (https://developers.openai.com/codex/auth/ci-cd-auth)

なぜ、いまTemporalなのか

ワークフローエンジンと言えば、n8nやDify、LangGraphなどAI特化型のツールが多々ありますよね。ただ、これらはコンセプト的にAIと密結合しすぎている気がしています。AIというパラダイムが一過的なものだった場合、一緒に廃れてしまうのが怖い。

なので、特定のパラダイムに縛られない、かつ分散環境との相性が良いTemporalを選びました。

最終的に比較したのは以下の3つ。

  • Windmill.dev: 一番低レベルでカスタマイズ性が高い。ただ、学習コストが異常に高い。
  • Kestra: 宣言的で使いやすい。
  • Temporal: 公式でCodexサポートがあったのと、ローカルのIDEでテストしたコードをそのままイメージ化してデプロイできるのが魅力。

Temporalはイメージに埋め込んだスクリプトがそのまま実行されるので、テスト時と同じ挙動がワークフローでも保証されるのが本当に嬉しい。AIにコードを書いてもらう際も、この「ポータビリティ」は大きな武器になります。

Temporalのワーカーイメージを作る

Temporalはワーカー側に依存関係やスクリプトをプリインストールしたイメージを置く必要があるので、まずはそのリポジトリを用意。

GitHub - tamara1031/temporal-repo-steward

Contribute to tamara1031/temporal-repo-steward development by creating an account on GitHub.

github.com

今回はステートマシン的に状態遷移を管理したかったので、サブエージェントは使わず、設計・実装・レビューを別フェーズとして実装しました。

全体構成

flowchart LR

メインワークフロー: periodicRefactorWorkflow

以下がリファクタリングの本体です。

flowchart TD

子ワークフロー: robustPRMergeWorkflow

CI待ちや自己修復を担当するワークフローです。

flowchart TD

動作確認: 状態が見える安心感

ローカルで実行してみたところ、コスト的にはCodex Plusプランの5時間予算の6%程度で収まりました。Claude Maxのサブスクに比べると、自由度も含めてこちらのほうが使いやすい。

リアルタイムな進捗

TemporalのWeb UIを開くと、今どのステップで時間がかかっているかが一目瞭然です。ステップを細かく分割したので、視認性がとても高い。

メインワークフローのタイムライン
メインワークフローのタイムライン

子ワークフローとして動く robustPRMergeWorkflow も、CI待ちやコンフリクト解消の状態が綺麗に見えています。

子ワークフローのタイムライン
子ワークフローのタイムライン

自動生成されたPR

実際にできたPRがこちら。

自動生成されたプルリクエスト
自動生成されたプルリクエスト
refactor(auto): Make workflow porcelain status handling testable by tamara1031 · Pull Request #4 · tamara1031/temporal-repo-steward

Theme and intent Make workflow porcelain status handling testable — The periodic workflow relies on parsing git status --porcelain entries to decide which paths to restore after failed iterations a...

github.com

CIが落ちた場合の自己修復(Codexによる修正と再コミット)も組み込んでいます。これ、実際に動くと感動しますね。

おうちサーバー(k8s)へのデプロイ

簡易的な動作確認が取れたので、早速k8sクラスタへ。

  1. PostgreSQLにDBとユーザーを追加
  2. Secret(Github/Codex認証)をExternalSecretsで追加
  3. HelmチャートのValuesを調整
  4. Worker用のDeploymentを追加
  5. 定期実行(Schedule)を登録するJobをArgoCDで管理

一点、ハマりポイント。 Helmチャートだと default ネームスペースが自動で作られないようで、Web UIがバグりました。Podに入って手動で作成。

Terminal window
kubectl exec -it deployment/temporal-admintools -n temporal -- /bin/sh
temporal operator namespace create --namespace default --address temporal-frontend:7233

これで、スケジュール通りにリファクタリングが走り始めました。

Temporalのスケジュール一覧
Temporalのスケジュール一覧

まとめ

あとはこれを無限に回していくだけ。

マージまで自動化すれば「リファクタリングし放題」の世界が来ます。もちろん、外部ツール(Linter/Formatter)による制約を強固にしたり、プロンプトを洗練させて出力の精度を上げていく必要はありますが、基盤としては十分。

次はいよいよIssue駆動のワークフローを試してみたいですね。気が向いたら、また書こうと思います。

まあ、思ったよりおおらかなCodexさんでした、ということで。

ちゃんちゃん。