Codex CLI × GitHub Actions でちょっとだけ楽をする

2025年4月17日にOpenAIからリリースされたCodex CLIをGitHub Actionsで利用する際にどういった活用方法があるかな？と考えていました。

https://github.com/openai/codex

Codex CLIは命令文から自律的に思考し、プロジェクトの全体構造を詳細に分析したうえでタスクを実行します。こういった特徴を活用できる良い使用方法を探っているときに、身近なところで1つ思いつき実験してみました。

### 思いついたこと

現在、個人で「SNSトラブルシミュレーター」というWebサイトを開発しています。

(👇️ ネット上で起こり得るトラブルをサイト上で再現するものです)

![img.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821082/75906722-bea6-46e6-b04f-9c9644660d1d.gif)

きっかけは、子どもが「スマホが欲しい」と言い出したことです。ネット上の危険性について事前に理解してほしいと考えたのですが、小学生にはまだ伝わりづらい内容も多く、伝えるって難しいなーと感じているところです。

今は友人や家族、身近な人たちに試してもらいながら改善を進めていますが、コンテンツがある程度まとまったら、正式に公開していくつもりではあります。

このWebサイトはSPAで構成しています。私は普段、インフラ寄りの仕事をしており、フロントエンド開発にはかなり苦手意識があります。そのため、これまでのコーディングにはAIをフル活用して進めてきました。もう本当にAI様様という感じです。

また、これまでユーザーからのフィードバックや要望をAIに整理してもらって改善を進めてきましたが、ふと「Codex CLI × GitHub Actions」を使えば、このプロセスを自動化できるのでは？と気づきました。具体的な流れは以下のようになります。

1. Googleフォームでユーザーから要望を収集
2. GitHubActions ワークフロー発火
Codex CLIが、現在のコードを読みつつ、要望に沿ったコンテンツ案を整理し必要な改修内容の洗い出しを行い、Issueに起票
3. ワークフロー終了
4. Issue内容に沿った開発をコーディングエージェントツールへお任せする

上記の2-3のGitHub Actionsのワークフロー内でCodex CLIを利用してみたというワケです。

やはりCodex CLIの強みとして、既存のコードベースを自律的に分析できるというのが大きいと感じてます。ユーザーの要望をどのように実現するか、どの部分のコードを修正すべきかまで、包括的な提案をしてくれるだろうと期待しました。

### 検証してみた

ということで、実際に試してみます。

まず、「[`repository_dispatch`](https://docs.github.com/ja/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#repository_dispatch)」イベントで発火するワークフローファイルを書きます。

[ワークフローをトリガーするイベント - GitHub Docs](https://docs.github.com/ja/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#repository_dispatch)

少し考えたポイントとしては Codexが最終的に出力するアウトプットをどこに書き出してもらうのが一番良いか。という点です。最終的に`.github/ISSUE_TEMPLATE/issue.md` のissueテンプレートに書き出してもらって、それを後続のステップで登録する。という流れに落ち着きました。

```yaml
name: Create Issue from Google Form
on:
  repository_dispatch:
    types: [google_form]

permissions:
  issues: write
  contents: read

jobs:
  make-issue:
    runs-on: ubuntu-latest
    steps:
      - name: webhook payload
        run : |
          echo ${{ github.event.client_payload.title }}
          echo ${{ github.event.client_payload.body }} 
      
      - name: checkout
        uses: actions/checkout@v4

      - name: set up node
        uses: actions/setup-node@v4
        with:
          node-version: '22'

      - name: codex
        timeout-minutes: 3
        run: |
          npm install -g @openai/codex@0.1.2504211509
          export OPENAI_API_KEY="${{ secrets.OPENAI_KEY }}"
          codex -a auto-edit --quiet "現在のプロジェクトにおいて、ユーザーからの以下要望:¥n
          ${{ github.event.client_payload.body }}  の内容がより良く実現可能かマークダウンでまとめてください。¥n
          現在のプロジェクトの内容を確認し、どこにどのように実装すれば良いかもまとめてください。¥n
          まとめ終わったらその内容を .github/ISSUE_TEMPLATE/issue.md に書き出してください。"
        env:
          CODEX_QUIET_MODE: 1
      
      - name: Create issue
        uses: peter-evans/create-issue-from-file@v4
        with:
          title: "[要望]: ${{ github.event.client_payload.title }}"
          content-filepath: .github/ISSUE_TEMPLATE/issue.md
          labels: "task"
        
```

:::note warn
npm install -g @openai/codex でインストールすると、“Invalid schema error: Missing 'workdir' in function 'shell’” というエラーが発生しました。[このIssue](https://github.com/openai/codex/issues/524)に書かれているようにバージョンを指定することで一旦は解消しました。
:::

次に、Googleフォームからワークフローを発火させるためのGoogle Apps Script（GAS）を作成します。先程のrepository_dispatchイベントをAPIで叩いて発火させます。

[リポジトリの REST API エンドポイント - GitHub Docs](https://docs.github.com/ja/rest/repos/repos?apiVersion=2022-11-28#create-a-repository-dispatch-event)

GitHub APIへのアクセスには、Personal Access Token（PAT）を使用しました。

トークンの作成方法に関しては[こちら](https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens)をご参照ください。

```jsx
// トリガー: フォーム送信
function onFormSubmit(e) {
  var responses = e.response.getItemResponses();
  var title = responses[0].getResponse();
  var request = responses[1].getResponse();

  const payload = {
    event_type: 'google_form',
    client_payload: {
      title: title,
      body:  request
    }
  };
  const github_token = "<GitHub PAT>"
  const res = UrlFetchApp.fetch(
    'https://api.github.com/repos/<OwnerName>/<RepositoryName>/dispatches',
    {
      method: 'post',
      contentType: 'application/json',
      payload: JSON.stringify(payload),
      headers: { 
        'Authorization': 'Bearer ' + github_token,
        'Accept': 'application/vnd.github+json',
        'X-GitHub-Api-Version': '2022-11-28'
      }
    }
  );
  Logger.log(res.getResponseCode());
}

```

### 動作確認

- Googleフォームに要望を投稿します

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821082/6b73a2e8-f3f1-4c03-a6b3-aa46a706c66e.png)


- ワークフローが発火します。Codexが色々と考えてくれている事が分かります

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821082/d5f86180-6fb5-4190-b9ce-c6ceccadcc71.png)

- Isueeが起票されました

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2821082/dcfc6fc1-4752-42c3-b04c-f6954d1f03ea.png)

内容を確認し、コーディングはDevinやClineへアウトソーシングすることにします。

## さいごに

今回は、要望を受けてからの「検討・整理・Issue作成」といった一連の流れをCodex CLIとGitHub Actionsで自動化してみました。

まずは実験的にGoogleフォームから直接ワークフローを発火させる形で動かしましたが、実際にはGoogleフォーム → Slack (内容を目視確認し許可) → ワークフロー発火 という流れにしようかなと思ってます。(全て起動させてたらコストかかるので…)

この個人開発の目的は、「子どものネット教育」に親としてちゃんと向き合って子に伝える時間をつくることです。そのために、AIでできることはどんどん任せていきたいと思っています。