AIコーディングエージェントが同じミスを繰り返さないようにするには、ミスをするたびに人がCLAUDE.mdを直す代わりに、「ユーザーが正した言葉」をセッション記録から自動で集めて、2つの方向で使えばよいのです。1つは、そのリポジトリの次のセッションの最初の入力に、最近の訂正をそのまま示すこと(最初の訂正からすぐ学ぶ)、もう1つは、同じリポジトリで同じ型が別の日に2回以上出たら、規則の候補として提案台帳に上げること(文として固める)です。Claude Codeはセッションを JSON Lines(.jsonl)で残すので、ユーザーのメッセージのうち「見落としたでしょう」「やるなと言ったでしょう」のような形だけを正規表現で選り分け、型を付ければよいのです。
この記事は、一人で使う開発環境をAIエージェント中心に変えながら(AX、AI転換)作った仕組みを、1日に1つずつ整理する連載の第5回です。前回はレビュー記録のないコミットをフックが止める話でした。
なぜ「ミスをしたらCLAUDE.mdを直せ」では足りなかったのか?
エージェントがミスをしたら「このミスを繰り返さないよう、規則ファイルを直して」と頼む方法は広く知られていて、私もそう始めました。引っかかったのは2つです。
1つ目は、直す主体が人であることです。正す言葉は、作業中に短く飛び出します。「そうじゃなくて」「抜けてるよ」と一言言うと、また作業に戻ってしまい、規則ファイルを開いて文を整える作業は後回しになります。リポジトリが複数あれば、どのファイルに書くかから悩むことになります。
2つ目は、一度正した言葉は、そのセッションが終わると消えることです。モデルは、会話が終わると何も覚えていません。翌日、同じリポジトリで新しいセッションを開くと、同じ前提で同じミスをし、私は同じ言葉をもう一度言いました。規則になるまでの空白が問題でした。
正した言葉はどこに残っているのか?
Claude Codeは、セッションごとにすべてのメッセージとツール呼び出しを、~/.claude/projects/<作業フォルダ>/<セッションid>.jsonl に残します。ユーザーのメッセージも、その中にそのまま入っています。ですから、これらのファイルを日付の範囲でたどってユーザーのメッセージだけを取り出し、その中から「正す言葉」の形だけを選べば、訂正の事例になります。訂正の直前のエージェントの作業(どのツールで何をしたか)も同じファイルにあるので、「何が間違っていたか」の要点も一緒に残せます。
最初は、「訂正率」だけを測る指標がありました。率は悪くなったかどうかは教えてくれますが、何が間違っていたかは教えてくれず、指針を直す根拠にはなりませんでした。そこで2026-10-10に、文そのものを事例として集めるスクリプトを別に作りました。
どんな言葉を「訂正」とみなすのか?
ここでいちばん時間がかかったのが、選り分ける基準です。「もう一度確認してみて」「~ではないか?」のような言葉は、ミスではないことが多いのです。30日分のサンプルを手で見ると、半分がこうした再確認や疑いでした。こうした言葉まで規則に上げると、間違った規則が積み重なって、エージェントをさらに悪くします。そこで、精度を優先して、規則ベースで認める型を4つに絞りました。
TYPES = ( # 先頭から最初に一致したもの。疑問符で終わる場合は「指示違反」だけを認める
("누락", re.compile(r"놓쳤|빠졌|빠뜨|빼먹|누락"), False),
("지시 위반", re.compile(r"말라(?:고|니까|니깐|했)|말랬|하지\s?말(?:라|랬|래|자)|하라고\s*[.!]*$"), True),
("전제 착오", re.compile(r"(?:그게|그거|이게)\s?아니|[가-힣A-Za-z0-9_.]+(?:이|가|게)\s?아니(?:고|라)(?=\s)"), False),
("결과 오류", re.compile(r"잘못(?:됐|되었|했|만들|계산|나왔)|틀렸|틀린|이상해|엉뚱|엉망"), False),
)
規則に引っかからない言葉は、「その他」として集めておくだけです。そこに、例外がさらに加わりました。「私が言い間違えた」は人のほうのミスなので除き、「間違えたら」は仮定なので除き、「うん、そうじゃなくて …」のように、相づちの後に説明する言葉も除きます。ほかのセッションが送ったメッセージ(「[」で始まる)と、200字を超える長い指示文も、訂正ではありません。「その他」は、後で小さなモデルにもう一度尋ねて、4つの型のどれかに分け直しますが、既定値は「訂正ではない」にしました。間違った訂正1件は、正しい訂正10件より害になるからです。
集めた事例をどこで使うのか?
2つの方向があります。
1つ目は、次のセッションの最初の入力に示します。セッションの最初のプロンプトが入るときに動くフック(UserPromptSubmit)が、そのリポジトリの直近30日の訂正のうち、型が決まったものだけを最大4件選び、そこにレビューエージェントやガードフックが自ら見つけたミス2件を足して、一度だけ入れます。セッションidで目印のファイルを残して、同じセッションに2回入れないようにします。こうすれば、規則になる前でも、最初の訂正から、次のセッションが知った状態で始まります。
[最近の訂正] このリポジトリで、ユーザーが直近30日以内に正した言葉と、
レビューや自分で見つけたミスです。同じ前提・同じミスをする前に、
この一覧と合っているかをまず確認します — 根拠として引用するときは、原文を確認し直します:
- 2026-10-20 見落とし: …
- 2026-10-18 指示違反: …
2つ目は、繰り返されたら規則の候補に上げます。リポジトリと型が同じ事例が、「セッションと日付が違う単位」で2回以上あれば、提案台帳に番号を付けて上げます。同じセッションで同じ日の繰り返しは、1回と数えます。同じ問題を何度も言っただけかもしれないからです。人の訂正が1件もなく、エージェントが自ら見つけたものだけが積み重なった束は、上げずに保留します。レビューをよく呼ぶセッションほど、保留がなければ提案があふれました。台帳には、リポジトリ・型・セッション数・日付だけを書き、原文はローカルにだけ置きます。
# 毎晩の自動化が回す1行 — 直近4日の事例を集め、「その他」をモデルで分け直し、繰り返された型を台帳に上げる
python3 scripts/corrections-collect.py --days 4 --llm --propose
# 上がった束の事例を見る(ローカルの画面専用)
python3 scripts/corrections-collect.py --show <リポジトリ>/<型>
今の1日はどう変わったのか?
2026-10-23時点で測った値です。2026-09-11から2026-10-21までに集まった事例は363件で、そのうち人が正した言葉が135件、レビューエージェント・ガードフック・エージェント自身が先に気づいたミスが228件です。型別では、指示違反80・結果の誤り63・見落とし48・前提の取り違え46で、「その他」として残ったものが126件です。最初の入力への注入は、2026-10-11から、セッション141個に297回入りました。提案台帳には、「訂正の繰り返し」の項目が32個上がり、そのうち27個が規則の文やフックとして反映されました。
変わったのは2つです。正した言葉をどこに書くかで、私が悩まなくなりました。作業中に一言言って先へ進めば、その日の夜に自動化が集め、翌日、そのリポジトリのセッションがその言葉を見てから始まります。そして、規則ファイルに入る文は「2回以上繰り返されたもの」に限られるので、一度だけ腹が立ったことのために規則が増えることが減りました。代償もあります。正規表現ベースなので「その他」がいちばん大きな束で、そこに隠れた本物の訂正は、モデルによる再分類が拾ってくれるまで待つことになります。
よくある質問
セッション記録のファイルはどこにあり、何が入っていますか?
Claude Codeは、作業フォルダごとに、~/.claude/projects/<フォルダ名をエンコードした値>/ の下に、セッションごとに .jsonl ファイルを置きます。1行がメッセージ1つで、ユーザーのメッセージ・エージェントのメッセージ・ツール呼び出しとその結果が、順番に入っています。この記事のスクリプトは、そのうちユーザーのメッセージと直前のツール呼び出しだけを読みます。
訂正の原文をgitに上げてもよいですか?
上げません。正す言葉には、作業中のデータ・ファイル名、ときには秘密の値が混ざります。事例ファイルはローカルのフォルダにだけ置き、秘密の値やSQLが入った文は、原文の代わりに伏せた表示だけを残します。gitへ行く提案台帳には、リポジトリ・型・セッション数・日付だけを書きます。
なぜ最初からモデルにすべて分類させないのですか?
精度のためです。間違った訂正が規則になると、エージェントが見当違いの規則を守ろうとします。そこで、規則ベースの4つの型だけをまず認め、モデルは「その他」を分け直すことにだけ使います。それでも、1つのモデルの判定は、別のモデルが同じ質問でもう一度分けて、両者が一致したときだけ、規則による判定と同じ重みで数えます。食い違えば、「その他」に戻します。