開発記事公開日
Codex の導入から、Android 測定アプリが実乗車で動くまで

Windows に Codex を入れるところから、新幹線と在来線の通信状況を測る Android アプリが電車の中で動くまで。要件書、20本の設計判断記録、GitHub Actions、エミュレータ、実機、実乗車という段の分け方と、3つのAIの役割分担を記録します
AIに言えばアプリができる。その言い方は、半分は本当でした。新幹線と在来線の通信状況を測る Android アプリは、GitHub Actions が緑になった日から、電車の中で実際に動いた日まで、およそ3週間かかっています。その3週間に何をしていたかが、この記事の主題です。
道具は Codex です。ただし、Codex にアプリを頼んだ話ではありません。Codex が動ける場所を用意し、Codex に読ませる文書を先に書き、Codex が「できました」と言ったものを別の目で確かめる。その順番の記録です。
Windows に Codex を入れる
公式ドキュメントによれば、Codex のCLIは npm で入ります。作業を始める前にリポジトリの AGENTS.md を読み、そこに書かれた規約と検査コマンドに従います。ローカルではOSが強制するサンドボックスの中で動き、読み取り専用、作業ディレクトリ内の書き込み、制限なしの3種類から範囲を選びます。承認の方針は別に設定し、既定のプリセットでは作業ディレクトリ内の編集とコマンド実行を自動で行い、それを越える操作で止まって承認を求めます。
Windows では、PowerShell から動かすとネイティブのサンドボックスが使われ、WSL2 の中で動かすと Linux 側の実装が使われます。公式ドキュメントは、既定ではネイティブを使い、Linux 向けの道具が要るときや作業環境がすでに WSL2 にあるときだけ WSL2 を選ぶよう案内しています。BenriWorks はネイティブ側です。
導入で決めたのは、Codex そのものより、その周りでした。ホストに常設するのは Git と Android Studio と Codex の3つだけ。JDK、Android SDK、Gradle のキャッシュ、エミュレータ、Maestro は、リポジトリの bootstrap.ps1 が1か所の作業ディレクトリへ展開します。スクリプトはJDKとコマンドラインツールのSHA-256を検証し、Windows の永続的な環境変数には触りません。エージェントに触らせる環境を、再現できる形に固定する。ここから始めました。
コードより先に書いた文書
AGENTS.md の2行目に、こうあります。
「GitHub is the single source of truth. A decision that exists only in a chat log is not a specification.」
正本は要件書 SCR-REQ-001 です。エージェントはコードを変える前に、引き継ぎ書、開発ガイド、テスト戦略、該当する設計判断の記録、該当する GitHub Issue を読むことになっています。
設計判断の記録は ADR と呼ぶ形式で、20本あります。たとえば4本目は、バックグラウンド位置情報の権限を要求しない、という判断です。画面を消しても測定を続けたいなら、その権限を取るのが近道に見えます。ADRはそれを退け、理由を5つ並べています。利用者が明示的に始める前面サービスなら位置情報の型で足りること、「常に許可」の要求は利用者の離脱を増やすこと、Google Play が書面の正当化と審査を求めること、製品として「利用者に見えない常時測定」を除外していること、そして権限は具体的なAPIと対象OSと機能価値を Issue に書いてから足すという規則です。
この5つは、AIが提案しない種類の理由です。審査の義務も、利用者の離脱も、コードの中にはありません。ADRに書いておくと、あとから来たエージェントが「便利そうだから」で権限を足すことを止められます。
モジュールも先に切ってあります。Android に依存しない純Kotlinの :domain と :testkit、Android に依存する :app と :data。依存は一方向で、ドメイン層に Android の型を持ち込むことは AGENTS.md で禁じています。プライバシーの規則も同じ場所にあり、IMEI、電話番号、IMSI、連絡先、広告IDは収集しません。
サンドボックスの制限が設計になった
Codex のサンドボックスや Claude Code のクラウド環境は、外への通信が制限されています。このリポジトリでは、Google の Maven リポジトリに届きませんでした。Android Gradle Plugin も androidx も Android SDK も取れないので、Android のモジュールは構成すらできません。
7本目のADRは、この制限を設計に変えたものです。-PjvmOnly=true を付けると、settings.gradle.kts が :app と :data を含めず、純Kotlinのモジュールだけでビルドが組まれます。ADRには、それだけでは足りなかった理由も書いてあります。ルートのビルドファイルで Android のプラグインに触れると、apply false であっても構成時に解決が走って落ちること。そして、Gradle は404を「ここにはない、次を探す」と扱う一方で、403は致命的な失敗として扱うため、遮断されたリポジトリが宣言に残っているだけで、Maven Central にある普通の依存関係の解決まで巻き込んで落ちること。
この分け方の効き目は、テスト戦略の原則に1行で書いてあります。「純 Kotlin にできるロジックは :domain / :testkit に置く。そこに置いたものだけが制限環境でも高速に反復検証できる。」エージェントが自分で回せるテストの範囲を、モジュールの境界で決めています。
検証の段を4つに分ける
テスト戦略の冒頭に、太字でこう書いてあります。「CI が green であることは『動作確認済み』を意味しない。」
検証は G、E、D、F の4段です。GitHub Actions、エミュレータ、実機、実乗車。段ごとに観測できるものが違います。Gでは純Kotlinの単体テストとビルドと Lint。Eでは Room の実SQLite、前面サービスの通知、Compose の画面遷移。Dでは Telephony の実値、GPS、画面消灯、Doze、電池。Fではトンネル、ハンドオーバー、通信断。エミュレータの位置と電波と電池は合成値なので、Dより上でしか分からないことがあります。
実機で確かめていない実装には「実装済み・実機未検証」と付けます。プルリクエストのテンプレートには実行済み検証のチェック欄と、未検証項目の欄が分かれていて、実行していない検証にチェックを入れないことがコメントで念を押されています。
CIは6つのジョブです。Gradle ラッパーの検証、純Kotlinテスト、開発版APKのビルド、単体テスト、Android Lint、そしてエミュレータ上の計測テスト。最後のジョブには continue-on-error を付けていません。設定ファイルのコメントに理由があります。「E1 は『実際に動いたか』の信号そのものであり、落ちたジョブを緑に見せることは §0 の正直さ要件に反する。」別のワークフローが、署名鍵や local.properties や実測データのファイルがリポジトリに入っていないかを機械で検査します。
3つのAIと、1 Issue 1 Writer
このアプリでは、3つのエージェントを役割で分けています。開発ガイドの表では、ドメイン層と状態機械とテストとRoomとAPI契約の書き手候補が Codex、Android のサービスと権限と Telephony とエミュレータ操作が Antigravity、要件とADRと障害仮説とプライバシーレビューが Claude です。それぞれに別のエージェントか人がレビュー候補として付いています。路線データの調査は researcher:codex という役割名で Codex が担い、そのライセンスレビューは調査者以外が行う、と手順書に書いてあります。
規則は「1 Issue 1 Writer」です。同じ作業ツリーに2体を同時に書き込ませない。書き手には gh pr merge を禁じ、マージは統括役が自分でテストを回し直してから行う。引き継ぎ書には「writer の『PASS しました』を鵜呑みにせず、--rerun-tasks で自分で回す」とあります。
もうひとつ、統括役の側の規則があります。「仮説を writer に押し付けない。」Issue #78 では、統括役が立てた「タイル計画の欠落」という推定が、書き手の失敗するテストによって否定され、真因は別の場所にありました。人が立てた仮説も、AIが立てた仮説も、テストの前では同じ扱いです。

CIが3週間止まっていた
引き継ぎ書の「最初に読むべき3行」の1行目は、こうです。「GitHub Actions は 2026-09-02 に復旧した。2026-08-11〜09-01 の約3週間、課金停止で全ジョブが起動すらしていなかった。」
この3週間の変更は、CI未検証のまま main に入っています。復旧したCIは、即座に退行を1件見つけました。エミュレータ上の計測テストだけが落ち、原因はローカルの検査スクリプトがその段を実行していなかったことでした。門が止まっていたあいだ、門を通ったつもりの変更が積み上がっていた形です。
引き継ぎ書には、環境の罠も並んでいます。PowerShell 5.1 でネイティブコマンドに 2>&1 を付けると、標準エラーの1行が失敗扱いになって成功したビルドが失敗に見えること。adb のスクリーンショットは端末側の /sdcard を経由しないと PowerShell で壊れること。路線データの改行コードが変換されてハッシュが実体と合わなくなった事故があること。どれも「実際に踏んだもの。繰り返さないこと」として残っています。エージェントが次のセッションで同じ穴に落ちないための文書です。
実機、そして実乗車
Dの段は、2026年8月末に Pixel 10a で確認しました。画面を消してロックしたまま53分、4,282件を記録し続けたこと。端末に溜めた5,367件を1回の操作で Supabase へ排出できたこと。バックエンドは Vercel の関数と Supabase で、テーブル名には接頭辞を付けて他のアプリと同居させています。
Fの段は、2026年9月2日が初回です。埼京線の赤羽から新宿までの24分54秒で、位置のサンプルが142件、HTTPの成功が296件に対して失敗が2件、最大の連続通信断が11秒。マッチングされた位置は、赤羽から十条、板橋、池袋と線路に沿って並びました。証跡の文書には駅名と区間と集計値だけを書き、座標は載せていません。生のGPSと診断データはリポジトリにも公開の Issue にも置かない規則です。
ただし引き継ぎ書は、この結果を「承認に足るカバレッジにはまだ遠い」としています。承認には各路線の両方向と全駅間が要り、走ったのは片方向の一部です。緑になった段がどこまでかを、ここでもはっきりさせています。
3週間の中身
GitHub Actions が緑になった日から電車の中で動いた日までの3週間に、あったのはこういうものでした。段の名前を付けた検証、実行していない検証を書かない規則、エージェントが落ちた穴の記録、そして「まだ足りない」と書き残す判断。
Codex は速く書きます。速く書いたものがどの段まで確かめられているかは、Codex には分かりません。それを分かる形にするのが、AIに Android アプリを作らせるときの、人の側の仕事でした。Webアプリの側で同じ考え方をどう置いているかは、「Codex と GitHub と Vercel で、Webアプリを公開するまでの流れ」にあります。
参照した公式情報
- OpenAI「Codex CLI」「Custom instructions with AGENTS.md」「Sandbox」「Agent approvals & security」「Windows sandbox」(developers.openai.com/codex、2026年9月時点)
- BenriWorks shinkansen-measurement リポジトリの AGENTS.md、README、開発ガイド、テスト戦略、ADR、引き継ぎ書、実乗車の証跡、CI設定




