コンテンツにスキップ

コンセプト

このページでは、heal がなぜこの形をしているのかを説明します。まず使ってみたい場合は クイックスタート から始めて、あとで戻ってきてください。

AI コーディングエージェントは、頼まれた次の変更を作るのが得意です。けれどもコードベースは裏で動き続けます。修正や機能追加のたびに複雑さが少しずつ増え、同じファイルが何度も書き換えられ、重複したブロックが紛れ込みます。エージェントはそこを見ていません。実際のコードベースでは、あるファイルが扱いにくくなったと人が気づくころには、リグレッションはもうリリースされています。

コードベースの健全性を、エージェントを動かすきっかけに変える。

リンターを忘れずに実行するよう人に任せるのではなく、コードベース自身にシグナルを出させます。

  • コミットのたびに、post-commit フックがすべてのオブザーバを実行し直し、Critical / High の項目をコミットの出力にそのまま表示します。デーモンを常駐させなくても、次に手を付ける問題が目に入ります。
  • 必要なときに、heal status が同じ項目を Tier、Severity、ファミリ内のスコアの順に並べます。/heal:refactor スキルがそのリストを順に処理し、変更を提案して、承認されたものを 1 件ずつコミットします。

人がエージェントを起こしに行くのを待つのではなく、コードベースの側からエージェントを起こすループになります。

「CCN が 10 以上なら High」のような決め打ちのしきい値は、プロジェクトをまたぐとうまく働きません。200 行のスクリプトと 20 万行のサービスでは、置かれた状況がまるで違うからです。heal は各メトリクスをそのコードベース自身の分布に合わせて calibration します。そのコードベースの中で複雑度が上位 10% のものが High、上位 5% のものが Critical です。calibration のやり直しは手動(heal calibrate --force)にしています。リファクタでコードベースが本当に良くなったときに、基準がこっそり動いてしまっては困るからです。

このパーセンタイルによる分類の上下には、文献に基づく絶対値のフロアを 2 つ置いています。全体が荒れたコードベースでも最悪の箇所はきちんと浮かび上がり、全体がきれいなコードベースでも「上位 10% はいつまでも赤」という状態に縛られません。段階の詳細は Code › メトリクス を参照してください。

Hotspot — レバレッジが集中する場所

Section titled “Hotspot — レバレッジが集中する場所”

Hotspot とは、読みにくく、しかも頻繁に書き換えられているファイルのことです。 heal はすべてのファイルを commits × complexity でランク付けします。コードを犯罪現場のように調べるという、Adam Tornhill の Your Code as a Crime Scene で広まった考え方です。有限の候補が 5 件以上あれば、上位 10% に入り、かつファミリのフロアを超えたファイルに 🔥 が付きます。候補が 1〜4 件のときは、既存の絶対値のフロアだけで判定します。スコアが NaN や無限大のファイルは対象外です。

考え方はこうです。誰も触らない複雑なファイルは、負債ではあっても急ぎではありません。チームが 1 日おきに書き換えている複雑なファイルは、先に確かめる価値があります。Hotspot はその交わりを狙った指標で、スコアが高いほど、よく触られていてしかも読みにくいことを示します。

つまり Hotspot は、どこに手を入れると効くかを示すシグナルです。ただし 🔥 そのものは並べ替えのキーではありません。HEAL はまず有効な解消 Tier と Severity を当て、残った同じファミリの中を hotspot_score の高い順に並べます。そのため同じグループの中では、🔥 の付いていない Finding が、スコアの高さで 🔥 付きの Finding より先に来ることがあります。

オプトインの Test と Docs には、それぞれのファミリ用の Hotspot の計算があります。Test Hotspot(commits × uncovered %)と Doc Hotspot(ペアのソースの churn × ドキュメントの遅れ)です。同じ 🔥 が、次にテストを書く価値の高いファイルや、次に書き直す価値の高いドキュメントを指します。考え方は同じで、入力だけがファミリに合わせて変わります。

HEAL がこれらのスコアを使うのは、解消 Tier と Severity を決めた後、同じファミリの中で並べるときだけです。スコアは欠陥が起きる確率でも、ファミリをまたいで比べられる単位でもなく、修正したときの効果を約束するものでもありません。

2 つの役割 — heal が負債を見せ、スキルが減らす

Section titled “2 つの役割 — heal が負債を見せ、スキルが減らす”

設計の段階から、仕事を 2 つに分けています。heal CLI は計測する側です。観測し、calibration し、手を付ける価値のあるコードの負債をシグナルとして見せますが、ソースファイルは 1 行も書き換えません。heal プラグインの Claude スキルは直す側です。heal が出した結果を読み、コミットに変えます。

計測ツールが「親切に」修正まで済ませてしまうと、何が問題かと、このチームがそれにどう対処するかの境目があいまいになります。そこで、この 2 つの問いを別々のプログラムに持たせ、それぞれが自分の基準で答えられるようにしています。

直す側のスキルは、考えることと手を動かすことのあいだに、承認という 1 段階をはさみます。

  • 考える。 /heal:refactor は TODO リストを 1 つのまとまりとして読み、フラグの立ったコードを深く読んでから変更を提案します。変数名の変更から、根拠が十分なら、混ざった概念に沿ってファイルを分けるところまで扱います。各提案には、どの摩擦を取り除くのか、どこに触るのかが書かれます。
  • 承認する。 どの提案を適用するかは、自分で選びます。公開する名前や、どのモジュールがその責務を持つかのように、利用者にしか決められないことは、具体的な選択肢の付いた質問として届きます。
  • 手を動かす。 スキルは選ばれた提案を 1 提案 1 コミットで適用し、コミットの前には毎回テストを実行します。作業ツリーに未コミットの変更があるときは始めず、push も amend もしません。

この確認の段階があるから、自律的な作業を任せられます。承認するまで何も変わらず、承認したものはすべてレビューできるコミットとして残ります。heal が何を伝えているのかを理解したいだけなら、/heal:refactor plan で提案までにとどめられます。

コードの健全性は、互いに独立した 3 つの観点から観測します。どのファミリも「観測する、直す価値のあるものを見せる、専用のスキルに渡す」という同じ流れに乗っていますが、答えようとしている問いはそれぞれ違います。

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

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

常時オンのファミリです。チームの時間を静かに奪っているファイルを探します。分岐の深い関数、メソッドどうしがばらばらになったクラス、ツリーのあちこちにコピーされたブロック、変更がいつも周りに波及するハブといったものです。そのうえで、チームが実際にどれだけ編集しているかで並べ替えるので、キューの先頭には、過去の負債よりも、いま手間を生んでいる場所が来ます。

/heal:refactor はそのキューを、関数の抽出(Extract Function)、条件式の分解、重複を共通のヘルパーへ引き上げるといった定番のリファクタで片付けます。複数のシグナルがそろえば、ファイルの分割や、関数を本来の置き場所へ移すといった構造的な変更も行います。どのファイルを触ればいいかさえ分かれば当たり前の作業でも、手で探し回るのは面倒です。

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

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

[features.test] は、既存のリポータがすでに出力している lcov.info を読み、ファイルの変更履歴と突き合わせます。見つけるのは 3 種類です。最近書き換えられているのにテストの届いていない本番コード、カバーしていたソースの変化についていけなくなったテスト、そして黙って skip されているテストです。最後のものは、守っていたはずのバグが本番に出るまで、たいてい誰も気づきません。

/heal:tests は、足りないテストを 1 コミットずつ書き、ずれたテストを揃え直します。heal 自身がテストを実行することはありません。「このあたりはもっとカバレッジが欲しい」という漠然とした感覚を、ファイル単位で順位の付いた TODO に変えるだけです。

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

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

[features.docs] は、ペアになったドキュメントを、それが説明するソースと比べます。「このドキュメントはこのファイルを説明している」という小さな対応表が手がかりです。そのうえで、ドキュメントが取り残されている箇所を見せます。例に出てくる識別子がもう存在しない段落、たどれない内部リンク、どこからもリンクされていないページ、TODO マーカーが静かにたまっていくセクションなどです。

/heal:docs は、リンク切れ、存在しない識別子の参照、孤立ページといった機械的に直せる壊れを直し、それ以外は Diátaxis の観点で整理します。安定したリファレンスより先に、初めて読む人が迷っている箇所に手を入れる、という順番です。

全体像は 機能 を参照してください。

  • クイックスタート — インストールして、実際のリポジトリで試す
  • 機能 — Code / Test / Docs の各ファミリの概要
  • CLI — すべてのサブコマンド
  • Code › メトリクス — 各コードメトリクスが測るものと、Severity の決まり方
  • Code › 設定 — 常時オンのファミリ向けの .heal/config.toml リファレンス
  • Code › スキル — heal プラグイン、/heal:setup、/heal:refactor