Imported from DIO0550/design-composer (
.claude/skills/harness-growth/SKILL.md). Install upstream withnpx skills add DIO0550/design-composer --skill harness-growth. Copyright stays with the author.
ハーネスの育て方
harness/records/ に溜まった記録を数え、再発している分類にだけ手を入れる。
「何回出たか」を判断の入力にするのがこのスキルの要で、印象や読み直しでは決めない。
入力は既にある記録の集計。記録の新規作成はしない(→ harness-record)。
数えたい回の記録がまだ無いなら、先に harness-record で残してからここへ戻る。
Step 1: 数える
harness-counter サブエージェントへ投げる。 記録は 30 本を超えて増え続けるので、
本文をこのコンテキストへ入れない。返ってくるのは count.sh の出力・分岐の割り当て表・
根拠の要約だけ。
自分で数える場合は次を実行する(エージェントが使えない環境のときだけ)。
bash harness/records/count.sh # 分類ごとの再発数(増やす側の入力)
bash harness/records/count.sh --shrink # 縮める側の入力(Step 3。--unused を含む)
2 つとも必ず走らせる。 縮める側を数字で出していなかった間、rules/ が正味マイナスに
なったコミットは全履歴で 0 件だった。数字が出ない条件は満たされていても発火しない。
| 列 | 意味 |
|---|---|
| 再発 | 最後の介入より後の記録に出た件数。Step 2 の分岐はこれで決める |
| すり抜け | 再発のうち出どころが人・botだった件数。層を上げる根拠になる(次節) |
| 通算 | 全記録での件数。語彙が飽和していないかを見るときの参考 |
| 以降 | 最後の介入より後の記録の本数(「介入後 N 本再発ゼロ」の N) |
| 最終介入 | 前回置いた層と、その回の PR 番号。無ければ「未介入」 |
通算ではなく再発で分岐する。 通算は単調増加するので介入が効いたかを表さない。
すり抜けが 0 の分類へ観点を厚くしても再発は止まらない(もともと捕まえられている形を
補強するだけ)。どこが漏れているかはすり抜け列にしか出ない。 理由は
harness-record/templates/record.md「出どころの語彙」。
分類: なし の中身は数えられないので、目視で似た話が過去に無いかを確認する。
Step 2: 数えた結果で分岐する
該当する最初の規則に従う。1 件しか出ていない分類は何もしない (1 件で規約を足すと、その回限りの事情がルールとして固定される)。
2a. 未介入で 2 回以上 → 介入する
置き場所は強制力の強い順に検討する。上から順に「これで防げるか」を確かめ、採らなかった
ものは理由を記録に書く。 理由を書かずに下へ降りない。降りた記録が残らないと、毎回
いちばん弱い「rules/ に一文足す」へ落ち着き、次の回も同じ分類が出る。
| # | 層 | 置き場所 | 選ぶ条件 |
|---|---|---|---|
| 1 | hook |
まず linter の設定(.oxlintrc.json / Biome)。ルールで書けなければ git hooks(harness/githooks/)または CI(自前の検査は .claude/hooks/lib/ に置いて 3 層で共有する) |
機械的に判定できる(文字列・AST・コマンドの成否で白黒が付く) |
| 2 | skill |
.claude/skills/ に新しいスキルを作る |
毎回同じ段取りを踏む作業があり、順番を間違えると結果が変わる |
| 3 | 観点 |
既存スキルの手順、または .claude/agents/ の検証エージェントの観点に足す |
実装前・検証時に気づける観点 |
| 4 | rules |
rules/ に追記する、または表現を直す |
判断基準がどこにも書かれていない / 書いてあるが読まれていない |
層 1 の中では linter の設定を最初に確かめる。 1 つの設定変更が既存の配線
(編集後 lint・push 前 lint・CI)にそのまま乗り、3 点へ同時に効く。自前スクリプトは
3 層それぞれに配線が要る。リポジトリの構造を読まないと判定できないものは linter では
書けない(実測は .claude/hooks/README.md)ので、自前スクリプトへ降りる。
rules は読み手の記憶に頼るのでいちばん弱い。 ここへ落とすのは 1〜3 が使えないと
確かめたときだけにする。Claude Code のフックだけを 1 段目として数えない
(発火しない実行環境がある / .claude/hooks/README.md)。
「フック化は不成立」と書くときは、linter 設定・自前スクリプトのどちらも確かめたうえで
書く(これまでの介入は 38 件中 28 件が観点へ降りている。確かめずに降りると弱い層へ偏り続ける)。
層 3 の中では「観点」と「エージェント」を分ける
強制力は同じだが、コンテキストの置き場所が違う。次の 3 つが揃うものは
.claude/agents/ のエージェント定義へ置き、揃わないものはスキル本体の手順へ足す。
- 毎回同じ役割で呼ぶ
- 読ませたい資料が呼び出し側の常時コンテキストに要らない
- 返ってくるのが判断ではなく指摘
エージェントを作らないのは、呼び出し側の判断を代行してしまうもの・1 回きりの手順・ 既存エージェントに観点を足せば済むもの。エージェントが増えるほど「どれを呼ぶか」の判断が 要るので、数が増えること自体がコストになる。
介入したら 3 つを同じ PR に含める
-
その分類が最後に出た記録の「規約への反映」の末尾へ次を足す。この行が次回の起点になる
**この回の介入(`count.sh` が数える行):** - 対策済: `naming` 層=rules at pr-168 -
上の層に置けたら、下の層の記述を参照 1 行に縮める。 フックにしたのに
rules/の 該当節をそのまま残すと、総量が増える一方になる -
rules/へ足したなら、同量を削る(次節)
2a-1. rules/ を触るときの 3 つの検算
分類: rules-consistency(規約自身が矛盾する / 例で逆の答えを出す / 表の行が網羅していない)が
繰り返し出ているので、手順として踏む。
- 足す節の判定文を、同じファイルが既に挙げている例すべてに当てる。 1 つでも逆の答えが 出たら判定文が誤っている
- 足す節と、同じファイルの前後の節が矛盾しないかを読む。 表を足したなら、その表が
src/に実在するケースを網羅しているかも数える - Why not に書く事実が、いま直されつつあるものでないかを確かめる。 一時的な事実は 直った瞬間に嘘になる
2a-2. 常時ロードの予算
AGENTS.md + rules/ の合計は 900 行以内(AGENTS.md「常時ロードには上限がある」)。
wc -l AGENTS.md rules/*.md | tail -1
超えるなら、足す前に同量の削り先を出す。出せないなら、その追加は rules/ ではなく
判例(harness/case-law/)・観点・フックのどれかに置く。
判例に落とすものの判断軸: 別のリポジトリへ持っていって意味が通るか。 通らないもの
(NG/OK の実例・このリポジトリ固有のシンボル名・PR 番号への言及)は harness/case-law/ へ。
2b. 介入済みで、介入後に 2 回再発 → 層を 1 つ上げる
前回と同じ層への追記は選択肢に入れない。 「rules/ に書いたのに再発した」は
「読み手の記憶に頼る層は弱い」の実測データであり、同じ層で表現を変えても同じ結果になる。
すり抜けが 2 以上なら、前回の層が 観点 でも同じ扱いにする。 検証エージェントへ
観点を足したのに人まで届いているなら、その観点は読まれていないか判断に使われていない。
.claude/agents/ へもう 1 項目足す案は、採らなかった理由を書いて捨てる。
上の層で表現できない(機械判定できず、毎回の段取りでもない)ときだけ、その理由を書いて
据え置きにできる。据え置きも判断なので 対策済 の行は書く(次の 2 回をそこから数える)。
2c. 介入後 5 回以上 → 分類が飽和している。語彙を割る
同じ分類が対策後も 5 回出るのは、その語彙が別種の問題を 1 つのタグに畳んでいるサイン。 「N 回目」にもう情報が無い。
- 直近の同分類の指摘を並べ、亜種ごとに新しい語彙を切って
harness-record/templates/record.mdの 語彙表へ足す(語彙表はharness-record側にあるが、更新するのはこのスキル) - 旧タグにも締めの
対策済行を足す。 新語彙側にしか足さないと、count.shは旧タグの 最終介入を書き換え前のまま読み続け、旧タグに残っていた記録がいつまでも「介入後の再発」 として数えられ続ける。旧タグの対策済行は層を変えず(据え置き)、at pr-<最後に出た記録の番号>で締める - 過去の記録は書き換えない。 新しい語彙の数えは、足したあとの記録から始まる
- 割った結果、片方の亜種が機械判定できるなら、その場で 2a に戻ってフック化を検討する
なし の逃し弁
なし が 10 件溜まったら、目視でグルーピングして語彙へ昇格する。
harness-record 側の「語彙を勝手に増やさない」は各記録を書く時点での規則であって、
語彙表そのものの更新をここで行うのは正常な手順(置き場所は 2c と同じ)。
昇格させたら なし の 対策済 の行(層は昇格先の層)を書き、なし の数えをそこから
始め直す。2 件以上まとまったものだけ昇格させる(1 件は判例の「単発」へ書き足して待つ)。
フックにする / しない
- 機械的に判定できるものだけをフックにする。 「帰属先が正しいか」「この正規化は過剰か」 のような判断はフックにできない(文字列一致では偽陽性しか出ない)
- フックが誤って止めると実装者はエスケープハッチを探すようになり、フック全体が信用
されなくなる(経緯は
.claude/hooks/README.md「例外」) - 迷ったら既存のフックが何を見ているかを読む。
check-test-rules.shのように 「test()ブロックの中だけ」と対象を絞れるなら成立する。絞れないなら成立しない - 弱める(報告に留める / 追加行だけに絞る)前に、
--all相当で件数を数えて、埋められる なら埋める。 埋めれば絞る理由そのものが消える。弱めるなら、その理由といつ強められるかを.claude/hooks/README.mdへ書く - 足したら配線も更新する。git hooks は
harness/githooks/、Claude Code のフックは.claude/settings.jsonと.claude/hooks/README.mdの表
新しいスキルを作る / 作らない
- 作る: 同じ段取りを毎回踏んでいて、順番を間違えると結果が変わるもの
- 作らない: 判断基準が 1 つ増えただけ(→
rules/)。1 回しか通らない手順。 既存スキルの 1 フェーズに収まるもの(→ そのスキルへ足す)
Step 3: 棚卸し(条件を満たしたときだけ)
条件は目で確かめない。count.sh --shrink が出した数字で分岐する(Step 1 で実行済み)。
該当があればその回の PR に棚卸しを含める。無ければこの Step は飛ばす
(カレンダーでは発火させない)。
--shrink の節 |
条件 | やること |
|---|---|---|
| — | 2b / 2c / なし 10 件に該当がある |
Step 2 の該当規則を実行する |
| 1 | 「以降」10 本以上で「再発」0 の分類 | その対策より下の層に残る同内容の記述を削る(効いている証拠が出たので二重に持つ理由が無い)。層=rules は下の層が無いので、実例・経緯を判例へ落とせるかを見る |
| 2 | 未使用の分類 | その分類が対応する rules/ の節を縮める候補にする(下記) |
| 3 | AGENTS.md + rules/ が 900 行超 |
判例へ落とせる記述(実例・固有名・PR 番号)を harness/case-law/ へ移す。移すものが無ければ、フック / CI で強制済みの節を参照 1 行へ縮める |
| 3 | このファイル(SKILL.md)が 200 行超 |
判例(件数・経緯)を harness/case-law/ への参照 1 行に置き換える |
| 4 | 発火の計測 10 本以上で発火 0 の装置(スキル・エージェント) | 退役候補。装置ごと消すか、呼ばれ損ね(description のトリガー文言が悪い)を直すかを選び、理由を書く。発火 0 は「不要」と「呼ばれ損ね」の 2 通りで、どちらかは中身を読んで判断する |
該当したのに縮めなかった回は、理由を PR に書き、その分類が最後に出た記録へ
- 見送り: `<分類>` at pr-<番号> を足す(--shrink が見送り回数として出す。この行を
書けるのは 対策済 と同じくこのスキルだけ)。PR にしか書かないと、同じ候補を何回
見送ったかが数えられない。見送りが 2 回続いた候補は、3 回目に理由の書き足しでは
済ませない(見送る理由自体を疑う — 増やす側の 2b と同じ形)。
未使用の節を縮める
足したばかりの語彙は必ず --unused に出る(数えは足したあとの記録から始まるため)。
2c や逃し弁で語彙を割った回の分は除いてから読む。
「効いているから 0 件」と「読まれていないから 0 件」は、記録だけでは区別できない。 区別は強制の有無で付ける。
| その分類を強制しているものが | 判断 |
|---|---|
| ある(linter / フック / CI / 型) | 効いている。下の層の記述だけを削る(ガード自体は消さない) |
| 無い | このリポジトリでは起きていない問題。節を縮め、縮めた旨と理由を節の冒頭に書く(指摘が出たらその回に必要な分だけ書き戻す) |
Step 4: PR にする
Step 2・3 の改善を 1 本の PR にする。
- PR 本文には、数えた結果(どの分類が何回で分岐がどれになったか)と、介入したものの対応を書く。 対応には「どこへ置いたか」だけでなく「なぜ上の層にしなかったか」も書く
- 縮めただけの回も PR を出す。 増やす側に該当が無くても、Step 3 に該当があれば それがその回の成果になる(削った節と、削ってよいと判断した根拠を書く)
- 改善が無い回は PR を出さない。 出すものが無いのは正常な結果
- フックを足した回は配線が揃っていることを確かめる(片方だけだと動かない / 誰も知らない)
rules/を触った回はwc -l AGENTS.md rules/*.mdの合計を PR 本文に書く- 記録ファイルに触るのは
対策済の行の追加と、2c / 逃し弁での語彙表の更新だけ。 新しい記録は作らない(→harness-record)
注意事項
- 過去の記録を書き換えない。 判断が変わったら新しい記録に書く。
書き換えると履歴が消えて回数を数えられなくなる
(例外は
対策済の行の追加。判断ではなく、その記録が既に結論したことの機械可読な再掲) - 数え直しのために記録を編集しない。数えた結果が実感と合わないなら、それは語彙が 飽和しているサインなので 2c を見る
- 判例(
harness/case-law/)を書けるのはこのスキルだけ。 過去の判例も書き換えない (判断が変わったら新しい判例を足し、古いほうに更新された旨を 1 行添える)
参照ファイル
| ファイル | 内容 | 読むタイミング |
|---|---|---|
.claude/agents/harness-counter.md |
集計と分岐の割り当て(エージェントが読む) | Step 1 |
harness/records/count.sh |
分類ごとの再発数の数え方 | Step 1 |
harness-record/templates/record.md |
分類の語彙(2c と逃し弁で更新する) | Step 2 |
harness/case-law/README.md |
判例の置き方・誰が書くか | Step 2a-2 |
.claude/hooks/README.md |
既存フックが何を見ているか・強制力の序列・配線の場所 | Step 2(フックにするか判断するとき) |
harness/githooks/README.md |
実行環境に依存しない push 前検査の置き場所 | Step 2(層 1 に置くとき) |