この記事は、連載「動かさない技術」の第 9 回です。うまくいかない症状と、その対処を一つずつ並べています。各回はファイルやスクリプトを一つ置けば完結します。その仕組みがなぜ要るのかは、置いたあとに解説を読めば分かります。連載の全体像と各回の一覧は序論にあります。
今回は、次に読む側のために書き残した知見の話です。が知見を書き残すのは、次に読む側がそれに頼って、自分で調べ直す手間を省き、正しい数を使ってくれると思うからです。ところが、書き残した知見は、そのとおりには働きませんでした。は、会話を引き継がないサブエージェントに、同じ 40 件の指摘の一覧と、前の担当者が残した引き継ぎメモを渡して、同じ仕事を 12 回頼みました。メモには、一覧についての数が 3 つ書いてあります。12 回のうち、メモの数に頼って成果物を書いたのは 1 回だけで、その 1 回は、メモの古い数をそのまま写しました。残りの 11 回では、サブエージェントはメモの数を使わずに、一覧を自分で数え直していました。メモの 3 つの数が 3 つとも合っていたときも、です。メモを読んだサブエージェントにできるのは、確かめるか、確かめずに使うかのどちらかです。
まず一つだけ、確かめてみてください。
あなたのプロジェクトの指示ファイルか引き継ぎメモを開いて、そこに書いてある数字を 1 つ選び、いま数え直してみてください。
合っていましたか。
CC BY 4.0
同じ一覧に、古さの違うメモを添えました
題材は、コードへの指摘を 40 件並べた一覧です。1 件ずつが、ファイルのパスと数行のコードと 1 文の説明でできています。はサブエージェントに、その一覧と一緒に、前の担当者が残した引き継ぎメモを 1 枚渡しました。メモには 3 つの数が書いてあります。
一覧に載っている指摘は 40 件です
そのうち、置き場所が app/jobs/ のものは 8 件です
拡張子が .rb のファイルに付いた指摘は 37 件です
が頼んだ仕事は 1 つだけです。次に入る人へ渡す要約として、その 3 つの数をファイルに書くことです。依頼文には、「数えてください」とも「メモから写してください」とも書いていません。
12 回のあいだで違うのは、メモの 3 つの数のうち、いくつがいまの一覧とずれているかだけです。
| メモの状態 | 回 |
|---|---|
| 3 つとも合っている | 3 |
| 1 つだけ古い | 6 |
| 3 つとも古い | 3 |
古い数として使ったのは、一覧に 6 件が足される前の数です(足された 6 件のうち、置き場所が app/jobs/ のものが 3 件、拡張子が .rb のものが 6 件です)。
古い数が写されたのは、15 行のうち 1 行でした
メモの数がいまの一覧とずれていた行は、全部で 15 行あります。そのうち、サブエージェントがメモの数をそのまま成果物に写したのは 1 行でした。
| メモの状態 | ずれていた行 | 古い数を写した |
|---|---|---|
| 1 つだけ古い | 6 | 1 |
| 3 つとも古い | 9 | 0 |
古い数を写した 1 回は、報告でずれに触れていませんでした
メモの数がずれていた 9 回のうち 8 回で、サブエージェントは、メモの数がいまの一覧とずれていることを、自分から報告してきました。は、ずれがあるかどうかを尋ねていません。
HANDOFF.md の「分かっていること」に記載された件数(total 34 / app_jobs 5 / rb 31)は
items.mdの中身と一致しなかったため(実際は C01〜C40 の 40 件、app/jobs/は 8 件、.rbは 37 件)、items.mdを実際に数え直した値を SUMMARY.tsv に記載しました
そして、その 8 回の成果物に書かれた古い数は、合わせて 0 行でした。
古い数を写した 1 回は、サブエージェントがずれに 1 度も触れていない 1 回でした。報告はこうです。
内容は HANDOFF.md の「分かっていること」に記載の 3 つの数値をそのまま反映しました(total 34 / app_jobs 8 / rb 37)
12 回のうち、サブエージェントが一覧を数えずに書いたのは、この 1 回だけです。
メモの数が合っていても、サブエージェントは数え直しました
12 回のうち 11 回で、サブエージェントはメモに書いてある数を自分で数え直しています。メモの数が 3 つとも合っていた 3 回も、3 回とも数え直していました。
items.md の C01〜C40 を数えて HANDOFF.md の記載と一致することを確認済み
あなたは、プロジェクトの指示ファイルに、テストファイルの数やAPIのエンドポイントの数のような、いまのコードの数を書いています。書いておくのは、AI がその数に頼って、作業のたびに数え直さずに済み、報告にも正しい数を書くようにするためです。あなたは、AI の報告を、全部は確かめずに受け取っています。あるとき作業の記録を開くと、AI は指示ファイルの数を使わずに、自分でコードを数え直していました。そのときの指示ファイルの数は合っていました。別の日の報告には、指示ファイルに書いたままの古い数が載っていて、報告はそのことに触れていませんでした。その日までに、コードのほうが変わっていました。書いておいた数が、思ったとおりに働いていません。あなたなら次のどちらにしますか。
- 数は指示ファイルに書いておき、コードが変わるたびに書き直す
- 数は指示ファイルに書かず、AI がその場で数えるスクリプトを置く
答えは、数を書かずにスクリプトを置くほうです。AI は、セッションのたびに、前の会話を持たずに始まります。前に何があったかをAIに運ぶのは、あなたが書いたファイルだけで、それは書いたときの文のまま届きます。その文には、書いたあとにコードが変わったかどうかは書かれていません。一方で、テストファイルやエンドポイントの数は、AI がコードから自分で数えることのできる数です。報告に正しい数が要る作業なら、AI は、コードから数え直すか、数え直さずに書いてある数を使うかのどちらかになります。数え直せば、書いておいた数は使われません。記録で数え直していたのは、こちらです。数え直さずに使えば、コードが変わっていた日には、古い数がそのまま報告に入ります。別の日の報告が、こちらです。あなたが書き直して合わせておいても、AI に届くのは書いたときの文なので、この 2 つのどちらかになることは変わりません。スクリプトを置けば、AI は、その場でいまのコードを数えた数を使います。の実験でも、12 回のうち 11 回で、サブエージェントは一覧から自分で数えていて、その 11 回の成果物には、古い数が 1 つも入りませんでした。
理解したことは一文にできます。
AI は前の会話を持たずに始まり、書き残した知見を書いた時点の文として読む。コードから導けることは AI が自分で導くので、書き残しても使われず、導かずに使えば古くなっていても使われる。だから、コードから導ける知見は書き残さず、その場で AI に導かせる。
なぜ、書き残した知見は期待どおりに働かないのか
Claude Code のメモリのページは、セッションは毎回、まっさらなコンテキストから始まると書いています。会話を引き継がないサブエージェントも、起動するときに、メインの会話の履歴を受け取りません。前に何があったかをAIに運ぶのは、ファイルに書いたものだけです。そして AI が読むのは、書いた時点の文です。今回のメモも、一覧に 6 件が足されたあとも、足される前の数のままでした。
メモの文には、書いたあとに一覧が変わったかどうかは書かれていません。が渡したメモは、数字を伏せると、3 つの条件で 1 文字まで同じです。サブエージェントの手元にあったのは、この文と、いまの一覧だけでした。
一方で、一覧の数は、AI がいまの一覧から自分で導くことのできる数です。Claude Code のメモリのページによれば、指示ファイルを整理する /doctor は、ディレクトリの構成や依存の一覧やアーキテクチャの概要のような、Claude がコードベースから導ける内容を削り、落とし穴・理由・ツールの既定と違う慣習を残します。今回も、12 回のうち 11 回で、サブエージェントは一覧から自分で数え、ずれを報告した 8 回は、8 回ともそうしていました。一覧を数えなかった 1 回のサブエージェントは、メモの 3 つの数を「そのまま反映しました」と報告し、そのうちの 1 つが古い数でした。
CC BY 4.0 はここまで
残さなくなったもの
は、AI に覚えておいてほしいことを、文章で書き残すのをやめました。代わりに、知見の種類ごとに、AI がそれを必要とするその瞬間に出てくる場所に書いています。
| 知見の種類 | 置き場 |
|---|---|
| コードから数えたり読み取ったりできるもの(件数・一覧・ファイルの場所・構成) | 書かない。数えるスクリプトを置く |
| 破られたらプログラムで見つけることのできる決まり | 自動テストの失敗文言か、hook が止めたときのメッセージ |
| どちらでもないもの(判断の理由・経緯・落とし穴) | 文章で残す |
表の 1 行目と 3 行目は、さきほどの /doctor の分け方と同じです。2 行目の決まりを文章に書かないのは、書いた知見が、AIにとっては文脈として扱われるからです。メモリのページは、指示ファイルとメモリの中身を、文脈として扱い、強制される設定としては扱わないと書いています。は 1 作目「読まない技術」の第 8 回で、同じ「失敗したらアプローチを変えろ」という方針でも、セッションの始めに読ませたときには AI は失敗した直後に同じやり方でもう一度試し、もう一度試そうとしたその場で読ませたときには方針に従った、と書きました。
- 自動テストの失敗文言には、「この数を上げてください」だけでなく、なぜ上げるのかまで入れます。失敗文言は、テストがいまのコードに対して走り、落ちたときにだけ出ます
- hook が止めたときのメッセージには、代わりにやることを書きます。このメッセージは、その操作の瞬間に届きます。hook がツールの呼び出しを止めたとき、AI に届くのは、そのとき hook がエラー出力に書いた文です。ただし、1 作目「読まない技術」の第 2 回では、特定の語が含まれるかどうかでメモリへの保存を止める hook を、AI が語を言い換えるだけで素通りしました
それでもAIは、覚えておいてほしいことを忘れません。忘れないように見えるのは、それが要る瞬間に、書いた場所(自動テスト、hook、スクリプト)から出てくるからです。
CC BY 4.0
注意: 測ったのは、コードから導ける数だけです
判断の理由や経緯は、コードから導けないので、文章で残すしかありません。AI は、そういう知見を、書いた時点の文として読みます。この回で測ったのは、いまの一覧の数を要約に書く作業で、メモに一覧から導ける数を書き残した場合だけです。
実験手順: 残したメモの数だけを、いまの題材からずらす
前提
いまの題材からプログラムで数えることのできる数を 3 つ決めます。選ぶのは、数え方が 1 通りに決まる数です(今回の題材では「拡張子が .rb」がそれに当たります。.erb や .rake が混ざっていても、末尾が .rb かどうかで 1 通りに決まります)。渡すメモは 1 枚で、その 3 つの数のほかは、どの条件でも 1 文字まで同じにします。
所要時間: 12 回で 7 分(サブエージェントの実行時間の合計。1 回あたり、メモの数が 3 つとも合っているほうが 22 秒、どこかが古いほうが 37 秒)
手順
- 同じ題材を、会話を引き継がないサブエージェントに n 回渡します。メモに書く数だけを、0 か所 / 1 か所 / 3 か所ずらします
- ずらす向きをそろえます。「あとで増えた」形にすると、メモの中で筋が通ります。でたらめな数にはしないでください。でたらめな数だと、サブエージェントは、数が古いことよりも、メモの中で筋が通らないことに反応します
- 成果物を 1 つだけ頼みます。「数えて」とも「写して」とも書かないでください
- 書かれた数を、いまの題材の数 / メモの数 / どちらでもない、の 3 つに分けます。どれに当たるかは、判定のプログラムで決めます
- 報告のほうを別に見ます。いまの題材の数とメモの数が両方出ているかで、ずれに触れたかを数えます。語のリストは補助にとどめます
合格条件(すべて満たすこと)
合格の条件は 4 つです。1 つ目に、渡した題材が全条件で 1 バイトまで同じであることを、ハッシュで確かめておきます。2 つ目は、数字を伏せると、メモが全条件で同一であること(形が変わっていないこと)です。3 つ目は、依頼文に、確かめる/写すを促す語が 1 つも入っていないことです。4 つ目に、メモの数が 3 つとも合っている条件で、全回が正解していることを確かめます。これで、課題そのものが難しすぎないことが分かります。
合格しなかったとき
- メモの数が 3 つとも合っている条件でも誤答が出た —— 課題が難しすぎます。この状態では、メモのせいの誤りと、ただの数え間違いが、同じ誤答として数えられ、分けることができません
- 全回でメモの数がそのまま写された —— 依頼文が写すほうを促しています。依頼文を 1 語ずつ見直してください
- 全回で数え直された —— それ自体が結果です(今回がそれに近い形でした)。ただし、指示ファイルに「古い記録を疑え」に当たる 1 行があるかどうかを、先に確かめてください。あるなら、測ったのは、その 1 行にAIが従ったかどうかのほうです
- ずらした数(1 か所と 3 か所)で差が出た —— 回数を先に数えてください。6 回対 3 回で出る差は、たいてい偶然です
後始末
サブエージェントに渡したディレクトリと、正解表を削除します。正解表を残すと、あなたは、次に題材を作り直したつもりのまま、古い答えのほうで採点することになります。それは、この記事で測ったのとまったく同じ事故です。
CC BY 4.0 はここまで
次回は最終回、「実験しない技術」です。