repo に機械ゲート(format / lint / type check / security / dependency audit / test)を立てる、または既存のゲートが古びていないか棚卸しする。Use when starting a new project, when a repo has no automated quality gate, when the user says 「lint を入れて」「この repo にゲートを立てて」「型チェックを入れたい」「静的解析を整備して」「ツールが古い」「verify を棚卸しして」, \"set up linting\", \"add a quality gate\", \"bootstrap the toolchain\", or invokes /verify-bootstrap. 使うツールは skill が知っているのではなく、その時点で search-first に調べさせる — repo のスタックが何であれ同じ手順で回る。NOT for — 既に立っているゲートを 1 回実行するだけ(それは repo の...
Scanned 9/4/2026
Install to Claude Code
npx -y skills add shimo4228/claude-harness --skill verify-bootstrap --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Verify Bootstrap?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/shimo4228-verify-bootstrap)More formats (shields.io, HTML) on the badges page.
---
name: verify-bootstrap
description: "repo に機械ゲート(format / lint / type check / security / dependency audit / test)を立てる、または既存のゲートが古びていないか棚卸しする。Use when starting a new project, when a repo has no automated quality gate, when the user says 「lint を入れて」「この repo にゲートを立てて」「型チェックを入れたい」「静的解析を整備して」「ツールが古い」「verify を棚卸しして」, \"set up linting\", \"add a quality gate\", \"bootstrap the toolchain\", or invokes /verify-bootstrap. 使うツールは skill が知っているのではなく、その時点で search-first に調べさせる — repo のスタックが何であれ同じ手順で回る。NOT for — 既に立っているゲートを 1 回実行するだけ(それは repo の verify entrypoint を直接実行)、ハーネス自身の設定監査(→ config-gc)、コードの意味的レビュー(→ implementation-chain の Review 群)。"
compatibility: Developed and tested on Claude Code; portable to other Agent Skills-compatible agents.
license: MIT
metadata:
author: shimo4228
version: "1.0"
user-invocable: true
origin: shimo4228
---
# verify-bootstrap — repo に機械ゲートを立てる
人間がコードを読む速度は、AI が書く速度に追いつかない。だから構造的な正しさの判定は
**機械に移す**。この skill は repo ごとに、
その時点で最良の検査ツールを立てる。
## この skill が持たないもの(設計上の中核)
**ツール名の一覧を持たない。言語の検出テーブルも持たない。** ツールは陳腐化する
(flake8 + black + isort → ruff は 2 年で起きた)。固定表を持てば表が腐り、
腐った表が repo に配られる。
持つのは **調べ方と契約**だけ:
- repo の実態を列挙する手順(静的な言語リストを参照しない)
- category ごとに何を search-first に問うか
- 生成物 `.claude/verify.sh` の契約(global hook がこれだけを知る)
- strictness と陳腐化検知の規律
結果として、この skill が書かれた時点で存在しなかった言語・ツールでも同じ手順で回る。
## モード
| モード | 起動条件 | やること |
|---|---|---|
| **bootstrap** | `.claude/verify.sh` が無い | Step 1–6 を通す |
| **audit** | 既にある(`--audit` / 「棚卸し」) | Step 1 を再実行し、`.claude/verify.md` の選定を search-first で引き直して差分を提案 |
## Step 1 — repo の実態を列挙する(検出、静的表なし)
推測しない。**実測する**。
```bash
# 追跡ファイルの拡張子分布(上位)— 生成物・依存ディレクトリは除く
git ls-files | sed -n 's/.*\.\([A-Za-z0-9_]*\)$/\1/p' | sort | uniq -c | sort -rn | head -20
# ビルド/依存マニフェストの実在
git ls-files | grep -iE '(^|/)(pyproject\.toml|package\.json|Cargo\.toml|go\.mod|Gemfile|pom\.xml|build\.gradle.*|\*\.xcodeproj|Package\.swift|mix\.exs|composer\.json|Makefile|justfile)$'
# 既存のゲート痕跡(重複導入の防止)
git ls-files | grep -iE '(pre-commit-config|lefthook|\.github/workflows/|trunk\.yaml|\.golangci|\.eslintrc|ruff\.toml)'
```
上のマニフェスト grep は**発見の補助であって権威ではない**。1 本目の拡張子分布が正本で、
grep に載っていない生態系が出てきたらそれを Step 2 にそのまま渡す(表を編集して
この skill に足さない — 表を持たないことがこの skill の設計)。
散文・設定・スキーマも対象に含める。コードだけがゲートの対象ではない
(Markdown の日本語 prose、YAML、CI 定義、シェルスクリプトはいずれも機械検査できる)。
## Step 2 — category ごとに現時点の最適ツールを調べる
検出した生態系ごとに、**6 category** を埋める。埋まらない category は「無い」と明記する
(空欄と「その言語には該当がない」は別物)。
| category | 問い |
|---|---|
| **format** | 整形の正規化。差分ノイズを消し、レビュー対象を意味の変化だけにする |
| **lint** | 構造的な誤り・複雑度・デッドコード |
| **type check** | 型で表現できる契約。型なし言語なら「型注釈を段階導入する手段があるか」 |
| **security** | 危険な構文・秘密の混入(秘密スキャンは harness 側にもあるので重複を確認) |
| **dependency** | 既知脆弱性・未使用依存・ライセンス |
| **test** | テストランナーとカバレッジ測定 |
**予算系 rule(閾値を要する複雑度・関数/ファイル長・bundle サイズ等)は既定に頼らない。**
主要 linter は予算系を既定 OFF で出荷するのが通例(閾値が opinionated なため)—
「最大 strict」の運用では構造的に素通りする(2026-08-28 実測でカバー 0 を確認 —
数値の正本は ADR-0056)。lint category を埋めるとき明示的に問う。stack の標準 toolchain が
既定で予算を持つ場合(例: SwiftLint の cyclomatic_complexity / file_length)は追認して
verify.md に 1 行記録するだけでよい。閾値は global に定めない — repo 間で分布は数倍
割れる(同実測、正本は ADR-0056)。
既存 corpus 全件の分布を実測してから、現状の外れ値だけが赤くなる位置に置く
(skill `review-to-lint` の免除境界の原則。ゲートを初日に赤くする閾値は設計ミス)。
**lint / type check の選定方針は LLM-first**(読者・編集者とも LLM で、人間はコードを
読まない前提。2026-08-31 の harness 棚卸しで確立 — 実例と根拠は
`~/.claude/.claude/verify.md` の同日付節)。言語を問わず同じ 4 軸で select を組む:
1. **バグクラス検出**(未定義名・未使用・既知の危険パターン・型矛盾)— 無相関の
検証者の中核。最優先
2. **正準形**(formatter・import 順)— 目のためでなく diff 安定のため。別セッションが
触っても偽 diff が出ない = golden・review が静かに保てる
3. **予算**(複雑度・ファイル長)— context 制限つきの次の編集者のための編集信頼性予算
(閾値は上の分布実測で)
4. **境界の明示型強制** — 型は機械検証可能な仕様で、再生成・別セッション編集の凍結端。
production 側のみ(テスト関数は消費される境界ではないので除外)。
Python での実装例: ANN001-003 + ANN201 + ANN401、`tests/**` 除外
**人間美学系(docstring 様式・命名規約・コメント整形)は select しない。** 削る対象では
なく、最初から入れない。「人間が読みにくい」だけを理由とする rule には LLM-first の
正当化が立たない。
各 category について **`search-first` skill を呼ぶ**(WebSearch を直接叩かない —
依存追加・自作 utility の前は search-first、が `rules/common/planning.md` の配線)。問いには必ず
「**今日の日付時点で**」の時点指定と「既存の代替から乗り換えが起きていないか」を含める。
記憶している定番を答えにしない — この skill が防ごうとしているのはまさにそれ。
Verdict が出たら、次を確認してから採用する:
- **最終リリースが 12 ヶ月以内か**(放置プロジェクトを新規 repo に入れない)
- **単一バイナリ / on-demand 実行が可能か**(`uvx` / `npx` / `brew` 等。repo の
実行環境を汚さずに走るか)
- **設定を持ち込めるか**(strictness を宣言でき、例外を許可リスト化できるか)
- **CI とローカルで同じものが走るか**(乖離するとローカルが形骸化する)
## Step 3 — 最大 strict で導入する
**既定は最大 strict**。AI は厳しさに文句を言わないので、従来「人間の忍耐」を理由に
緩められていた分の天秤は正しさ側に倒す。
- 警告を warning のまま放置しない — **error にする**
- 型の抜け穴(`any` 相当・型チェック抑制コメント)を **禁止側に倒す**
- 版を **pin する**(`ruff==0.16.0` のように。supply chain の固定。bump は手動)
- 例外は**インラインの抑制コメントでなく、設定ファイルの許可リストで理由付き**に
(インライン抑制は理由が消えて無限増殖する)
**新規 repo は初日から最大 strict**(drain すべき負債がゼロなので ratchet 不要)。
**既存 repo への後付けだけ ratchet を使う** — 全 rule を warn で入れ、既存違反を
drain し切ってから error に上げる。初日から block にすると「回避の作法」が育つ。
予算系 rule の閾値も同じく**一方向** — 超過したら閾値を上げるのではなく**刈る**
(dead code・重複の除去、分割)。閾値の設定行に「上げずに刈る — 変更は verify.md に
日付つき理由」のコメントを付ける。ゲートが赤くなった瞬間に config を触る agent の
目に入る位置が、この運用規約の配達点である。
## Step 4 — `.claude/verify.sh` を生成する(global hook との契約)
repo が持つ **唯一の入口**。ハーネス側の hook はこのファイルの存在と exit code しか
見ない — だから repo が何語で書かれていても hook を変更せずに済む。
**契約(厳守)**:
| 項目 | 仕様 |
|---|---|
| パス | `<repo root>/.claude/verify.sh`(実行可能) |
| 引数 | `--staged` = commit 境界の高速検査(staged ファイルのみ)。引数なし = repo 全体の完全検査 |
| 環境 | `$VERIFY_REPO_ROOT` があれば repo root として使う(承認機構が渡す) |
| exit code | `0` = PASS / `1` = FAIL(commit を止める)/ `2` = 検査不能(ツール不在等、fail-soft) |
| 出力 | FAIL 時は**人間と LLM が読んで直せる検出行**。PASS 時の出力は **advisory**(commit は止めないが伝えたいこと — 昇格待ちの ratchet、眠っているゲートの通知)として `verify-precommit.sh` が model へ渡す。言うことが無ければ**無出力**(無言 PASS にノイズを足さない)。**stdout と stderr は区別されない** — hook は `2>&1` でまとめて受けるので、成功時に stderr へ出る進捗・非推奨警告も advisory になる。黙っていたいものは黙らせる |
| 実行時間 | `--staged` は**数秒以内**。超えるものは無引数側にだけ置く |
**速い / 遅いの分離**(これを守らないと bypass の作法が育つ):
- `--staged`: format check・lint・security scan(ファイル単位で完結するもの)
- 無引数: build・type check・test・dependency audit(repo 全体・分単位)
ツール解決は `PATH にあれば使う → 無ければ on-demand 実行(uvx / npx 等)→ それも
無ければ exit 2 で fail-soft`。**fail-soft でも無音にしない** — どのゲートが眠って
いるかを stdout に出す(眠っているゲートは、無いゲートより危険)。
**実装上の罠(どちらも実測で踏んだもの)**:
- **repo root は `$VERIFY_REPO_ROOT` → 自分自身の位置、の順で決める** — cwd 起点にすると
hook 経由で**別 repo を検査して無言で PASS する fail-open** になる。承認機構は照合済み
バイト列を一時ファイルに置いて実行する(TOCTOU 回避)ので `BASH_SOURCE` が repo を
指さない場合がある。両対応が必須:
```bash
if [[ -n "${VERIFY_REPO_ROOT:-}" ]]; then
ROOT="$VERIFY_REPO_ROOT"
else
ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P) || exit 2
fi
```
- **追跡されているか確認する** — `.gitignore` が `.claude/*` を除外している repo は多い。
除外されたままだと CI と他クローンからゲートが消える。`git check-ignore` で確認し、
必要なら `!.claude/verify.sh` / `!.claude/verify.md` を足す
**生成しただけでは commit 境界で走らない** — hook は permission プロンプトを経ずに実行するため、
「ファイルがある」を「実行してよい」と読み替えない設計になっている(clone しただけの外部 repo で
コードが自動実行される経路を塞ぐ)。**人間が内容を読んで承認**して初めて実行される:
```
python3 ~/.claude/scripts/hooks/verify_allow.py approve <repo>
```
承認は内容ハッシュに紐づくので、`verify.sh` を編集したら `verify_allow.py` の台帳を更新する前に
新しい本文を確認する。これは permission prompt を経ない repo-local code 実行の信頼境界である。
生成した `verify.sh` は**その場で 1 回実行して動作を確認する**。さらに
**違反を一時注入して category ごとに発火を実証する**(format 崩し・未使用 import・
`eval` 等)。PASS するだけの確認は、ゲートが眠っていても PASS するので証拠にならない。
実証が済んだら注入した probe を必ず削除する。
## Step 5 — 選定を記録する(陳腐化を可視化する)
`<repo root>/.claude/verify.md` に、category ごとに次を残す:
```
## type check
tool: pyright ==1.1.x
選定日: 2026-07-31
理由: mypy より速く既定が strict。ty / pyrefly は 2026-07 時点で pre-1.0
再調査トリガー: 12 ヶ月経過 / 代替が 1.0 到達 / 現行ツールの最終リリースが 12 ヶ月以上前
```
この記録が無いと audit モードが「何を引き直すべきか」を判断できない。
**選定日と再調査トリガーは必須**、理由は 1 行でよい。予算系 rule は**閾値と実測分布の
as-of** も記録する(例: `C901=15 — p99=14、2026-08-28 実測`。audit 時に分布の再実測と
突き合わせる基点になる)。
## Step 6 — CI に同じものを配線する(任意だが推奨)
ローカルゲートだけでは、bypass された commit が素通りする。CI が `.claude/verify.sh`
を無引数で実行する job を持てば、ローカルと CI の乖離が構造的に起きない
(**同じ入口を両方から呼ぶ**。CI 用に別のコマンド列を書くと必ず drift する)。
## audit モード
1. Step 1 を再実行(stack が変わっていないか — 言語が増えていれば category が空く)
2. `.claude/verify.md` の各 category について、**再調査トリガーに該当するものだけ**
search-first で引き直す(全件引き直すと毎回コストが出る)
3. 差分を提示: 現行 → 候補、乗り換えコスト、据え置きの理由
4. 判断はユーザー。**自動で乗り換えない** — ツール変更は repo 全体の diff を生み、
元に戻すコストが導入コストを上回る
## アンチパターン
- **固定のツール表をこの skill に足す** — 表が腐り、腐った表が全 repo に配られる。
Step 1–2 を回すコストを惜しんで表を作った時点でこの skill は死ぬ
- **インラインの抑制コメントを許す** — 理由が消え、例外が無限に増える
- **警告を warning のまま運用する** — 誰も見ない。error にするか、消すか
- **repo 固有の特殊ルールを積む** — 「この repo だけ独自」は設計不足のサイン。
まずスタックを標準に寄せ、それでも要る例外だけ理由付きで許可リストへ
- **遅い検査を `--staged` に入れる** — commit のたびに数十秒待たされ、bypass が常態化
- **生成して実行せずに終える** — 動作未確認のゲートは、無いゲートより悪い(あると誤認する)
## 関連
- Phase 0 のエントリポイント: skill `search-first`(ツール選定は必ずここを通す)
- ゲートを含む実装フロー全体: skill `implementation-chain`
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!