$ARGUMENTS変数と、具名引数($issue、$branchなど)はどう使い分ければよいですか?
判断基準は、コマンドが複数の、それぞれ明確な用途を持つ入力を必要とするかどうかだ。コマンドが一塊のテキストをそのまま取り込むだけでよい場合(「どの環境にデプロイするか」など)、$ARGUMENTSはコマンド名の後に入力されたすべての内容をそのまま挿入する。これが最もシンプルな書き方だ。
コマンドが同時に複数の異なる用途を持つ引数を必要とする場合(「あるコンポーネントをある言語から別の言語に移行する」など、コンポーネント名、移行元の言語、移行先の言語という3つの情報が同時に必要な場合)、具名引数の方が明確だ——フロントマターのargumentsフィールドに引数名を列挙し、内容内で$名前を使ってそれぞれ参照する。例えばarguments: [component, from, to]と本文の$component、$from、$toを組み合わせ、/migrate SearchBar JavaScript TypeScriptを実行すると、3つの名前が3つの入力値に順番に対応する。すべてを一つの$ARGUMENTSに詰め込んでClaude自身に分解させるより、はるかに信頼できる。
コマンドが単一行ではなく複数行のシェルコマンドを必要とする場合、どう書けばよいですか?
単一行の動的コンテキスト注入は、行頭の!構文を使う(バッククォートの位置に注意し、コマンド!は行頭または空白文字の直後に現れなければならない。そうでなければプレーンテキストとして扱われ、コマンドは実行されない)。一度に複数行のコマンドを実行する必要がある場合は、代わりに三つのバッククォートと感嘆符で始まるブロック構文を使う:
## Environment
node --version
git status --short
```</code></pre><p>このブロック形式は、複数行のコマンドの出力を一度にまとめて注入でき、複数の環境情報を同時に調べる必要がある状況に適しており、各行を個別の<code>!` `</code>文に分割する必要がない。
コマンドを書いてテストにも成功しましたが、しばらくしてSKILL.mdの内容を変更しました。ClaudeCodeを再起動しないと反映されませんか?
再起動は不要だ。個人レベルまたはプロジェクトレベルの.claude/skills/配下にある既存のコマンド内容を編集する場合、ClaudeCodeは現在のセッション内でリアルタイムに変更を検知して適用するので、再起動する必要はない。このリアルタイム検知は、コマンドディレクトリ配下の内容の追加、修正、削除をカバーしている。
一つ例外がある:セッションがすでに開始された後で、それまで存在していなかったトップレベルのSkillディレクトリを初めて新規作成した場合(例えばプロジェクトにもともと.claude/skills/フォルダがなく、セッション開始後に手動で作成した場合)、この場合はClaudeCodeを再起動しないと、新しく現れたこのディレクトリの監視を開始できない——なぜならリアルタイム検知の仕組み自体が、セッション起動時にすでに存在していたディレクトリを対象に監視するものだからだ。
チームの他のメンバーも私が書いたこのコマンドを使いたがっています。どうやって共有すればよいですか?
このコマンドをどの範囲で共有したいかによる。同じプロジェクトのすべての協力者が使えるようにしたい場合、最も直接的なやり方は.claude/skills/summarize-changes/フォルダをバージョン管理にコミットすること(Gitリポジトリに追加するなど)だ。そうすればこのプロジェクトをcloneした誰にとってもコマンドが自動的に有効になり、追加のインストール手順は不要になる——これはこの種のコマンドをプロジェクトレベルで共有する公式推奨方法の一つでもある。
より広い範囲での共有を望む場合、例えば一つのプロジェクトだけでなくチームや組織全体で同じコマンド群を使えるようにしたい場合は、プラグインとしてパッケージ化するか、組織レベルの管理設定を通じて一律にデプロイすることを検討するとよい。単一コマンドの共有にはバージョン管理へのコミットで十分であり、コマンドの数が増え、複数のプロジェクトにまたがって再利用する必要が出てきたときに初めて、より正式な配布形式にする追加の労力をかける価値がある。
「ClaudeCode カスタムslash command 書き方」を検索すると多くのチュートリアルが見つかるが、その一部は/project:command_nameのような名前空間プレフィックス付きの旧構文を示している——これは現在の公式ドキュメントではもはや推奨されるやり方ではない。この記事は、公式が現在示している最新の標準に沿って、ディレクトリの作成からファイルの記述、実際のテストまでの完全な流れを一通り実践し、つまずきやすい箇所を特に指摘していく。
抽象的な「Hello World」の例を書くのではなく、実用的なものを直接扱う:現在のGitプロジェクトでまだコミットされていない変更を要約し、潜在的なリスクを指摘するコマンドだ。このシナリオは、単純なテキスト指示より一段複雑になるよう意図的に選んでおり、「リアルタイムデータを動的に取り込む」という応用テクニックがどう動作するかも同時に見られるようにしている。
公式が現在示している標準的なやり方は、コマンドを単一の.claude/commands/ファイルではなく、Skillディレクトリ構造として書くことだ(後者は依然として動作するが、新しく書く際の推奨方法ではない)。このコマンドを現在のプロジェクトだけで使えるようにしたい場合、プロジェクトレベルのディレクトリを作成する:
mkdir -p .claude/skills/summarize-changes自分のすべてのプロジェクトで使えるようにしたい場合は、個人レベルに置く:
mkdir -p ~/.claude/skills/summarize-changesディレクトリ名自体が、後で入力するコマンド名になる。つまりフォルダ名がsummarize-changesであれば、後で/summarize-changesと打ってトリガーすることになる。このディレクトリ内にSKILL.mdを作成し、内容を二つの部分に分ける:先頭に---で囲まれたYAMLフロントマターがあり、Claudeにこのコマンドをいつ使うべきかを伝える。その下が実際の操作指示だ。
---
description: Summarizes uncommitted changes and flags anything risky. Use when the user asks what changed, wants a commit message, or asks to review their diff.
---
Current changes
!git diff HEAD
Instructions
Summarize the changes above in two or three bullet points, then list any risks you notice such as missing error handling, hardcoded values, or tests that need updating. If the diff is empty, say there are no uncommitted changes.
ここで特に説明する価値があるのは!という一行だ——これは動的コンテキスト注入構文であり、ClaudeCodeはまずこのコマンドをバックグラウンドで実行し、実際の出力結果でこの行を置き換える。Claudeが読むのは「すでに現時点の実際のdiff内容を含んだ」完全なプロンプトであり、自分で調べる方法を考えなければならない空虚な文言ではない。これもカスタムコマンドとプレーンテキストのプロンプトとの重要な違いだ。コマンドは先にリアルタイムデータを調べておき、そのデータをタスクと一緒にClaudeに渡すことができる。git diff HEAD
Gitのあるプロジェクトで、どれか一つのファイルに軽微な変更を加え、ClaudeCodeを起動し、二つの方法でテストできる:descriptionに記述された状況に合致する質問を直接入力する(例えば「何を変更した?」)と、Claudeが自動的にこのコマンドを読み込むべきか判断する。あるいは直接手動でトリガーする:
/summarize-changesどちらの方法でも、Claudeは変更内容の短い要約といくつかのリスク指摘を返すはずだ。
参照しているのが比較的古いチュートリアル記事の場合、/project:command_nameや/user:command_nameのような名前空間プレフィックス付きのトリガー方式の例をよく見かけるだろう。これは旧バージョンのシステムの書き方であり、現在の公式ドキュメントの例はすでに直接/command-nameと書く形に統一されており、追加のプレフィックスは不要だ——もし古いチュートリアルをそのまま真似てプレフィックス付きのコマンドを入力しても反応がなければ、これが通常の原因だ。あるチュートリアルが十分新しいかどうかを見分ける簡単な手がかりの一つは、トリガーコマンドの例示にこの種のプレフィックスが出てくるかどうかを見ることだ。
次に書きたいコマンドが実際の結果を伴う操作(デプロイ、メッセージ送信など)に関わる場合、フロントマターにdisable-model-invocation: trueを追加すれば、このコマンドは自分で手動入力した場合にのみ実行されることを保証でき、Claudeが「タイミングが機が熟したように見える」と判断して勝手にトリガーすることはない:
---
name: deploy
description: Deploy the application to production
disable-model-invocation: true
Deploy $ARGUMENTS to production:
- Run the test suite
- Build the application
- Push to the deployment target
- Verify the deployment succeeded
ここでの$ARGUMENTSは、コマンドを入力する際に付け加えた引数に置き換えられる——例えば/deploy stagingと打てば、Claudeが受け取るのは「Deploy staging to production」となる。
最初のコマンドを書き終えたら、次に「同じプロンプトをもう3回貼り付けた」と気づいたときが、それをコマンドとして書くべきシグナルだ。着手する前に自分に二つの問いを立てよう:このワークフローはリアルタイムデータを動的に取り込む必要があるか(!構文が必要かどうかを決める)、このワークフローに実際の副作用があるか( disable-model-invocation: trueを追加すべきかどうかを決める)。この二点をはっきりさせてから、公式が現在示している構文に照らして書く方が、新旧のわからないチュートリアルをそのまま真似るより信頼できる。