Claude Code のSKILL.mdでエラーを防ぐTips

Claude Code のスキル機能では、SKILL.md に書いたガイドに従ってエージェントがタスクを実行します。 ただ、SKILL.mdの書き方次第でエージェントの安定性は大きく変わります。パフォーマンスも大きく異なります。

SKILL.mdは人間向けドキュメントとは異なる設計原則が必要だと感じたので、問題になったパターンを具体例を提示していきます。

$()によるコマンド置換のような自然なパターンがブロックされる問題

エージェントは最も自然で効率的なパターンを選びます。しかしながら、その「自然なパターン」が制約に引っかかることがあります。

たとえば Claude Code は $() によるコマンド置換を含むコマンドに対して、手動承認(permission prompt)を要求します。

# エージェントが自然に書くパターン → ブロックされる
QUERY_ID=$(aws logs start-query ... | jq -r '.queryId')
aws logs get-query-results --query-id "$QUERY_ID"

$() はシェルスクリプトとしてはごく自然な書き方ですが、不審なコマンドとして検出され、毎回承認を求められてしまいます。厄介なのは、明示的に禁止しないとエージェントは何度でも同じパターンを生成するということです。「前回ブロックされたから別の方法を試す」とはなかなかいきません。

SKILL.md に MUST ルールとして禁止パターンを追加し、「こう書いてはいけません」を具体例付きで示すのが最も効果的でした。「やるべきこと」だけでなく「やってはいけないこと」を書くのが、エージェント向けガイドの基本だと思います。

で、この $() 問題の解決策自体はシンプルで、ガイド上で明示的にステップを分離するだけです。

# Step 1: クエリを開始して ID を取得する
aws logs start-query ... | jq -r '.queryId'
# → 出力された queryId を次のコマンドに使う

# Step 2: 結果を取得する
aws logs get-query-results --query-id <出力された queryId>

各ステップを別のコマンドとして実行させれば、セキュリティチェックとの衝突を回避できます。「クエリ開始 → ID 取得 → 結果取得」のような非同期フローでは、エージェントは効率を重視して 1 行にまとめようとするので、ガイドの構造でそれを制御してあげるのがポイントです。

サブエージェントに権限が継承されない

SKILL.md の allowed-tools で定義したツール許可は、Agent ツールで起動したサブエージェントには引き継がれません。。。。

スキル内でサブエージェントを活用する設計にしていると、リッチなエージェントにするとユーザーに毎回権限の許可を求めることになってしまいます。 サブエージェントの役割を Read や Grep 等の標準の読み取り系ツールに限定するか、メインエージェントで処理を完結させるかは要検討です。

Claudeが好むツール選択ではなく、堅牢な方法を与えてあげる

Claudeは JSON のフィルタリングや加工に python3 -c "import json, sys; ..." のようなインラインスクリプトを好む場合があります(自分だけ?)。 もちろん動くには動くんですが、長くて壊れやすく可読性も低いですし、同意を求められる可能性が高くなります。

jq--query(JMESPath)のほうが適切な場面は多いので、ガイドで優先順位を明示しておくのが有効です。 自分の場合は以下のような優先順位をガイドに書いています。aws cli の出力を加工する場面が多いので、jq を第一選択にしています。

優先度ツール用途
1jq第一選択(全ツール共通)
2—query + —output tableAWS CLI の簡単な一覧表示
3python3上記で対応できない複雑な計算のみ

こうした方針をガイドに書いておかないと、エージェントは毎回「最も汎用的な手段」として Python を選びがちです。特に複数のガイドファイルにまたがる場合、方針は実装に入る前に固めておかないと、あとから全部書き直すハメになります。

まとめ

SKILL.md は「人間が読むドキュメント」ではなく「エージェントの実行を制御する設計書」です。今回紹介した 3 つのパターンを振り返ると、共通しているのは「エージェントの自然な振る舞いを理解した上で、ガイドで制約をかける」ということだと思います。

  • 禁止パターンは MUST ルールで明示する。 $() のようにエージェントが好む自然なパターンでも、プラットフォームの制約に引っかかるなら具体例付きで禁止する
  • 非同期処理はステップを分離する。 1 行にまとめさせず、Step 1 / Step 2 でガイドの構造から実行パターンを制御する
  • サブエージェントの権限境界を意識する。 allowed-tools はサブエージェントに引き継がれないので、役割設計に注意する
  • ツール選択の優先順位を与える。 指定しないとエージェントは Python のような汎用的な手段を選びがちなので、jq 等の適切なツールを明示する