Claude CodeでADRを後追いで起こす — git logとPRから決定記録を作る
決定記録のないリポジトリで、過去の設計判断をgit logとPRの議論から拾い、MADR形式のADRに起こす手順です。出典コミットを残し、痕跡のない欄を推測で埋めないための指示を載せます。
ADR(Architecture Decision Record、設計判断の記録)を最初から書いてきたリポジトリは多くありません。多くの現場では、「なぜRedisではなくPostgresで持っているのか」の答えが、数年前のコミットメッセージとPRの議論に埋もれています。
この記事では、その痕跡をClaude Codeに拾わせ、MADR形式のADRとして後追いで起こす手順を説明します。要点は2つです。材料をコマンドで絞って渡すこと。そして、痕跡のない欄を推測で埋めさせないことです。
技術選定の場でADRを新規に書く手順はarchitectureスキルでADRを書く記事にあります。ここで扱うのは、すでに下された決定を後から文書にする作業です。
後追いADRで書けること、書けないこと
後追いのADRは、決定の場にいた人が書くADRとは性質が違います。git logとPRに残っているのは、結果と、その時に言葉になった理由だけです。
| ADRの欄 | 後追いで拾える度合い | 主な材料 |
|---|---|---|
| 決定の中身(Decision Outcome) | 後追いで拾える度合い高い | 主な材料差分、コミットの件名 |
| 背景と問題(Context) | 後追いで拾える度合い中 | 主な材料コミット本文、PR本文、リンクされた課題 |
| 検討した選択肢(Considered Options) | 後追いで拾える度合い低い | 主な材料PRのレビューコメントに出た代案だけ |
| 帰結(Consequences) | 後追いで拾える度合い低い | 主な材料その後の修正コミット、revert |
| 決定者・日付 | 後追いで拾える度合い日付は高い | 主な材料作者、マージ日 |
選択肢と帰結は、議論が文字で残っていた場合に限って書けます。残っていないなら、空欄のまま出すほうが正確です。Claude Codeに流暢な作文をさせると、この空欄が「それらしい理由」で埋まります。後追いADRで一番避けたいのはそれです。
手順1: 起こす決定を絞る
リポジトリ全体を一度に渡す必要はありません。まず、決定が起きたコミットを特定します。git logには、そのための絞り込みが揃っています。
# 件名・本文に語を含むコミット
git log --grep="redis" -i --oneline
# 文字列の出現回数が変わったコミット(依存の導入・撤去を探す)
git log -S"ioredis" --oneline -- package.json
# ファイルの改名をまたいで履歴を追う(単一ファイルのみ)
git log --follow --oneline -- src/cache/client.ts
# マージコミットだけを、本流に沿って並べる
git log --first-parent --merges --oneline-S はpickaxeと呼ばれるオプションで、指定した文字列の出現回数が増減したコミットを返します。ライブラリの導入や撤去は、この形で見つかることが多くなります。--follow は単一のファイルにしか使えません。
候補が出たら、ここで人が一度目を通します。10件ほどに絞れたら、1件ずつADRにするかどうかを決めます。「そのコミットはリファクタリングで、決定ではなかった」という外れも混じります。
手順2: コミットとPRの議論を材料にまとめる
ADRの背景と選択肢は、コミットよりもPRの本文とレビューコメントに書かれていることがよくあります。GitHub CLIの gh pr view は、--json でPRの項目を取り出せます。指定できる項目には、body、comments、commits、reviews、mergeCommit などがあります。
# 対象PRの本文・コメント・レビューをJSONで取る(PR番号は例)
gh pr view 482 --json title,body,comments,reviews,mergeCommit \
> /tmp/pr-482.json
# 該当コミットの全文(本文つき)と変更ファイル
git show --stat --format=fuller <コミットSHA><コミットSHA> は自分のリポジトリの値に置き換えます。出力を一度ファイルに落としておくと、Claude Codeに「このファイルを読んで」と指示できます。長いPRの議論をプロンプトに貼り込むより、ファイルで渡すほうが取り違えが起きません。
コミットメッセージにPR番号が残らない運用のリポジトリでは、git log --grep="#482" のような検索が空振りします。その場合は、gh pr view で mergeCommit を引いて逆向きにたどります。
差分の行に付いたレビューコメントは別に取る
gh pr view --json comments,reviews で取れるのは、PRの会話欄のコメントと、レビューごとの本文です。差分の特定の行に付いたレビューコメントは、ここに含まれません。GitHubのREST APIでは、これを「pull request review comments」と呼び、会話欄のコメント(issue comments)とは別物として扱っています。
「Redisではなくsessionsテーブルでは?」といった代案は、該当コードの行に付くコメントとして出ることが多いものです。Considered Optionsの材料になるので、別に取ります。
# 差分の行に付いたレビューコメント(全ページ分)
gh api repos/{owner}/{repo}/pulls/482/comments --paginate \
> /tmp/pr-482-inline.jsongh api は、エンドポイント中の {owner} と {repo} を、カレントのリポジトリの値で埋めます。--paginate を付けると全ページを順に取得します。プロンプトの材料には、/tmp/pr-482.json と並べて /tmp/pr-482-inline.json も渡します。
決定を含むPRが分からないときは、行から遡る
「このRedisの設定はいつ、なぜ入ったのか」から始める場合は、PR番号が手元にありません。その行を導入したコミットを、行の範囲から探します。
# src/cache/client.ts の10〜30行目に起きた変更の履歴
git log -L10,30:src/cache/client.ts --oneline
# 導入コミットに関連するPRを引く(SHAは例)
gh api repos/{owner}/{repo}/commits/3f9a1c2/pullsgit log -L<start>,<end>:<file> は、指定した行範囲の変更履歴を追います。出てきたコミットのSHAをGitHubのREST APIの「List pull requests associated with a commit」に渡せば、そのコミットに関連するPRが返り、手順2のPR番号が得られます。リファクタリングや整形で行が書き換わっている場合は、その手前のコミットまで遡る必要があります。
手順3: MADRの欄に当てはめる
ADRの書式にはMADR(Markdown Architectural Decision Records)を使います。MADRのリポジトリには4種類のテンプレートがあり、全欄入りの adr-template.md と、必須欄だけの adr-template-minimal.md が基本です。保存先は docs/decisions、ファイル名は nnnn-title.md の形が案内されています。
後追いには、最小テンプレートの欄に出典を足した形が扱いやすくなります。最小テンプレートの欄は次のとおりです。
- Context and Problem Statement
- Considered Options
- Decision Outcome(Consequencesは任意)
全欄入りのテンプレートには、これに加えて冒頭のメタデータ(status・date・decision-makersなど)、Decision Drivers、Confirmation、Pros and Cons of the Options、More Informationがあります。後追いでは、出典を書く場所としてMore Informationが使えます。
全欄入りを使う場合、追加される欄の扱いは材料次第です。
| 追加される欄 | 後追いでの扱い |
|---|---|
| Decision Drivers | 後追いでの扱いPRやコミット本文に制約・要求が書かれているときだけ書く。無ければ欄ごと削る |
| Confirmation | 後追いでの扱い決定の遵守を確かめるテストや設計レビューが履歴に見えるときだけ。見えなければ削る |
| Pros and Cons of the Options | 後追いでの扱いレビューコメントで選択肢ごとの利点・欠点が語られているときだけ。なければ削る |
| decision-makers | 後追いでの扱いPRの作者とレビュー承認者から候補を挙げられる。ただし実際の決定者かは本人に確認する |
テンプレートは、これらの欄を「optional element. Feel free to remove.」と注記しています。空欄を「記録なし」で埋めるより、欄ごと消すほうが読みやすくなる欄です。一方、Considered OptionsとConsequencesは、空なことに意味があるので「記録なし」と書いて残します。
プロンプトは、材料と欄の対応、そして書けない欄の扱いを明示します。次の例は、MADRの最小テンプレートを docs/decisions/0000-template.md として置いてある前提です。
docs/decisions/0000-template.md の形式(MADRの最小テンプレート)で、
次の決定のADRを docs/decisions/0007-cache-with-redis.md に作って。
材料:
- コミット: <コミットSHA>(git show で全文を読むこと)
- PR: /tmp/pr-482.json(会話欄のコメントとレビュー本文)
- PRの行コメント: /tmp/pr-482-inline.json
ルール:
- 材料に書かれている理由・代案だけを使う。書かれていない欄は
「記録なし」と書き、推測で埋めない
- Considered Options は、PRのコメントに実際に出た代案だけを列挙する
- More Information に、出典のコミットSHAとPR番号を残す
- statusは accepted、dateは決定のコミット日にする「材料に書かれていることだけ」と制約をかけるのが肝心です。この一文がないと、Claude Codeは一般論から選択肢を補います。
出力の形の例
次は、この指示から得られる形の一例です(内容は説明用に作った架空のものです)。
---
status: accepted
date: 2025-03-14
---
# セッション保存先にRedisを採用する
## Context and Problem Statement
ログインセッションをアプリサーバーのメモリに持っていたため、
サーバーを2台に増やすとログインが切れた(PR #482 の本文より)。
## Considered Options
* Redis
* PostgreSQLのsessionsテーブル(PR #482 のレビューコメントで提案)
## Decision Outcome
Chosen option: "Redis", because 有効期限をキー単位で設定でき、
PostgreSQLの負荷を増やさないため(PR #482 のレビュー返信より)。
### Consequences
記録なし。
## More Information
* 出典コミット: 3f9a1c2(依存の導入)
* 出典PR: #482「記録なし」の欄が残るのは欠陥ではありません。後からPRの議論を掘り返す人にとって、その欄は「追加の調査が要る」という目印になります。
推測の混入を機械的に止める
指示で縛っても、文章は流暢になりやすいものです。2つの確認を足すと取りこぼしが減ります。
出典の突き合わせ。生成したADRの各文に、コミットSHAかPR番号が紐づいているかを確かめます。「(PR #482のレビュー返信より)」のように根拠を括弧で残させておくと、レビューする人がPRを開いて照合できます。
別セッションでの検証。書かせたセッションとは別に、サブエージェントへADRと材料を渡し、「ADRの記述のうち、材料に根拠のない文を列挙して」と頼みます。サブエージェントは自分のコンテキストウィンドウで読み、要約だけを返すので、材料が大きくても本体の会話を圧迫しません。
use a subagent to compare docs/decisions/0007-cache-with-redis.md
with /tmp/pr-482.json and list every sentence in the ADR that has
no supporting text in the PR指摘された文は、削除するか「記録なし」に戻します。
決定者に確認を取ってから確定する
後追いADRは、書き手が決定の場にいなかったため、PRの読み違いが入りえます。いきなり accepted で取り込まず、status: proposed で出す選択肢があります。MADRのテンプレートは、statusの値に proposed、rejected、accepted、deprecated、superseded by ADR-0123 などを例示しています。
運用の流れは次のとおりです。
- ADRを
proposedでPRとして出す - 当時のPR作者やレビュアーに、PR上でレビューを依頼する
- 「記録なし」の欄に、本人の記憶による補足があれば、その旨を明記して追記する
- 確認が取れたら
acceptedに変えてマージする
手順3の補足は、履歴から拾った内容とは出所が違います。「担当者への聞き取り」と書き分けておけば、後から読む人が根拠の種類を区別できます。
複数の決定をまとめて起こす
対象が10件、20件になると、1件ずつ手で回すのは手間です。Claude Codeの非対話モード(claude -p)をシェルスクリプトから呼べば、決定ごとの繰り返しを自動化できます。--allowedTools に許可するコマンドを列挙し、読み取り系のgitコマンドだけに絞ります。
#!/usr/bin/env bash
# decisions.txt: 「PR番号 ファイル名」を1行1決定で書いたもの
while read -r pr name; do
gh pr view "$pr" --json title,body,comments,reviews,mergeCommit \
> "/tmp/pr-$pr.json"
gh api "repos/{owner}/{repo}/pulls/$pr/comments" --paginate \
> "/tmp/pr-$pr-inline.json"
claude -p "PR #$pr の材料 /tmp/pr-$pr.json と /tmp/pr-$pr-inline.json だけを根拠に、
MADR最小テンプレートで docs/decisions/$name.md を作って。
材料に無い理由・選択肢は書かず『記録なし』とする。
More Information に出典PR番号を残す。" \
--allowedTools "Bash(git log *),Bash(git show *),Read,Edit(docs/decisions/**)"
done < decisions.txt--allowedTools のルールは、末尾の * で前方一致になります。Bash(git log *) は git log で始まるコマンドを許可し、git push は許可しません。
書き込み先は、Edit(docs/decisions/**) のようにEditルールで絞ります。パスを指定した Write(...) のルールは受け付けられても、ファイル操作に一致しないと権限のドキュメントに書かれています。パス指定はEditルールで書く、というのが同ドキュメントの案内です。
ただし、許可の範囲を絞っても、出力の中身までは保証されません。生成されたADRは、人が差分を見て出典と照合してから取り込みます。
材料の収集と生成を分けておけば、生成だけをやり直せます。PRのJSONは1回取れば済みます。
規約をCLAUDE.mdに残す
毎回プロンプトを書き直さずに済むよう、後追いADRのルールをCLAUDE.mdに置きます。CLAUDE.mdはセッションの開始時に読まれる、持続的な指示の置き場所です。
## ADR(後追い)
- 保存先は docs/decisions、ファイル名は nnnn-title.md
- 形式はMADRの最小テンプレート
- 材料(コミット・PR)に書かれていない理由・選択肢は書かない。
書けない欄は「記録なし」とする
- 決定ごとに、出典のコミットSHAとPR番号を More Information に残す
- 日付は決定のコミット日。ADRを起こした日にしない最後の1行は見落としやすい点です。ADRの date を起こした日にすると、2025年の決定が2026年の決定に見えてしまいます。
つまずきやすい点
- PRの議論がない。小さな変更は、PRのやり取りなしにマージされています。この場合は「記録なし」が正しい出力です。
- 決定が複数のPRに分かれている。導入、移行、旧方式の撤去が別々のPRになっている決定は、PRを複数渡してADRを1本にまとめます。出典には全PRを並べます。
- 決定が後で覆っている。後のコミットが前の決定を取り消している場合、古いADRを書き換えず、新しいADRを足して古いほうのstatusを更新します。MADRのテンプレートには、statusに
superseded by ADR-0123のような値が例示されています。 - コミットメッセージが短い。件名だけのコミットからは、決定の理由を取り出せません。無理に起こさず、その決定は担当者への聞き取りの候補に回します。
関連する作業との組み合わせ
後追いADRは、履歴を読む他の作業と材料を共有できます。変更の多いファイルをgit logから洗い出す技術負債のホットスポットの記事で見つけた箇所は、決定の記録が欠けている可能性が高く、ADRを起こす優先候補になります。CHANGELOGの整理はgit-cliffの記事にあります。コミット履歴を読み、別の文書に変換する点は、ADRと共通しています。
まとめ
後追いADRの品質は、材料をどこまで絞って渡せたかと、痕跡のない欄に「記録なし」と書かせられたかで決まります。git logの --grep や -S で決定のコミットを探し、gh pr view --json でPRの議論を取り、MADRの欄に出典つきで当てはめる。この流れなら、あとから読む人が根拠をたどれます。
最初の1本は、直近で理由を聞かれた決定を選ぶと検証しやすくなります。記録なしの欄が多いなら、そのリポジトリは「理由を残す習慣」から整える段階です。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。