受託でお預かりしているサイトの改修中、同じ一行を三度書いておりました。「コードに説明のコメントは付けないでください」。一度目は効きます。二度目も効きます。四往復ほど進んで別のコンポーネントに移ったところで、// 状態を更新する という、コードをそのまま言い直しただけの行が戻ってまいりました。
最初のうち私は、言い方が足りないのだろうと考えておりました。強い語を足し、大文字にし、理由まで添えて書き直しました。結果は芳しくありませんでした。指示は弱かったのではなく、読み直されない場所に置かれていたのです。
置き場所には段があります。そして段ごとに、読み直される回数がまったく違います。好みは上の層に、外せない決まりは下の層に。 この線引きに移してから、同じ指示を三度書く日がほとんどなくなりました。
指示が戻るのは、置いた場所が読み直されないからです
Claude に指示を渡せる場所は、大きく四つに分かれます。上ほど手軽で、下ほど回数に強い構造です。
| 層 | 置く場所 | 読み直されるタイミング |
|---|---|---|
| ① 会話 | その場のメッセージ | 直後の数ターンのみ。要約や話題の転換で薄まります |
| ② スタイル・カスタム指示 | Claude アプリのカスタムスタイル、プロジェクトのカスタム指示、Claude Code の output styles | 会話をまたいで効きます。主題が離れると弱まります |
| ③ プロジェクト設定ファイル | CLAUDE.md、プロジェクト直下の設定 | セッションの開始ごと。置き場所とキー名が正しい場合に限ります |
| ④ 実行時の歯止め | フック、検査スクリプト | ツールが動くたび。判定できる指示だけが対象です |
同じ困りごとは Claude Code の Issue にも積み上がっております。議論が割れているのは「どう言えば効くか」の部分で、層を分けて比べた記録は見当たりませんでした。それなら自分の手元で比べるのが早い、と考えた次第です。
同じ一文を四か所に置いて、そのあとの十往復を見ました
条件をそろえます。指示は「コードに説明のコメントを付けない」の一文だけ。作業は、受託サイトの小さな UI 修正を十回続けるというもの。毎回ファイルを開いて直させ、コメント行が復活した往復の番号を数えました。
| 層 | 戻ってきた往復 | 破れ方 |
|---|---|---|
| ① 会話の冒頭で一度だけ伝える | 三〜四往復目 | ファイルが替わった直後に戻ります |
| ② スタイルに書く | 七往復目以降 | 会話はまたげますが、長い実装の途中で薄れます |
| ③ 設定ファイルに書く | 戻らず | ただし書き間違いに気づけません |
| ④ フックで止める | 戻らず | 判定できない指示は、そもそも載せられません |
意外だったのは③です。戻らなかったのではなく、戻っていないことを自分で確かめる手立てがない——そこが③と④の本質的な差だと気づいたのは、数日おなじ設定のまま走らせたあとでした。設定ファイルは、キー名を一文字間違えても何も言わずに無視されます。この黙り方についてはsettings.json のキー名を1文字間違えても、Claude Code は何も言わずに無視しますで詳しく書いております。
好みは上に、決まりは下に
四つの層を、指示の性質で振り分けます。私が使っている基準は二つです。破れたときに実害が出るか。そして、破れたかどうかを機械で判定できるか。
- 好み(口調、段落の長さ、絵文字の有無、説明の詳しさ)は①②で足ります。戻っても言い直せば済みますし、そもそも厳密に測れません。
- 決まり(触らせないファイル、コミットの可否、命名規則、訳さない固有名詞)は③④へ移します。戻ると後片付けが要りますので、言い直しでは追いつきません。
個人開発で続けている壁紙アプリのストア文言を多言語へ広げるときも、同じ形で詰まりました。「アプリ名と機能名は訳さないでください」を会話で伝えますと、言語が三つ、四つと増えたあたりから訳され始めます。いまは訳さない語を一覧にしたファイルを置き、仕上がりに固有名詞がそのまま残っているかを最後に機械で見ております。会話で頼むのをやめた、というより——頼む相手を層ごとに変えた、という感覚に近いです。
決まりを外させないなら、読ませるのではなく止めます
④の実物をお見せします。編集が終わった直後に、そのファイルだけを見る形のフックです。settings.json に置きます。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/no-echo-comments.sh"
}
]
}
]
}
}呼ばれるスクリプトです。標準入力に届く JSON から、いま編集されたファイルのパスを取り出します。
#!/usr/bin/env bash
# PostToolUse フック: 編集直後のファイル 1 つだけを見ます
INPUT=$(cat)
FILE=$(printf '%s' "$INPUT" | python3 -c 'import json,sys; print(json.load(sys.stdin).get("tool_input",{}).get("file_path",""))')
# 対象を絞ります。設定ファイルや Markdown まで見ると誤検知が増えます
case "$FILE" in
*.ts|*.tsx|*.js|*.jsx) ;;
*) exit 0 ;;
esac
# コードをそのまま言い直しただけの行を拾います
HITS=$(grep -nE '^[[:space:]]*//[[:space:]]*.+を(返す|設定する|更新する|取得する|初期化する)[[:space:]]*$' "$FILE")
# 何も無ければ黙って終わります
[ -z "$HITS" ] && exit 0
{
echo "コードを言い直しただけのコメントが残っています。削ってから次へ進んでください:"
echo "$HITS"
} >&2
exit 2期待される動きはこうなります。
$ # Claude が Edit を実行した直後
コードを言い直しただけのコメントが残っています。削ってから次へ進んでください:
42: // 状態を更新する要点は三つです。第一に、exit 2 は「やり直させる」合図で、標準エラーへ書いた文面がそのまま Claude へ戻ります。第二に、対象拡張子を先に絞ります。全ファイルを見ますと、設定ファイルのコメントまで拾って作業が止まります。第三に、通ったときは何も出しません。成功時まで饒舌なフックが何を招くかは、検証スクリプトの出力を、そのまま hook から返してはいけませんに書いたとおりです。
なお、コードを書かない使い方でフックが手元に無い場合は、③までで止めて構いません。そのかわり、③に置く一文を「判定できる書き方」にしておきます。「簡潔に」ではなく「一文を四十字以内に」と書けば、あとから自分の目でも数えられます。
それでも戻るときに確かめる三つのこと
- 置き場所とキー名が正しいか。 効いていないのではなく、読まれてすらいない場合があります。まずファイルが読み込まれた形跡を確かめます。
- その指示は判定できる形か。 「丁寧に」「賢く」は、層をいくら下げても守られたかどうかを確かめられません。数えられる言葉へ置き換えます。
- 同じ層に矛盾する二文が無いか。 設定ファイルが育ってきますと、半年前の一行と今日の一行が逆を向いていることがあります。長い会話で指示が薄れる感覚については前回の続きを頼むとき、メモリと過去チャットの検索のどちらに頼るかにも書いております。
今日できることを一つだけ挙げます。いま会話のなかで三度言い直している指示を一つ選び、ひとつ下の層へ移してみてください。三度書いているという事実そのものが、その指示の置き場所が合っていないという合図です。
私自身、いまだに②で足りるものを④まで下ろしてしまい、誤検知に足を取られることがあります。層を上げ下げしながら落ち着く場所を探すことも、作業のうちなのかもしれません。お読みいただきありがとうございました。