Chapter 6

第6章: 専用ツールはなぜ多いのか ─ Read/Edit/Write と Bash の分業

ある日、エンジニア仲間と話していてこう聞かれた。

「Claude Code って Bash tool 持ってるんでしょ? じゃあ cat でファイル読めるし、sed で編集できるし、grep で検索できるじゃん。 なんで Read とか Edit とか Grep とか わざわざ別のツール にしてるの?冗長じゃない?」

いい質問だ。実際、原理的には Bash 一本あれば何でもできる。 それでも Claude Code は Read、Edit、Write、Grep、Glob、Bash と分業させている。

これは冗長ではなく、意図された設計 だ。 そしてこの設計判断こそが、Claude Code の「賢さ」と呼ばれているものの正体に近い。

6.1 そもそも、ツールはなぜ “増える” のか

第5章で見たとおり、利用可能な道具のカタログは system prompt に乗って毎ターン LLM に渡される。つまり道具を増やすには、トークン的コスト(定義が長くなる)と 認知的コスト(LLM が迷う材料が増える)の二つを払うことになる。普通に考えれば、Bash 一本にまとめたほうが短くて済むし、LLM も迷わないはずだ。

それでも Claude Code は 専用ツールを増やす道 を選んだ。なぜか。

専用ツールは、Bash で代替できない 4 つの利点 を持っているからだ。 (a) 出力フォーマットが安定 (b) 副作用が予測可能 (c) パーミッション制御が細かい (d) LLM が選びやすい。

この章では、この 4 つを 1 つずつ解いていく。

6.2 利点 (a) ── 出力フォーマットの安定

cat file.txt でファイルを読むのと、Read(file.txt) でファイルを読むのは、結果として 同じ内容 が返ってくる。 しかし「返り方」が違う。

方法返ってくるもの
Bash("cat fibonacci.py")生のファイル中身。OSやシェル設定によって改行コードや文字コードが揺れる可能性
Read("fibonacci.py")行番号付きの整形済みテキスト。一定の長さで自動切詰め、頭/末尾の空行除去など、フォーマット保証あり

Read tool が返すフォーマットの例(行番号 + タブ + 中身):

1	def fibonacci(n):
2	    if n < 2:
3	        return n
4	    return fibonacci(n-1) + fibonacci(n-2)

行番号を付けるのは、後で Edit tool で部分編集するときに「何行目を直すか」を LLM が指せるようにするため。道具と道具が 整った形 で連携できるよう、出力が設計されている。Bash で cat -n を呼んで毎回整える小細工に、LLM は脳を使わなくて済む。

6.3 利点 (b) ── 副作用の予測可能性

LLM は「続きを書く機械」なので、たまに 存在しないコマンド危険なオプション を書く。 Bash tool で find / -delete を呼ばれたら一発でシステムが壊れる。

専用ツールは 副作用の範囲がメタデータとして明示 されている。

ツール副作用
Read読み取りのみ(ファイルシステムを変更しない)
Grep / Glob読み取りのみ
Write指定ファイルを 新規作成 or 全書き換え
Edit指定ファイルに 部分置換
Bash任意の副作用(最も危険)

ハーネスは、ツールの種類を見ただけで「これは読み取りだから無条件で許可していい」「これは Bash だから許可確認を取る」と判断できる。 Bash 1 本にまとめてしまうと、毎回コマンド文字列を解析して危険度を判定 しなければならず、判定漏れがそのまま事故になる。

専用ツールに分けることは、LLM 側の利便性 だけでなく ハーネス側の安全制御 のためでもある。 読み取り系と書き込み系を別ツールにすることで、「読み取りはノーチェック、書き込みは要確認」という単純なルールが書ける。

6.4 利点 (c) ── ツール単位の権限制御

(b) と地続きの話だが、Claude Code は ツール単位で許可・拒否のルール を持てる仕組みになっている(permissions、第10章で詳述)。

設定ファイルに、たとえばこう書ける:

{
  "permissions": {
    "allow": ["Read", "Grep", "Glob"],
    "ask":   ["Edit", "Write"],
    "deny":  ["Bash(rm -rf *)", "Bash(git push --force)"]
  }
}

読み取り系は 無条件で許可、書き込み系は 毎回ユーザー確認、危険な Bash の特定パターンは 完全拒否。これは「道具がカテゴリで分かれている」からこそ書けるルールだ。もし全部 Bash で代替していたら、「cat は許可、rm は拒否、sed -i は確認」というような コマンド文字列ベースのルール を、無数のパターンマッチで維持しなければならない。

6.5 利点 (d) ── LLM にとって「選びやすい」

最後の利点が、実は実用上いちばん効いている。

LLM が道具を選ぶとき、カタログの中から名前を選ぶ という挙動をする(第2章)。 ツールの名前と説明が 役割を端的に表していると、選びやすい

比較してみよう。

Bash 一本

LLM の判断:

  • 「ファイル中身を見たい → Bash("cat foo.py")
  • 「ファイル一覧を見たい → Bash("ls -la")
  • 「検索したい → Bash("grep -r ...")」?それとも find
  • 「編集したい → Bash("sed -i ...")」OS によって挙動が違う

毎回コマンド文字列を組み立てる 必要があり、ミスやプラットフォーム差が混入する

専用ツール群

LLM の判断:

  • 「ファイル中身を見たい → Read
  • 「ファイル一覧 → Glob
  • 「検索 → Grep
  • 「編集 → Edit

道具名と用途が 1 対 1 で対応。LLM は名詞を選ぶだけ。プラットフォーム差はハーネス側が吸収

動詞 1 個に道具 1 個」の対応関係を保つことで、LLM は 判断ノイズを大きく減らせる。 これが、専用ツールを増やしてでも分業させる、いちばん実用的な理由だ。

6.6 図で掴む ── Bash 一本 vs 専用ツール群

ここまでの 4 つの利点をまとめて、対比図にしておく。

Bash 一本LLMBash tool任意のシェルコマンドcat / ls / grep / findsed / awk / rm / mvgit / pytest / curl …出力フォーマットが不安定副作用が事前に読めない権限ルールはコマンド文字列頼りLLM が毎回文字列を組むプラットフォーム差を踏む専用ツール群 (+ 逃げ道の Bash)LLMRead読取専用Grep / Glob読取専用Edit / Write書き込みBash逃げ道(汎用・要権限制御)出力が安定/副作用が明示ツール単位で許可・拒否LLM は名詞を選ぶだけ
図 6.1 — Bash 一本ですべて代替するか、役割ごとに専用ツールを分けて Bash は逃げ道に残すか。Claude Code は明確に後者を選んでいる。

6.7 Bash は「逃げ道」として残す ── そして Edit が部分編集できる理由

ここまで読むと「じゃあ Bash いらなくない?」と思うかもしれない。 ところが、Claude Code は Bash も律儀に持っている。理由は単純で、未知のことが起きるから だ。git rebase -ipnpm installpytest ...::test_barcurldocker compose up -d ── これらを全部「専用ツール化」していたら、ツール定義が無限に膨らむ

そこで設計判断はこうなる:

道具の種類設計
頻繁に使う & 副作用パターンが定型専用ツール化(Read, Edit, Write, Grep, Glob)
何が来るか分からない / 一回限りBash で汎用的に扱う(要権限制御)

専用ツールで 80% の典型作業を効率化 し、残り 20% は Bash の逃げ道で逃がす。これが Claude Code のツール構成の基本思想だ。

ここでもう一つ、専用ツール側の利点を具体例で見ておく。Edit tool は「ファイル全体ではなく、指定文字列を別の文字列に置換」する道具だ。たとえば 500 行のファイルの 1 関数だけ直したいとき:

方法LLM が出力するトークン
Write で全書き換え500 行ぶん(数千 〜 1 万トークン)
Edit で部分置換変更前文字列 + 変更後文字列(数十 〜 数百トークン)

1〜2 桁少ない出力で済む。出力トークンは入力トークンより単価が高いことが多く、これは実コストにも体感速度にも効く。さらに副次効果として、LLM が大規模な書き換えを写経して打ち間違える という事故も減る。Bash で sed -i を呼ぶより、Edit が LLM がやりたいことを最短距離でやれる粒度 で切られているのが効いている。

6.8 Grep が速い理由 ── ripgrep の採用

Claude Code の Grep tool は、内部的に ripgrep を使っている。

ripgrep (rg)

Rust 製の高速な grep。.gitignore を尊重しつつ並列で走り、大規模リポをサブセコンドで走査できる。

Bash("grep -r ...") ではなく Grep(...) を独立した道具にしたことで、ハーネスは中身を ripgrep に置き換え、LLM 側のコードを 1 行も変えずに高速化 できた。

専用ツールは「今日の利便性」だけでなく「将来の最適化余地」も生む。 ツールが抽象化されていれば、中身の実装をいくらでも差し替えられる。

6.9 ツール設計の角度から、第1章の主張を確認する

ここまで見てきたとおり、ツールセットの設計は次の 4 つを同時に決める。

前章で system prompt の角度から確認した「Claude Code らしさはハーネス側に宿る」という第1章の主張は、ツール設計の角度から見ると最も実装に近い形 で現れる。条文 (system prompt) だけでなく、LLM が手にできる動詞の切り方 がそのままエージェントの賢さになる。LLM は同じでも、道具セットの切り方一つで、別物のエージェントになる

そして本書の残りは、この「ツール設計の哲学」が どこまで広がるか を追いかける旅でもある。

後章ツール周りの何を扱うか
第10章 permissionsツール単位の 許可・拒否 をどう書くか
第11章 hooksツール呼び出しの 前後にフック を挟む仕組み
第12章 MCPツールを 外部から拡張 する標準プロトコル
第Ⅱ部 各グループ個々のコマンド (/agents /mcp /hooks) で実際に手を動かす

ツールという概念は、Claude Code の中で 最も拡張ポイントが多い 領域。本章で握った「なぜ分業させているか」の感覚が、これら全部の章で効いてくる。

私はエージェントを評価するとき、まず ツールセットの一覧 を見る。 ここに用意された動詞の解像度を見るだけで、そのエージェントが どこまで考えてくれるか がだいたい分かる。

Bash 一本しか持っていないエージェントは、便利だが「何でも自分でやれ」と言われている感じがする。 Read / Edit / Grep / Glob まで揃ったエージェントは、「よく使う動詞は私が引き受けます」と差し出してくれる感じがする。

この設計の優しさが、毎日の作業の疲労度を大きく変える。

6.10 この章の振り返り

この章で読めるようになるツイート / ブログ

ここで 構造編 (第4-6章)は終わりだ。 context window、system prompt、ツール設計 ── エージェントの “机・憲法・道具” を見渡した。

次章からは 制御編 に入る。 ループを御す仕組み ── 計画、長期記憶、サブエージェント、権限、hooks ── を順に解いていく。