---
title: "読まない技術 第4回：スキルを使わない技術"
author: garplab
publisher: TypingTube
license: CC BY 4.0
license_url: https://creativecommons.org/licenses/by/4.0/
license_scope: 「CC BY 4.0」の印から始まる節（仕組み・検証手順・コード）。印の無い本文は著作権を留保
canonical: https://typing-tube.net/articles/8f9ae8791b448d
series: "バイブコーディングにおける読まない技術"
language: ja
---


> この記事は、連載「読まない技術」の第 4 回です。各回はファイルやスクリプトを一つ置けば完結します。連載の全体像と各回の一覧は[序論](https://typing-tube.net/articles/34b02627c718fa)にあります。

今回は、スキルの話です。スキルというのは、AI にカスタムコマンドやツールを登録しておく仕組みのことです。使う条件を AI に選ばせるのをやめて、代わりに何を置くかを扱います。

まず一つだけ、数えてみてください。AI に登録してあるスキル（カスタムコマンド、ツール）はいくつありますか。そのうち、**直近 1 週間で AI が自分から選んで使ったもの**はいくつありますか。

登録した数より使われた数がずっと少ないなら、書き方が悪いのではありません。スキルは「こういうときに使う」という条件文付きの道具登録で、使うかどうかの判断を AI に委ねます。コストは二重です。条件文は一覧ごと毎セッション読み込まれるので、**登録しただけで常駐コンテキストが増える**。そして似た条件文が並ぶほど食い合って、一番使ってほしいものほど埋もれる。[序論](https://typing-tube.net/articles/34b02627c718fa)の「足すほど薄まる」が、ルールだけでなく道具でも起きます。

私の手元の本番プロジェクト——YouTube の音楽動画でタイピング練習ができる Web サービス [typingtube](https://typingtube.net)——には、AI に回させるスクリプトが **84 本**あります（十数言語ぶんの翻訳の検証、デザインのラチェット、ベンチマーク、キャラクター画像の生成……画面に出ている機能の数だけ、裏方の道具があります）。スキル登録は **1 個**です。84 本ぶんの説明文はどのセッションにも常駐していません。

理解したことは一文にできます。

> **スキルは使う条件を並べるほど選ばれなくなる。だから選ばせるのではなく、使う前に読ませる。**

## 仕組み: 選ばせる代わりに、入口で読ませる

コマンドは素のスクリプトのまま置き、使い方はドキュメントに書きます。ここまでは普通です。置くのは hook 1 つ——**間違った入り方をしたときだけ止まって、読むべき 1 枚を案内する**。第 1 回のラッパー案内と同じ形です。

準備が要るコマンドには、一歩進めた形を使います。例は pre-commit hook——コミットのたびに秘密情報の混入や規約違反を落とす類の仕組みで、git の hook の設置が前提です。手順どおりに設置すると `.git/hooks/pre-commit` が生まれます。Claude Code の hook は、AI が `git commit` を打ったら**このファイルの存在だけ**を確かめ、無ければ手順を案内して止まります。

```bash
#!/bin/bash
# .claude/hooks/require_setup.sh — 手順を踏んだ形跡（生成物）が無ければ止める（実物からの簡約版）
command=$(cat | python3 -c 'import json,sys; print(json.load(sys.stdin).get("tool_input",{}).get("command",""))')
case "$command" in *--no-verify*|*SKIP_HOOK_CHECK=*) exit 0 ;; esac   # 明示の逃げ道は通す
printf '%s' "$command" | grep -qE '(^|[;&|[:space:]])git[[:space:]]+commit([[:space:]]|$)' || exit 0
hooks_dir=$(git rev-parse --git-path hooks 2>/dev/null || echo .git/hooks)   # worktree でも正しい場所を見る
if [ ! -x "$hooks_dir/pre-commit" ]; then
  echo "Pre-commit checks are not installed. Run the setup in docs/setup.md (bash scripts/setup_hooks.sh) first" >&2
  exit 2   # 実行させず、stderr の案内を AI に読ませる
fi
exit 0
```

先に一つ、はっきりさせておきます。**この hook は「ドキュメントを読んだか」を判定していません**。読んだかどうかは測れないからです。見ているのは「**ドキュメントを見なければ作られないファイルの存在**」だけ。そこにファイルがあるなら、経路はどうあれ手順は踏まれています。

これで回るのは、**AI は止められるとドキュメントを探す**からです。止まる → 案内を読む → 手順を踏む → 進む。「いつ使うか」を事前に選ばせる代わりに、「使うなら読む。読んでいなければ動けない」に変わり、必要になった瞬間に必要な 1 枚だけが読まれます。

止まらなかった世界の数字を一つ。この形にする前、私がクローンした作業ディレクトリに pre-commit hook が未設置のまま、**39 コミット、別環境では 2 ヶ月ぶん**が、どの hook も通らずに積もっていました。怖いのは落ちなかったことです。落ちないものには誰も気づきません。

## 読まなくなったもの

スキルの説明文群です。書くのも、AI に毎セッション読ませるのも、選ばれるように条件文をチューニングし続けるのも、私はやめました。84 本のスクリプトの使い方は各ドキュメントに 1 枚ずつあり、読まれるのは止まったときだけです。

## 注意: 入口を全部に付けるのではない

hook を 84 本ぶん書くわけではありません。止める価値があるのは**間違えると高くつく入口**だけ——私の環境ではテスト実行、コミット、サブエージェント起動の数か所です。残りは間違えてもすぐ分かって安いので素のまま。全部にガードレールを立てたら、条件文の一式を hook で作り直すだけです。

## 検証手順: 外して、止まることを確かめる

**前提**

- この回の hook を 1 つ登録し終えていること
- **止める対象のコマンド**と、**存在を確かめるファイル**の組が決まっていること（本文の例では、AI が `git commit` を打ったときに `.git/hooks/pre-commit` の存在を見ます）

**所要時間**: 5 分

**手順**

1. **あなたが**、存在を確かめている側のファイルを退避します（`mv .git/hooks/pre-commit /tmp/` のように）。⚠️ 消すのではなく**退避**です。後始末で戻します
2. **AI に**、対象のコマンドを実行させます（本文の例なら「コミットして」と頼みます）

**合格条件**（すべて満たすこと）

- コマンドが**実行されずに**止まる
- 止まった場所に、**読むべきドキュメントの在りか**が出ている

**合格しなかったとき**

- **止まらずに通ってしまった** —— hook が登録されていないか、見ているパスが手順 1 で退避したファイルと違います
- **止まったが、案内が出ない** —— hook は半分しか働いていません。⚠️ 行き先を示されなかった AI は、その場で自分の回り道を探し始めます

**後始末**

- 退避したファイルを元の場所へ戻し、**同じコマンドをもう一度** AI に実行させます。今度は止まらずに通れば終わりです
- まだ止まるなら、hook が見ているパスと、あなたが戻した場所が食い違っています

止める仕組みは「止まらない」方向に壊れます。一度も止まったことのない hook は、動いている hook と**同じ見え方をします**。どちらも、黙って通すからです。

---

次回からは応用編、「サブエージェントの出力だけは読め」。**サブエージェントの出力だけは、読まないととんでもないことになります。**

---

**連載「読まない技術」**

- ← 前回: [第 3 回 単体テストを読まない技術](https://typing-tube.net/articles/e4ad91d2fd6c67)
- → 次回: [第 5 回 サブエージェントの出力だけは読め](https://typing-tube.net/articles/62f714d7c2b599)
- 全回の一覧: [序論 AIの出力を、もうほとんど読んでいない](https://typing-tube.net/articles/34b02627c718fa)
