# Claude Code skill スターターキット

配布元: AIディア（株式会社PENGIN） https://aidia.pengi-n.co.jp/articles/claude-code-skills/
作成日: 2026-09-09 / ライセンス: 自由に使ってください。帰属表示は不要です。

このキットは「SKILL.md をどう書くか」ではなく、**書いた skill が起動されるようにする**ためのものです。
配布元の環境では、定義済み64本のうち35日間で起動されたのは3本でした。
そのとき効いたのは description の厚さではなく、常時ロード層からの名指しでした。

顧客名・実案件・認証情報・社内パスは含んでいません。

---

## 0. まず数える（推測でやらない）

どれが使われていないかを、感覚で決めないでください。
下のスクリプトを保存して実行すると、自分の環境の起動実数が出ます。

```python
# skill_usage.py
import json, os, pathlib
from collections import Counter

projects = pathlib.Path(os.path.expanduser("~")) / ".claude" / "projects"
calls, tools, sessions, with_skill = Counter(), 0, 0, set()

for jf in projects.rglob("*.jsonl"):
    sessions += 1
    for line in jf.read_text(encoding="utf-8", errors="replace").splitlines():
        if not line.strip():
            continue
        try:
            rec = json.loads(line)
        except ValueError:
            continue
        if rec.get("type") != "assistant":
            continue
        for b in (rec.get("message") or {}).get("content") or []:
            if isinstance(b, dict) and b.get("type") == "tool_use":
                tools += 1
                if b.get("name") == "Skill":
                    calls[(b.get("input") or {}).get("skill", "?")] += 1
                    with_skill.add(jf.stem)

print("sessions          :", sessions)
print("tool calls        :", tools)
print("skill calls       :", sum(calls.values()))
print("skill share       : {:.3f}%".format(100.0 * sum(calls.values()) / max(1, tools)))
print("sessions w/ skill : {} ({:.1f}%)".format(len(with_skill), 100.0 * len(with_skill) / max(1, sessions)))
for name, n in calls.most_common():
    print("  ", name, n)
```

出力は件数だけです。会話本文・顧客名・パスの中身は読みません。

### 定義した数と、起動された数を突き合わせる

```python
# skill_inventory.py
import os, pathlib

home = pathlib.Path(os.path.expanduser("~"))
found = {}
for root, kind in [(home / ".claude" / "skills", "personal"),
                   (home / ".claude" / "plugins", "plugin")]:
    if not root.exists():
        continue
    for sk in root.rglob("SKILL.md"):
        found.setdefault(sk.parent.name.split(":")[-1].lower(), kind)

print("定義済み:", len(found))
for name, kind in sorted(found.items()):
    print("  ", name, kind)
```

`skill_usage.py` の出力に出てこない名前が、あなたの死蔵 skill です。

---

## 1. SKILL.md の最小テンプレート

必須は `SKILL.md` だけです。`references/` `templates/` `scripts/` `assets/` は必要になってから足します。

```
~/.claude/skills/<skill-name>/
└── SKILL.md
```

```markdown
---
name: <skill-name>
description: <何をするか1文>。TRIGGER when：「<ユーザーが実際に打つ言葉1>」「<言葉2>」「<言葉3>」。SKIP for：<この skill を使わない場面>。
---

## 使う前に確認すること
- <この skill が前提にしている環境・権限>

## 手順
1. <ステップ>
2. <ステップ>
3. <ステップ>

## 承認が必要な操作
- <外部送信・本番反映・削除に当たるもの。1件ずつ承認を取ると明記する>

## やらないこと
- <よくある誤用>
```

frontmatter はすべて任意で、推奨されているのは `description` だけです。
手動起動だけにしたいときは `disable-model-invocation: true` を足します。

---

## 2. description を条件文に直す（前後の実例）

長く書くほど良い、ではありません。skill 名と説明の一覧は毎セッション読み込まれ、
一覧が文字予算を超えると、呼び出し回数の少ない skill から説明が削られます。
配布元の環境では、一覧の合計が 26,102 字あり、既定の 1% 予算（1M コンテキストで 10,000 字）の 261% でした。

### 直す前（起動0回だったもの）

```yaml
description: サイトのトンマナ・配色・タイポグラフィ・余白設計の方針を、
  参考サイトの分析から言語化して提案するスキル。ヒアリング内容と
  参考サイトのスクリーンショットをもとに、ブランドの性格づけ、
  カラーパレット、フォント選定、余白のリズム、写真の方向性までを
  一貫した資料としてまとめる。デザイナーへの発注前の共通言語づくりに使う。
```

何をするかは詳しく書けていますが、**いつ呼ぶのかが書かれていません。**
そしてユーザーが実際に打つ言葉が1つも入っていません。

### 直したあと

```yaml
description: トンマナ提案を作る。TRIGGER when：「トンマナ決めて」「配色どうする」
  「参考サイトに寄せて」。SKIP for：既存デザインの微修正、コーディング。
```

原則は3つだけです。

1. **ユーザーが実際に打つ言葉を前に置く。** 一覧が短縮されても前は残ります
2. **TRIGGER と SKIP を書く。** 呼ぶ条件と呼ばない条件の両方
3. **短くする。** 使っていない skill の説明ほど先に削られるので、長さで殴っても勝てません

---

## 3. 常時ロード層に1行足す（これが本体）

配布元の環境で、起動13回と0回を分けたのはこの1行でした。
`~/.claude/CLAUDE.md`（またはプロジェクトの `CLAUDE.md`）に、依頼と skill の対応表を置きます。

```markdown
## タスクトリガー（依頼内容で起動するものが決まる）

| 依頼パターン | 起動するもの |
|---|---|
| Chatwork へ送る / 報告する / 共有する | `chatwork-send` SKILL を起動 |
| GA4 / Search Console / スプレッドシートを扱う | `google-data` SKILL を起動 |
| <あなたの依頼パターン> | `<skill-name>` SKILL を起動 |
```

**手順はここに書きません。** 書くのは対応だけです。
手順を CLAUDE.md に書くと毎回読まれ、他の指示が薄まります。
skill の中身は呼ばれたときにだけ読まれる、という性質を捨てないでください。

---

## 4. 振り分け表：skill にしないほうがよいもの

| やりたいこと | 置き場所 | 理由 |
|---|---|---|
| 破ったら事故になる操作を止める | **hooks** | 登録した対象のツール呼び出しを必ず通る。skill は通らない |
| 決まった1手順を手で呼ぶ | **commands / skill のスラッシュ起動** | 覚えていられるなら十分 |
| 3ステップ以上の作法一式 | **Skills** | 使うときだけ読み込める |
| 判断基準と、下の層への導線 | **CLAUDE.md** | 毎回読まれる。増やすほど薄まる |
| コンテキストを分けたい調査・独立監査 | **subagent** | 中間生成物を本体に読ませない |
| 参照するだけの資料 | **knowledge / references** | 行動は規定しない |

判断の順番は「守らせたいのか、思い出させたいのか」です。
守らせたいものを skill に書くと、届く頻度が桁で落ちます。

---

## 5. 承認の線引き（skill に実行系を持たせる場合）

`allowed-tools` は「そのスキルが動いている間、承認を求めずに使えるツール」を指定する欄です。
利用可能なツールを**制限する**欄ではありません。付与する側です。

| 区分 | 扱い | 例 |
|---|---|---|
| 読む・調べる・下書きする | 承認なしで実行 | ID解決、過去ログ確認、下書き作成 |
| ローカルへ書く | 実行して差分を証拠に残す | ファイル保存、テスト実行 |
| 外部へ送る・本番へ出す・消す | **1件ずつ承認を取る** | メッセージ送信、デプロイ、削除 |

```yaml
# 事前承認してよい例（読み取り系のみ）
allowed-tools: Bash(git status *) Bash(git diff *) Read Grep

# 事前承認しない（skill が自動起動した瞬間にゲートが消える）
# allowed-tools: Bash(git push *) Bash(rm *)
```

skill 本文にも、承認の線を文章で書いておきます。

```markdown
## 承認が必要な操作
- 送信・アップロード・削除は、対象1件ごとに承認を取る
- 提示はまとめてよいが、同意は1件ずつ取る
- 過去の承認を別の操作へ流用しない
```

まとめて取った承認は、別の操作へ流用されます。ここは実際に事故が起きた側の話です。

---

## 6. 1週間後にもう一度数える

`skill_usage.py` を1週間後に回します。判定はこれだけです。

- **増えた** → その skill は生きています。description をさらに削って軽くする
- **増えない** → skill に向いていない作業です。hooks か commands へ移すか、消す

**直らないものを直そうとし続けないでください。**
配布元は、この判断をせずに4本を35日放置しました。

---

## 7. トラブルシューティング

| 症状 | 見るところ |
|---|---|
| スラッシュでは動くが自動で呼ばれない | frontmatter の YAML が壊れていないか。不正だと本体が空メタデータで読まれ、一致用の description が無くなる。`--debug` でパースエラーを確認 |
| 一覧に出てこない | 保存場所とフォルダ名。`~/.claude/skills/<name>/SKILL.md` の階層になっているか |
| 説明が途中で切れている | skill の総数が多すぎる。使っていないプラグインを外す。`/doctor` で一覧のコンテキストコストを確認 |
| 呼ばれすぎる | description を具体化する。手動だけにするなら `disable-model-invocation: true` |
| 名前が衝突する | personal がプロジェクトを上書きする。プラグインは `plugin-name:skill-name` で衝突しない |

---

## 参照した公式ドキュメント

- スキルで Claude を拡張する https://code.claude.com/docs/ja/skills （2026-09-09 取得）
- Hooks リファレンス https://code.claude.com/docs/ja/hooks （2026-09-09 取得）

実測の詳細と集計方法は記事本文にあります。
https://aidia.pengi-n.co.jp/articles/claude-code-skills/
