📁GitHubにコード公開: tf_claudecode02
シリーズ記事一覧
- 第1回:Skills比較
- 第2回:サブエージェント活用
- 第3回:Skillsインストール&実践
- 第4回:CLAUDE.mdカスタムルール
- 第5回:カスタムサブエージェント自作
- 第6回:カスタムエージェント&Agent Teams
📑 目次
- この記事について
- この記事のゴール
- 前提知識:カスタムサブエージェントとは
- 前提条件
- Step 1:2つのレビュアーを設計する
- Step 2:並列でレビューを実行する
- Step 3:結果を比較する
- 考察:なぜ Skills が後退したのか
- 体験して分かったこと
- まとめ
1. この記事について
1-1. シリーズの位置づけ
本記事は「Terraform × Claude Code」シリーズの第5回です。
| 記事 | サブタイトル | 状態 |
|---|---|---|
| 01 | Skills比較|4つの公開スキルを調べて分かった最適な組み合わせ | ✅実施済み |
| 02 | サブエージェント活用|並列調査で01記事の数値を裏付け検証してみた | ✅実施済み |
| 03 | Skillsインストール&実践|コード生成の品質がどう変わるか検証してみた | ✅実施済み |
| 04 | CLAUDE.mdカスタムルール|チーム独自のルールをAIに教えてみた | ✅実施済み |
| 05 | カスタムサブエージェント自作|AIにコードレビューさせたら意外な発見(本記事) | 📝本記事 |
| 06 | カスタムエージェント&Agent Teams|AI開発チームを編成してみた | 📄未 |
1-2. なぜこの記事を書いたか?
04記事で CLAUDE.md にチームルール(A〜E)を書き、
コード生成に反映されることを確認しました。
結果は「5つのルール全て反映、ほぼ完璧」でした。
しかし、04記事の最後にこう書きました。
「守られた」ことの確認を 人間が毎回やるのは大変 です。
この問題を解決するために、
カスタムサブエージェントを自作して、レビューを自動化 します。
さらに、もう1つ気になることがありました。
04記事では CLAUDE.md のルールだけを確認しましたが、
Skills のベストプラクティスはどうなっているのか は未確認です。
03記事で確認された
for_each 優先やバージョン制約の ~> は、
今回も維持されているのでしょうか?
本記事では、2つのサブエージェントを自作して、この疑問に答えます。
1-3. 05記事の方針
| 項目 | 方針 |
|---|---|
| サブエージェント | 自作して使う(本記事の主役) |
| レビュー対象 | 04記事で生成されたコード(iac_04/ 配下) |
| 検証観点 | ①CLAUDE.md ルール準拠 ②Skills ベストプラクティス |
02記事ではサブエージェントを「調査」に使いました。
本記事ではサブエージェントを 「レビュー」 に使います。
同じ道具を、
目的を変えて使うことで、サブエージェントの汎用性を示します。
1-4. 対象読者
- 02記事でサブエージェントの基本を学んだ方
- コードレビューを自動化したい方
- CLAUDE.md と Skills の関係を深く理解したい方
2. この記事のゴール
| # | ゴール |
|---|---|
| ① | カスタムサブエージェントの設計・実行ができる |
| ② | CLAUDE.md ルールと Skills ベストプラクティスの違いを理解できる |
| ③ | CLAUDE.md + Skills 併用時の注意点が分かる |
3. 前提知識:カスタムサブエージェントとは
3-1. サブエージェントの復習(02記事より)
02記事で学んだ内容を簡単に振り返ります。
| 用語 | 説明 |
|---|---|
| サブエージェント | メインの Claude セッションから Task ツールで起動する別プロセス |
| 並列実行 | 複数のサブエージェントを同時に実行し、それぞれ独立して作業させる |
| コンテキスト分離 | サブエージェント同士は互いの作業を知らない。 結果のみメインに返る |
3-2. 02記事との違い
| 02記事 | 05記事(本記事) | |
|---|---|---|
| 用途 | 調査(GitHub リポジトリの情報を並列取得) | レビュー(生成済みコードの品質チェック) |
| 入力 | URL やキーワード | Terraform コードファイル |
| 出力 | 調査結果のテキスト | チェック項目ごとの判定(✅/⚠️/❌) |
| プロンプトの特徴 | 「〇〇を調べて」 | 「〇〇のルールに照らしてチェックして」 |
サブエージェントの「仕組み」は同じですが、
プロンプトの書き方で役割が変わる のがポイントです。
3-3. カスタムサブエージェントの設計パターン
レビュー用サブエージェントを設計するときの基本パターンです。
1. 役割を定義する(あなたは〇〇レビュアーです)
2. チェック対象を指定する(以下のファイルを読んでください)
3. チェック観点を列挙する(以下のルールに照らして...)
4. 出力形式を指定する(判定: ✅/⚠️/❌、根拠: ...)
4. 前提条件
4-1. 環境
| 項目 | 内容 |
|---|---|
| OS | Windows 11 + WSL2(Ubuntu)※筆者環境 |
| ツール | Claude Code(最新版) |
| プラン | Claude Max |
| レビュー対象 | 04記事で生成された iac_04/ 配下のコード |
4-2. レビュー対象ファイル
04記事で Skills + CLAUDE.md の状態で生成されたコードです。
iac_04/
├── provider.tf
├── variables.tf
├── locals.tf
├── main.tf
├── outputs.tf
└── modules/vpc/
├── main.tf
├── variables.tf
└── outputs.tf
5. Step 1:2つのレビュアーを設計する
5-1. 目的
レビューの観点を2つに分け、それぞれ専用のサブエージェントを設計します。
| # | レビュアー名 | 役割 | チェック内容 |
|---|---|---|---|
| 1 | ルール準拠チェッカー | CLAUDE.md の ルールA〜Eを守っているか |
タグ・命名・バケットポリシー・日本語description・fmt/validate |
| 2 | ベストプラクティス監査 | Skills の パターンが適用されているか |
for_each vs count・シングルトン命名・変数バリデーション・ファイル構成 |
なぜ2つに分けるのか?
-
関心の分離:
CLAUDE.md のルールと Skills のベストプラクティスは出所が違う。
混ぜると「どちらの問題か」が分かりにくくなる。 -
並列実行:
2つを同時に走らせて結果を比較できる。(02記事で学んだパターン)
5-2. レビュアー1:ルール準拠チェッカーのプロンプト
あなたは Terraform コードレビュアーです。
以下のルール A〜E に対して、生成されたコードが準拠しているかチェックしてください。
## チェック対象ファイル
すべて ~/iac_04/ 配下にあります。
以下のファイルを読んでください:
- variables.tf
- locals.tf
- provider.tf
- main.tf
- outputs.tf
- modules/vpc/main.tf
- modules/vpc/variables.tf
- modules/vpc/outputs.tf
## チェックするルール
### A. 必須タグ
全てのリソースに以下の3つのタグが付与されているか?
- Project(var.project)
- Owner(var.owner)
- CostCenter(var.cost_center)
locals でマージする方式が使われているか?
### B. リソース命名規則
リソースの Name タグが {project}-{env}-{リソース種別} の形式になっているか?
### C. S3 バケットポリシー
S3 バケットにバケットポリシーが付与され、
指定 IAM ロール(var.allowed_role_arn)のみアクセス許可になっているか?
### D. セキュリティグループの description
セキュリティグループおよび各ルールの description が日本語で記述されているか?
### E. コード品質チェック
terraform fmt と terraform validate が実行可能な状態か?
## 出力形式
各ルールについて以下の形式で報告してください:
- 判定: ✅ 準拠 / ⚠️ 一部不備 / ❌ 未準拠
- 根拠: 具体的なファイル名と行番号を示す
- 改善提案: 不備がある場合のみ
最後に総合スコア(5点満点)を付けてください。
5-3. レビュアー2:ベストプラクティス監査のプロンプト
あなたは Terraform ベストプラクティス監査官です。
antonbabenko/terraform-skill の推奨パターンに照らして、
生成されたコードを監査してください。
## チェック対象ファイル
(レビュアー1と同じファイルリスト)
## チェック観点
### 1. for_each vs count
- リソースの繰り返しに for_each が使われているか?
- count が使われている場合、index ベースの参照による
削除・再作成リスクがあるか?
### 2. シングルトン命名規則
- 同種リソースが1つしかない場合、リソース名が "this" になっているか?
### 3. 変数バリデーション
- 入力変数に validation ブロックが付いているか?
### 4. ファイル構成
- versions.tf / variables.tf / main.tf / outputs.tf の
4ファイル分割がされているか?
### 5. output の形式
- for_each を使ったリソースの output は Map 形式か?
- 全 output に description が付いているか?
### 6. セキュリティグループのリソース型
- 旧式の ingress/egress ブロックではなく、
aws_vpc_security_group_ingress_rule が使われているか?
### 7. terraform ブロック
- required_version でバージョンが固定されているか?
- バージョン制約の書き方は ~> か >= か?
## 出力形式
各観点について以下の形式で報告してください:
- 判定: ✅ ベストプラクティス準拠 / ⚠️ 一部乖離 / ❌ 非準拠
- 現状: 具体的なファイル名と行番号
- 推奨: ベストプラクティスではどうすべきか
- 影響度: 高/中/低
最後に総合評価を付けてください。
5-4. プロンプト設計のポイント
| ポイント | 理由 |
|---|---|
| チェック対象ファイルを明示 | サブエージェントは文脈を共有しないため、ファイルパスを完全に指定する |
| チェック観点を番号付きで列挙 | 曖昧な「レビューして」ではなく、具体的な観点を与える |
| 出力形式を指定 | 結果を比較しやすくするため、判定・根拠・改善提案の形式を統一 |
| スコアリングを要求 | 定量的な比較を可能にする |
6. Step 2:並列でレビューを実行する
6-1. 目的
2つのレビュアーを 並列で 実行します。
02記事で学んだ「Task ツールの並列実行」の実践です。
6-2. 実行方法
Claude Code の Task ツールで、2つのサブエージェントを同時に起動します。
2つのサブエージェントは
互いの作業を知らず、独立して ファイルを読み、チェックし、結果を返します。
6-3. 実行結果
2つのサブエージェントがそれぞれ約1分で完了しました。
7. Step 3:結果を比較する
7-1. レビュアー1:ルール準拠チェック — 4.5 / 5.0
| ルール | 判定 | 根拠 |
|---|---|---|
| A. 必須タグ | ✅ 準拠 |
locals.tf で common_tags 定義。全リソースで merge(local.common_tags, {...})。VPCモジュールには common_tags 変数で受け渡し |
| B. 命名規則 | ✅ 準拠 | 全リソースの Name タグが {project}-{env}-{種別} 形式。例に挙げていないIGW・NAT・サブネットにも自動拡張 |
| C. S3バケットポリシー | ⚠️ 一部不備 |
aws_s3_bucket_policy.logs で var.allowed_role_arn を許可。ただし 明示的な Deny がない |
| D. SG description 日本語 | ✅ 準拠 | SG本体・SSH・Egress の3つ全て日本語 |
| E. コード品質チェック | ✅ 準拠 |
terraform fmt / terraform validate ともに成功 |
ルールC の不備の詳細
レビュアー1が指摘した唯一の不備は、S3 バケットポリシーの構造です。
現状(Allow のみ):
Statement = [
{
Sid = "AllowAccessFromSpecifiedRole"
Effect = "Allow"
Principal = {
AWS = var.allowed_role_arn
}
Action = ["s3:GetObject", "s3:PutObject", "s3:ListBucket"]
Resource = [aws_s3_bucket.logs.arn, "${aws_s3_bucket.logs.arn}/*"]
}
]
問題点:
Allow だけでは、
他の IAM ポリシーで許可されたプリンシパルもアクセスできてしまう。
レビュアーの改善提案:
# 指定ロール以外を明示的に拒否する Deny ステートメントを追加
{
Sid = "DenyAccessFromOtherPrincipals"
Effect = "Deny"
Principal = "*"
Action = "s3:*"
Resource = [
aws_s3_bucket.logs.arn,
"${aws_s3_bucket.logs.arn}/*"
]
Condition = {
StringNotEquals = {
"aws:PrincipalArn" = var.allowed_role_arn
}
}
}
[!NOTE]
これは CLAUDE.md のルールCに「のみアクセスを許可する」と書いたにもかかわらず、
コード生成では Allow のみで Deny が欠落したケースです。
「のみ」という曖昧な表現では、
明示的な Deny まで生成されないことが分かりました。
7-2. レビュアー2:ベストプラクティス監査 — 1 / 7 準拠
| 観点 | 判定 | 影響度 | 詳細 |
|---|---|---|---|
| 1. for_each vs count | ❌ 非準拠 | 高 | サブネット・NAT・ルートテーブルすべて count + index ベース |
| 2. シングルトン命名 | ⚠️ 一部乖離 | 低 | VPCモジュール内は "this" だが、ルートは "logs" / "web"
|
| 3. 変数バリデーション | ❌ 非準拠 | 中 |
validation ブロックが一切ない |
| 4. ファイル構成 | ⚠️ 一部乖離 | 低 |
versions.tf がない。provider.tf に terraform ブロックが同居 |
| 5. output の形式 | ⚠️ 一部乖離 | 中 | リスト形式(Map 形式ではない)。 description は全て付与 |
| 6. SG リソース型 | ✅ 準拠 | — |
aws_vpc_security_group_ingress_rule / egress_rule を使用 |
| 7. terraform ブロック | ⚠️ 一部乖離 | 中 |
>= 1.0.0 / >= 5.0.0(~> ではなく >=) |
7-3. 2つの結果を並べる
ここで、2つのレビュアーの結果を並べてみます。
| CLAUDE.md ルール準拠(レビュアー1) | Skills ベストプラクティス(レビュアー2) |
|---|---|
| 4.5 / 5.0(ほぼ完璧) | 1 / 7 準拠(大半が後退) |
CLAUDE.md のルールはほぼ完璧に守られた。
しかし、Skills のベストプラクティスは大半が後退していた。
これは04記事の時点では見えていなかった発見です。
04記事では
CLAUDE.md のルール(A〜E)だけを確認し、
「5つ全て反映、ほぼ完璧」と結論付けました。
しかし、
別の観点でチェックしたら別の結果が見える ことを、
サブエージェントによるレビューが明らかにしました。
7-4. 具体的にどこが後退したのか
03記事(Skills のみ)と04記事(Skills + CLAUDE.md)を比較します。
| 項目 | 03記事(Skills のみ) | 04記事(Skills + CLAUDE.md) | 変化 |
|---|---|---|---|
| サブネットのループ |
for_each(map) |
count(list) |
❌ 後退 |
| SSH ingress |
for_each で複数CIDR対応 |
count + [0] で先頭1つだけ |
❌ 後退 |
| リソース名 |
"this"(シングルトン) |
"logs", "web" 等(用途名) |
⚠️ 変化 |
| 変数バリデーション | CIDR の validation あり | validation なし | ❌ 後退 |
| versions.tf | あり(~> 1.9) |
なし(provider.tf に >= 1.0.0) |
❌ 後退 |
| サブネット変数の型 | map(string) |
list(string) |
❌ 後退 |
| output の形式 | Map(AZ → ID) | リスト | ❌ 後退 |
7項目中6項目が後退 しています。
8. 考察:なぜ Skills が後退したのか?
8-1. 3つの仮説
| # | 仮説 | 説明 |
|---|---|---|
| 1 | CLAUDE.md が Skills より優先された |
CLAUDE.md はプロジェクトに直接紐づくため、Claude の注意がCLAUDE.mdに集中した |
| 2 | 統合プロジェクトの 文脈が影響した |
03記事は個別リソースだったので "this" が自然だったが、統合プロジェクトでは複数リソースがあるため "this" が使えない → 他のパターンも連鎖的に変わった |
| 3 | ルールA〜Eへの注意力が Skills を押し出した |
5つのカスタムルールに注意を向けた結果、Skills のパターンへの注意リソースが減少した |
8-2. 仮説の検証
| 仮説 | 支持する根拠 | 限界 | 評価 |
|---|---|---|---|
| 1. CLAUDE.md 優先 | CLAUDE.md: 5つ中4つ完璧、Skills: 7つ中1つ準拠。注意配分の偏りを示唆 | — | ◎ 有力 |
| 2. 統合プロジェクト |
"this" は統合時に区別がつかない → 合理的判断 |
for_each・validation の後退は説明不能 |
△ 部分的 |
| 3. 明示 > 暗黙 | CLAUDE.md = 具体的指示、Skills = 暗黙注入(SKILL.md)。明示ルールが勝った | — | ◎ 有力 |
8-3. 結論
3つの仮説はそれぞれ一部を説明しますが、最も有力なのは 仮説1 + 仮説3 の組み合わせ です。
CLAUDE.md は「プロジェクト固有の明示的なルール」であるため、
Skills の「汎用的な暗黙のルール」よりも優先される傾向がある。
これは「バグ」ではなく、設計上の自然な振る舞い と言えます。
プロジェクト固有のルールが優先されるのは、人間のチームでも同じです。
新メンバーに「業界のベストプラクティスより、まずうちのルールを覚えて」と言うのと似ています。
8-4. 実務への示唆
この発見から導かれる実務的な教訓です。
| 教訓 | 対策 |
|---|---|
| CLAUDE.md に書いたルールは 高い確率で反映される |
反映させたいルールは CLAUDE.md に明示的に書く |
| Skills のパターンは CLAUDE.md と併用すると後退しうる |
Skills のパターンも重要な場合は CLAUDE.md に重複記載する |
| 「のみ」「必ず」などの曖昧な表現は 厳密に解釈されない場合がある |
実装方法まで具体的に指示する(例:Deny ステートメントを追加する) |
9. 体験して分かったこと
9-1. サブエージェントについて
-
プロンプトの書き方で役割が変わる:
02記事では「調査」、本記事では「レビュー」に使った。
同じ Task ツールでも、プロンプト次第で別の仕事ができる -
並列実行が効果的:
2つのレビュアーを同時に走らせて、それぞれ約1分で完了。
人間が全ファイルを2つの観点でチェックするより圧倒的に速い -
「別の視点」を入れられるのが最大の価値:
04記事ではCLAUDE.mdのルールだけを見て「完璧」と思っていた。
しかしサブエージェントで「Skills のベストプラクティス」という別の視点を入れたら、見落としが発覚した
9-2. CLAUDE.md と Skills の関係について
-
CLAUDE.md は「強い指示」:
反映率が非常に高い。
チーム独自のルールは CLAUDE.md に書くのが正解 -
Skills は「弱い指示」になりうる:
CLAUDE.md と併用すると後退する場合がある。
Skills のパターンも重要なら CLAUDE.md に重複記載が必要 -
「完璧」は観点次第:
1つの観点では完璧でも、別の観点からは問題がある。
レビュー観点を複数持つことの重要性を実感した
9-3. 期待と違った点
-
Skills が有効なのにパターンが後退したこと:
Skills は有効のまま実験したので、
Skills + CLAUDE.md の「両方の良いとこ取り」を期待していた。
実際には CLAUDE.md が優勢で、Skills が後退するケースがあった。 -
CLAUDE.md の「のみ」が厳密に解釈されなかったこと:
ルールCで「指定 IAM ロールのみアクセス許可」と書いたが、
生成されたのは Allow だけで Deny がなかった。
自然言語の曖昧さは CLAUDE.md でも完全には解決しない。
10. まとめ
10-1. この記事で分かったこと
| ゴール | 結果 |
|---|---|
| ①カスタムサブエージェントの設計・実行 | 「役割定義 → チェック対象 → チェック観点 → 出力形式」の設計パターンで作成。 並列実行も成功 |
| ②CLAUDE.md ルール vs Skills ベストプラクティス | CLAUDE.md: 4.5/5.0(ほぼ完璧)、Skills: 1/7(大半が後退)。 明示的ルールが暗黙ルールに勝つ |
| ③併用時の注意点 | Skills のパターンも重要な場合は CLAUDE.md に重複記載する。 「のみ」等の曖昧表現は避けて具体的に書く |
10-2. シリーズを通して学んだこと
ここまでの5記事で、以下の知識が積み上がりました。
| 記事 | 学んだこと | 積み上がった知識 |
|---|---|---|
| 01 | Skills の比較と選び方 | 「何を使うか」 |
| 02 | サブエージェントの基本 | 「道具の使い方」 |
| 03 | Skills の効果検証 | 「汎用ルールの威力」 |
| 04 | CLAUDE.md のカスタムルール | 「チーム固有ルールの威力」 |
| 05 | サブエージェントでレビュー + 意外な発見 | 「自動レビュー」+「2つの仕組みの関係」 |
10-3. 次のステップ
01〜05で 個人 としての Claude Code 活用を学びました。
- Skills でコード品質を上げる
- CLAUDE.md でチームルールを教える
- サブエージェントでレビューを自動化する
次回の06記事では、
Agent Teams でインフラ設計チームを組みます。
複数のエージェントを
「チーム」として編成し、インフラ設計を分担させる方法を紹介します。