汎用エージェントを構築している現場で、最も多く繰り返されるアドバイスは何か。Claude Codeチーム所属のThariq氏が2025年10月27日にXで投稿したスレッド「Why even non-coding agents need bash」は、29万インプレッションを集めた。彼が過去数週間で30社近くと話した結論はシンプルだった。use the bash tool more——専用ツールを並べる前に、まずbashツールの活用度を上げよ、というものだ。
本記事ではThariq氏のスレッドを起点に、bashが「ユニバーサルアダプター」として機能する理由、メールエージェントの具体例、ツール過多が引き起こすcontext rot、そしてallowed-tools制約による安全な実装パターンまでを順に解説する。コーディングを目的としないエージェント——たとえばメール処理、データ集計、社内オペレーション補助——を作る人ほど、このメッセージは重い。
Claude Code全体の使い方は Claude Code完全ガイド2026:インストールから本番運用まで をご覧ください。
01 Thariqが30社のヒアリングで出した結論
Thariq氏はAnthropicでClaude Codeの設計に関わるエンジニアであり、外部の企業がエージェントを設計する際の相談を頻繁に受けている。彼自身がXで述べているのは、ここ数週間だけで「数十回(dozens of calls)」を汎用エージェントを構築する企業と行ったという事実だ。そのうえで、ほぼ全ての会話で同じことを助言している——bashツールの利用を増やせ、と。
このメッセージの裏にあるのは、現場で観測される共通の失敗パターンである。多くのチームは、エージェントに新しい機能を持たせたいときにまず「専用のtool」を実装する方向に進む。メール検索ならsearch_email、メール送信ならsend_email、添付処理ならextract_attachment、というように、ユースケースが増えるたびに専用ツールが追加されていく。結果としてエージェントが扱うツール数は10、20、30と肥大化し、Claudeはどのツールを呼ぶべきかの判断にコンテキストを浪費し、しばしば誤ったツールを選ぶ。
Thariq氏はこの設計思想を逆転させる。bashツール1個で済むことを、なぜ専用ツール10個に分解するのかと。bashはあらゆるCLIユーティリティ・スクリプト・パイプラインを呼び出せる「万能の口」であり、UNIX哲学的に組み合わせ自由度が高い。エージェントに必要なのは、grepやjqやcurlを「使えるようにする」ことであって、それぞれをラップした専用ツールではない場合が多い。
彼自身が運用しているメールエージェントを引き合いに出して、画像付きで具体例を示している。専用ツールを最低限に抑え、ほぼ全てのオペレーションをbash経由のCLIで完結させる構成だ。これは単なる設計者の趣味ではなく、運用してみると専用ツールを増やすほどエージェントの精度が落ちるという現実への対応である。
# Thariq氏が暗示するシンプルな構成イメージ
# 専用ツールは最小、bashで CLIユーティリティを叩く
$ notmuch search "from:[email protected] date:7d.." | head -20
$ notmuch show --format=json id:abc123 | jq '.[] | .body'
$ curl -sS -X POST "https://api.example.com/notify" \
-H "Content-Type: application/json" \
-d '{"text":"重要メール3件あり"}'
このスレッドは1万を超えるエンゲージメントを集め、エージェント設計者の界隈で大きな反響を呼んだ。後述するが、彼の主張は単なる「bashが便利」というレベルを超えて、ツール設計の優先順位そのものへの問題提起になっている。
Anthropicのエンジニアが30社近くと話した結論は「専用ツールを増やすより、まずbashツールの使い方を磨け」。専用ツール乱立はエージェントの精度低下を招くという現場知が背景にある。
02 なぜbashが「ユニバーサルアダプター」になるのか
bashが汎用エージェントの基盤として優れている理由は、単に「便利だから」ではない。ユニバーサルアダプター(universal adapter)として機能する構造的な強みがある。ここで言うユニバーサルアダプターとは、異なる規格・プロトコル・データ形式を1つの口で繋げる装置のことだ。
第一に、bashはあらゆるCLIツールへの統一インターフェースになる。grep・awk・sed・jq・curl・gitといった単機能ツールから、notmuch・mbsync・pandoc・ffmpegのような特化ツール、さらにはユーザーが書いたシェルスクリプトやPythonスクリプトまで、全て同じbash -c "..."のかたちで呼び出せる。エージェント側から見れば「bashという1つのインターフェース」を覚えれば、その下の無数のツールを使い分けられる。
第二に、パイプとリダイレクトによる組み合わせが自由だ。grep | sort | uniq -c | sort -nrのような連結は、エージェントが文脈に応じて動的に組み立てられる。専用ツールで同じ柔軟性を提供しようとすると、引数として「集計方法」「ソート順」「フィルタ条件」などをすべてパラメータ化する必要があり、ツールのスキーマが肥大化する。
第三に、bashは状態を持たない(あるいは持たせるかをユーザーが選べる)ため、エージェントが推論しやすい。専用ツールがセッション状態や接続プールを抱えると、Claude側で「今どんな状態か」を追跡する必要が生じる。bashの場合、コマンドは入力→出力の純粋な変換に近く、出力を見れば結果が分かる。
第四に、エコシステムの厚みが圧倒的だ。世界中のデータ処理・ファイル操作・ネットワーク・テキスト処理のツールはほぼすべてCLIを持つ。新しいユースケースが出てくるたびに、専用ツールを書かずとも「既存のCLIをbashで呼ぶ」だけで対応できる場面が多い。
この4点を踏まえると、汎用エージェントにおけるbashは、Webブラウザにおける<iframe>や<canvas>に近い役割を果たす。1つの汎用機構の上に、無数の特化機能を載せられる。Thariq氏が「use bash more」と繰り返すのは、この階層構造の頂点としての価値を見ているからだ。
Claude"] --> B["bashツール
1つのインターフェース"] B --> C["テキスト処理
grep awk sed"] B --> D["データ整形
jq xsv pandas-cli"] B --> E["ネットワーク
curl wget rsync"] B --> F["専用CLI
notmuch git ffmpeg"] B --> G["自作スクリプト
shell python"] C --> H["出力テキスト"] D --> H E --> H F --> H G --> H H --> A
bashが優れている理由は「便利」ではなく構造的なもの。統一インターフェース、パイプによる組み合わせ自由度、ステートレス性、CLIエコシステムの厚み——この4点が「ユニバーサルアダプター」を成立させる。
03 メールエージェント実例——notmuch/jq/curlだけで完結
Thariq氏がスレッドで添付した画像は、彼自身のメールエージェントの構成を示すものだった。詳細な内部実装は公開されていないが、彼の発言と一般的なLinux/macOSメール環境の慣習を踏まえると、以下のような設計が浮かび上がる。
「未読メールを要約して」"] --> B["Claude
(エージェント)"] B --> C["Bash Tool
(唯一のアダプター)"] C --> D["notmuch search
(メール検索)"] C --> E["jq
(JSON加工)"] C --> F["curl
(外部API)"] C --> G["awk / sed
(テキスト整形)"] D --> H["結果をClaudeへ"] E --> H F --> H G --> H H --> B B --> I["ユーザーへ要約返答"]
主役のCLIはnotmuchである。これはメールにタグを付けてSQL的に検索できるオープンソースのメールインデクサで、コマンドラインからnotmuch search "tag:inbox AND date:7d.."のように直感的にクエリを書ける。出力は--format=jsonでJSON化でき、jqと組み合わせて加工しやすい。受信側にはmbsyncやisyncを使ってIMAPから定期的にメールを取得する構成が多い。
メールエージェントが「先週上司から来たメールを3行に要約して」と頼まれたとき、典型的にはこんな処理になる。まずnotmuchでメールを検索し、jqで件名と本文を抽出し、それをClaude自身が要約する。この一連を専用のsearch_and_summarizeツールにする必要はない——bashで素直に書ける。
# 上司からの直近1週間のメールを件名と本文先頭で取得
notmuch search --output=messages \
"from:[email protected] date:7d.." \
| head -20 \
| while read msgid; do
notmuch show --format=json "$msgid" \
| jq -r '.[0][0][0] | "件名: \(.headers.Subject)\n本文: \(.body[0].content[:200])\n---"'
done
データ集計も同様だ。「未読メールの送信元別件数」を出したい場合、専用ツールではなくシェルワンライナーで十分対応できる。grepやsortやuniqの組み合わせは、Claudeが文脈に応じて動的に書き下ろせる類のものだ。
# 未読メールを送信元ドメイン別に集計
notmuch search --output=files tag:unread \
| xargs grep -h "^From:" \
| sed 's/.*@\([^>]*\)>.*/\1/' \
| sort | uniq -c | sort -nr | head -10
外部APIへの通知もcurlでそのまま叩ける。Slackに「重要メールが届いた」と知らせたいなら、Webhook URLにPOSTするだけだ。専用のslack_notifyツールは不要である。エージェントが状況を見て、curlコマンドを組み立てる。
# Slack Incoming Webhookに通知
curl -sS -X POST "https://hooks.slack.com/services/XXX/YYY/ZZZ" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg msg "重要メール3件あり" '{text: $msg}')"
この設計の肝は、「メール」という業務領域に対して特化ツールを1つも作っていない点だ。使っているのはbashと、汎用CLI(notmuch・jq・curl・grep・sort)だけ。それでも実用的なメールエージェントが組める。Thariq氏が「even non-coding agents need bash」と言うとき、彼が念頭に置いているのはまさにこういう構成である。
メール処理という非コーディング業務でも、notmuch・jq・curl・grepなどの汎用CLIをbash経由で呼ぶだけで実用的なエージェントが組める。専用「メールツール」を作る必要はほとんどない。
04 ツール過多が引き起こすcontext rot問題
なぜ専用ツールを乱立させるのが悪いのか。Thariq氏は明示していないが、Anthropicが他の文脈で繰り返し語っているテーマがここに重なる——context rot(コンテキスト腐敗)である。
ツールが増えるほど、Claudeが各ツールの説明(description)を読み込み、そのうえで「今この状況でどれを呼ぶべきか」を判断するコストが増える。30個のツールがあるエージェントでは、各ツールのdescriptionだけで数千トークンを消費し、しかも判断の選択肢が30通りに広がる。これは人間が30個並んだボタンの中から正しいものを押すのに似ている——ボタンが3個ならまず間違わないが、30個では誤押しが急増する。
加えて、ツール名と機能の対応はモデルの推論能力に依存する。search_recent_emails_from_senderとfetch_emails_by_addressは人間には微妙に違うが、Claudeがどちらを選ぶかは状況依存になる。テストでは正しく動いていても、本番では別のツールを呼んでしまう、という不安定さが生まれる。
bashツール1つに集約すると、この問題はかなり緩和される。Claudeはまず「bashで何をするか」を考え、次に具体的なコマンドを組み立てる。判断の自由度が高い代わりに、選ぶべきツールという離散選択が消える。コマンドを書くのはClaudeにとって得意領域なので、ここの誤りは比較的少ない。
さらに、bashコマンドはエラー時のフィードバックが豊富だ。grep: no matchのようなメッセージから、Claudeは「条件を緩めて再試行する」「別のフィルタを試す」といった次手を即座に判断できる。専用ツールが返す{"error": "NO_RESULT"}のような構造化エラーよりも、自然言語に近いstderrのほうがLLMには扱いやすいことも多い。
| 観点 | bash中心設計 | 専用ツール乱立 |
|---|---|---|
| ツール数 | 1〜数個 | 10〜50個以上 |
| descriptionトークン | 少ない(数百) | 多い(数千) |
| 選択判断の難度 | 低い(離散選択なし) | 高い(似た名前で混乱) |
| 機能拡張のコスト | 低い(CLI追加だけ) | 高い(毎回ツール実装) |
| エラー情報 | 自然言語のstderr | 構造化エラーコード |
| 状態管理 | ほぼステートレス | ツール側に状態が残りやすい |
| 安全制御 | allowed-toolsで包括制限 | 各ツールに個別ガード |
| 学習コスト | bashの知識が必要 | ツール固有の使い方を覚える |
この比較表が示すのは、ツール数を絞ることそれ自体がエージェントの精度を上げるという事実だ。多機能であることと使いやすいことは別であり、エージェント設計においては後者が圧倒的に重要になる。
ツール数の増加はdescriptionトークンの肥大と選択判断の不安定化を招く。bashへの集約は離散選択を減らし、stderr経由の自然言語フィードバックでリトライ判断もしやすくなる。
05 bash向きの作業 vs 専用ツール向きの作業
Thariq氏の主張は「全部bashにしろ」ではない。スレッドの含意を素直に読むと、「迷ったらまずbashで試せ、それで足りないものだけ専用ツールにせよ」という優先順位の話になる。具体的な切り分けは以下のとおりだ。
bashが向く場面を列挙すると、まずデータ整形・集計が筆頭に来る。CSVの列抽出、JSONの変形、ログの統計、テキストのフィルタリング。これらはjq・xsv・awk・sortといった枯れたCLIで完結し、エージェントが状況に応じてワンライナーを組み立てやすい。次にファイル操作——コピー・移動・差分・圧縮はcp/mv/diff/tarで足りる。
外部APIへのアクセスもcurlで十分なケースが多い。GETやPOSTで結果を取得して、jqでフィールドを抜き出すパターンは大半のWeb APIに当てはまる。OAuthのような複雑な認証フローを伴わない限り、専用クライアントは過剰装備になる。
ローカルのCLIエコシステム連携もbash向きだ。Gitの操作、Dockerのコンテナ管理、データベースクライアント(psql・mysql・sqlite3)、メディア処理(ffmpeg・imagemagick)など、CLIネイティブな世界はそのまま叩いたほうが早い。
一方、専用ツールが向く場面もある。第一に、状態を持つUI操作だ。ブラウザのDOMを操作する、Slackのメッセージスレッドを追跡する、といった作業はステートフルなセッションが必要で、bashで毎回起動するより専用ツール(Playwright MCPなど)のほうが効率的だ。
第二に、安全制御が厳格に必要な操作。たとえばデータベースの本番環境への書き込み、決済APIの呼び出し、ファイルの永続削除といったものは、bashにそのまま投げるより、ホワイトリスト化された専用ツールでガードレールを敷くべきだ。
第三に、ベンダーが提供する公式SDKを使ったほうが圧倒的に便利な領域。たとえばAWSのS3操作はaws-cliで十分だが、複雑なIAM操作はboto3経由のスクリプトのほうが安全で読みやすい。
| 領域 | 推奨アプローチ | 理由 |
|---|---|---|
| データ整形・集計 | bash + jq/awk/sort | ワンライナーで完結、組み合わせ自由 |
| ファイル操作 | bash + cp/mv/diff/tar | CLIが枯れていて安定 |
| 外部API(単純) | bash + curl + jq | OAuth不要なら最短経路 |
| ローカルCLI連携 | bash経由で直接 | エコシステムの厚みを活用 |
| ブラウザ自動化 | 専用ツール(Playwright MCP等) | ステートフル、DOM操作 |
| 本番DB書き込み | 専用ツール + 認可 | 危険操作のガードが必須 |
| 決済・送金 | 専用ツール + 二段確認 | 取り返しがつかない |
| 公式SDKがある複雑操作 | 専用ツール(SDKラップ) | 認証・リトライがSDK側 |
この切り分けに従うと、多くの「非コーディングエージェント」は8割がbash、2割が専用ツールという構成に落ち着く。そして残りの2割を後から増やすほうが、最初から30個のツールを並べるより遥かに健全だ。
データ整形・ファイル操作・単純なAPI・ローカルCLI連携はbashで十分。状態を持つUI、危険な副作用を伴う操作、複雑な公式SDK連携は専用ツール。「迷ったらbashから」が原則。
06 allowed-toolsで安全制約をかける実装パターン
「bashを増やせ」と言うと反射的に出る懸念は「危険なコマンドを実行されたらどうする」である。Anthropic公式のClaude Codeドキュメントは、この懸念に対してallowed-toolsという仕組みで答えている。bashツールを呼び出せる範囲を、コマンド単位で制限できる仕組みだ。
Claude Codeの設定では、bashツールに対して許可するコマンドパターンを列挙できる。たとえばBash(notmuch *)と書けば、notmuchで始まるコマンドだけが許可される。Bash(rm *)を書かなければ、Claudeはrmコマンドを実行できない。これにより、bashの汎用性を活かしつつ、危険な操作だけを排除できる。
メールエージェントなら、許可するコマンドはたとえば以下のような構成になる。読み取り系のCLIを広めに許可し、書き込み系(特に削除・送信)は明示的に絞る。
# .claude/settings.json (一例)
{
"permissions": {
"allow": [
"Bash(notmuch search:*)",
"Bash(notmuch show:*)",
"Bash(notmuch tag:*)",
"Bash(jq:*)",
"Bash(curl -sS https://hooks.slack.com/*)",
"Bash(grep:*)",
"Bash(awk:*)",
"Bash(sort:*)",
"Bash(uniq:*)",
"Bash(head:*)",
"Bash(tail:*)",
"Bash(wc:*)"
],
"deny": [
"Bash(rm:*)",
"Bash(mv ~/Mail:*)",
"Bash(notmuch new --remove:*)"
]
}
}
この構成では、Claudeは検索・整形・通知に必要なコマンドを自由に組み合わせて使える一方、ファイルの削除や移動はできない。bashの柔軟性を享受しつつ、最低限のガードレールを敷ける。
ただし、allowed-toolsは完璧な防御ではないことに注意したい。許可されたコマンドの組み合わせで予期せぬ副作用を起こせる場合がある(curl許可のみでも、外部スクリプトを引っ張ってきて実行する経路はゼロではない)。本番のエージェントでは、以下の追加ガードを併用するのが現実的だ。
- 危険操作(送信・削除・支払い)は専用ツール側で人間承認を挟む
- bashコマンドの実行ログを全て記録し、後から監査できるようにする
- ネットワークアクセスを必要最小限のホストに制限する(イグレスフィルタ)
- 実行ユーザーの権限を最小化する(root禁止、専用ユーザーで動かす)
それから、Hookを使ったpost-execチェックも有効だ。Claude CodeにはツールやBash実行の前後にカスタムスクリプトを差し込めるHook機構があり、たとえば「rmコマンドが実行されたら通知を飛ばす」「対象ディレクトリ外への書き込みを検出したらブロックする」といった動的な防御を組める。
#!/bin/bash
# .claude/hooks/post-bash.sh の例
# 実行されたコマンドをログに残し、危険パターンを検出
cmd="$1"
echo "$(date -Iseconds) | $cmd" >> ~/.claude/bash-audit.log
# 監視対象パターン
if echo "$cmd" | grep -qE "^(rm -rf|mv .* /tmp|curl .* \| sh)"; then
echo "[WARNING] 危険コマンド検出: $cmd" >&2
# 必要なら通知も飛ばす
fi
この構成なら、bashの柔軟性を取りながら、後から「いつ・何を・どんな結果で実行したか」を追跡できる。エージェントの行動を信頼するための土台になる。
bashを多用しても`allowed-tools`でコマンド単位に許可・拒否を設定でき、Hookで実行ログ・危険パターン検出を追加できる。柔軟性と安全性は両立可能。
07 Skillsとbashを組み合わせる実践構成
Anthropicが2025年に正式公開したClaude Skillsは、特定の作業手順をMarkdownで束ねてClaudeに渡せる仕組みだ。bashとの相性が極めて良い。Skillsで「何をすべきか」を、bashで「どうやるか」を分担させると、エージェントの設計が一気に整理される。
たとえば「毎朝のメール整理」というSkillを作るとしよう。Skillの中身は、bashコマンドのレシピ集として書ける。Claudeはこのレシピを見て、状況に応じてコマンドを組み立てる。SkillとbashとMCPの位置づけは、別記事のClaude Skillsを徹底解説で詳しく扱っているので併読してほしい。
---
name: email-morning-triage
description: 毎朝、未読メールを優先度別に分類して通知する手順
allowed-tools:
- Bash(notmuch *)
- Bash(jq *)
- Bash(curl -sS https://hooks.slack.com/*)
---
# 朝のメール仕分け手順
1. 未読メールを取得
```bash
notmuch search --output=messages tag:unread
```
2. 各メールの送信元と件名を抽出
```bash
notmuch show --format=json id:{msgid} | jq -r '.[0][0][0].headers | "\(.From) | \(.Subject)"'
```
3. 上司・顧客からのメールを抽出(高優先度)
- 上司ドメイン: example.com
- 顧客ドメイン: client-a.jp / client-b.co.jp
4. 高優先度メールが3件以上あればSlackに通知
```bash
curl -sS -X POST "$SLACK_WEBHOOK" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg c "$count" --arg list "$urgent_list" \
'{text: "高優先度メール\($c)件:\n\($list)"}')"
```
5. 処理済みのメールに `tag:triaged` を付与
```bash
notmuch tag +triaged tag:unread
```
この構成のポイントは3つある。第一に、Skill自身がallowed-toolsを宣言しているので、このSkillが起動された文脈ではbashの実行範囲が自動的に絞られる。第二に、bashコマンドを「テンプレート」としてSkillに書いておくことで、Claudeは毎回ゼロから考えずに済み、再現性が高まる。第三に、手順そのものはMarkdownなので、人間が読んで修正できる。
Agentハーネスの基礎で扱った「ツール・記憶・実行ループ」の3点セットの観点でも、bashは「ツール」という1点を最小コストで満たす存在だ。記憶(memory)と実行ループ(loop)はSkillsとフックで補強できるので、全体としてシンプルな構成が実現する。
Claude Code開発者Thariqが語るエージェント設計の全貌では、Thariq氏がエージェントの全体設計について語った別の発言群を扱っている。bashの位置づけを理解した上で、より広い設計思想を読むと一段深く理解できる。
最後に、実践への第一歩として推奨するアプローチをまとめておく。まず現在使っているエージェントが呼んでいるツールを棚卸しする。次に、それぞれが「bashで代替できないか」を問う。データ整形系・ファイル操作系・単純API呼び出し系のツールは、ほぼ間違いなくbashに統合できる。残った専用ツールは、ステートフルな操作・危険な副作用・複雑な認証フローを担うものだけになる。
この棚卸しをやると、多くのエージェントで「専用ツールの3割は不要だった」という気付きが出る。Thariq氏が30社と話して同じ助言を繰り返すのは、この気付きが普遍的だからだ。汎用エージェントを作るすべての人にとって、bashツールは最初に磨くべき基本武器である。
SkillsとbashとHookを組み合わせると、手順の宣言・実行の柔軟性・安全制御が綺麗に分離できる。まずは現在のエージェントのツール棚卸しから始め、bashで代替可能なものを統合していくのが実践への近道。