• Claude Code
  • Skills
  • スラッシュコマンド
  • 設定

Claude Code の Skills(SKILL.md)入門:スラッシュコマンドとの違いと実用スキル3例【動作確認済み】

公開 更新

端末画面の横に、魔法の杖、書類、ロケット、チェックリストのアイコンが描かれたカードが扇状に重なっているイラスト
イラスト(生成画像)。実際の画面ではありません。
確認したバージョン
Claude Code 2.1.303
確認日
2026/10/19
確認した環境
Debian GNU/Linux 13(GUI なしのサーバー環境)

この記事でわかること

  • SKILL.md の置き場所と最小の書き方
  • Claude が自動で使う場合と /名前 で呼ぶ場合の違い(実際に確認)
  • disable-model-invocation と user-invocable: false の効き方
  • claude -p でスキルの自動呼び出しが拒否されたときの対処
  • 実用スキル 3 例(差分の要約・リリースノート・表記ルール)
  • 旧カスタムスラッシュコマンド(.claude/commands)からの移行手順
目次(10項目)
  1. 検証環境
  2. スキルとスラッシュコマンドの違い
  3. スキルの置き場所
  4. 1実用スキル 3 例を作る
  5. 2認識されたか確認する
  6. 3自動呼び出しと明示呼び出しを試す
  7. 4旧スラッシュコマンドから移行する
  8. つまずきポイントのチェックリスト
  9. まとめ
  10. 参考

Claude Code の Skills(スキル) は、SKILL.md というファイルに手順や知識を書いておくと、Claude が必要なときに読み込んで使ってくれる仕組みです。/スキル名 で自分から呼ぶこともできます。

以前からある カスタムスラッシュコマンド(.claude/commands/*.md)とよく似ていて、公式ドキュメントにも「カスタムコマンドはスキルにマージされた」と書かれています。では何が違って、どう移行すればいいのか。実際にスキルを 3 つ作り、旧形式のコマンドからの移行まで試しました。

この記事の画面について

端末の画像は、tmux の capture-pane で取り込んだ文字と色をそのまま画像にしたものです。内容は編集していません。/skills の一覧には筆者の claude.ai アカウントから同期されたスキルも並ぶため、その部分は画像から切り出して省いています。一部の端末画像では、日本語が行末で折り返された位置に表示上の空白が入っています(入力したコマンドには空白はありません)。

検証環境

項目 内容
確認日 2026-10-19
Claude Code 2.1.303(ネイティブ版、Claude Pro でログイン)
OS Debian GNU/Linux 13(trixie)
モデル --model haiku(claude -p で 1 回ずつ実行)
検証用リポジトリ Python のファイル 1 つとコミット 2 つだけの小さな Git リポジトリ

スキルとスラッシュコマンドの違い

公式ドキュメントの内容と、今回確認したことをまとめます。

項目 スキル(.claude/skills/<名前>/SKILL.md) 旧コマンド(.claude/commands/<名前>.md)
/名前 で呼ぶ できる(確認) できる(確認)
Claude が自動で使う できる(description を見て判断)(確認) 未確認(ドキュメントでは name・paths 以外の frontmatter は共通)
補助ファイル(スクリプト・資料) フォルダにまとめて置ける 置き場所がない
name / paths の指定 できる できない(ドキュメントより)
同じ名前があるとき スキルが優先(確認) —
今後 新しく作るならこちら 引き続き動く(確認)

ポイント

スキルの本文は使われるときだけ読み込まれます。普段コンテキストに入るのは description(説明文)だけです。毎回は要らない長い手順書は、CLAUDE.md に書くよりスキルにしたほうがコンテキストを節約できます。

スキルの置き場所

場所 パス 使える範囲
個人 ~/.claude/skills/<名前>/SKILL.md このマシンのすべてのプロジェクト
プロジェクト .claude/skills/<名前>/SKILL.md そのリポジトリ(コミットすればチームで共有)
プラグイン <プラグイン>/skills/<名前>/SKILL.md /プラグイン名:スキル名 として

同じ名前のスキルが個人とプロジェクトの両方にあると、個人のほうが優先されます(ドキュメントより。今回は未確認)。この記事では、試したスキルがほかのプロジェクトに影響しないよう、すべてプロジェクトの .claude/skills/ に作りました。

手順 1:実用スキル 3 例を作る

役割の違う 3 つを用意しました。どれも、使われたことが出力でわかるように、最後に目印の一文を書かせています。

スキル 役割 呼び出し設定
summarize-changes-ja 未コミットの変更を日本語で要約し、危険な点を指摘 既定(自分でも Claude でも呼べる)
release-note 指定バージョンのリリースノート下書き disable-model-invocation: true(自分で呼ぶときだけ)
jp-style 日本語の表記ルール(背景知識) user-invocable: false(Claude だけが使う)

例 1:差分を日本語で要約する(summarize-changes-ja)

公式ドキュメントの最初の例(summarize-changes)を日本語向けにしたものです。!`git diff HEAD` の行は、スキルが Claude に渡される前にコマンドが実行され、その出力に置き換わります(動的コンテキスト注入)。

.claude/skills/summarize-changes-ja/SKILL.md:

---
description: 未コミットの変更を日本語で要約し、危険な点を指摘する。ユーザーが「何を変更した?」「差分を見て」「コミットメッセージを考えて」と聞いたときに使う。
allowed-tools: Bash(git diff *)
---

## 現在の変更

!`git diff HEAD`

## 指示

上の差分を日本語の箇条書き 2〜3 点で要約し、続けて気づいたリスク(ハードコードされた値、エラー処理の欠落、更新が必要なテストなど)を挙げてください。差分が空なら「未コミットの変更はありません」とだけ答えてください。
最後の行に「(summarize-changes-ja スキルで回答)」と書いてください。

例 2:リリースノートの下書き(release-note)

勝手に動いてほしくない作業向けに、disable-model-invocation: true を付けました。$ARGUMENTS には /release-note v0.2.0 の v0.2.0 の部分が入ります。argument-hint は入力中に表示されるヒントです。

.claude/skills/release-note/SKILL.md:

---
description: 指定したバージョンのリリースノート下書きを git log から作る
disable-model-invocation: true
argument-hint: "[version]"
allowed-tools: Bash(git log *)
---

## 直近のコミット

!`git log --oneline -n 10`

## 指示

上のコミット履歴から、バージョン $ARGUMENTS のリリースノート下書きを日本語で作ってください。
見出しは「## $ARGUMENTS」、本文は「追加」「修正」の 2 区分の箇条書きにします。
最後の行に「(release-note スキルで作成)」と書いてください。

例 3:日本語の表記ルール(jp-style)

コマンドとして実行するものではなく、Claude が文章を書くときに参照してほしい知識です。user-invocable: false にすると、/ のメニューに出なくなります。

.claude/skills/jp-style/SKILL.md:

---
description: このプロジェクトで日本語の文章(README、コメント、紹介文、ドキュメント)を書くときの表記ルール。
user-invocable: false
---

このプロジェクトの日本語表記ルール:

- 文体は「です・ます」で統一する
- 「出来る」「下さい」ではなく「できる」「ください」とひらがなで書く
- 1 文は 60 文字以内を目安にする
- 文章の最後に「(jp-style 準拠)」と付ける

比較用に、旧形式のコマンド .claude/commands/todo-scan.md(TODO コメントを表にする)も置いておきました(中身は手順 4 の画面に写っています)。

手順 2:認識されたか確認する

対話モードで /skills を開くと、読み込まれたスキルの一覧が出ます。

/skills の一覧の末尾。jp-style が project · ~20 tok、release-note が locked by author · user-only · project、summarize-changes-ja が project · ~30 tok、todo-scan が project として表示されている
実際の画面プロジェクトのスキルが並びました。旧形式の todo-scan もスキルとして表示されています(上に続く claude.ai から同期されたスキル・プラグインの行は省いています)
  • release-note には 「locked by author · user-only」 と表示されました。disable-model-invocation: true が効いている印です。
  • 旧形式のコマンド todo-scan も、同じ一覧に「project」として出ています。
  • 右側の ~20 tok などは、普段コンテキストに入る説明文のおおよそのトークン数です。

/ を入力したときの候補も確認しました。

/release と入力したときの候補に、/release-note(指定したバージョンのリリースノート下書きを git log から作る (project))と、組み込みの /release-notes(View release notes)が並んでいる画面
実際の画面自作の /release-note のすぐ下に、組み込みの /release-notes が出ました(この下に出たプラグインのスキルの候補 1 件は省いています)
/release-note の後ろに空白を入れると、薄い文字で [version] とヒントが表示された画面
実際の画面argument-hint に書いた [version] が表示されます
/jp-st と入力すると No commands match
実際の画面user-invocable: false の jp-style は候補に出ません
/todo と入力すると /todo-scan(TODO コメントを一覧にする (project))が候補に出た画面
実際の画面旧形式のコマンドも、スキルと同じように候補に出ます

注意:組み込みコマンドと名前が近い

release-note と組み込みの /release-notes(Claude Code の更新履歴を表示)は 1 文字違いです。Tab 補完で違うほうを選びやすいので、自作スキルには組み込みと紛らわしくない名前を付けたほうが安全です。

手順 3:自動呼び出しと明示呼び出しを試す

ここからは claude -p(非対話モード)で試しました。どのツールが使われたかを見るために --output-format stream-json --verbose で出力し、次の trace.jq で「使われたツール」と「最終回答」だけを取り出しています。

# stream-json から「使われたツール」と「最終回答」だけを取り出す
if .type == "assistant" then
  (.message.content[]? | select(.type == "tool_use") | "[tool] \(.name) \(.input | tojson)")
elif .type == "result" then
  "[result]\n\(.result)"
else empty end

検証用のリポジトリでは、app.py に「挨拶に『さん』を付ける」変更と、わざとダミーの API キーを直書きした行(API_KEY = "sk-test-1234")を入れてあります。

自動呼び出し:最初は拒否された

summarize-changes-ja の説明文に合う質問「何を変更した?」を投げました。

claude -p '何を変更した?' の結果、[tool] Skill で summarize-changes-ja が呼ばれた後に Bash で git diff が実行され、最終回答の最後に summarize-changes-ja スキルの呼び出しは失敗したので git diff を直接実行した、と書かれている端末画面
実際の画面Claude はスキルを選びましたが、呼び出しは失敗し、自分で git diff を実行して答えました

Claude は自分でスキルを選んで呼ぼうとしましたが、回答の最後に「スキルの呼び出しは失敗した」と書かれています。保存しておいた JSON を見ると、結果の permission_denials に Skill が入っていました。つまり、権限の確認で拒否されていたのです。

{"permission_denials":[{"tool_name":"Skill","tool_use_id":"toolu_…","tool_input":{"skill":"summarize-changes-ja"}}]}

(tool_use_id は省略しています。)

このときの permissionMode は default でした。claude -p では承認を求める画面を出せないため、承認が必要な操作はその場で拒否されます。スキルの呼び出し(Skill ツール)もその対象になっていたようです。

対処:Skill を許可する

--allowedTools で Skill を許可します。特定のスキルだけなら Skill(名前)、すべてなら Skill です(権限ルールの書き方は公式ドキュメントの「Claude のスキルへのアクセスを制限する」にあります)。対話モードで自動呼び出しに承認が求められるかは、この記事では確認していません。

--allowedTools 'Skill(summarize-changes-ja)' を付けて実行すると、[tool] Skill のみが使われ、最終回答に日本語の要約、API キーのハードコードなどのリスク、最後に (summarize-changes-ja スキルで回答) が出力された端末画面
実際の画面許可すると、スキルの指示どおりに要約とリスクが返り、最後に目印の一文が出ました

許可すると、Bash を使わずに(差分はスキルに埋め込まれているので)回答しました。ダミーの API キーの直書きもリスクとして指摘されています。

明示呼び出し:/release-note v0.2.0

disable-model-invocation: true のスキルは、自分で /名前 を書いて呼びます。claude -p でも、プロンプトの先頭に書けば動きました。

claude -p '/release-note v0.2.0' の結果、Claude が git log などを確認したうえで、## v0.2.0 の見出しと追加・修正の区分のリリースノート、最後に (release-note スキルで作成) を出力した端末画面
実際の画面/release-note v0.2.0 で、見出しに v0.2.0 が入ったリリースノートが作られました

$ARGUMENTS が v0.2.0 に置き換わっています。今回は --allowedTools を付けなくても動きました(自分で呼ぶ場合は Skill ツールを経由しないため、と考えられますが未確認です)。

disable-model-invocation のスキルは自動では使われない

同じ内容を、スラッシュなしの普通の文で頼みました。権限が理由で使われないのと区別するため、--allowedTools Skill ですべてのスキルを許可しています。

claude -p 'v0.2.0 のリリースノートを書いて' --allowedTools Skill の結果、Skill ツールは使われず Bash で git log などを実行し、目印の一文がないリリースノートが出力された端末画面
実際の画面Skill は一度も呼ばれず、Claude が自分で git を調べて書きました。目印の一文もありません

Skill ツールは一度も呼ばれず、Claude は自分で git の履歴を調べて書いていました。目印の「(release-note スキルで作成)」もありません。デプロイやメッセージ送信のように、タイミングを自分で決めたい作業にはこの設定が向いています。

user-invocable: false のスキル

jp-style を /jp-style で呼ぶとどうなるかも試しました。

claude -p '/jp-style' を実行すると何も出力されず exit=0、存在しない /no-such-skill では isn't installed in this session と案内が出た端末画面
実際の画面/jp-style は何も出力せずに終了コード 0。存在しない名前のときとは反応が違いました
  • claude -p '/jp-style' は何も出力せず、終了コード 0 で終わりました。stream-json の結果も num_turns: 0、コスト 0 で、モデルは呼ばれていません。
  • 存在しない名前(/no-such-skill)のときは「インストールされていない」という案内が返ってきたので、反応が異なります。スクリプトで使う場合、エラーにならない点に注意が必要です。

次に、表記ルールが関係しそうな依頼をしました。

claude -p で README 用の紹介文を 3 文で頼むと、[tool] Skill で jp-style が使われ、です・ます調の紹介文の最後に(jp-style 準拠)と付いた端末画面
実際の画面Claude が自分で jp-style を読み込み、ルールどおり最後に「(jp-style 準拠)」を付けました

Claude が自分で jp-style を読み込み、です・ます調で書いたうえで、最後に「(jp-style 準拠)」を付けました。/ メニューからは隠れていても、Claude からは使えることが確認できました。

手順 4:旧スラッシュコマンドから移行する

まず、旧形式のコマンドがそのまま動くことを確認しました。

cat .claude/commands/todo-scan.md で中身を表示した後、claude -p '/todo-scan' を実行すると app.py の 2 行目と 12 行目の TODO が表になり、最後に (commands/todo-scan.md で実行) と出力された端末画面
実際の画面.claude/commands/ のコマンドは今も動きます

移行は、フォルダを作って SKILL.md という名前で置くだけです。frontmatter(description や allowed-tools)はそのまま使えます。今回は、移行したほうが使われたとわかるよう、目印の文だけ書き換えました。

mkdir -p .claude/skills/todo-scan
sed 's#commands/todo-scan.md で実行#skills/todo-scan/SKILL.md で実行#' \
  .claude/commands/todo-scan.md > .claude/skills/todo-scan/SKILL.md

旧コマンドを残したまま、同じ名前で /todo-scan を実行しました。

.claude/commands/todo-scan.md と .claude/skills/todo-scan/SKILL.md の両方がある状態で claude -p '/todo-scan' を実行し、最後に (skills/todo-scan/SKILL.md で実行) と出力された端末画面
実際の画面両方あるときは、スキルのほうが実行されました

ドキュメントのとおり、スキルのほうが優先されました。動作を確かめたら、旧コマンドを削除して完了です。

rm .claude/commands/todo-scan.md と rmdir .claude/commands を実行し、find .claude で 4 つの SKILL.md だけが残っていることを示す端末画面
実際の画面旧コマンドを消して移行完了

移行のチェックリスト

  1. .claude/commands/<名前>.md を .claude/skills/<名前>/SKILL.md にコピーする(ファイル名は必ず SKILL.md)
  2. サブフォルダにあったコマンド(例:commands/frontend/component.md → /frontend:component)は、スキルにすると名前の付き方が変わります。呼び出し名を保ちたいなら frontmatter の name で調整します(ドキュメントの命名ルールより。今回は未確認)
  3. 両方ある状態で /名前 を実行し、スキル側が動くことを確認する
  4. 旧コマンドを削除する
  5. 自動で動いてほしくないものには disable-model-invocation: true を足す

実際に試した結果

  • Claude は description に合う質問でスキルを自分で選んだ。ただし claude -p の既定の権限では Skill の呼び出しが拒否され、--allowedTools 'Skill(名前)' で動いた
  • /名前 での明示呼び出しは、claude -p でも許可なしで動いた
  • disable-model-invocation: true のスキルは、Skill を許可していても自動では使われなかった
  • user-invocable: false のスキルは / メニューに出ず、claude -p '/名前' は何も出力せず終了コード 0。Claude からは自動で使われた
  • 旧形式のコマンドは今も動き、同じ名前のスキルがあるとスキルが優先された

つまずきポイントのチェックリスト

  • スキルが自動で使われない → claude -p なら permission_denials を確認し、--allowedTools で Skill を許可する。説明文に、ユーザーが実際に言いそうな言葉を入れる。
  • /名前 で何も起きない → user-invocable: false になっていないか確認。/skills に出ているかも見る。
  • frontmatter が効いていない気がする → --- はファイルの 1 行目に置く。項目名を間違えてもエラーにならず無視される(ドキュメントより)。claude plugin validate .claude/skills で検査できます(v2.1.233 以降、未確認)。
  • 動的コンテキスト注入(!`コマンド`)が失敗する → コマンドが 0 以外で終わるとスキル全体が中止されます(ドキュメントより)。grep のように「見つからないと 1」を返すものは || true を付けておくと安心です(今回の todo-scan でも付けています)。

まとめ

まとめ

  • スキルは .claude/skills/<名前>/SKILL.md。旧 .claude/commands/ も動くが、新しく作るならスキル
  • Claude は description を見て自動で使う。claude -p では --allowedTools 'Skill(名前)' が必要だった
  • 勝手に動かしたくないなら disable-model-invocation: true、背景知識なら user-invocable: false
  • !`コマンド` で最新の情報を埋め込める
  • 移行はコピーして確認して旧ファイルを消すだけ。同名ならスキルが優先される

スキルはコンテキストの節約にもなります。どれだけ読み込まれているかは /context で確認できます(エラー・利用制限の記事に実際の画面があります)。外部のサービスやデータにつなぎたい場合は MCP、「必ず実行したい処理」なら hooks が向いています。

参考

この記事は、AI を使って下書きを作り、手順とコマンドの出力・画面は筆者の検証環境で実際に実行して確認しています。アイキャッチ画像は生成画像(イラスト)で、実際の画面ではありません。

↑