Claude Code Skill設計の実践ガイド — blog-agentsの実Skillから学ぶ意思決定ロジック

公式ドキュメントを読んでSKILL.mdの書き方はわかったのに、いざ自分で設計しようとすると手が止まる。「descriptionは何を書けばいいのか」「context: forkはいつ使うべきなのか」「allowed-toolsはどこまで広げていいのか」――こういった判断基準が、公式には書いていない。本記事では、このブログを動かしているblog-agentsの6つのSkillを題材に、「なぜそう設計したか」の意思決定を公開する。

Skillとは何をするものか

Claude Code のSkillは、.claude/skills//SKILL.md という1ファイルで定義される。YAML frontmatterにメタ情報を書き、その下にMarkdown本文でClaudeへの指示を書く。起動されると会話に1メッセージとして投入され、セッション中ずっとコンテキストに残る設計だ。

公式が「SKILL.mdは500行以下に保て」と推奨しているのもこの理由で、長すぎると毎回トークンコストがかさむ。参考資料は別ファイルに切り出すのが基本だ。

frontmatterのフィールドで設計の大半が決まる。Claudeがいつ起動するか判断する descriptionwhen_to_use、明示的起動のみに絞る disable-model-invocation、サブエージェント分離を制御する context: fork、権限を制限する allowed-tools あたりだ。以降ではblog-agentsの実例を通じてこれらの判断を掘り下げる。

設計判断1: いつ起動するか — trigger設計

descriptionの書き方が、Claudeが適切にSkillを選択できるかどうかを左右する。descriptionwhen_to_use の合計に1,536字の上限があるため、何でも書けるわけではない。

descriptionを書くときに意識することがある。動詞で始め(「〜する」「〜を生成する」)、実際のトリガーフレーズを列挙し、副作用も明示する。blog-agentsの write-article Skillでは次のように書いている。

description: リサーチ結果をもとにブログ記事を執筆する。「記事を書いて」「執筆して」等の依頼時に使用。

「リサーチ結果をもとに」という前置きで、このSkillが何を期待するかを示し、「『記事を書いて』『執筆して』等の依頼時に使用」でトリガーフレーズを具体的に列挙している。「品質を改善する」といった抽象的な書き方ではClaudeが発火タイミングを判断できず、精度が落ちる。

ただし、descriptionだけでtriggerをコントロールできない場面がある。それが disable-model-invocation だ。

設計判断2: 誰が起動するか — invocation control

disable-model-invocation: true を設定すると、Claude自身の自動判断による起動が禁止される。ユーザーが /article-pipeline テーマ名 と明示的に入力したときだけ動く。

blog-agentsの article-pipeline Skillにこれを入れた理由は「暴走防止」だ。「記事を書いて」という一言でリサーチ→執筆→WordPress公開まで全工程が走る。もしClaudeが会話の流れを読んで勝手にSkillを発火させると、意図しないタイミングで複数の記事が量産される。副作用が大きいアクションほど、明示的なトリガーに絞るべきだ。

---
name: article-pipeline
description: テーマから記事の完成まで全工程を一気通貫で実施する。「記事パイプライン」「全工程やって」「記事を作って」等の依頼時に使用。
argument-hint: <テーマ>
disable-model-invocation: true
---

逆に user-invocable: false を使うと、ユーザーの / メニューから隠れてClaudeだけが起動できる。背景知識として常に効かせたい場合はこちらだ。ただblog-agentsでは全Skillをユーザーからも手動起動できる設計にしている。

「Claudeが勝手に判断してほしい」か「自分が明示的に指示したときだけ動いてほしい」か。この問いへの答えが、invocation controlの設定を決める。

設計判断3: 権限をどう絞るか — context: fork と allowed-tools

blog-agentsの6つのSkillのうち、article-pipeline 以外の5つはすべて context: fork を使っている。これはメインの会話コンテキストとは独立したサブエージェントとして動かす設定だ。

通常実行context: fork
メインのコンテキストを共有サブエージェントで分離
短いSkillに最適長い処理・専門化に最適
コスト低コスト高(コンテキスト2重)

リサーチ・執筆・レビューはそれぞれ長いコンテキストを持つ。これらをメイン会話に混在させると、トークン消費が膨らみ、コンテキストウィンドウを圧迫する。context: fork で分離することでメインの会話を汚さずに済む。

allowed-tools については、最小権限の原則を徹底した。以下が6つのSkillの権限比較だ。

SkillWriteBashWebSearch / WebFetch
article-pipeline
write-article
audit
research
plagiarism-check
tone-check

tone-check が Write を持たない理由は、新規ファイル作成が不要だからだ。AI臭の検出と修正はEditだけで完結する。audit だけがBashを持つのは、WordPressへのcurl投稿とファイル移動(mv)が必要なためだ。

plagiarism-check が WebSearch / WebFetch を持ちながらBashを持たないのは意図的な役割分離だ。出典を外部で確認する権限は持つが、危険な副作用を物理的に防ぐためにBashは与えていない。実際の運用で、このSkillが過去に致命的な誤りを4件検出・修正した実績がある。auditが全部を抱え込む設計にせず、ファクトチェックを専任のSkillに切り出したことが功を奏した。

権限の絞り込みは「セキュリティ」のためだけではない。各Skillの責務を明確にする効果もある。allowed-toolsを見るだけで「このSkillが何をするものか」がわかる設計を目指した。

設計判断4: 動的コンテキスト注入の威力 — researchの実例

research Skillには、Skillファイルに静的な情報を書くだけでなく、実行時にシェルコマンドの出力を埋め込む仕組みを使っている。

---
name: research
description: テーマのリサーチを実施し research/ にマークダウンで出力する。「リサーチして」「調べて」「テーマ調査」等の依頼時に使用。
context: fork
agent: researcher
allowed-tools: Read, Write, Glob, Grep, WebSearch, WebFetch, Skill, mcp__recall__qdrant-find, mcp__recall__qdrant-store
---

「$ARGUMENTS」のテーマについてリサーチを実施してください。

## 既存の公開済み記事(重複チェック用)

!`ls ~/project/blog-agents/articles/published/ 2>/dev/null | sed 's/\.md$//' | sort`

末尾の !ls ...`` 構文がポイントだ。Skill起動のたびにシェルが走り、その時点での公開済み記事一覧がプロンプトに自動的に挿入される。リサーチャーは常に最新の記事リストを参照しながら重複テーマを避けられる。

$ARGUMENTS でユーザーが渡したテーマを本文に埋め込むのと組み合わせることで、Skill本文に静的な文字列を書くだけで「テーマ × 最新の記事状況」という動的なコンテキストが毎回生成される。

注意点として、重いシェルコマンドを書くとSkill起動のたびに待ち時間が発生する。ls のような軽量なコマンドに限定するのが望ましい。

運用で学んだ落とし穴

SKILL.mdが肥大化する

公式が500行以下を推奨しているのには理由がある。Skillは起動するたびにコンテキストに追加されるため、長いほどトークンコストが上がる。詳細な指示は各サブエージェントのシステムプロンプト(agent: xxxのファイル)に移し、Skill本文には「何をするか」だけを書くのが健全だ。

context: fork なのにタスクを書いていない

公式ドキュメントが明示的に警告しているが、context: fork のSkillにガイドラインだけを書くと、サブエージェントは何もせず返ってくる。必ず動詞で始まる指示文(「〜してください」)を含めること。blog-agentsでは全Skillが「〇〇してください」で始まる指示を持っている。

allowed-toolsを広げすぎる

「便利だから」とWrite・Bash・WebFetchを全部許すと、Skillが何をするのか境界が曖昧になる。最小権限から始めて、必要に応じて足す運用がいい。最初から全部許可したSkillは、後で絞るときに「本当に必要か?」の判断ができなくなる。

descriptionが抽象的でSkillが起動しない

「記事を改善する」だけでは、Claudeは何のSkillか判断しにくい。「『記事を書いて』『執筆して』等の依頼時に使用」のように、実際のトリガーフレーズを具体的に列挙する。ユーザーが言いそうな言葉を並べると精度が上がる。

まとめ

6つのSkillを設計してきて気づいたのは、「このSkillが誰のために、何をするものか」が自分の中で明確なときは、trigger・invocation control・allowed-toolsの答えが自然と決まるということだ。迷ったときは決まってそこが曖昧だった。

Skillを自作するなら、まず1つだけ作ってみてほしい。descriptionを書いて、allowed-toolsを最小権限で設定して、実際に動かす。「Claudeが起動しない」「権限が足りない」「暴走した」というフィードバックを直していくうちに、自分のユースケースに合った設計感覚が出てくる。

Skillの設計で詰まったときは、「このSkillのallowed-toolsを見て責務が一言で言えるか」を確認してほしい。それが言えないなら、まだ分割できる余地がある。

参考リンク

コメント

タイトルとURLをコピーしました