Hashloom について
Hashloom は、ソフトウェア単位を依存関係付きのコンテンツアドレス可能なコントラクトとして扱う、コーディングエージェント向け MCP サーバーです。検証結果をキャッシュし、変更範囲を算出して、コード生成用の簡潔なコンテキストを提供します。
主な機能
- 01YAML コントラクトによるソフトウェア単位の記述
- 02コントラクトと依存ハッシュに基づく検証キャッシュ
- 03直接・推移的な無効化範囲の算出
- 04コントラクト・依存・呼び出し元のコンテキスト提供
- 05コントラクトと検証キャッシュの状態表示
活用シーン
- 01コントラクトに基づくコードの生成・再生成
- 02コントラクト変更後の影響単位の特定
- 03有効なテスト結果の検証間での再利用
MCP 対応
MCP サーバーとして、コーディングエージェント向けにコントラクトの読み書き、依存関係の影響範囲の照会、実装の検証、プロジェクト状態の確認ツールを提供します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
hashloom

Hashloomは、ソフトウェアのユニットをファイルではなく、コンテンツアドレス方式のコントラクトとして扱います。 エージェントの再生成ループを低コストにするMCP サーバーです。
コントラクトはコンテンツアドレス方式で、依存関係も認識するため、エージェントは検証結果を再利用し、影響範囲を正確に計算し、ファイル全体を読み直す代わりに、数百トークンのコンテキストからコードを再生成できます。ビルドシステムが尋ねるのは、どのファイルが変更されたかです。Hashloomが尋ねるのは、どのソフトウェア上の要件が変更されたかです。
この名前は、まさにその仕組みを表す造語です。ハッシュで鍵付けされた織機です。織機では、経糸は固定された耐久性のある糸で、杼がその間に使い捨ての緯糸を織り込みます。コントラクトが経糸で、コードが緯糸です。(0.3.3までは、このプロジェクトはheddle-mcpとして提供されていました。エンジンに変更はありません。)
問題点
エージェントはソフトウェアの構造を何度も再発見するために、繰り返しコストを払っています。仕様駆動開発ツールは、仕様を永続的な成果物、コードを再生成可能なものとしましたが、通常のファイルを基盤としているため、再生成のたびにプロジェクトがすでに把握していることを導き直します。
- コンテキストの取得にコストがかかります。 1つのユニットを再生成するには、仕様ファイルとソースファイル全体を読み直す必要があります。数百トークンで伝わる内容を把握するために、数千トークンを消費します。
- 検証結果がキャッシュされません。 ユニットのコントラクトが変更されていなくても、再生成のたびに関連するテスト全体を再実行し、その出力も読み直します。
- 影響範囲の特定は仕組みではなく慣習に頼っています。 仕様が変更されても、どの依存先が無効になるかをエージェントに正確に伝えるものはありません。
モデル
Hashloomは、各ソフトウェアユニットをファイルではなく、依存関係を明示したコンテンツアドレス方式のコントラクトとして扱います。コントラクトは小さなYAML仕様(シグネチャ、不変条件、例、依存先の名前)であり、その背後の実装は再生成可能な緯糸です。すべてのコントラクトがハッシュ化され、依存先の名前も明示されているため、エージェントがファイルから繰り返し導き直していた構造を、hashloomが一度計算して提供できるようになります。
得られる効果
このモデルにより、機械的に次の3つの効果が得られます。
- 検証結果のキャッシュ。 テストの成功結果は、コントラクト、実装、依存先のハッシュをキーとして保存され、そのいずれかが変更されるまでキャッシュから提供されます。pytestが実行されるのは、実際にキャッシュがミスしたときだけです。
- 機械的な影響範囲の特定。 コントラクトが変更されると、慣習に頼らず、ハッシュに基づいて、無効になる依存先を推移的にすべて正確に報告します。
- 小さなコンテキストパケット。 ユニットを再生成するエージェントには、コントラクト、その依存先のシグネチャ、呼び出し元が数百トークンの1つのパケットとして渡されます。ファイル一式を丸ごと読み込む必要はありません。
数値
20 件のコントラクトを含むサンプルプロジェクトで、同じ 3 つの再生成タスクを実行しました。1 回はファイルを直接読み込み、もう 1 回は hashloom 経由で実行しています(tiktoken cl100k、uv run python bench/benchmark.py で再現できます)。
| task | raw files | hashloom | reduction |
|---|---|---|---|
| revenue_by_region | 1,925 | 369 | 5.2x |
| top_customers | 2,137 | 337 | 6.3x |
| revenue_by_category | 1,942 | 396 | 4.9x |
| total | 6,004 | 1,102 | 5.4x |
Raw モードでは、ファイルベースのエージェントが各タスクで読み込むものを数えます。ユニットの仕様ファイル、推移的な依存関係にあるすべての仕様ファイル、依存関係の閉包に含まれるすべてのソースモジュール、ユニットのテストファイル、そしてテストスイートを実行した出力です。ベースラインに意図的に有利な条件を設定しており、エージェントが依存関係の正確な閉包をすでに把握しているものとします。まさに hashloom が計算する情報です。
同じ手法で、5 つのサンプルプロジェクト(Python、Go、TypeScript、Java、C#)のすべてのユニットを bench/sweep.py で調査できます。また、お使いのプロジェクトを含む、あらゆる hashloom プロジェクトで利用できます。全件調査の平均値はゲートを下回ります(効果がほとんどない末端の型も数えるため)。比率は依存関係の深さに応じて変わるため、より深いプロジェクトほど高くなります。すべての数値、その分布、率直な注意点は docs/benchmarks.md にまとめています。
クイックスタート
pip install hashloom
# or from source: pip install "git+https://github.com/davet47/hashloom"
cd your-project
hashloom init # creates .hashloom/ and contracts/
hashloom index # builds the store from contracts/
Claude Code の接続先に指定します。
claude mcp add hashloom -- hashloom serve
(Stdio トランスポートです。サーバーは作業ディレクトリから上位へたどり、最も近い .hashloom/ を見つけてプロジェクトを特定します。)
このワークフローを初めて使う方は、docs/getting-started.md をご覧ください。エージェントと一緒に、コントラクトファーストでパッケージを構築する手順を紹介しています。エージェントに与える作業ルール、レビューの反復、検証ゲートについて説明しています。
コントラクト
contracts/ にユニットごとに 1 つの YAML ファイルを置きます。最小限の内容で、手作業で記述でき、ハッシュ化できます。
name: revenue_by_region
signature: "(sales: list[Sale]) -> dict[Region, float]"
deps: [Sale, Region] # other contract names
invariants:
- excludes sales where completed is false
- excludes sales with null amount
examples:
- in: "[Sale(region='QLD', amount=10, completed=True)]"
out: "{'QLD': 10.0}"
tests: [tests/test_revenue.py::test_revenue_by_region] # pytest node IDs
impl: src/revenue.py::revenue_by_region # current woven weft
status: inferred # reverse-engineered, not yet human-reviewed; omit once confirmed
サブディレクトリは名前空間です。たとえば、contracts/billing/invoice.yaml は billing/invoice コントラクトを表すため、同じ短い名前を別々のフォルダーに配置できます。コントラクトの name は、contracts/ 以下のパスと一致している必要があります。
コントラクトを作成するタイミング
コントラクトは、安定した境界に置きます。つまり、他のユニットが依存し、現在の実装よりも長く存続すると見込まれるインターフェースです。その背後にある実装は使い捨ての織物であり、自由に再生成できます。コントラクトを置く価値のない場所に置かないのは、失敗ではなく正しい使い方です。失敗につながるのはその逆で、喜んで書き換えるような内部まで過剰に固定し、永続層を単なる雑務にしてしまうことです。
コントラクトはレビュー対象の成果物です。作成は簡単で、ますます簡単になっています。そのため、実際のコストは作成ではなくレビューにあります。誤ったコントラクトは、コントラクトがないよりも悪いものです。永続的な成果物が誤った内容を示すため、エージェントはそれ自体が間違っている仕様を満たすようにコードを再生成してしまいます。コントラクトは生成コードをざっと見るのではなく、インターフェースと同じようにレビューしてください。
エージェントが既存のコードからリバースエンジニアリングしたコントラクトには、まだレビューを通過していないことを示す status: inferred を指定できます。ツールは、こうしたコントラクトを根拠とする影響範囲や検証結果をデフォルトで警告します。ただし、拒否することはありません(依存先には inferred: true、検証結果には inferred リスト、status にはレビュー待ちキューを表示します)。未検証のコントラクトを厳格に拒否したいチームは、厳格なプロベナンスモード(.hashloom/config.json → {"strict_provenance": true})を有効にできます。この場合、レビューが完了するまで verify は対象ユニットを構造化された inferred_contract エラーで拒否します。テストは実行されず、判定もキャッシュされません。読み取りと書き込みは引き続き助言的な扱いとなるため、ドラフトの配置と確認は可能です。値が設定されていない場合は confirmed とみなされます。また、レビュー後に推定済みコントラクトを確定しても、追加のコストはかかりません。状態は来歴を示すもので、意味を示すものではないため、切り替えても無効化は発生しません(厳格モードでは、すでに存在する成功済みの結果が、確定時に再び有効になります)。
ハッシュのセマンティクス
- コントラクトハッシュ:正規化形式の sha256 です。キーはソートされ、空白は正規化され、コメントは除去され、例の順序は維持され、依存関係の順序は無視されます。
impl、tests、invariants、statusは除外されるため、ファイルを移動しても無効化されず、不変条件の表現を変えても影響はなく、推論されたコントラクトを確認しても何も無効化されません。不変条件はドキュメントであり、機械的な義務ではありません。実際のチェックはテストで行われ、そのソースは検証キーに含まれます。 - 実装ハッシュ:実装の正規化済み AST の sha256 です。そのため、再フォーマットやコメントの編集ではキャッシュは無効化されません。ドキュメンテーション文字列も除去されます。
- 検証キー:
(contract hash, impl hash, test-source hash, toolchain identity, transitive dep contract hashes)です。Hashloom は検証結果をキャッシュし、依存関係の閉包内のコントラクト、実装、テスト自体のソース、またはツールチェーンの識別情報のいずれかに変更があれば、再実行を強制するようキーを設定します。識別情報はツールチェーンのバージョン(python 3.11.7、go 1.21.5、node <v> ts <v>、java 21.0.3、dotnet 9.0.303)に加え、プロジェクトが依存関係のソースをルートにコミットしている場合(uv.lock、go.sum、package-lock.json、pom.xml、…)は、そのダイジェストを示すdeps <file>=<hash>です。これにより、宣言された依存関係のセットが異なる環境での成功結果は決して信頼されず、3.11 での合格結果が 3.13 に提供されることもありません。粒度は コミット済みの宣言された セットであり、OS/アーキテクチャは含まれません。CI での合格結果はすべてのプラットフォームで利用できます。自身のロックファイルと一致しない venv はキーの対象外であり、これが共有キャッシュの無効化機能が存在する理由のひとつです。失敗結果がキャッシュから提供されることはありません。Python では、テストソースハッシュに各テストの フィクスチャの閉包 も含まれます。具体的には、テストが要求するフィクスチャ(引数、usefixtures、リテラルのgetfixturevalue)、スコープ内の autouse フィクスチャ、およびフィクスチャが使うフィクスチャです。これらはテストのモジュールと conftest のチェーンを通じて静的に解決されます(最も近いものが優先されます)。そのため、conftest のフィクスチャだけを編集しても、それに依存するテストだけが無効化されます。静的な走査で解決できないフィクスチャの使用がある場合は、チェーン全体のハッシュに切り替わります。過剰に無効化することはあっても、無効化が不足することはありません。注意点が 2 つあります。キャッシュされた合格結果はテストが決定的であることを前提とするため、壁時計の時刻、ネットワーク、または乱数に依存した成功結果は、その成功をもたらした条件がなくなった後も有効なままになることがあります。また、テストがインポートして呼び出す通常のヘルパー関数(および Python 以外のテストヘルパー)は、依然としてハッシュの対象外です。対象となるのはフィクスチャのグラフだけです(ISSUES.md を参照)。
MCP ツール(すべての機能)
| ツール | 内容 |
|---|---|
get_contract | 約300トークンのコンテキストパケット:コントラクト、ハッシュ、1行の依存関係シグネチャ、呼び出し元の一覧 |
put_contract | 検証し、contracts/<name>.yaml に書き込み、新しいハッシュ、変更内容のセマンティック差分、無効化されたすべての依存先を返します |
get_dependents | 直接または推移的な影響範囲の照会。名前とハッシュを返し、推論済み(未レビュー)のコントラクトにはフラグを付けます |
verify | ユニットごとの cached-pass/pass/fail と、トップレベルの ok ゲートビットを返します。radius=true の場合、各名前を影響範囲全体に拡大します。テストはキャッシュミス時にのみ実行されます。失敗時はスタックトレースではなく、≤40トークンのアサーション要約を返します。閉包内の推論済みコントラクトにはフラグを付けます(厳格な来歴モードでは拒否されます) |
status | 変更されたコントラクト、古くなった検証、キャッシュヒット率、解決された verify インタープリター、累積トークンカウンター |
すべてのツールは構造化エラーを返します。たとえば {"error": {"code": "unknown_dep", "message": "'Regoin' not found — nearest: 'Region'"}} のような形式で、スタックトレースは返しません。
verify インタープリター
verify は、プロジェクト固有の Python を使ってテストを実行します。インタープリターは次の順に解決されます。
hashloom serve --python PATH → .hashloom/config.json({"python": "..."})→
自動検出された <project>/.venv → hashloom の実行に使われているインタープリター。これにより、
グローバルにインストールされた hashloom でも、プロジェクトの仮想環境にインストールせずに、
その環境を使ってプロジェクトを検証できます。hashloom status で解決されたインタープリターを確認できます。
.hashloom/config.json では、デフォルトより長い時間が必要なテストスイート向けの
verify_timeout(pytest の実行ごとの秒数、デフォルトは 300)、pycache_trust(デフォルトは
true)も指定できます。pycache_trust: false を設定するか、--no-pycache-trust を渡すと、
各 verify の実行前にプロジェクトの __pycache__ をクリアします。これにより、古い .pyc が
現在のソースを上書きすることはありません。また、strict_provenance(デフォルトは false)を
設定すると、クロージャに推定された契約が含まれるユニットの verify を拒否します。
Python 以外の言語
impl のファイル拡張子によって言語アダプターが選択されます。各アダプターには正規化 AST ハッシャーとテストランナーが含まれており、同じ装飾と意味のハッシュ化セマンティクスが 各言語で適用されます。
- Go(
.go):標準ライブラリのgo/astを使ってハッシュ化し、go test -jsonを実行します。ツールチェーンはインタープリターと同様に解決されます。.hashloom/config.jsonの{"go": "..."}が指定されていればそれを使い、そうでなければ PATH 上のgoを使います。 - TypeScript(
.ts/.tsx/.mts/.cts):対象プロジェクト独自のtypescriptコンパイラー API を使ってハッシュ化し、package.jsonからテストランナーを自動検出します(vitest/jest、それ以外の場合は Node 組み込みのnode:test)。Node >= 22.6 が必要です。設定キーは{"node": "..."}です。 - Java(
.java):単一ファイルのjavacツリー helper を使ってハッシュ化します(JDK のみで動作し、依存関係はありません)。ビルドマニフェストからテストランナーを自動検出します。pom.xmlは Maven に、build.gradle/build.gradle.ktsは Gradle に振り分けられます。また、コミット済みのmvnw/gradlewラッパーが PATH 上のバイナリより優先されます。JDK >= 11 に加えて Maven または Gradle が必要です。設定キーは{"java": "..."}です。 - C#(
.cs):Roslyn トークンストリーム helper を使ってハッシュ化します。hashloom は SDK に同梱されたMicrosoft.CodeAnalysisに対して SDK 独自のcscを使い、SDK のバージョンごとに一度コンパイルします(パッケージもネットワークも不要です)。ルートプロジェクト/ソリューションにFullyQualifiedName~フィルターを指定してdotnet testを実行します(xUnit、NUnit、MSTest がすべて対象です)。Microsoft.Testing.Platform プロジェクト(xunit v3)も動作しますが、注意点が 1 つあります。そこでdotnet testはフィルターを無視するため、verify のたびにそのプロジェクトのテストスイート全体を実行します。これは保守的な動作です(無関係な失敗でもブロックされますが、成功すれば契約のテストもカバーされます)。.NET SDK >= 8 が必要です。設定キーは{"dotnet": "..."}です。
Python がデフォルトですが、プロジェクトでは言語を自由に混在させられます。
チームで共有する検証キャッシュ
デフォルトでは、キャッシュはローカルの .hashloom/store.db に保存されます。共有バックエンドを指定すると、1 回の verify の成功をチーム全体で利用でき、CI がユニットを 1 回検証すれば、チームメイト全員のエージェントが cached-pass を取得できます。
// .hashloom/config.json
{"shared": {"url": "https://cache.internal:8770", "token": "..."}}
python -m hashloom.cache_server を使って、バックエンドを任意の場所で実行します(SQLite ストア上で動作する小規模な Bearer トークン認証付き HTTP サービスです。CLI コマンドではなく、運用プロセスです)。認証は役割ごとに設定できます。サーバーに任意の --publish-token を指定すると、それを持つクライアントだけが成功結果を書き込めます(CI は公開し、読み取りトークンだけを持つラップトップは結果を利用します。以前と同様、単一のトークンで両方の役割を許可することもできます)。読み取り専用クライアントは "publish": false を設定して、公開リクエストを完全に省略できます。サーバーはリクエストを並行して処理し、同じ検証キーの重複した公開は何もしません(最初の書き込みが優先されます)。公開されるのは成功結果だけで、失敗が境界を越えることはありません。また、前述の「キーにツールチェーンを含める」ルールにより、マシン間で共有しても成功結果の妥当性が保たれます。共有ストアに接続できない場合、verify は通知なしでローカルに切り替わります。
CLI
hashloom init · hashloom index · hashloom serve · hashloom status · hashloom verify。.hashloom/ 内の sqlite ストアは派生状態です。いつでも削除でき、hashloom index を実行すれば contracts/ から再構築されます。古い回答が返されることもありません。ディスク上の contracts/ とストアにずれがある場合(再インデックスせずに git pull した場合など)、verify は古いハッシュに基づく判定を返す代わりに、影響を受けるユニットについて構造化された stale_store エラーを返し、hashloom index を実行するまで処理を拒否します。
hashloom verify <name>… は、MCP ツールと同じキャッシュ済み検証をコマンドラインから実行し、すべてのユニットが正常でない限りゼロ以外の終了コードを返します(失敗、未知の名前、検証不能なユニットはいずれも処理をブロックします)。CI や pre-commit フックに組み込めます。--radius を指定すると、各名前をその名前自身と、推移的な依存先すべてに拡張します。これにより、1つのコマンドで変更の影響範囲全体をチェックできます。例:hashloom verify --radius Sale。
サンプルプロジェクトを試す
cd examples/sales
hashloom init && hashloom index && hashloom serve # then point your agent at it
20件のコントラクトと25件のテストがあり、依存関係の連鎖は最大6階層です。 各サンプルディレクトリには、言語ごとの実行手順を記載した独自の README が含まれています。
同じ init && index の手順を使うサンプルが、ほかに4つの言語にもあります。
- Go —
examples/go-ledger:小規模な複式簿記台帳を対象とする8件のコントラクトです。hashloom verify --radius Entryは内部でgo testを実行し、影響範囲をチェックします。Go ツールチェーンが必要です。 - TypeScript —
examples/ts-cart:ショッピングカートを対象とする8件のコントラクトです。まずnpm installを実行してtypescriptをインストールしてください。検証では Node 組み込みのnode:testを実行します。Node >= 22.6 が必要です。 - Java —
examples/java-payroll:週次の給与計算を対象とする11件のコントラクトで、3階層構成です。レコード、Class.methodの修飾子、パラメーター化されたブラケットテーブル、ドット区切りのノード ID を持つ@Nestedテストクラスが含まれます。フレームワーク依存のない Spring サービスレイヤーの構成例です。hashloom verify --radius TimeSheetは内部で Maven を実行します。JDK >= 17 と Maven が必要です。 - C# —
examples/csharp-invoices:請求処理を対象とする11件のコントラクトで、Java のサンプルと同じ3階層構成を C# の慣習に合わせています。レコード全体のハッシュ化、Class.Methodの修飾子、[InlineData]のブラケットテーブル、ドット区切りのノード ID を持つネストしたテストクラス(ランタイムでの表記はOuter+Inner)が含まれます。hashloom verify --radius DiscountCentsは内部でdotnet testを実行します。.NET SDK >= 8 が必要です。
開発
uv sync
uv run pytest # full suite; hash stability is the load-bearing suite
uv run python bench/benchmark.py
integrations/ には、リポジトリ専用のブートストラップツールがあります。graphify のナレッジグラフから status: inferred のコントラクト案を作成するインポーター(手順については販売サンプルを参照)と、キャッシュとゲートのワークフローを /speckit.implement に組み込む GitHub spec-kit 拡張(integrations/speckit-hashloom/)があります。機能ごとに作成するシームコントラクト案を入力とし、出力として verify --radius を完了条件にします。これらはツールであり、公開機能ではありません。MCP ツールや CLI コマンドは追加されません。
意図的に小規模に保っています。MCP ツールは5つ、CLI コマンドは5つで、コントラクトはプレーンな YAML です。この README に記載されていないものはすべてイシューです。
ライセンス
Apache 2.0
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。