はじめに
下記の本をがとても分かりやすく、かつ実用的だったのでまとめてみました。実際には私が要点を書き出して、その要点をもとにclaudeが肉付けした文章になります。
『実践Claude Code入門 ― 現場で活用するためのAIコーディングの思考法』
西見公宏・吉田真吾・大嶋勇樹 著 / 技術評論社 / 2025年12月発売
本記事の対象は、"Claude Codeを使ってるけど、なんとなく使っている。公式ドキュメントはほとんど読んだことがない"ような方です。
1. コンテキスト工学の基本思想
1.1 段階的明示(Progressive Disclosure)
**「必要な時に必要なだけコンテキストを読み込ませる」**という設計原則。
LLMのコンテキストウィンドウは有限であり、最初から全情報を詰め込むと後述の「コンテキストロット」を招く。そのため Claude Code は以下のような階層構造でコンテキストを段階的に読み込ませる仕組みを持つ。
| 層 | 役割 | 読み込まれるタイミング |
|---|---|---|
CLAUDE.md(プロジェクト直下) |
プロジェクト全体の前提・規約 | セッション開始時に常時 |
CLAUDE.md(サブディレクトリ) |
サブモジュールの規約 | そのディレクトリのファイルに触れた時 |
Skill(SKILL.md) |
「どのように」やるかの手順書 | LLM が必要と判断した時に自動ロード |
| Subagent | 専門的な役割を持つ別エージェント | 明示的に呼び出された時 |
| ファイル本体 | 実装の詳細 |
Read ツールで参照した時 |
補足: この思想は Anthropic の公式ドキュメントでも "Progressive Disclosure" として説明されており、Skill の
SKILL.md自体には概要だけ書き、詳細は別ファイルに分けて必要時に参照させるのがベストプラクティスとされる。
サンプル: 段階的明示を意識した CLAUDE.md
サンプル: 段階的明示を意識した CLAUDE.md(クリックで展開)
# プロジェクト概要
ECサイトのバックエンドAPI。Python 3.12 + FastAPI + PostgreSQL。
## 重要な規約(常時参照)
- 関数には必ず型ヒントをつける
- DB操作は `app/repositories/` 経由で行う(直接 SQLAlchemy を呼ばない)
## 詳細は必要時に参照
- アーキテクチャ全体図: `docs/architecture.md`
- DBスキーマ詳細: `docs/db-schema.md`
- APIエンドポイント仕様: `docs/api-spec.md`
docs/ 以下は最初から読ませず、必要になったタイミングで Claude が自発的に読みに行く設計。
1.2 コンテキストロット(Context Rot)
コンテキストが逼迫すると LLM 自体の性能が劣化する事象。
長い会話履歴や大量のファイル読み込みでコンテキストウィンドウが埋まると、以下のような問題が顕在化する。
- 指示の取りこぼし(前半の重要な制約を忘れる)
- 推論の質低下(複雑な判断ができなくなる)
- ハルシネーション増加
- 古い文脈と新しい文脈の混線
補足: 一般に「Lost in the Middle」現象としても知られ、コンテキスト中盤の情報ほど無視されやすい。Anthropic Research でも長いコンテキストでの精度低下は確認されている。
対策の基本方針
-
/clearでこまめに会話履歴をリセットする(タスクが切り替わるタイミングで) - Subagent を活用してコンテキストを分離する
- 不要なファイル読み込みを避ける(grep で当たりをつけてから Read する等)
- 長大なログや出力は要約させてから次のターンへ渡す
2. サブエージェント(Subagent)戦略
2.1 なぜサブエージェントか
メインエージェントのコンテキストを汚さないために、専門的・大量のコンテキストを必要とするタスクは別エージェントに分離する。
サブエージェントは独立したコンテキストウィンドウを持ち、タスク完了後は結果(要約)だけがメインに返る。つまり「メインから見れば1回のツール呼び出しに見える」ため、コンテキスト効率が劇的に良くなる。
2.2 特にレビューはサブエージェントに分けるべき
レビューは以下の理由でコンテキストを激しく消費する:
- 複数ファイルの全文読み込みが必要
- diff の前後を理解するため広い範囲を見る
- 静的解析・テストの出力など外部ツール結果が大量に流れ込む
これをメインのコーディングエージェントに直接やらせると、レビュー後の修正フェーズで**「さっきレビューしたコードの詳細」がコンテキストから押し出される**問題が発生する。
サンプル: レビュー専用サブエージェント定義(.claude/agents/reviewer.md)
サンプル: レビュー専用サブエージェント定義 .claude/agents/reviewer.md(クリックで展開)
---
name: reviewer
description: コード変更のレビュー専用。差分とテスト結果を読み、指摘事項のリストだけを返す。
tools: Read, Grep, Glob, Bash
---
あなたはシニアエンジニア視点のコードレビュアーです。
## 役割
- 指定された差分(または変更ファイル)をレビューする
- 関連するテストコードも確認する
- 出力は **指摘事項の箇条書きのみ** に絞る(コードの再掲はしない)
## レビュー観点
1. ロジックの正しさ
2. エッジケース漏れ
3. プロジェクトの規約(CLAUDE.md 準拠)
4. テストカバレッジ
## 出力フォーマット
- 🔴 Critical: ...
- 🟡 Warning: ...
- 🟢 Suggestion: ...
これにより、メインエージェントには「レビュー指摘リスト」という圧縮された情報だけが戻り、コンテキストが温存される。
3. Skill とコマンドの使い分け
3.1 大前提: 「明示されていないこと = 任意」と扱われる
Skill やコマンド、CLAUDE.md を書くときに最も重要な原則を先に述べる。
LLM は「明示されていないこと」を基本的に任意として解釈する。
つまり:
- 「可能なら テストも書いてください」 → 書かれない可能性が高い
- 「できれば ロールバック手順も用意」 → 用意されない可能性が高い
- 「余裕があれば ドキュメントも更新」 → 99% 更新されない
- 「〜することもできます」 → ほぼ採用されない
これは Claude が手を抜いているわけではなく、「任意 = やらなくてよい」と解釈してコンテキストを節約しようとする合理的な挙動である。後述のコンテキストロットを避けるためにも、LLMはオプションをスキップする傾向がある。
必須にしたい操作は必ず断定形で書く
| ❌ 任意として扱われる書き方 | ✅ 必須として扱われる書き方 |
|---|---|
| 可能であればテストを追加する | テストを 必ず 追加する |
| 余裕があればドキュメントを更新 | ドキュメントを更新する(更新しない場合は理由を報告) |
| ロールバック手順も書けると良い | ロールバック手順を書く |
| 〜することもできる | 〜する / 〜してはならない |
| なるべく型ヒントを付ける | 全ての関数引数・戻り値に型ヒントを付ける |
「任意」を意図的に使う場面もある
逆に、本当に任意で良い場合は明示的に「任意」と書くこと。書かないと「これは必須?任意?」とエージェントが推測することになり、結果がブレる。
(任意) パフォーマンス計測のログを追加してもよい。追加する場合は `metrics.timer()` を使う。
この原則を踏まえて、以下のサンプルはすべて**「必須/任意/禁止」を明示**したスタイルで書く。
3.2 もう一つの重要原則: 「ルールの優先順位を明示する」
3.1 と並んで重要なのが、ルールが衝突したときの優先順位を明示しておくこと。
実プロジェクトのドキュメント・Skill・CLAUDE.md は、書き足されていくうちに必ず矛盾やトレードオフが発生する。
- 「テストを必ず書く」と書いてあるが、「最小差分で修正する」とも書いてある → 大量のテスト追加は最小差分か?
- 「型ヒントを必ず付ける」と書いてあるが、「サードパーティ製ライブラリの型が壊れている時はどうする?」
- 「セキュリティ最優先」「パフォーマンス最優先」が両方書いてある → どちらが上?
これを明示しておかないと、Claude は毎回その場で推測することになり、結果が安定しない。さらに悪いことに、コンテキストの状態によって判断が変わるため、同じ指示でも昨日と今日で違う結果になるという再現性のなさにつながる。
優先順位の書き方パターン
パターン1: 番号付きで全体順位を決める
## 設計方針の優先順位(上が優先)
1. セキュリティ
2. データ整合性
3. 可読性・保守性
4. パフォーマンス
5. コードの簡潔さ
複数の方針が衝突した場合は、必ず上位を優先する。
これで「パフォーマンスのために型チェックを省略していい?」と聞かれた時、Claude は「順位3 > 順位4 なので NG」と判定できる。
パターン2: 個別ルール同士の優先関係を明示
## 衝突時のルール
- 「テスト必須」と「最小差分」が衝突した場合: **テスト必須が優先**
- つまり、テストを書くためにコード変更量が増えるのは許容する
- 「型ヒント必須」と「外部ライブラリの型不整合」が衝突した場合: **型ヒント必須が優先**
- 外部ライブラリは `# type: ignore[コメント]` を付けて理由を明記する
- 「DRY原則」と「可読性」が衝突した場合: **可読性が優先**
- 重複を消すために抽象化レベルを上げるのは禁止
パターン3: 「迷ったら聞く」を最終手段として宣言
## 判断に迷った場合の最終ルール
上記の優先順位でも判断できない場合は、**勝手に決めずユーザーに確認する**。
特に以下のケースは必ず確認:
- 既存の公開APIの破壊的変更
- セキュリティとUXのトレードオフ
- 1コミットで100行を超える変更
これは「優先順位を全部書き切るのは無理」という現実への対処。「明示されていないケース=聞く」を明示しておくのがミソ。
CLAUDE.md レベルでの優先順位明示の例
# プロジェクト規約
## 規約の優先順位(衝突時は上を優先)
1. **セキュリティルール**(`docs/security.md`)
2. **データベース規約**(`docs/db-rules.md`)
3. **コーディング規約**(このファイル下部)
4. **スタイルガイド**(lintルール)
## 個別の衝突時ルール
- パフォーマンス改善のためにセキュリティルールを緩めることは禁止
- スタイルガイドと可読性が衝突した場合は、コメントで理由を残して可読性優先
- 既存コードのリファクタリング欲求は常に「最小差分」原則に劣後する
優先順位を書かないとどうなるか(実例)
| 状況 | 優先順位なし | 優先順位あり |
|---|---|---|
| 「テスト必須」と「最小差分」 | テストを省略して最小差分にしたり、逆だったり、毎回ブレる | 必ずテストを書く、と一意に決まる |
| 「セキュリティ」と「UX」 | その時の文脈で判断が変わる | 常にセキュリティが優先される |
| 「DRY」と「可読性」 | LLMが抽象化を盛りがち | 可読性優先で過剰抽象化を防げる |
優先順位明示のチェックリスト
- 大方針(セキュリティ/整合性/可読性/性能 等)の順位を書いたか
- 過去にプロジェクトで実際に衝突した個別ルール同士の関係を書いたか
- 「迷ったらユーザーに確認」のラインを書いたか
- Skill 内のルール同士が衝突しうる場合、Skill 内でも優先順位を書いたか
3.3 Skill とコマンドの違い(一覧)
| Skill | コマンド | |
|---|---|---|
| 書く内容 | "How"(どのように考える/作るか) | "What & Order"(何をどの順で実行するか) |
| 呼び出し方 | LLMが文脈から自動判断して呼ぶ | ユーザーが /コマンド名 で明示的に呼ぶ |
| 再利用単位 | 知識・ノウハウ・規約 | 手順・ワークフロー |
| 配置場所 | .claude/skills/<name>/SKILL.md |
.claude/commands/<name>.md |
| 発火タイミング | 関連する作業をしている時、いつでも | コマンドを打った時、その時だけ |
| 引数 | なし(文脈から判断) | あり($ARGUMENTS で受け取れる) |
この違いを、同じ「バグ修正」というシチュエーションで対比してみる。
3.4 同一題材で比較する: 「バグ修正」をやる場合
🅰️ Skill で書く場合(バグ修正の "考え方" を常備させる)
「ユーザーから不具合報告を受けた時、どう考えてどう動くか」というノウハウ。いつ呼ばれるかは Claude が文脈から判断する。
ファイル: .claude/skills/bug-fixing/SKILL.md
サンプル: bug-fixing Skill の中身(クリックで展開)
---
name: bug-fixing
description: バグ修正に取り組むときの考え方。「バグがある」「動かない」「エラーが出る」「不具合」「直して」といった要求があったら使う。再現→特定→修正→再発防止の順で進める方針を提供する。
---
# バグ修正スキル
## 必須ルール(守らないと不可)
- **再現テストを書く前に修正コードを書いてはならない**
- **推測でコードを変更してはならない**(再現できたものだけ直す)
- **修正は最小差分で行う**(ついでのリファクタリングは禁止、別PRで対応)
## 推奨ルール
- スタックトレースは上から順に読む(中段から推測しない)
- `git log -p -- <該当ファイル>` で直近の変更履歴を確認する
## 任意ルール
- (任意) 修正後、同種のバグが他箇所にないか `git grep` で確認する
- (任意) 根本原因が設計レベルの問題なら ADR を起票する
## ルール衝突時の優先順位
- 「再現テスト必須」と「最小差分」が衝突 → **再現テスト必須が優先**
- テストのために修正と無関係なファイルが増えるのは許容する
- 「最小差分」と「規約準拠」(lintルール等)が衝突 → **規約準拠が優先**
- 上記で判断できない場合は **ユーザーに確認**(勝手に決めない)
## 進め方(この順序を守る)
### Step 1: 再現
- 報告された手順を試して再現する
- 再現しない場合は、環境・データ条件を**必ずユーザーに確認する**(推測で進めない)
### Step 2: 失敗するテストを書く
- 再現条件をテストコードに落とす
- このテストが **失敗すること** を必ず確認してから次へ進む
### Step 3: 原因特定と修正
- 最小差分で修正
- Step 2 のテストがパスすることを必ず確認
### Step 4: 完了報告
- 修正内容・追加したテスト・影響範囲をユーザーに報告する
## サンプル: 良いバグ修正PRの差分
```diff
+ # tests/test_user.py
+ def test_create_user_with_empty_email_raises_error():
+ with pytest.raises(ValidationError):
+ create_user(email="")
+
# app/user.py
def create_user(email: str):
+ if not email:
+ raise ValidationError("email is required")
...
やってはいけない例(禁止)
- ❌ テストを書かずに修正する
- ❌ try-except でエラーを握りつぶす
- ❌ 同じファイルの別箇所まで一緒にリファクタする
</details>
**ここがポイント**: ユーザーが「ログインできないんだけど」と言うだけで、Claude が `description` を見て「これはバグ修正案件だな」と判断し、このSkillを自動で読み込む。**ユーザーは Skill の存在を意識する必要がない**。
また、**「必須/推奨/任意/禁止」を明示的に分けて書いている**ことに注目。これにより、Claude は「ADR起票はやらなくていい、でも再現テストは絶対やる」と確実に判定できる。
---
#### 🅱️ コマンドで書く場合(バグ報告対応の "決まった手順" を実行する)
「Issueが上がってきたら、必ずこの順番で動く」という固定ワークフロー。**ユーザーが明示的に叩く**。
ファイル: `.claude/commands/fix-bug.md`
<details>
<summary>サンプル: /fix-bug コマンドの中身(クリックで展開)</summary>
```markdown
---
description: 指定された Issue 番号のバグを修正する標準フロー
---
引数: $ARGUMENTS(Issue番号、例: 1234)
以下を **この順序で必ず** 実行してください。途中で失敗した場合は停止して報告すること。
**スキップは禁止です。** やらない場合は明示的に理由を述べてください。
## Step 1: Issue の取得(必須)
```bash
gh issue view $ARGUMENTS --json title,body,labels
Step 2: ブランチ作成(必須)
git checkout main
git pull
git checkout -b fix/issue-$ARGUMENTS
Step 3: 再現テストの追加(必須)
-
bug-fixingスキルの方針に従って、まず失敗するテストを書く - 追加先:
tests/配下の該当箇所 - テストが 失敗すること を必ず確認:
npm test -- --testNamePattern="issue.*$ARGUMENTS" - 失敗が確認できない場合は Step 4 に進まず停止する
Step 4: 修正実装(必須)
- 最小差分で修正
- Step 3 のテストがパスすることを必ず確認
Step 5: 関連箇所の確認(必須)
git grep -n "<該当の関数名やパターン>"
類似パターンが見つかった場合は、ユーザーに報告して指示を仰ぐ(勝手に直さない)。
Step 6: コミット(必須)
git add .
git commit -m "fix: <Issue タイトル> (#$ARGUMENTS)"
Step 7: PR作成(必須)
gh pr create --title "fix: ..." --body "Closes #$ARGUMENTS"
Step 8: 完了報告(必須)
- PR の URL を報告
- 追加したテスト名を報告
- Step 5 で見つかった類似箇所があれば併記
任意ステップ
- (任意) 修正がパフォーマンスに影響しうる場合、ベンチマーク結果を PR 本文に添付してよい
</details>
**ここがポイント**: `/fix-bug 1234` と叩くと、**毎回同じ8ステップが同じ順序で**走る。Step 3 の中で `bug-fixing` Skill が自動的に参照される(Claude が判断して呼ぶ)。
すべてのステップに**「必須」と明記**し、スキップ可能な作業だけを「任意ステップ」に分離している。これで「PR作成は今回はやらなくていいかな」とエージェントが勝手に判断する事故を防げる。
---
### 3.5 両者の関係: 「コマンドが手順、Skillが各ステップの考え方」
上の例で重要なのは、**コマンドとSkillは競合せず、レイヤーが違う**ということ:
ユーザー: /fix-bug 1234
↓
コマンド (fix-bug.md) — 8ステップの順序を決める
↓
Step 3 で「再現テストを書く」 → Claudeが文脈判断
↓
Skill (bug-fixing) が自動ロード — "テストを先に書く" "最小差分" などの考え方を提供
↓
実際のコード修正
つまり、
- **コマンド** = レシピの「作業手順」部分(湯を沸かす→麺を入れる→3分待つ)
- **Skill** = レシピの「コツ・原則」部分(茹で汁は捨てない、塩を入れる量、火加減)
両方あって初めて、再現性のある美味しい料理(=意図通りの実装)ができる。
---
### 3.6 もう一つの対比例: 「DBマイグレーション」
別題材でも同じ構造が見えることを確認する。
| | Skill: `db-migration` | コマンド: `/add-migration` |
|---|---|---|
| **内容** | 「マイグレーションを書く時の方針」(破壊的変更は2段階で、ロールバック必須、大規模テーブルは要相談、etc.) | 「マイグレーションファイルを作って、ローカルDBで試して、テストが通ることを確認するまでの一連の手順」 |
| **発火** | "DBにカラム追加して" と言われたら自動で参照される | `/add-migration add_email_to_users` と明示的に叩く |
| **何度も呼ばれる?** | プロジェクト中ずっと「DB変更時の規約」として効き続ける | コマンドを叩いた時だけ |
#### 🅰️ Skill 抜粋("How" だけ書く・必須と任意を明示)
<details>
<summary>サンプル: db-migration Skill の抜粋(クリックで展開)</summary>
```markdown
---
name: db-migration
description: DBスキーマ変更時の方針。"カラム追加"、"テーブル作成"、"マイグレーション"、"スキーマ変更" の話が出たら使う。
---
# DBマイグレーション スキル
## 必須ルール
- 破壊的変更は **必ず2段階デプロイ**にする(追加 → アプリ切替 → 削除)
- **ロールバック手順を必ず書く**(downgrade関数を空にしてはならない)
- NOT NULL カラムを追加する場合は **必ず DEFAULT を設定する**
## 推奨ルール
- インデックス作成は CONCURRENTLY を使う(テーブルロックを避けるため)
## 確認が必要なケース(勝手に進めず必ずユーザーに確認)
- 100万行を超えるテーブルへの ALTER
- カラム削除・テーブル削除
- 一意制約の追加(既存データに違反がある可能性)
## 任意
- (任意) マイグレーションのパフォーマンス計測ログを残してよい
🅱️ コマンド抜粋("What & Order" だけ書く)
サンプル: /add-migration コマンドの抜粋(クリックで展開)
---
description: 新しいマイグレーションファイルを作成し、検証する
---
引数: $ARGUMENTS(マイグレーション名、snake_case)
以下を **この順序で必ず** 実行する。スキップ禁止。
1. (必須)`alembic revision -m "$ARGUMENTS"` でファイル生成
2. (必須)`db-migration` スキルの方針に従って upgrade/downgrade を実装
3. (必須)`alembic upgrade head` でローカル適用
4. (必須)`alembic downgrade -1` でロールバック検証
5. (必須)`alembic upgrade head` で再適用
6. (必須)`pytest tests/db/` でDBテスト実行
全ステップ成功したら完了報告。途中失敗時は停止して報告。
コマンド側は手順だけ書き、各手順の中身(特に2.の「どう書くか」)はSkillに丸投げしている。これが理想的な分業。
3.7 判断基準まとめ
「Skillにすべきか、コマンドにすべきか」迷ったら、次の質問を順に:
- 「ユーザーが明示的に呼びたいか?」 → Yes ならコマンド
- 「同じ手順を毎回踏むか?」 → Yes ならコマンド
- 「引数を取りたいか?」 → Yes ならコマンド
- 「複数の異なる文脈で(何度も)参照されるノウハウか?」 → Yes ならSkill
- 「"考え方" や "規約" を伝えたいか?」 → Yes ならSkill
- 「テンプレート/サンプルと一緒に渡したい知識か?」 → Yes ならSkill
両方該当することも多い。その場合は両方作って連携させるのが正解(前述のバグ修正例のように)。
そして両方とも、「必須/推奨/任意/禁止」を明示的に書くことを忘れない。書かなければ、Claude は「任意」として扱う。
3.8 Skill/コマンドのドキュメントには必ずサンプルを書く
本書のメモにもある通り、サンプルを書いておくことで以下のメリットがある。
- コンテキストの逼迫を防ぐ — エージェントが「どう書けばいいか」を別途調べに行く必要がなくなる
- 意図した実装になる確率が上がる — Few-shot learning的に、サンプル形式に沿った出力が出やすくなる
- 新しいメンバー(人間)にとっても読みやすい
サンプルは「規約に従った正しい例」と「やってはいけない例」を両方書くと、より意図通りになりやすい(断定形で書いていても、悪い例を明示するとさらに精度が上がる)。
Bad / Good 例
Bad(曖昧で、必須・任意・禁止が不明):
---
name: write-test
description: テストを書く
---
ユニットテストをなるべく書いてください。可能ならエッジケースも追加。
問題点:
-
descriptionが短すぎてトリガーされない可能性が高い - 「なるべく」「可能なら」が任意として解釈され、書かれない or 雑になる
- 規約・サンプルがないので、出力フォーマットが毎回ブレる
Good(明示的・サンプル付き):
サンプル: write-test Skill の中身(クリックで展開)
---
name: write-test
description: pytest を使ったユニットテストを書く。「テスト追加して」「テスト書いて」「ユニットテスト」と言われたら使う。
---
# ユニットテスト作成スキル
## 必須ルール
- ファイル配置: `tests/unit/test_<対象モジュール>.py`
- 関数命名: `test_<対象関数>_<シナリオ>_<期待結果>`
- AAA パターン(Arrange-Act-Assert)で書く
- 正常系・異常系・境界値の3種類を**最低1つずつ**含める
## 禁止
- 1つのテスト関数に複数のシナリオを詰め込む
- `assert True` のような中身のないアサーション
- 外部APIを実際に呼ぶ(必ずモックを使う)
## 任意
- (任意) パラメタライズが有効な場合は `@pytest.mark.parametrize` を使ってよい
## 正しいサンプル
```python
# tests/unit/test_calculator.py
import pytest
from app.calculator import divide
def test_divide_normal_returns_quotient():
# Arrange
a, b = 10, 2
# Act
result = divide(a, b)
# Assert
assert result == 5
def test_divide_by_zero_raises_value_error():
with pytest.raises(ValueError, match="cannot divide by zero"):
divide(10, 0)
悪いサンプル(このように書いてはならない)
# ❌ 1つの関数に複数シナリオを詰め込んでいる
def test_divide():
assert divide(10, 2) == 5
assert divide(10, 0) # 例外を期待してるはずなのにアサートがない
# ❌ 関数名から何をテストしているか分からない
def test_1():
...
</details>
---
## 4. 権限承認が煩雑な場合は Sandbox を検討する
### 4.1 「承認疲れ」という現実的な問題
Claude Code は「起動しただけではシステムを変更しない」設計のため、Bash 実行・ファイル編集・Web Fetch などの副作用を伴う操作には**毎回ユーザーの承認**が必要になる。これはセキュリティ原則として正しい一方で、実際に使ってみると以下のような問題に直面する。
- ループ的な作業(lintを走らせ → 修正 → 再度lint…)で都度承認ダイアログが出る
- `npm install` のような子プロセスが大量に走る処理で承認が連鎖する
- 「許可するに決まっている」操作の承認に注意を奪われ、本当に危険な操作の承認が雑になる(**警告疲れ**)
`allow` リストを広げれば承認は減るが、今度は**意図しない破壊的操作まで通してしまうリスク**が増える。このトレードオフを解決する仕組みが **Sandbox** である。
### 4.2 Sandbox の仕組み(ネイティブ Sandbox)
Claude Code のネイティブ Sandbox は、**OSレベルのセキュリティ機構を使って Bash コマンドとその子プロセスを隔離**する機能。Docker コンテナを使わず、OS標準の仕組み(macOS の Apple Seatbelt、Linux の bubblewrap)で実現される。
分離は主に2層:
| 層 | 内容 |
|---|---|
| **ファイルシステム** | プロジェクトディレクトリ外への書き込みを遮断。`Read`/`Edit` 権限で詳細制御 |
| **ネットワーク** | デフォルトで外部通信遮断。`WebFetch` 権限で許可ドメインを制御 |
「Sandbox 内で完結する操作は安全と見なせるので自動許可する」というのが基本的な発想。
### 4.3 起動方法と3つのモード
Claude Code 起動後、`/sandbox` コマンドで設定する。
| モード | 挙動 | 向いている用途 |
|---|---|---|
| **Sandbox BashTool, with auto-allow** | Sandbox 内で実行できるコマンドは自動許可。Sandbox 外アクセスが必要なときだけ通常の承認フローへフォールバック | **承認疲れ解消が目的ならこれ**。多くのケースで推奨 |
| **Sandbox BashTool, with regular permissions** | Sandbox 化はされるが承認ダイアログは通常通り出る | 承認ダイアログは残しつつ、OSレベルの隔離だけ強化したい場合 |
| **No Sandbox** | Sandbox を使わない(従来通り) | Sandbox が使えない環境、または明示的に無効化したい場合 |
### 4.4 settings.json での詳細設定
`/sandbox` コマンドは内部的に `settings.json` を更新する。直接書く場合のサンプル:
<details>
<summary>サンプル: settings.json での sandbox 設定(クリックで展開)</summary>
```json
{
"permissions": {
"allow": [
"Read(./src/**)",
"Read(./docs/**)",
"Edit(./src/**)",
"WebFetch"
],
"ask": [
"Bash(git push *)",
"Bash(npm publish)"
],
"deny": [
"Read(./.env*)",
"Edit(./.env*)",
"Bash(rm -rf *)",
"Bash(git push -f *)"
]
},
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true,
"excludedCommands": ["git"],
"network": {
"allowedDomains": ["github.com", "*.npmjs.org", "registry.npmjs.org"]
}
}
}
ポイント解説:
-
excludedCommands: ["git"]— git は完全なファイルシステムアクセスを必要とするため、Sandbox の外で動かす必要がある(公式の推奨) -
network.allowedDomains— npm install や git push で必要な通信先だけホワイトリスト化 -
保護パス(Protected Paths) —
.git/、.bashrc、.mcp.json、.claude.jsonなどへの書き込みは、どのモードでも強制的に承認が必要になる。これは Claude が自分自身の権限設定を書き換えるリスクを防ぐためのハードガード - 評価順序は
deny→ask→allow。denyが最優先
4.5 評価ロジックの落とし穴
ask を広く書きすぎると、より限定的な allow が到達しなくなる:
// ❌ Bad: ask が広すぎて allow に到達しない
{
"ask": ["Bash(git *)"],
"allow": ["Bash(git status)"] // 永遠に到達しない
}
// ✅ Good: ask を破壊的操作だけに絞る
{
"ask": ["Bash(git push *)", "Bash(git reset --hard *)"],
"allow": ["Bash(git status)", "Bash(git diff *)", "Bash(git log *)"]
}
4.6 いつ Sandbox を導入するか
| 状況 | 判断 |
|---|---|
| プロトタイピング、調査タスクで Bash がたくさん走る | 導入推奨(auto-allow モード) |
| 長時間の自律実行(バックグラウンドで走らせて結果だけ確認したい) | 導入必須レベル |
| プロダクションコードの破壊的変更を伴う作業 | Sandbox + ask でガード |
.env や秘密鍵を扱う作業 |
Sandbox に加えて deny で .env* を明示遮断 |
| 一回限りの小さな修正 | Sandbox なしでも可(ただし常用するなら有効化推奨) |
補足:
dangerouslyOverrideSandboxというオプションが Bash ツールに存在するが、これは原則として使わない。LLM への指示やプロンプトインジェクションでこの引数を渡されてしまうと Sandbox の意味がなくなるため、本当に必要な場面以外では Bash ツール経由でこのパラメータが使われないよう注意する。
4.7 まとめ: Sandbox は「自動化」と「安全性」の両立手段
- 「承認が煩雑だから全部 allow にする」 → 危険
- 「都度承認する」 → 疲弊して結局雑になる
- 「Sandbox で隔離し、その中で自動許可」 → 安全性を OS レベルで担保しつつ、承認疲れを回避
特に、本ノートで扱ったサブエージェント運用やスペック駆動開発では Bash 呼び出しが頻発するため、Sandbox との組み合わせが現実的な落としどころになる。
5. ドキュメントは「エージェント間のやり取り」を補う
4.1 なぜドキュメント生成が重要か
Claude Code に限らず、エージェント運用では以下のような エージェント間の引き継ぎ が発生する。
- メインエージェント → サブエージェント(タスク委譲)
- セッションA → セッションB(後日の作業継続)
- Claude Code → 人間レビュアー → Claude Code(修正反映)
- Claude → Claude Code Action(CI/CDでの自動レビュー)
このとき口頭(プロンプト内)での申し送りには限界がある。コンテキストは消える、セッションは終わる、別のエージェントには履歴が見えない。
そこで ドキュメントが「永続化されたコンテキスト」として機能する。
4.2 重要なドキュメント類
スペック駆動開発の文脈で、特に重要な成果物:
| ドキュメント | 役割 | 配置例 |
|---|---|---|
| 要件定義 / PRD | 「何を作るか」 | docs/specs/<feature>/requirements.md |
| 設計 / Design Doc | 「どう作るか」 | docs/specs/<feature>/design.md |
| タスクリスト | 「どの順で作るか」 | docs/specs/<feature>/tasks.md |
| ADR | 「なぜそう決めたか」 | docs/adr/NNNN-*.md |
| CLAUDE.md | エージェントへの常時指示 | プロジェクト直下+サブディレクトリ |
補足: GitHub の
spec-kitや Kiro の影響もあり、requirements.md→design.md→tasks.mdの3点セットで進めるスペック駆動開発スタイルが広まっている。本書もこの流れに位置づく。
4.3 「正しくアウトプットさせる」ための仕掛け
ドキュメントを意図通りに出させるには:
-
テンプレートを Skill に同梱する(前述の
write-adrの例) -
コマンドでドキュメント生成手順を固定する(
/create-spec <feature-name>等) - CLAUDE.md にドキュメント配置規約を明示する
- 生成ドキュメントを次のフェーズで必ず Read させる(タスク実装時に design.md を読ませる、など)
サンプル: スペック駆動コマンド(.claude/commands/create-spec.md)
サンプル: /create-spec コマンドの中身(クリックで展開)
---
description: 新機能のスペックドキュメント3点セット(requirements/design/tasks)を作成する
---
引数: $ARGUMENTS(機能名、kebab-case)
以下の手順で機能 `$ARGUMENTS` のスペックを作成してください。
## Step 1: requirements.md
- ユーザーに「この機能で達成したいゴールは?」をヒアリング
- EARS記法(The system shall ...)で受け入れ基準を列挙
- `docs/specs/$ARGUMENTS/requirements.md` に保存
## Step 2: design.md
- requirements.md を踏まえて設計
- アーキテクチャ図(mermaid)、データモデル、API仕様、エラーハンドリング方針を含める
- `docs/specs/$ARGUMENTS/design.md` に保存
- 必要なら ADR を別途起票(write-adr スキルを利用)
## Step 3: tasks.md
- design.md を実装可能な粒度のタスクに分解
- 各タスクにチェックボックス `- [ ]` を付ける
- 依存関係を明示
- `docs/specs/$ARGUMENTS/tasks.md` に保存
## 完了報告
3ファイルのパスを列挙し、次のステップ(実装開始)を提案してください。
6. まとめ: コンテキスト工学の実践チェックリスト
書籍と一般的なベストプラクティスから抽出した実践チェックリスト。
プロジェクトのセットアップ時
-
CLAUDE.mdを書いた(プロジェクト概要・重要規約・参照すべき詳細ドキュメントの場所) -
サブディレクトリ固有の規約はサブの
CLAUDE.mdに分けた - 必須/推奨/任意/禁止を明示的に書き分けた(「可能なら」等の曖昧表現を排除)
- ルール衝突時の優先順位を明示した(大方針の順位+個別の衝突パターン)
- **判断不能時は「ユーザーに確認」**することを明示した
- よく使うノウハウは Skill 化した(description にトリガー語を網羅)
- 定型作業は Command 化した
- Skill/Command のドキュメントにサンプルを書いた
-
settings.jsonでpermissionsのallow/ask/denyを整理した -
承認が頻発する作業がある場合は
/sandboxを有効化した -
.env*や秘密鍵はdenyで明示的に遮断した
タスク実行時
-
タスクが切り替わる時に
/clearした - 大量コンテキストを使う作業(レビュー・大規模調査)は Subagent に投げた
- スペック(requirements/design/tasks)を先に作ってから実装に入った
- 生成されたドキュメントを後続フェーズで読ませる導線を作った
コンテキストロット予防
- 不要なファイルの Read を避けた(Grep/Glob で当たりをつけてから)
- 長いログは要約させてから次のターンへ
- 1セッションを長く引っ張らず、区切りで終わらせて新セッションへ
参考リンク
- 書籍ページ(技術評論社): https://gihyo.jp/book/2026/978-4-297-15354-0
- Anthropic 公式ドキュメント(Claude Code): https://docs.claude.com/en/docs/claude-code
- Anthropic Skills 概念: https://docs.claude.com/en/docs/claude-code/skills
- Making Claude Code more secure and autonomous with sandboxing(Anthropic公式ブログ)
-
anthropic-experimental/sandbox-runtime(OSレベルで動くサンドボックスツール)