Back to skills
SKILL.md
Verify Bootstrap
ASecurityrepo に機械ゲート(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. ツール表を持たない設計なので、未知のスタックでも同じ手順で使える。NOT for — 既に立っているゲートを 1 回実行するだけ(それは repo の verify entrypoint を直接実行)、コードの意味的レビュー(→ imp...
- 3 stars
- 0 votes
- 0 copies
- 0 views
- Added September 4, 2026
Works with
Security analysis
100/100npx -y skills add shimo4228/claude-harness --skill verify-bootstrap --agent claude-codeAre you the author of Verify Bootstrap?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/shimo4228-verify-bootstrap)---
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. ツール表を持たない設計なので、未知のスタックでも同じ手順で使える。NOT for — 既に立っているゲートを 1 回実行するだけ(それは repo の verify entrypoint を直接実行)、コードの意味的レビュー(→ 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 で、人間はコードを
読まない前提。実例と根拠は `~/.claude/.claude/verify.md` の「lint の LLM-first 棚卸しと ANN 導入」節)。言語を問わず同じ 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 が防ごうとしているのはまさにそれ。
報告を受けたら、次を確認してから採用する:
- **最終リリースが 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 固有の例外が要るときは、**まずスタックを標準に寄せる** — 寄せた上で残る分だけ
理由付きで許可リストへ(「この repo だけ独自」は設計不足のサイン)
**新規 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 する)。
build 役が cloud session で走る repo では、CI が verify の唯一の判定者になる — 判断役は
ローカルで再実行せず、branch tip に対する run の結論を読む(ADR-0075)。CI を持たない repo は
cloud に出せないので、github.com に remote がある repo ではこの Step を bootstrap に含める。
雛形は `references/ci-verify.yml`。固定するもの: `main` と `claude/**` への push で発火 /
actions は commit SHA で pin(tag から `gh api repos/<o>/<r>/git/ref/tags/<tag>` で引く)/
`permissions: contents: read` / `persist-credentials: false` / 履歴全体の secret scan job
(ローカル hook `secret-scan-precommit.sh` は staged 追加分しか見ない)。埋めるもの: verify.sh が
PATH から解決するツールの導入(`.claude/verify.md` の選定記録が正本)と言語 setup。
Linux runner で落ちるテスト(macOS 専用の launchd / BSD `stat`)は `skipif` で自己申告させ、
production 側の platform ガードでテストが `SystemExit` になる形は直す — 「CI で赤 = ローカルでも
赤」を保つため。
## audit モード
1. Step 1 を再実行(stack が変わっていないか — 言語が増えていれば category が空く)
2. `.claude/verify.md` の各 category について、**再調査トリガーに該当するものだけ**
search-first で引き直す(全件引き直すと毎回コストが出る)
3. 差分を提示: 現行 → 候補、乗り換えコスト、据え置きの理由
4. 判断はユーザー。**自動で乗り換えない** — ツール変更は repo 全体の diff を生み、
元に戻すコストが導入コストを上回る
## 関連
- Phase 0 のエントリポイント: skill `search-first`(ツール選定は必ずここを通す)
- ゲートを含む実装フロー全体: skill `implementation-chain`
Attribution
Comments
Loading comments…
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.