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つの問いに答える:どう移行するか、そして移行する価値があるのか。
公式の互換性保証は明確だ。.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 はエントリーポイントで、同じディレクトリには任意の補助ファイルを置ける。こんな構成を想像してほしい:
.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行以内に収め、それ以外は補助ファイルに逃がすことを推奨している。
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 が自動でロードするが、ユーザーが手動で叩く意味はない)に向いている。
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 の宣言的属性に変えたということだ。
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/ に残したほうがいい条件:
単純な /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/ の互換性保証は明確だ——これは「今すぐ全部移行しないと消される」変更ではなく、「新しい能力を渡すが強制はしない」拡張だ。違いを理解して必要なときに移行すればいい、見た目の統一を追う必要はない。