Free

Slash Commands から Skills へ:いつ、どう移行するか

custom commands は Skills に統合された。いつ `.claude/skills/` に移行すべきで、移行すると何が増えるか


これまでの3回で slash command の使い方をひと通り見てきた。Markdown ファイルから始まり、!command の注入、subagent と MCP のオーケストレーションまで。これらの内容は今でも有効だが、公式は裏で一度統合を行った:custom commands は Skills に合流した

.claude/commands/review.md は今も動くし、/review もそのまま使える。何も変更する必要はない。ただし、command にもっと能力を持たせたい場合——複数ファイル、fork 実行、パスによる自動アクティブ化——新しい置き場所は .claude/skills/review/SKILL.md だ。今回は2つの問いに答える:どう移行するか、そして移行する価値があるのか。


最小の移行:パスを1つ変えるだけ、あとはそのまま

公式の互換性保証は明確だ。.claude/commands/deploy.md.claude/skills/deploy/SKILL.md はどちらも /deploy として登録され、挙動は完全に同じ。名前がぶつかった場合は skills が優先される。

最小の手順:

cd .claude/commands
mkdir -p ../skills/review
mv review.md ../skills/review/SKILL.md

ファイルの中身は1行も変える必要がない。YAML frontmatter、!`command`@file$ARGUMENTS——すべて互換。

ただしこれだけだと「じゃあ何のために移したの?」と聞かれる。答えは、skill ディレクトリには複数のファイルを置けるが、command は1つしか持てない、という点にある。


なぜ移行するか:SKILL.md で増える4つのもの

1. 補助ファイル:長いドキュメントを外に出す

SKILL.md はエントリーポイントで、同じディレクトリには任意の補助ファイルを置ける。こんな構成を想像してほしい:

.claude/skills/review/
├── SKILL.md            # エントリ。短い指示 + 参照
├── checklist.md        # 長大なコードレビューチェックリスト
├── examples/
│   └── good-diff.md    # 良い例
└── scripts/
    └── lint.sh         # SKILL.md から呼べるスクリプト

SKILL.md から相対パスで参照する:

現在の diff をレビューし、[checklist.md](checklist.md) の基準に従うこと。
期待する出力形式は [examples/good-diff.md](examples/good-diff.md) を参照。

これらの補助ファイルは自動的には context に入らない——Claude が必要に応じて読む。公式は SKILL.md を500行以内に収め、それ以外は補助ファイルに逃がすことを推奨している。

2. disable-model-invocation:手動でしか呼ばれない skill

デフォルトでは、Claude は適切なタイミングを見て任意の skill を自律的に呼び出す。これは /deploy/commit/send-email のような副作用のあるコマンドには危険だ——「コードが良さそうだから勝手にデプロイしました」は勘弁してほしい。

---
name: deploy
description: 本番環境へデプロイ
disable-model-invocation: true
allowed-tools: Bash(kamal deploy:*), Bash(git push:*)
---

この1行を追加すれば、/deploy はあなたが手動で入力したときだけ発火する。会話の途中で Claude が勝手に呼ぶことはない。

逆の user-invocable: false は「Claude だけが呼び出せて、/ メニューには出てこない」という設定——背景知識型の skill(例えば legacy-system-context、関連シーンで Claude が自動でロードするが、ユーザーが手動で叩く意味はない)に向いている。

3. context: fork:skill をサブエージェントで走らせる

これが最大のアップグレードだ。前回の記事で、command は allowed-tools: Task を使って子エージェントを起動できると説明した——ただしその場合、prompt の中で「Explore サブエージェントを起動して……」と自分で説明を書く必要があった。

SKILL なら frontmatter の1行で済む:

---
name: deep-research
description: あるシンボルを深掘り調査する
context: fork
agent: Explore
---

$ARGUMENTS のすべての用法を調査:
- すべての呼び出し箇所
- ビジネスシーン
- 代替実装

300字以内でサマリを返す。

/deep-research SomeClass を叩くと:SKILL.md 全体が独立したサブエージェントの prompt になり、Explore agent type で実行され、終わったら結論だけが返ってくる。メインの会話の context はまったく汚れない。

これは「サブエージェントを起動する」という行為を、prompt 内の説明文から skill の宣言的属性に変えたということだ。

4. paths:ファイルタイプで自動アクティブ化

---
name: rails-conventions
description: Rails プロジェクトのコーディング規約
paths: ["app/**/*.rb", "config/**/*.rb"]
---

このプロジェクトの Rails 規約に従う:
- fat controller ではなく service object を使う
- ActiveRecord scope には名前をつけること
...

app/models/user.rb を編集しているときには、この skill が自動で context に追加される。package.json を編集しているときには追加されない。CLAUDE.md の常時ロードされる背景情報よりも精度が高い——「パスで階層化した CLAUDE.md」と言える。


実戦:/plan を skill に昇格させる

前回の最後に出た /plan は、もともと単一ファイルの command だった:

.claude/commands/plan.md

skill にすると:

.claude/skills/plan/
├── SKILL.md
├── research-prompt.md     # サブエージェント 1 の指示
└── risk-prompt.md         # サブエージェント 2 の指示

SKILL.md:

---
name: plan
description: Linear チケットから実装プランを作る
disable-model-invocation: true
allowed-tools: mcp__linear__*, Task, Read, Grep, Bash(git log:*)
---

## コンテキスト

@.claude/context/architecture.md

## 状態

!`git log --oneline -10`

## タスク

Linear チケット $ARGUMENTS の説明とコメントを取得。

Task で2つのサブエージェントを並行起動:
1. コード調査:prompt は [research-prompt.md](research-prompt.md)
2. リスク評価:prompt は [risk-prompt.md](risk-prompt.md)

2つの結果を集約し、実装ステップ + リスク一覧 + commit 粒度の提案を出力する。

2つのサブエージェントの prompt を別ファイルに分けておけば、片方だけ直しても SKILL.md を触る必要はない。Skill 本体は30行以内にすっきり収まり、補助ファイルはそれぞれ数百行に及んでもいい。

自分でサブエージェントを指揮したくないなら、もっと攻めてもいい——skill 全体を fork に放り込んで、Explore agent に一気に実行させる:

---
name: plan
context: fork
agent: Explore
allowed-tools: mcp__linear__*
---

/plan ENG-4213 を叩く → 独立した context の Explore agent が SKILL.md の全内容をタスクとして受け取って実行 → 最終プランだけ返ってくる。メインの会話はまったく汚れない。


移行しなくていい場合

すべての command が昇格に値するわけではない。.claude/commands/ に残したほうがいい条件:

  • 単一 Markdown で十分:外出しすべき checklist、examples、scripts がない
  • fork 実行が不要:タスクがメインの会話と密結合で、完全な履歴を見ている必要がある
  • パスによる自動アクティブ化が不要:ユーザーが手動で叩くだけ
  • アクセス制御が不要:Claude に自由に呼ばせても問題ない

単純な /commit/pr-desc は frontmatter + 数行の prompt で済むものだ——.claude/commands/ に置いたほうがむしろ分かりやすい。公式も両方の形式が共存し、どちらも非推奨にならないと明言している。


共存の現状

今の .claude/ で一番すっきりする構成:

.claude/
├── commands/           # 軽量:単一ファイル + シンプルな prompt
│   ├── commit.md
│   └── pr-desc.md
├── skills/             # 重量:複数ファイル / fork / 権限制御
│   ├── plan/
│   │   ├── SKILL.md
│   │   ├── research-prompt.md
│   │   └── risk-prompt.md
│   ├── deploy/
│   │   └── SKILL.md    # disable-model-invocation
│   └── rails-conventions/
│       └── SKILL.md    # paths glob 自動アクティブ化
└── context/
    └── coding-standards.md

一度に全部移行しようとしないこと。移行のトリガーは「この command が膨らみ始めた」だ——本文が200行を超えた、ドキュメントを分けたい、サブエージェントに実行させたい。そのタイミングでパスを変えるのは数分で済む。


まとめ

欲しい能力 commands/ skills/
単一ファイルのプロンプトショートカット
!`command` / @file / $ARGUMENTS
allowed-tools 権限制御
補助ファイル(reference、scripts)
disable-model-invocation 誤発火防止
context: fork + agent: 隔離実行
paths: glob によるパス自動アクティブ化

最初の3つで commands と skills は完全に等価、後ろの4つは skills 固有。必要なものを選べばいい。

公式の方向性は skills に傾いているが、commands/ の互換性保証は明確だ——これは「今すぐ全部移行しないと消される」変更ではなく、「新しい能力を渡すが強制はしない」拡張だ。違いを理解して必要なときに移行すればいい、見た目の統一を追う必要はない。