投稿

SKILL.md の決定的処理はシェルに任せる

SKILL.md の決定的処理はシェルに任せる

まとめ

  • Claude にファイル探索や有無判定を「自然言語の指示」で任せると、似た名前のファイルを巻き込んで読んでしまう
  • 決定的に判定できる処理は test -f などのシェルコマンドに移譲し、echo で次にやるべき指示文を直接返す
  • SKILL.md の手順は「決定的処理(スクリプト)」と「判断・生成(Claude)」に分けて記述すると迷いが減る

起きたこと

Claude Code のスキル room.report を実行したところ、本来は Report.md だけを読むはずなのに、自動生成された Report.auto.md まで読み込んでしまった。SKILL.md には「既存の Report.md があればタイトルを読み取る」と書かれており、Report.auto.md を読めとは書いていない。

原因はシンプルで、Claude が「既存の Report.md があるか」を確認するために ls や Glob で類似ファイルを探した際、prefix が似ている Report.auto.md を「これも Report の一種だろう」と推測して読み込んだ。自然言語の指示は曖昧で、似たものに引っ張られる。

トレードオフ

観点 Claude に探索させる スクリプトで判定する
トークン消費 推論と読んだ内容が context に乗る 固定の短い出力のみ
ツール呼び出し回数 候補が複数あれば Read を重ねる 1 回
正確性 表現の揺れで誤判断する 決定的
再現性 プロンプトと文脈でブレる 同じ入力で同じ結果
適性 文脈解釈・自然言語生成 有無判定・パターンマッチ

決定的に答えが決まる処理ほどスクリプトに分がある。Claude に判定させると、毎回 context 汚染と誤読込のリスクを背負うことになる。

やった修正

SKILL.md の手順を「Report.md があるか確認して、あれば読む」という散文から、次のコマンドに置き換えた。

test -f Report.md \
  && echo "Report.md を Read し、frontmatter 直後の1行目タイトル (# ...) を使用する" \
  || echo "会話内容から自然なタイトルを付ける(仮名ディレクトリ YYYY-MM-DD_HHMMSS をそのままタイトルにしない)"

ポイントは、echo の中身を判定結果(exists / none)ではなく、 次にやるべき指示そのもの にしたこと。Claude はシェル出力をそのまま読んで実行すればよく、「判定 → 対応のマッピング」を介さない。

設計指針

SKILL.md のフローを書くときは、各ステップを 2 種類に分類する。

  1. 決定的処理 — スクリプト化して echo で次の指示を返す。シェルが「指示書ベルトコンベア」になる
  2. 判断・生成 — テンプレートと制約だけ提示し、自然言語で Claude に任せる

両者を混ぜて散文で書くと、Claude が決定的処理まで推論で解こうとして迷う。手順 1 を機械化しておけば、推論コストは判断と生成に集中投下できる。

似た構造のスキルを書くたびに、「これは決まった答えがある処理か、それとも文脈次第の判断か」を意識的に切り分けると、スキルの再現性と省トークン性が両立しやすい。

トレンドのタグ