Claude Media
Claude Codeで設計書とコードの乖離をPRごとに検出する手順

Claude Codeで設計書とコードの乖離をPRごとに検出する手順

PRの変更ファイルに紐づく設計書の記述をClaude Codeに照合させ、更新漏れの候補をコメントさせるGitHub Actionsの組み方と、誤検知を減らす入力の絞り方を扱います。

設計書とコードの乖離は、PRの時点なら候補を数件に絞れる

設計書とコードの乖離とは、コードが変わったのに設計書の記述(項目名・値・処理手順・画面遷移など)が古いまま残る状態です。リポジトリ全体を一度に照合すると指摘が数百件になり、誰も読まなくなります。PRの変更ファイルに限って照合すると、候補は数件で済みます。

Claude Codeは、GitHub Actions用のアクション(anthropics/claude-code-action@v1)から動かせます。workflowのpromptに指示を書くと、@claudeのメンションを待たずにPRの作成や更新をきっかけに実行されます。この仕組みに「変更されたコードに対応する設計書を読み、食い違いの候補を挙げる」役を持たせるのが、この記事の構成です。

作るものは次の3つです。

  • 設計書とコードの対応表(1ファイル)
  • PRごとに照合するworkflow(1ファイル)
  • 指摘の書式を縛るプロンプト(workflowの中)

アクションの導入そのもの(GitHub Appのインストールとシークレット登録)は、Claude CodeをGitHub Actionsに組み込む手順に沿って済ませてあるものとして進めます。

手順

PRごとに乖離候補を出す流れ

  1. 1

    PRが開かれる、または更新される

    pull_requestイベントで起動します。コードや設計書のパスに絞って、無関係なPRでは動かしません。

  2. 2

    変更ファイルを取り出す

    ベースブランチとの差分から、変更されたファイル名の一覧を得ます。

  3. 3

    対応表で設計書を引く

    変更ファイルが対応表に載っていれば、紐づく設計書の節だけを読みます。載っていなければ何もしません。

  4. 4

    食い違いの候補をコメントする

    設計書の記述、コード側の根拠、食い違いの種類が揃うものだけを、PRにコメントします。

準備: 設計書と対象コードの対応表を1枚置く

誤検知の最大の原因は、「どの設計書がどのコードの話なのか」をClaudeに推測させることです。設計書の数が多いリポジトリでは、無関係な設計書まで読みに行き、的外れな指摘が増えます。先に対応表を人間が書いておくと、この推測が要らなくなります。

置き場所はどこでもかまいませんが、ここではdocs/doc-map.mdとします。

# 設計書とコードの対応表
 
| 設計書(節) | 対応するコード | 照合する観点 |
|---|---|---|
| docs/design/order-api.md「項目定義」 | src/api/orders/** | 項目名・型・必須かどうか |
| docs/design/order-api.md「エラー応答」 | src/api/orders/errors.ts | ステータスコードとコード値 |
| docs/design/batch.md「処理手順」 | src/batch/** | 手順の順序・実行間隔 |
| docs/design/screens.md「画面遷移」 | src/routes/** | 遷移先のパス |

列は3つで足ります。「照合する観点」の列が肝で、設計書の全文を読ませずに、確かめてほしい種類の食い違いを限定する役割です。観点を書けない行は、機械的に突き合わせられる記述が設計書にないということなので、対応表に載せません。

設計書の用語とコードの識別子が違う現場(「受注」とorderなど)では、用語集を別ファイルで持っておくと照合が安定します。作り方はドメイン用語集をCLAUDE.mdに置く手順にまとめています。

workflowを組む: PRごとに対応表を読ませて照合する

次のworkflowは、Claude Code GitHub Actionsのドキュメントにあるコードレビューの例(pull_requestで起動し、promptでスキルを呼ぶ構成)を土台に、プロンプトを設計書の照合用に差し替えたものです。例示であり、実行結果ではありません。パスやファイル名は自分のリポジトリに合わせて書き換えます。

name: Doc Drift Check
on:
  pull_request:
    types: [opened, synchronize, ready_for_review, reopened]
    paths:
      - "src/**"
      - "docs/design/**"
jobs:
  drift:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: read
      issues: read
      id-token: write
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
      - uses: anthropics/claude-code-action@v1
        with:
          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
          prompt: |
            REPO: ${{ github.repository }}
            PR: ${{ github.event.pull_request.number }}
 
            docs/doc-map.md を読み、このPRの変更ファイルのうち
            対応表に載っているものだけを対象にしてください。
            変更ファイルは git diff --name-only で得ます。
            対応表に載っていないファイルは無視します。
 
            対象ごとに、紐づく設計書の節を読み、
            「照合する観点」の列にある種類の食い違いだけを探します。
 
            次の3点が揃う場合だけ、変更されたコード行に
            インラインコメントを付けてください。
            1. 設計書の該当記述(ファイル名と見出し)
            2. コード側の根拠(ファイル名と該当箇所)
            3. 食い違いの種類(名前 / 値 / 手順 / 削除済み)
 
            3点が揃わないものは書きません。判断できないものは
            「要確認」として最大3件、末尾に1行ずつ書きます。
            設計書もコードも編集しないでください。
          claude_args: |
            --max-turns 10
            --allowedTools "Read,Bash(git diff *),mcp__github_inline_comment__create_inline_comment"

ポイントは4か所です。

  • on.pull_request.paths: 指定したパスのファイルが変わったPRだけでworkflowが起動します。パスの絞り込みはGitHub Actions側の仕組みで、Claudeを呼ぶ前に実行そのものを止められるため、トークンの消費も抑えられます
  • fetch-depth: 0: ドキュメントの例はfetch-depth: 1ですが、ベースブランチとの差分を取るには履歴が必要です。浅いチェックアウトのままだと差分が取れないことがあるため、この用途では全履歴を取得します。手元の構成に合わせて調整してください
  • --allowedTools: プロンプトを文章で渡す場合、Claudeはシェルや外部APIの権限を持たない状態から始まるため、必要な道具を明示して許可します。ここでは読み取り(Read)、差分の取得(git diffで始まるコマンドだけ)、インラインコメントの投稿の3つに絞りました。Editを入れないので、設計書を勝手に書き換えることはありません
  • --max-turns 10: 1回の実行が何ターンまで進めるかの上限です。上限に達するとエラーで終了するため、照合が終わらない巨大PRで費用が膨らむのを防げます。複数の引数の渡し方はclaude_argsの渡し方に詳しくあります

--comment付きのレビュー用スキルと違い、このworkflowは自前のプロンプトで動きます。インラインコメントを投稿するツールは、claude_argsの--allowedToolsに書いて初めてアクション側がそのMCPサーバーを起動します。許可の行を消すと、指摘は投稿されず、実行ログに残るだけです。

手元で試走してから、CIに載せる

いきなりCIで回すと、プロンプトの調整のたびにPRを作り直すことになります。同じ指示はclaude -pで手元でも実行できます。--bareはCIやスクリプト向けのモードで、手元の~/.claudeにあるhooksやCLAUDE.mdを読まず、どのマシンでも同じ条件で動きます。APIキーは環境変数で渡します。

export ANTHROPIC_API_KEY="(自分のキー)"
claude --bare -p "$(cat .github/prompts/doc-drift.md)" \
  --allowedTools "Read,Bash(git diff *)" \
  --max-turns 10

プロンプトを.github/prompts/doc-drift.mdのような別ファイルに切り出しておくと、workflowのpromptと手元の試走で同じ文面を使えます。ただし、手元ではインラインコメントのツールが使えないため、指摘は標準出力に出ます。出力を読んで、「根拠が3点そろっているか」「対応表にない設計書に触れていないか」を確かめてから、CIへ移します。

プロンプトが長くなって育ってきたら、リポジトリの.claude/skills/にスキルとして置き、promptに/skill-nameを渡す方法もあります。この場合もactions/checkoutを先に実行してスキルのファイルを実行環境に置く必要があります。手順はリポジトリ内スキルをpromptに渡す方法で扱っています。

誤検知を減らす4つの絞り方

乖離検出の失敗は、見逃しより誤検知で起きます。誤検知が3回続くと、開発者はコメントを読まなくなり、仕組みごと形骸化します。入力の側で絞るのが先で、プロンプトの言い回しの調整は後です。

誤検知対策

入力を絞る4つの手段

  • 対象のPRを絞る

    pathsで、コードか設計書が変わったPRだけを対象にします。READMEの誤字修正やテストだけの変更では、そもそも起動しません。

  • 対象のファイルを絞る

    対応表に載っているファイルだけを照合します。載っていない変更は無視すると明記しておくと、Claudeが関係なさそうな設計書まで探しに行くのを防げます。

  • 読む範囲を節に絞る

    設計書は節単位で指定します。全文を読ませると、別の節の古い記述まで拾ってしまい、そのPRと無関係な指摘が混ざります。

  • 観点を絞る

    名前・値・手順・削除済みの4種類に限り、文章表現の好みや「もっと詳しく書くべき」といった改善提案は対象外にします。

4つのうち効果が大きいのは、対象ファイルを絞る手段と観点を絞る手段です。この2つは、対応表の「対応するコード」列と「照合する観点」列で表現できるため、プロンプトを書き換えずに、対応表の行を足したり消したりして運用できます。

もう1つ、見落としやすいのがPRの差分だけを根拠にさせないことです。たとえば定数名が変わったPRでも、設計書が参照している別ファイルの値は変わっていないかもしれません。差分の行だけを見て「値が変わったので設計書が古い」と言わせると、誤検知になります。プロンプトに「コード側の根拠は、変更後のファイルをReadで開いて確かめる」と書き添えると、差分の断片で判断する癖を抑えられます。

指摘の書式を縛ると、読むコストが下がる

指摘の書式は、プロンプトの出来を左右します。自由記述で「乖離があれば教えてください」と書くと、長い総評と推測を含んだ指摘が返り、読む側の負担が増えます。

前と後

プロンプトの指示を書式つきに変える

BEFORE

自由記述

設計書とコードに食い違いがないか確認し、あれば指摘してください。

AFTER

書式つき

設計書の記述・コード側の根拠・食い違いの種類の3点が揃うものだけを、変更された行へのコメントにしてください。揃わないものは書かず、判断できないものは「要確認」として最大3件にまとめてください。

書式つきの指示には、副次的な効果があります。根拠の欄を埋められない指摘は、そもそも書けないので、推測だけの指摘が出にくくなります。コメントを受け取った開発者も、設計書のどの節を直せばよいかを一目で判断できます。

--output-format jsonと--json-schemaを組み合わせると、出力を決まった構造で受け取れます。たとえば、指摘の配列を後続のステップで集計し、件数が一定数を超えたらジョブを失敗させる、といった使い方も可能です。ただしスキーマ指定は、コメントを直接投稿する構成とは別の設計になります。まずはコメント投稿で運用し、必要になった段階で検討するのが現実的です。

落とし穴

実行したのにコメントがなく、成功扱いで終わる

指摘がゼロのPRと、コメントの投稿ツールが許可されていないPRは、外から見るとどちらも「何も出なかった」になります。初回は、対応表に載っているコードを意図的に変え、対応する設計書は触らないテストPRを作り、コメントが付くことを確かめてください。付かなければ、--allowedToolsのツール名とインラインコメント用の許可を疑います。

動かない・コメントが出ないときの切り分け

ドキュメントの切り分け項目を、この用途に当てはめると、上から順に確かめる流れになります。

切り分け

コメントが付かないときの確認順

  1. Qworkflowの実行自体は始まっているか?
    答えがいいえのとき

    on.pull_request.pathsに、変更したファイルが含まれているか見直します。typesにPRの状態(openedやsynchronize)が入っているかも確認します。

    答えがはい
  2. Q実行は始まるが、Claudeの手前で失敗していないか?
    答えが失敗している

    実行を起こしたユーザーが書き込み権限を持つか、ボットが起動したPRならallowed_botsに載っているかを確かめます。アクションは、書き込み権限のないユーザーと、allowed_botsにないボットの実行を拒否します。

    答えがはい
  3. Q認証は通っているか?
    答えが通っていない

    APIキーまたはOAuthトークンがリポジトリのシークレットに登録されているか、手元でclaudeを起動して有効か確認します。

    答えがはい

それでも出ないとき

実行ログを開き、ツールの許可が拒否されていないか確かめます。--allowedToolsに書いたツール名が、実際に使われたツール名と一致していないことが多くあります。

フォークからのPRにも注意が要ります。公開リポジトリでは、GitHubがフォークからのPRで起動した実行にはシークレットを渡しません。このworkflowが動くのは同じリポジトリ内のブランチから出したPRだけで、外部の貢献者のPRは対象外になります。

この仕組みで拾えない乖離と、運用上の線引き

最後に、この構成で拾えない乖離を挙げておきます。拾えないものを知っておくと、期待しすぎて失望する事態を避けられます。

  • 設計書の意図とコードの意図が食い違っているケースは、記述の突き合わせでは見つかりません。「この画面は管理者だけが見られる」という設計書と、権限判定の漏れたコードは、どちらの名前も一致しているため、機械的な照合では通ってしまいます
  • 対応表に載っていない設計書は、そもそも対象になりません。対応表の保守が必要で、新しいモジュールを足したら行も足す運用が前提です
  • PRを出す前に既に生じていた乖離は、そのPRが触れない限り出てきません。既存の古さを洗い出したいなら、同じプロンプトをscheduleトリガーで回し、結果をIssueにまとめる別の運用になります

費用の面では、実行のたびにGitHub Actionsの実行時間とAPIトークンの両方を消費します。対策は、pathsで起動を絞ること、--max-turnsで上限を置くこと、対応表を肥大化させないことの3点です。ドキュメントには、GitHubの同時実行制御やジョブのタイムアウトを併用する案も挙がっています。

なお、Mintlifyのようなホスティング型のドキュメント基盤を使っているなら、基盤側のMCPで古い記述を探して直す道もあります。リポジトリ内のMarkdown設計書を対象にするこの記事の方法とは対象が違うので、ClaudeとMintlifyを連携する方法も見比べてください。

自動修正までやらせないほうが長続きする

指摘を受けて、Claudeに設計書を自動で直させたくなりますが、この構成では意図的に編集権限を渡していません。設計書の修正は「コードが正しいのか、設計書が正しいのか」の判断を含むからです。コードの側にバグがあって設計書が正しい場合、自動修正は誤りを設計書に書き込んでしまいます。判断は人間が受け持ち、Claudeには候補の提示までを任せる分担が安全です。

まとめ

設計書とコードの乖離検出は、全体を一度に洗う仕事ではなく、PRの変更ごとに少数の候補を出す仕事として設計すると続きます。誤検知は、プロンプトの言い回しより、対応表とpathsで入力を絞ることで減らせます。

最初の一歩は、更新頻度の高い設計書1本とそのコードだけで対応表を作り、手元のclaude -pで試走することです。出力の根拠が3点そろっていれば、CIに載せる準備が整っています。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. code.claude.com/docs/en/github-actions
  2. code.claude.com/docs/en/headless
  3. code.claude.com/docs/en/cli-reference
  4. docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax
この記事を共有:XはてブLinkedIn