コンテンツにスキップ

コンセプト

このページでは heal がどんな考えで作られているかを説明します。すぐに使い始めたい方はクイックスタートからどうぞ。

AI コーディングエージェントは、依頼された次の変更を作るのは得意です。一方でコードベースは裏側で少しずつ姿を変え続けます。修正や機能追加を重ねるうちに複雑度が積み上がり、特定のファイルばかりが繰り返し書き換えられ、似たコードがじわじわ入り込む。エージェントはそれを見ていません。実際のコードベースでは、「このファイル、最近触りにくくなったな」と人間が気づいた頃には、リグレッションはもう本番に届いています。

コードベースの健全性を、エージェントへのトリガーに変える。

「リンターを走らせるのを忘れないように」と人間が気を張る代わりに、コードベース自身にシグナルを出してもらいます。

  • コミットのたびに、post-commit フックが全オブザーバーを 1 回走らせ、Critical / High の項目をコミット出力にそのまま表示します。デーモンなしで「次の一手」が常に見えています。
  • オンデマンドでheal status が同じ項目を Severity 別の TODO リストとして並べ、同梱の /heal-code-patch Claude スキルが 1 コミット 1 修正で片付けていきます。

結果として、人間がエージェントを叩き起こすのではなく、コードベースの側からエージェントを呼び出すループになります。

「CCN ≥ 10 は High」のような決め打ちのしきい値は、プロジェクトをまたぐとうまく機能しません。200 行のスクリプトと 200kloc のサービスは別世界で動いています。heal は各メトリクスを そのコードベース自身の分布 に合わせてcalibrate します。あなたのコードベースの上位 10% が High、上位 5% が Critical です。再 calibrationは手動(heal calibrate --force)で行います。リファクタの結果でゴールポストが暗黙のうちに動いてしまうと、改善が見えなくなるからです。

このパーセンタイル分類の上下には文献由来の絶対フロアが置かれています。これにより、全体的に劣化したコードベースでもワーストケースは Critical のまま、逆にきれいなコードベースでも「上位 10% は永遠に赤」のループに縛られません。詳しいラダーは Code › メトリクス を参照。

Hotspot — 次にバグが生まれそうなファイルを指し示す印

Section titled “Hotspot — 次にバグが生まれそうなファイルを指し示す印”

Hotspot とは、読みにくく、なおかつ頻繁に編集されているファイルのことです。 heal は各ファイルを commits × complexity でランク付けし(Adam Tornhill の Your Code as a Crime Scene で広まった「コードを犯罪現場として見る」発想)、その分布の上位 10% に heal status 上で 🔥 を付けます。

直感的にはこうです。誰も触らない複雑なファイルは技術的負債です。気にはなるけれど、緊急ではありません。これに対して、チームが毎日のように編集している複雑なファイルは、次のバグが生まれる場所です。Hotspot はその交差点を狙います — スコアが高い = よく触られている かつ 読みにくい = リグレッションが集中する場所、というシグナルです。

だからこそ Code ファミリの中で 最初に見るべきは Hotspot です。Critical 🔥 の項目は Critical の 2 倍悪いという話ではなく、修正にかけた時間が一番返ってくる項目 です。/heal-code-patch スキルがデフォルトで 🔥 キューを最初に解消するのも同じ理由です。

オプトインの Test / Docs ファミリは、それぞれの観点に合わせた Hotspot コンポーザを別に持ちます — Test Hotspot(commits × uncovered %)と Doc Hotspot(ペアソースの churn × ドキュメントの遅れ)です。同じ 🔥 フラグが、次にテストを足すべきファイル・次に書き直すべきドキュメントを指し示します。発想は同じで、入力だけがファミリに合わせて差し替わっています。

2 つの役割 — heal は負債を可視化し、スキルが解消する

Section titled “2 つの役割 — heal は負債を可視化し、スキルが解消する”

設計は最初から仕事を 2 つに分けています。heal CLI は 計測側 で、コードベースを観測してcalibrate し、対処すべきコード負債のシグナルを見せます。ただしソースは 1 行も書き換えません。同梱の Claude スキルは 修復側 で、heal が出した結果を読み、コミットへ変換します。

「計測した上で、ついでに直してくれる」ツールは、何が問題かこのチームがそれにどう対処するか の境目を曖昧にします。heal はこの 2 つの問いを別々のプログラムに分けて持たせ、それぞれを独立に答えられる状態にしておきます。

修復側はさらに、考える動く の 2 つのスキルに分かれています:

  • /heal-code-review考える スキルです。読み取り専用。TODO リスト全体を 1 つの系として読み、フラグの立ったコードを深く読み、まだ人間が判断すべきアーキテクチャ的な打ち手を提案します。何かを変える前に、HEAL が何を言っているかを 理解 したいときに使います。
  • /heal-code-patch直す スキルです。機械的な修正だけを行います。ドメイン判断を必要としない確立されたリファクタパターンを使って、1 コミット 1 修正で TODO リストを片付けていきます。dirty な worktree では起動しません。push も amend もしません。次の項目がアーキテクチャ判断を必要としたら、そこで止まって /heal-code-review に渡します。

この線引きが、自律性を任せられる契約になっています。退屈な修正は勝手に進み、面白い判断は手元に残ります。

heal は直交する 3 つの観点からコードヘルスを観測します。どのファミリも「観測する → 直す価値のあるものを並べる → 専用の review ↔ patch スキルペアに渡す」という同じループに乗っていますが、答えようとしている問いはそれぞれ違います。

Code — このコードベースで変更しづらいのはどこか?

Section titled “Code — このコードベースで変更しづらいのはどこか?”

常時オンのファミリです。heal は、チームの時間を静かに削るファイル — 分岐の深い関数、責務がほどけて分かれそうなクラス、ツリーをまたいでコピペされたブロック、変更がいつも波及するハブ — を探します。さらに、それらを「実際にチームがどれくらい編集しているか」で並べ替えるので、キューに並ぶのは「昨日までの負債」ではなく「いまの摩擦」になります。

/heal-code-review/heal-code-patch は、そのキューを古典的なリファクタの手筋(Extract Function、条件式の分解、共有ヘルパへの引き上げ等)で解消します。「どのファイルを触るか」が分かれば機械的、手で探すと退屈、というタイプの後始末です。

Test(オプトイン) — テストから見えていない本番コードはどこか?

Section titled “Test(オプトイン) — テストから見えていない本番コードはどこか?”

[features.test] は、既存のリポータが吐いている lcov.info を読み、ファイル変更履歴と突き合わせます。指し示すのは 3 種類です — 最近編集されているのにテストが届いていない本番コード、ペアのソースから取り残されて一緒に動かなくなったテスト、そして黙って skip されているテスト(守っていたバグが本番に出るまで誰も気づかないやつ)。

/heal-test-review/heal-test-patch は、足りないテストを 1 コミット 1 件のペースで書き、ドリフトしたテストを書き直します。heal 自体はテストを実行しません。「もっとカバレッジが要る」という漠然とした気持ちを、ファイル単位の順序付き TODO に変換するだけです。

Docs(オプトイン) — ドキュメントは実装からどれだけずれているか?

Section titled “Docs(オプトイン) — ドキュメントは実装からどれだけずれているか?”

[features.docs] は、ペアになったドキュメントとそれが説明するソースを比較します(「このドキュメントはこのファイルを説明している」という小さな対応表が手がかりになります)。そして、ドキュメントが取り残されている箇所を表面化します — もう存在しない識別子を例に挙げているパラグラフ、解決しない内部リンク、どこからもリンクされていないページ、TODO マーカーが静かに積み上がっているセクション。

/heal-doc-review/heal-doc-patch は、機械的に直せる破損(リンク切れ、参照切れの識別子、孤立ページ等)は自動で直し、それ以外は Diátaxis のレンズで枠付けします。最初に読む人が迷うチュートリアル系の崩れを、安定した reference より先にケアする、という優先順位です。

詳しくは 機能 を参照。