

Claude Code の拡張層は 3 つあります。
agents/ — 独立 context を持つ subagent(連載第 3 回)
commands/ — slash command。/lint のようにショートカットとして実行される
skills/ — 多段手順 + 文脈を束ねた playbook
このうち commands / skills は、両方とも .md ファイル + frontmatter で書きます。見た目が似ているだけに、使い始めると 「これは command にしたほうがいいのか skill にしたほうがいいのか」 でその都度迫られます。そこを雑にさばくと、チームメンバーが /foo を打ったときに「今何が起きるのか」が予測できなくなります。
本記事では、実運用している 9 つの command と 4 つの skill を題材に、境界線と運用コツを整理します。
command と skill の設計上の違い
「何を command にし、何を skill にするか」の具体的な判断軸(3 つ)
allowed-tools で副作用の範囲を絞るテクニック
disable-model-invocation: true を付けるべきケース
argument-hint / $ARGUMENTS と ! プレフィックスの実動
skill を何本か書き始めて、command とどう棲み分けるか迷っている人
「Claude にだけ重たい処理を繰り返させている」と感じているチームリーダー
破壊的な作業を skill にしたいが、誤作動が怖い人
Claude Code の Slash commands / Skills を一度眺めている
連載第 1 回で「.claude/ は土台・ガード・拡張」の 3 層で見るという話を読んでいる
まず見た目ではなく「起動モデル」で比較します。
| slash command | skill | |
|---|---|---|
| 起動方法 | ユーザーが /foo と打つ — 明示 | 明示もしくはモデルが description を見て自動起動 |
| よくある使い方 | 「1 つのコマンド + 軽い指示」 | 「多段手順 + 判断ロジック」 |
| ファイル構造 | .claude/commands/foo.md 1 ファイル | .claude/skills/foo/SKILL.md と追加リソース |
| 代表例 | /lint 、/fmt 、/test-api | pipeline-trace 、release-notes 、azurite-reset |
| ! プレフィックス | 使うとその行がシェルとして実行 | 同じように使える |
| モデル自動呼び出し | なし(ユーザー明示のみ) | 有り(disable-model-invocation: true で off) |
一番重要な違いは最後の 1 行です。skill は description マッチでモデルが自動トリガーできる、という点で subagent に似ています。command は「ユーザーが明示で叩く」以外の起動経路がありません。
この違いが、後述する「どちらに寄せるか」の判断ロジックに直結します。
中規模のプロジェクトで実際に使っている command ファイルはこういう顔ぶれです。
| コマンド | 中身の要点 |
|---|---|
| /lint | make lint を走らせて、失敗なら file:line を拾って修正提案 |
| /fmt | make fmt と git diff --stat |
| /test-api | cd … && poetry run pytest -x $ARGUMENTS |
| /db-migrate | alembic revision --autogenerate -m “$ARGUMENTS” |
| /up /down | make up / make down |
| /seed | make seed、失敗時は README へ誘導 |
| /pr-summary | git diff --stat と git log を拾って PR 本文を作る |
| /verify-no-prod-touch | live env ディレクトリと destructive Alembic op を grep |
どれも「よく使うシェルコマンド + 軽い指示」のショートカットでしかないことに注目してください。中身はせいぜい 5 〜 15 行、多段の判断ロジックは入りません。
例として /lint だとこういう中身です。
---
description: Run ruff lint + format check on the API package.
allowed-tools: Bash(make:*), Bash(poetry:*), Bash(ruff:*)
---
Run the project lint:
!`make lint`
If anything fails, summarize the diagnostics and propose specific fixes referencing file:line. Do not auto-format unless the user asks.
frontmatter はたった 2 フィールド、本文は 1 コマンド + 補足指示だけです。これが command の「それらしい」重さです。
本文中でバックティック付きの !... と書くと、その行がシェルとして実行され、出力がその位置に挬られます。/pr-summary のように 3 つ 並べれば、実行結果をモデルの手元に一泛させた状態で、周辺の指示を決められます。
Gather the change set:
- Diff stat: !`git diff --stat origin/develop...HEAD`
- File list: !`git diff --name-only origin/develop...HEAD`
- Commit log: !`git log origin/develop..HEAD --oneline`
Produce:
1. **Title** — under 70 chars, conventional-commit style.
2. **Summary** — 1-3 bullets describing *what* and *why*.
このパターンは「その場で使うコンテキストを手元に揃えておいて、モデルの生成はその上でやらせる」という設計です。command の仕事の中でもとくに効きます。
argument-hint を frontmatter に書くと、UI で /foo を打ったときに次の引数が何かをホントしてくれます。本文側で $ARGUMENTS と書けば、ユーザーが渡した文字列に置換されます。
---
description: Run the FastAPI test suite via poetry.
argument-hint: "[pytest-args]"
allowed-tools: Bash(poetry:*), Bash(pytest:*)
---
Run the API test suite (pass-through args: $ARGUMENTS):
!`cd path/to/api && poetry run pytest -x $ARGUMENTS`
/test-api tests/test_foo.py::test_bar のように pytest のパススルー引数を渡せるようになります。
同じプロジェクトの skill を見ると、command とは明らかに重さが違うことがわかります。
| skill | 何をやるか |
|---|---|
| pipeline-trace | 1 つのドキュメントを multi-stage pipeline に流して、どこで詰まったかを切り分ける |
| release-notes | git log をナレージごとにグループして changelog を作る |
| customer-slide-narrative | スライドの PDF + git diff から事実ベースの補足文と図解プロンプトを生成する |
| azurite-reset | ローカル DB とストレージエミュレータの状態を破壊して seed し直す(破壊的) |
どれも 1 コマンドでは済まず、「この順番でこれを見て、何があったら次にこうする」というロジックが中身に入ります。
例として pipeline-trace の SKILL.md はこんな骨格です。
---
name: pipeline-trace
description: Trace a multi-stage pipeline run end-to-end against the local docker-compose stack. Use when a document upload does not produce expected output and you need to localise the failure to a specific stage.
allowed-tools: Bash(make:*), Bash(docker:*), Bash(docker compose:*), Bash(curl:*), Bash(jq:*), Read, Grep
---
# Pipeline trace
You will follow one document through the integrated pipelines container.
## Pre-flight
Confirm the stack is up:
make ps
If any service is down, run `make up` and wait for healthy.
## Step 1 — stage 1 (ingest)
- List blobs in the input container.
- Trigger the endpoint with curl.
- Check the output container for the expected artifact.
- If missing, look at logs for the ingest service.
## Step 2 — stage 2 (transform)
... 以下同様に手順を並べる。
## Troubleshooting
- If the classifier returns empty tags, the LLM prompt is fine; check the upload metadata.
- If a blob is in quarantine, check the move_to_quarantine call site.
framework としては command と同じ Markdown + frontmatter ですが、中身は「人間に渡すトラブルシュート」のスタイルで書きます。「こうしたらこうする」「これが見えたらこちら」という判断分岐を明示するのがポイントです。
skill は .claude/skills/foo/SKILL.md という位置に置きます。つまり foo/ というディレクトリを持てるので、補助スクリプト・テンプレート・リファレンス資料を同梱できます。release-notes に changelog テンプレートを同梱したり、customer-slide-narrative にスライドテンプレを同梱したり、という拡張が可能です。command ではできません。
ここから本題です。迷ったときはこの 3 つを順に見るとめとめまるはずです。
1 〜 2 コマンドで済む → command
3 段以上、判断分岐がある → skill
make lint は 1 コマンドで終わり、分岐は「出た警告をどう説明するか」だけなので command。一方 pipeline のトレースは「ステージ 1 の出力がある/ない」「ステージ 2 は実行されたか」と分岐が何段もあるので skill。
本文だけで足りる → command
テンプレート、サンプル、補助スクリプトが要る → skill
skill はディレクトリを持てるので、SKILL.md 以外のファイルも一緒に読ませたり、補助スクリプトを同梱したりできます。「多段手順」でさえ本文だけで足りるなら command でも構いません。
破壊的、モデルが勝手に走らせると困る → skill + disable-model-invocation: true
それ以外 → command または通常の skill
3 つ目が一番シビアな軸で、次節で詳しく見ます。
skill の frontmatter にこの一行を加えると、モデルはこの skill を自動で起動できなくなり、ユーザーが明示で呼んだときだけ動くようになります。
---
name: azurite-reset
description: Wipe local DB rows and Azurite blobs, then re-seed. Destructive — only invoke when the user explicitly asks.
allowed-tools: Bash(make:*), Bash(docker:*), Bash(docker compose:*)
disable-model-invocation: true
---
これを使うべき典型例は 3 つあります。
破壊的な作業。ローカル DB と Blob の wipe、git reset --hard、Docker volume の削除など。「モデルが『似たような記述を見つけて』勝手に呼んだ」という事故を起こさないため、このフォールドセーフティを付けます。
人間レビューを必須にしたい作業。出力をそのまま外部に出す他、コストがかかる作業。「うっかり走っちゃう」と本当に困るものは、明示呼び出し限定で人間の意思決定を挏みます。
狭いドメインに限定したい作業。例えば「特定顧客への資料作成」のようなものは、たまたまユーザーが似た話をしたからといって勝手に走られると困るので、同じく明示限定にします。
逆に pipeline-trace や release-notes は「モデルが便利だと思ったら勝手に使ってもらって OK」なので、disable-model-invocation は付けません。
frontmatter の allowed-tools は command / skill に共通で、「この command または skill が使えるツール」を明示します。.claude/settings.json の permissions と AND で効きます。
allowed-tools: Bash(make:*), Bash(poetry:*), Bash(ruff:*)
使い方のコツは 3 つあります。
使うコマンドだけを列挙する。/lint は make / poetry / ruff しか使わないので、それ以外の Bash コマンドは拒否されるように明示します。これだけで 「/lint を叩いたらやっぱり git status も見ようとした」という脱線を防げます。
人間へのドキュメントとしても効く。allowed-tools を読めば「この command と付き合うコマンドはこれだけ」がわかります。チームメンバーが他人の command を読んだとき、中身の見込みが一気につきます。
skill ではスコープステップごとに必要なツールだけを並べる。pipeline-trace なら docker / curl / jq / Read / Grep、release-notes なら Bash(git:*) だけ、という具合です。余計に与えないことで「この skill でやるべきこと」が明確になります。
最後に、command / skill をチームで長期運用するための設計原則を 1 つだけ。
「/foo を叩いたら何が起きるか」が予測できる状態を保つ。
command は「そのシェルコマンド + 軽い助言」だけ、という予測を保つ
skill は「この SKILL.md を読み、その手順に従う」という予測を保つ
両者を混ぜない — command の中で「状況に応じて 5 段適応」は書かない、skill の中で「1 行だけ」にはしない
この予測可能性が衰えると、チームメンバーは / を叩くのをやめます。.claude/ の拡張層が保動体になるか、それとも生きたためのツールになるかは、この「予測可能性」をどこまで守れるかに掛かっています。
「迷ったら command」をデフォルトにしない。多段手順を command に詰め込むと、何が起きるかを予測しづらいショートカットになる。逆に skill にはもっと重い値打ちのものを入れる
! プレフィックスは command の最大の武器。シェル出力をその位置に挬らめるので、「diff を見てコメントしろ」という仕事と相性がよい
disable-model-invocation は選ぶべきときに選ぶ。付けすぎると skill の価値が下がるし、付けなさすぎると事故につながる
allowed-tools は「使うツール」だけ並べる。「とりあえず Bash フル許可」なら frontmatter に書かないと同じなので、意味が薄れる
skill はディレクトリだという記憶を生かす。テンプレートやサンプルを同梱して「これに頂天して説明して」と言えると、skill の価値が一段上がる
command は「1 コマンド + 軽い指示」のショートカット、skill は「多段手順 + 判断ロジック」の playbook
迷ったら 3 つの軸で見る: 手順の段数 / リソース同梱の必要性 / 破壊的か
破壊的・明示呼び出し限定にしたい skill には disable-model-invocation: true を付ける
allowed-tools で副作用の範囲を絞り、チームメンバーへのドキュメントとしても機能させる
「/foo を叩いたら何が起きるか」の予測可能性を守ることが長期運用の鍵
全 4 回で話したことをシンプルにまとめるとこうです。
第 1 回: Claude Code Harness 入門 — .claude/ を「土台・ガード・拡張」の 3 層で設計する
第 2 回: hook で事故を未然に防ぐ — ガード層は exit 2 でブロック / exit 1 で警告
第 3 回: subagent 設計 — 独立 context window でスクラッチスペースを切り離す
第 4 回(本記事)— command / skill を「予測可能性」で棲み分ける
Claude Code のハーネスエンジニアリングは「個人の便利ツール」を「チームの標準装備」に変える作業です。事故を下層で止め、作業を上層で型化し、その間を人間の意思決定と LLM の柔軟さで埋めていく — という設計思想が、連載を通して伝わっていれば嬉しいです。