mcpField
L
limpet

limpet

ローカル
github.com/KSym04メモリ・ナレッジ37 週間前に更新

limpet について

limpetは、AIコーディングエージェント向けのローカルな開発知識用MCPサーバーです。決定事項や事実、失敗した手法をコード構造に結び付け、コード変更時には理由とともに古い記憶として示します。Rustの単一バイナリとSQLiteを使い、ネットワーク通信は行いません。

主な機能

  1. 01コードシンボルへの記憶の紐付け
  2. 02コード変更時の古さの表示
  3. 03セッションをまたぐ知識の想起
  4. 04影響を受ける記憶と検証キューの確認
  5. 05SQLite保存とインポート・エクスポート

活用シーン

  1. 01コーディングセッション間でプロジェクトの決定事項を保持
  2. 02コード変更で以前の知識が古くなったか確認
  3. 03差分の影響を受ける記憶や決定事項を確認
  4. 04チームでプロジェクトの記憶を共有

MCP 対応

標準MCPを通じて、記憶の想起・保存・マッピング・管理、影響分析、変更された事実の検証ツールを提供し、コーディングエージェント向けの記憶バックエンドとして機能します。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

インストール方法は未掲載です

このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。

リポジトリ

ツール

ツール一覧はまだ取得されていません

ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。

詳細

🐚 limpet

小さなシェル。長く続く記憶。

CI License: MIT Rust Platforms 100% local

コードと同じように古くなる、AI コーディングエージェントのための記憶です。 エージェントがコードベースについて学んだこと(決定事項、検証済みの事実、失敗したアプローチ、注意点)は、説明対象の実際のコードに結び付けられ、すべてのセッションを通じて保持されます。そのコードが変わった瞬間に、理由とともに stale に切り替わります。Rust のバイナリが 1 つ、SQLite ファイルが 1 つ、標準の MCP、ネットワーク呼び出しはゼロです。

アニメーションデモ:記憶からの回答、編集すると理由とともに stale に切り替わり、元に戻すと回復する様子
アンカーのライフサイクルを実際の出力で紹介:すぐに回答し、編集すると記憶が stale になり、元に戻すと回復します

AI コーディングアシスタントを駄目にするのは、忘れることではなく、もはや正しくないことを覚えていることです。ベクトルストアは類似性を信頼し、時間減衰ツールはカレンダーを信頼し、Markdown のメモは永遠を信頼します。そのため、先月の関数の状態を今も信じているエージェントは、役に立たないどころか、自信たっぷりに間違えます。limpet は、各記憶を説明対象のコードの正規化 AST ハッシュに結び付けます。コードの名前を変更したり移動したりすれば記憶も追従し、編集すれば記憶は理由とともに明確に stale になり、元に戻せば回復します。自らの古さを検知することが limpet の根本的な考え方であり、それを実現するオープンなメモリレイヤーはほかにありません。

⏱️ 起動まで 30 秒

curl -fsSL https://raw.githubusercontent.com/KSym04/limpet/main/install.sh | bash

(Windows の場合:irm https://raw.githubusercontent.com/KSym04/limpet/main/install.ps1 | iex。インストールの全オプションはこちらをご覧ください。)

Claude Code を再起動し、任意のプロジェクトで /limpet と入力して、いつもどおり作業するだけです。

セッション 1:「スキャナーのバッチサイズは 50 です。共有ホストでは長いリクエストが強制終了されるためです」→ decision として保存され、使用する関数に結び付けられます

セッション 30、新しいコンテキスト: あなた: バッチサイズが 50 なのはなぜ? → エージェント: recall 1 回、約 350 トークンで完全な回答。ファイルを探し回る必要も、自分のコードベースを再度教える必要もありません。

その関数を編集すると → 記憶が表示されるすべての場所で stale: body_edited に切り替わります。最新でないものが最新であるかのように扱われることはありません。

🎯 limpet を選ぶ理由:検証可能な 4 つの主張

  • 誤りに気付きます。 記憶は AST ハッシュに結び付けられ、名前の変更やファイルの移動に追従し、実際に編集されると理由とともに stale になり、元に戻すと回復します。→ アンカーのライフサイクル
  • 保存した内容を確認できます。 すべての recall について、置き換えたファイル読み込みと比較したコストを示します。ベンチマークではトークン数が 4.2 倍少なく、limpet stats ではプロジェクトごとの使用状況をリアルタイムで確認できます。→ 実測値
  • リポジトリ全体をアンカーします。 シンボルレベルのアンカーには 11 種類の文法を使用し、それ以外のすべてのファイル(テンプレート、スタイル、設定)もファイルレベルでアンカーできます。→ インデックス化するのはリポジトリ全体
  • 省略によって事実を曲げません。 すべての応答に、マッチした数と返した数、除外した内容とその理由、インデックスの鮮度、stale の割合を含む誠実性エンベロープが付きます。ベンチマークのゲートでは、この基準を超えた limpet 自身の機能も削除されてきました。

limpet はベクトルデータベースでも、コード検索エンジンでも、コールグラフの万能ツールでもありません。コードに結び付けて「なぜ」を記憶し、その理由がもはや当てはまらなくなったときに知らせるレイヤーです。→ limpet が目指さないもの · 苦い経験を経て築かれた設計原則:PHILOSOPHY.md

🧠 これが必要な理由

コードインデクサーが答えるのは「どこに何があるか」です。コストのかかる知識は、どのファイルにもありません。

  • バッチサイズが50である理由
  • どのリファクタリングが試されてロールバックされたのか、そして何が壊れたのか
  • 顧客がフックするため、名前が変更できないメソッド
  • あの奇妙な cron ジョブが実際に何を防いでいるのか

エージェントはセッションのたびにこの情報を再導出したり、質問し直したりするため、トークンを消費します。さらに悪いことに、推測してしまう場合もあります。limpet は、エンジニアが知識に与えるのと同じライフサイクルを、その知識に与えます。

valid -> code changed -> stale (reason attached, confidence drops) -> re-verified or superseded

これを実現するのは3つの特性で、これらをすべて備えているものはほかにありません。アンカー付き(行番号やパスではなく、AST のボディハッシュを使用)、正直(すべての応答にエンベロープを付与し、何も黙って切り捨てない)、証拠付き(事実に、それを証明したコマンドを添付でき、アンカーが古くなったときにはそのコマンドを返す)。

👥 対象ユーザー

対象limpet が提供するもの
AI エージェントを使う個人開発者最初のセッションではコードベースを学習するために数万トークンを消費しますが、以降は recall ひとつで確認できます。/clear、コンパクション、新しいマシンでも情報が残ります。
チームadmin export で .limpet/memory.jsonl が書き出され、Git で管理できます。チームメイトはプル後にインポートします。オンボーディングの知識はリポジトリとともに移動し、Wiki とは異なり、コードが変わると古くなったことを知らせます。affected を使うと、差分によってリスクにさらされたドキュメント化済みの判断を確認できます。
テンプレート中心の技術スタック(Rails、Laravel、Vue、各種 CMS テーマ)すべてのファイルにアンカーを設定できるため、「このレイアウトは幅480pxで固定」という情報を実際のスタイルシートに紐付けられ、誰かが編集すると古くなります。これはシンボルのみを扱うインデクサーではできません。
オープンソースのメンテナーintent/decision のメモリーは、「この奇妙なコードがここにあるのはなぜか」という疑問に答え、「修正」する PR がマージされる前に役立ちます。episode のメモリーは、すでに2回失敗したリファクタリングを3人目のコントリビューターが再び試すのを防ぎます。
エージェントの開発者標準 MCP に対応した、モデルに依存しないメモリーバックエンドです。バイナリは1つ、ネットワーク通信は不要、SQLite の内容を確認できます。セキュリティレビューで説明することもありません。

対象外となるユーザー: 使い捨てのスクリプト、一度しか触らないリポジトリ、AI エージェントを使わないチーム。質問が繰り返される場合にのみ、メモリーの効果が得られます。

🧰 6 つのツール

ツール機能
recallタスクの説明を入力すると、トークン予算に合わせて順位付けされたメモリパックを返します。古くなった項目や矛盾する項目には必ずフラグが付けられ、隠されることはありません。同じ関連度の場合、検証済みの事実は未検証の主張より優先されます。source フィールドがない項目は証拠ではなく、未検証の主張です。
rememberメモリ(fact、decision、episode、insight、intent)を保存します。コードにひも付けてください。証拠を添付すると検証済みになります。同じアンカーにほぼ同一の本文がある場合は拒否されます(置き換え対象の既存 ID が示されます。force: true で上書きできます)。同じアンカーに異なる値を主張するメモリがある場合は、possible_conflicts として返され、書き込み時に矛盾を検出できます。private: true を指定するとメモリはローカルに保たれ(ここでは呼び出せますが、エクスポートからは除外されます)、origin を指定するとシード処理での書き込みが冪等になります。
mapファイルまたはシンボルの構造概要と、それにひも付けられたすべてのメモリを返します。シンボルを対象にした場合は、各エッジに unique/ambiguous/unresolved のラベルが付いた lineage(祖先、子孫、呼び出し元)も返します。コードとナレッジを 1 つの回答にまとめます。
affectedコミットしていない差分が影響するものを返します。シンボル、リスクにさらされているメモリ、編集中のコードを制約する判断が含まれます。
verify_queueアンカー先のコードが変更された検証済みの事実と、その事実を最初に証明した正確なコマンドを返します。コマンドを再実行し、結果を admin {op:"reverify"} に渡してください。これでキューが行き止まりではなくなります。
adminindex、status、forget、archive/restore、export/import(保護付き)、ledger/ledger_reset(削減効果の記録)、reverify、consolidate を実行します。Archive はメモリを削除せずに保管します。recall からは隠されますが、コードの変更に応じて古さの追跡は続き、現在の真偽状態で復元されます。また、何も隠れて失われないよう、フラグ付きでエクスポートされます。エクスポートでは private_withheld が報告されるため、呼び出し元はローカルに残ったメモリの数を把握できます。Reverify は検証のループを完了させます。古くなった検証済み事実に新しい証拠を適用すると、ダイジェストを再記録し、アンカーを現在のコードに再結合し、検証済みの信頼度を完全に復元して、再びアクティブにします。アンカーが解決できなくなっている場合は、推測せずに拒否します。Consolidate は、1 つのエントリにまとめる価値のある、同じアンカーを持つ重複度の高いメモリのクラスターを一覧表示します(remember と supersedes リンクを使用)。自動で統合することはありません。

すべての応答は、次の誠実性エンベロープで囲まれます。

{
  "data": [ ... ],
  "meta": {
    "freshness": { "indexed_at": "2026-07-03T10:12:44Z", "dirty": 0 },
    "completeness": { "matched": 7, "returned": 3, "omitted_reason": "budget" },
    "staleness": { "stale": 1, "contradicted": 0 }
  }
}

呼び出された項目には、本文にそのまま含まれている重要なタスク用語も記載されます("matched": "sweep anchored" のように、タスク内の出現順で最大 3 件)。これにより、項目が提示された理由を、本文を読み直さずに確認できます。本文に重要なタスク用語が完全一致で含まれていない場合、このフィールドはありません。その場合、項目はアンカーの近さ、ストップワードのみの一致、または語幹化・部分一致のテキスト検索によってパックに含まれています。

⚓ アンカーのライフサイクル

code change            anchor resolution         memory becomes
---------------------  ------------------------  -----------------------------
reformat / comments    same normalized AST hash  active (untouched)
rename symbol          body found under new FQN  active, anchor follows
move file              body found in new file    active, anchor follows
edit function body     hash differs at FQN       stale (body_edited), conf drops
delete symbol          body found nowhere        invalidated (kept as history)
duplicate bodies       multiple matches          stale (ambiguous_anchor)
edit anchored file     file content hash differs stale (file_edited), conf drops
delete anchored file   file row gone             invalidated (kept as history)
lose SOME anchors      others still resolve      stale (anchor_lost), never killed
move a trivial body    unique match, too small   stale (low_entropy), never re-pointed

複数アンカーを持つメモリが消滅するのは、すべてのアンカーが失われたときだけです。他のアンカーが引き続き解決できる状態でアンカーを1つ失うと、stale:anchor_lost に劣化しますが、残った知識は引き続き利用できます。また、remember は解決できないアンカーを、書き込み時に明確なエラーとともに拒否します。メモリが生まれた時点ですでに使えない、ということはありません。

同名の関数など(トレイト実装、オーバーロード、アクセサーペア)は1つの FQN を共有するため、シンボル指定には任意の @<disamb> サフィックスを付けて、対象を正確に指定できます。ソースコードでの表記どおりに記述しますが、空白は問いません(f@(int a, String b) と、正規化して保存された形式は同じ表記です)。指定できるのは、Rust のトレイトパス(固有実装では impl)、Go のレシーバー型(パッケージ関数では func)、Ruby のレシーバー(インスタンスメソッドでは self.、<<self.、#)、および C++、Java、C#、Python、JS/TS のパラメーターリストです。ジェネリックのアリティと JS/TS の static も含みます。曖昧な指定は拒否され、入力可能な正確な形式が一覧表示されます。

symbol: "go"      → refused: matches t.T.go@A, t.T.go@B, t.T.go@impl
symbol: "go@A"    → anchors to the A impl's body, and only that one
symbol: "go@impl" → anchors to the inherent impl, and only that one
symbol: "x@"      → anchors to a twin that carries no discriminator at all
                    (a type sharing its name with a method, say)

名前変更の追跡には、根拠が必要です。空の関数、単なる委譲スタブ、ほとんど空のファイルなど、内容が単純なコードで一致候補が1つしかない場合、その一致は追跡の根拠として拒否されます。アンカーを見た目が似た別の同名関数に黙って付け替えるのではなく、stale:low_entropy として示されます。元のコードが戻れば、すぐに回復します。

回復によって信頼度が不当に変わることはありません。古い状態になると信頼度に対するペナルティが一度だけ適用され、その直前の値も保存されます。そのため、原因がなくなったとき(ブランチを元に戻す、リバートする、stash pop するなど)に、ペナルティは全額返還されます。減衰は解決処理の回数ではなく原因ごとに適用されるため、一時的に見えなくなってもメモリの価値は損なわれません。

古い状態からの回復も対称的です。コードを元に戻すと(取り消した実験や git checkout など)、アンカーのハッシュが再び一致するため、次の呼び出しでメモリは active に戻ります。取り消された変更について再検証する必要はありません。無効化についても同様です。ブランチ切り替え、git stash、リベース中の状態によってファイルが一時的に消えても、それで終わりではありません。コードが戻り、アンカーが解決できるようになれば、メモリは回復します。最終状態は superseded だけです。これはファイルシステムの一時的な変化ではなく、人間が意図的に決めたことを記録します。

矛盾は明示的なリンクとして扱われます。新しいメモリが古いメモリと矛盾している場合、どちらかがもう一方を supersedes するまで、矛盾のフラグを付けた状態で両方を表示します。履歴が黙って上書きされることはありません。

🔬 古い状態を検知する方式の比較

どのメモリツールも、いずれ同じ問いに直面します。これは今も正しいのか? 主流の回答は4つありますが、どれもコードの静かな変更を検知できません。

古い状態を検知する方式典型的な用途検知できないこと
時間ベースの減衰:スケジュールに沿ってメモリを「要確認」の状態に近づける減衰ポリシーのあるメモリツール時間の経過は真偽を示しません。カレンダーでは、5分前のリファクタリングでどのメモリが壊れたのか特定できず、変わっていない安定した知識にまで確認を促します。
LLM による無効化判定:モデルが新しい入力と古い事実の矛盾を判断する会話メモリレイヤー新しい発言があった場合にしか動作しません。セッション間でコードが変化しても何も起こらず、メモリは自信満々に誤ったままです。
埋め込み類似度ベクトルストアと RAG パイプライン矛盾とほぼ同一の内容を、コサイン類似度では見分けられません。
手動による整理:「定期的に学んだことを見直してください」レビューボットのナレッジベース、Wiki人間が、人間の都合のよいタイミングで文章を整理しますが、被害が出た後です。
決定論的 AST アンカー(limpet)古い状態かどうかは、コード自体から算出される事実です。編集後、次のツール呼び出しで、対象のメモリと正確な理由(body_edited、anchor_lost、low_entropy)を判定します。コードを元に戻せば回復します。

最初の4つは推測によって知識を失効させます。limpet は確認します。

🪙 領収書:トークン削減効果の実測

永続的なメモリは、事実を再導出するよりも大幅に低コストです。削減効果の内訳は次のとおりです。

  1. 回答は出典ではなく、結論として引き継がれます。 メモリは30トークンに要約された回答ですが、その学習に使ったファイルは数千トークンに及びます。すでにわかっている事実を再導出するためにコードを読むと、毎回のセッションで全額を支払うことになります。想起なら、質問ごとに一度だけです。
  2. 最も無駄な支出は、成功しない探索です。 バッチサイズが50である理由、ロールバックされたリファクタリング、凍結されたAPIは、どのファイルにも記載されていません。メモリがなければ、エージェントはgrepして読み込んでも、結局わかりません。つまり、トークンを使っても何も得られません。メモリがあれば、これらは最も低コストな質問になります。
  3. 応答は予算に合わせて詰められ、ノイズが削られます。 recall はトークン予算を受け取り、関連性の高いものから順に詰め、関連性の低い末尾を除外し、除外した内容を報告します。支出は設定した予算の範囲内で、たまたま該当した内容に左右されません。
  4. コンテキストを失っても、再び教え直す必要はありません。 圧縮、/clear、新しいセッションでも、知識はコンテキストウィンドウの外に保持され、再導出のコストではなく想起のコストで戻ってきます。

現実的な9ファイルのフィクスチャサービスに12件のメモリを登録し、エージェントが通常、毎セッションで再回答する10個の質問を行う再現可能なベンチマークで測定しました。

question                                                   files+grep   recall   ratio  in code?
----------------------------------------------------------------------------------------------------
why is the batch size 50 and why is there a queue at all         1929      368    5.2x  no (answer only in memory)
why does the scanner skip draft products, is that a bug          1630      316    5.2x  no (answer only in memory)
how is the health score computed                                 1630      364    4.5x  yes
why semicolon delimiter and BOM in the csv export                1327      373    3.6x  no (answer only in memory)
where do report files get written and why                        1327      325    4.1x  no (answer only in memory)
how long are download tokens valid                               1023      174    5.9x  yes
has anyone tried streaming the csv export                        1327      318    4.2x  no (answer only in memory)
can I rename check_product in the scanner                        1630      313    5.2x  no (answer only in memory)
what does the nightly cron actually exist for                     803      330    2.4x  no (answer only in memory)
how often does the dashboard poll progress and can I lower it    1072      345    3.1x  no (answer only in memory)
----------------------------------------------------------------------------------------------------
TOTAL                                                           13698     3226    4.2x

ベンチマーク全体でトークンを4.2倍削減(76%節約)。 次の手順で、ご自身でも再現できます。

cargo build --release
python3 bench/token_savings.py

この数値はベンチマークだけのものではありません。limpetはお客様自身の領収書も記録します。すべての想起について、同じ手法でファイルを読む場合の反実仮想コストと比較します。実行中のサーバーでは、admin {op:"ledger"} が実セッションの数値(節約したトークン数、回避した読み込み回数、想起回数)と累計の数値(同じ項目に加えて、重複のないクエリ数)の両方を報告します。limpet stats CLIとUIヘッダーが報告するのは累計のみです。どちらも想起を処理しないため、ここでセッションの数値を表示しても、常にゼロのままだからです。節約がマイナスの場合もそのまま表示し、ゼロに切り上げることはありません。また、アンカーのないメモリの基準値はゼロとして扱います。そのため、この数値はマーケティング上の誇張ではなく、控えめな下限値です。

有効なメモリが9件、節約したトークンが134kと表示されたターミナルのステータスライン
Claude Codeのステータスラインに表示されたリアルタイムの領収書:有効なメモリと累計の節約トークン数。ストアから直接読み取ります

数値を鵜呑みにするのではなく検証できるよう、測定方法を明記します。

  • 「limpetなし」のコストは、回答を含む最小限のファイルセットに、検索の往復分として一律300トークンを加えた値です。実際のエージェントは最小限のファイルセットより多く読むため、実際の節約量はさらに大きくなります。
  • 両方のコストで同じく、トークン数をceil(bytes/4)で推定します。
  • 10個の質問のうち8個は、上記で「no」としています。回答はどのファイルにも、どれだけトークンを使っても存在しません(意思決定、履歴、暗黙知)。ファイルを読めばコードは確認できますが、回答は得られません。それでも、節約が無限大だと主張するのではなく、ファイル読み込みコストに対してlimpetのコストを全額計上しています。
  • このスクリプトはリグレッションゲートとして機能します。節約率が4倍未満になると、ゼロ以外の終了コードで終了します。
  • フィクスチャのファイルは58~179行です。実際のソースファイルは数倍の大きさになるため、「なし」の側のコストはファイルサイズに応じて増えますが、想起の応答は増えません。

鮮度にも領収書があります。bench/lag_bench.py は2,000、10,000、50,000ファイルの合成リポジトリを構築し、アンカー付きシンボルを1、32、100件のバッチで編集して、すべての編集が検出されるまでにスイープ呼び出しが何回必要かを測定します。ファイル数とバッチ幅にかかわらず、1回です。スイープ予算内で、アンカーを含むファイルが先に再インデックスされるためです。同じ実行で、変更のないリポジトリでスイープを行うコストも測定します。2,000ファイルで1回あたり156ミリ秒、10,000ファイルで372ミリ秒、50,000ファイルで1,206ミリ秒です。最後の数値が、FSイベントウォッチャーが約束ではなく、ベンチマークで条件を検証するバックログ項目として設計されている理由です。鮮度の遅延にウォッチャーは不要ですが、50,000ファイルでのスイープコストには必要です。

🗺️ ビジュアルメモリ

limpet ui --port 9748

UI は MCP サーバーとは別の独立したコマンドです。limpet install の後に Claude Code が自動的に起動するのは limpet serve(stdio)です。自分で limpet ui を起動しない限り、ポートでリッスンするものはありません。http://127.0.0.1:9748 への接続が拒否されても、MCP サーバーが壊れているわけではありません。UI が起動していないだけです。

脳のシルエット状に配置されたlimpetのビジュアルメモリグラフ。皮質帯には健全性に応じた色のメモリがあり、白質にはコードシンボルが配置されている
limpet ui:脳として表現されたlimpetストア。緑色のメモリは信頼でき、琥珀色はコードの変更によって古くなり、灰色は置き換え済みです。四角形はメモリが結び付いているシンボルです

http://127.0.0.1:9748 を開くと、脳の形に配置されたナレッジグラフをリアルタイムで確認できます。メモリは皮質帯に収まり、結び付いているファイルやシンボルは白質に配置され、すべてのアンカーは内側へ伸びます。メモリのサイズは確信度に応じて変わり、色は健全性を示します(緑は有効、琥珀色は古い、赤は無効化済み、灰色は置き換え済み)。検証済みのメモリには明るいリングが付き、矛盾や置き換えのエッジも描画されます。全プロジェクト表示では、ストアが9つの葉に大きい順で配置され、それぞれにプロジェクト名が表示されます(ストアが9つを超えると、葉は共有されます)。そのため、メモリ全体の形をひと目で把握できます。シルエットは表示されている内容に合わせて拡大縮小され、小さなプロジェクトではシルエットを埋められないことをフッターで知らせます。レイアウトは決定論的で(同じデータは常に同じ図になります)、グラフが安定すると、表示中にフレームごとの処理は発生しません。「要確認」フィルターを使うと、何がなぜ古くなったのかを正確に確認でき、再検証コマンドもワンクリックで実行できます。他のツールがコードの構造を可視化するのに対し、limpet はエージェントが把握している内容と、それが今も正しいかどうかを可視化します。同じ単一バイナリで配信され、127.0.0.1 のみで待ち受けます。

📦 インストール

1行でインストールできます。 インストーラーはお使いのプラットフォーム向けの最新リリースバイナリをダウンロードし、sha256 を検証してインストールしたうえで、Claude Code に登録します。

macOS / Linux:

curl -fsSL https://raw.githubusercontent.com/KSym04/limpet/main/install.sh | bash

Windows(PowerShell):

irm https://raw.githubusercontent.com/KSym04/limpet/main/install.ps1 | iex

その後、Claude Code を再起動し、任意のプロジェクトで /limpet と入力します。これでセットアップは完了です。(LIMPET_INSTALL_DIR でインストール先を変更でき、LIMPET_VERSION でリリースタグを指定できます。)

スクリプトをシェルにパイプするのを避けたい場合は、以下の手順で同じ操作を手動で行えます。Apple Silicon 搭載 macOS、x86_64 Linux、x86_64 Windows 向けのビルド済みバイナリは最新リリースで提供されています。すべてのアセットには sha256 が公開されています。バイナリを信頼する前に、必ず検証してください。

macOS(Apple Silicon)

curl -fsSLO https://github.com/KSym04/limpet/releases/latest/download/limpet-aarch64-apple-darwin.tar.gz
curl -fsSLO https://github.com/KSym04/limpet/releases/latest/download/limpet-aarch64-apple-darwin.tar.gz.sha256
shasum -a 256 -c limpet-aarch64-apple-darwin.tar.gz.sha256
tar xzf limpet-aarch64-apple-darwin.tar.gz          # extracts a single `limpet` binary
sudo install -m 755 limpet /usr/local/bin/limpet
limpet install

macOS がダウンロードしたバイナリを隔離する場合があります。実行できない場合は、xattr -d com.apple.quarantine /usr/local/bin/limpet でフラグを解除してください。

Linux(x86_64)

curl -fsSLO https://github.com/KSym04/limpet/releases/latest/download/limpet-x86_64-unknown-linux-gnu.tar.gz
curl -fsSLO https://github.com/KSym04/limpet/releases/latest/download/limpet-x86_64-unknown-linux-gnu.tar.gz.sha256
sha256sum -c limpet-x86_64-unknown-linux-gnu.tar.gz.sha256
tar xzf limpet-x86_64-unknown-linux-gnu.tar.gz      # extracts a single `limpet` binary
sudo install -m 755 limpet /usr/local/bin/limpet    # or ~/.local/bin if it is on your PATH
limpet install

Windows(x86_64、PowerShell)

Invoke-WebRequest https://github.com/KSym04/limpet/releases/latest/download/limpet-x86_64-pc-windows-msvc.zip -OutFile limpet.zip
Invoke-WebRequest https://github.com/KSym04/limpet/releases/latest/download/limpet-x86_64-pc-windows-msvc.zip.sha256 -OutFile limpet.zip.sha256
# compare the two hashes; they must match
(Get-FileHash limpet.zip -Algorithm SHA256).Hash
Get-Content limpet.zip.sha256
Expand-Archive limpet.zip -DestinationPath "$env:LOCALAPPDATA\limpet"   # extracts limpet.exe
# add the folder to PATH once, then restart the terminal
[Environment]::SetEnvironmentVariable('Path', $env:Path + ";$env:LOCALAPPDATA\limpet", 'User')
limpet install

Rust を使用する場合(rustup.rs):Intel 搭載 Mac、ARM Linux、およびビルド済みバイナリがないプラットフォーム向けの方法です。

cargo install limpet
limpet install

Claude Code を再起動すれば完了です。(limpet install --dry-run を実行すると、設定に加わる変更を事前に正確に確認できます。limpet uninstall で変更を元に戻せます。)

後で更新するには limpet update を実行します。お使いのプラットフォーム向けの最新リリースバイナリを取得し、公開済みの sha256 と照合して検証した後、実行中の実行ファイルをアトミックに置き換えます。limpet update --check は、インストールせずに新しいバージョンがあるかどうかを報告します。ネットワークに接続するコマンドはこれだけです。MCP サーバーが新しいバイナリを読み込むよう、実行後に Claude Code を再起動してください。

🚀 日常的な使い方

任意のプロジェクトで /limpet を実行すると、コードがインデックス化され、すでに把握している内容がすべて呼び出され(古くなった項目にはフラグが付きます)、セッションがメモリ優先モードに切り替わります。以降、エージェントは学習した内容をその都度保存します。上記の30秒で起動が、一連の流れのすべてです。

日常的に使うコマンド:

コマンド機能
/limpetセッションのインデックス作成+想起+メモリ優先モード
/limpet status件数と対応が必要な項目
/limpet review保存済みの検証コマンドを使って古くなった事実を再検証
/limpet export.limpet/memory.jsonl を書き出して、コミットしてチームと共有
limpet statsトークン節約の記録:累計と算出方法(セッションの数値は、実行中のサーバー内で admin {op:"ledger"} を実行すると取得できます)
limpet doctor1画面でセットアップを診断します。インストール後とアップデート後にも自動実行されます
limpet uiナレッジグラフを http://127.0.0.1:9748 で表示し、すべてのプロジェクトを1つのビューに表示
limpet statuslineステータスラインのセグメント(メモリ+節約したトークン数)。読み取り専用で即時表示
limpet hookClaude Code フック用の1行の SessionStart ブリーフ。読み取り専用
limpet update最新リリースにセルフアップデートします。チェックサムで検証済み(ネットワーク接続を行う唯一のコマンド)
limpet demo使い捨てリポジトリでアンカーのライフサイクル(active → stale → healed)を実演します。自己検証機能付き
limpet seed <file>既存の MEMORY.md / CLAUDE.md をアンカー付きメモリに取り込みます。再実行しても何も行いません

データは ~/.local/share/limpet/ に保存され、リポジトリごとに SQLite ストアが1つ作成されます。JSONL をプルした後、チームメイトは limpet import を実行します(--path <repo-relative file> を指定すると、別のエクスポートをインポートできます)。

MEMORY.md は残しておきましょう。 limpet seed MEMORY.md はプレーンなメモファイルを個別のメモリに分割します。箇条書きと段落はエントリになり、リポジトリ内のファイル名を含むチャンクはそのファイルにアンカーされます(そのファイルが変更されると古くなります)。また、すべてのメモリは mined として登録されます(再確認されるまでは、検証済みの事実より信頼度が低くなります)。変更のないファイルに対して再実行しても何も行いません。言い換えたメモは異なるものとして扱われます。元の文面はすでに保存されているため、書き込み時の重複排除によって新しい文面は拒否され、その旨がレポートに表示されます。新しい文面も保存するには --force を付けて再実行し、その後、エージェント側で古いメモを置き換えてください。

あらゆるプラットフォームで使えるステータスライン。 limpet statusline --root <project dir> はシェル用のセグメント(| 🐚 13 · ↑32k tokens saved。UI の実行中は、件数からプロジェクトのグラフにリンクします)を出力するか、何も出力しません。ストアを厳密に読み取り専用で開き、書き込みは一切行わず、常に終了コード 0 で終了するため、プロンプトに安全に組み込めます。描画処理はバイナリに含まれているため、同じ1行のコマンドを macOS/Linux の bash ステータスラインでも、Windows の PowerShell または cmd のステータスラインでも使えます。sqlite3 CLI も bash も不要です。

# inside a Claude Code statusline.ps1
$limpetSeg = & limpet statusline --root $projectDir

最も簡単な設定は、Claude Code からバイナリをステータスライン全体として直接呼び出す方法です。~/.claude/settings.json に追加してください。

{
  "statusLine": {
    "type": "command",
    "command": "limpet statusline --root \"$CLAUDE_PROJECT_DIR\""
  }
}

すでにカスタムのステータスラインを使っていますか?バイナリの出力を1つのセグメントとして追加してください。ただし、store.db を sqlite3 で直接クエリしないでください。リポジトリごとのストアキーの方式はバージョン間で変更されます(v0.9.0 ではパスのハッシュから移植可能な git リモート ID に変更されました)。そのため、手書きのクエリは気づかないうちに一致しなくなり、セグメントが表示されなくなります。現在の方式に対応しているのは limpet statusline だけです。ステータスラインの設定を確認するには limpet doctor を実行してください。バイナリを呼び出している場合は ok、方式が変わると動作しなくなる手書きのストアクエリがある場合は warn と表示され、何も設定されていない場合は追加すべき正確な行が示されます。

/limpet statusline で無効にできます(~/.claude/.limpet-statusline-off に書き込みます。このコマンドはこのフラグを参照します)。

セッション開始時の自動想起。 フックがない場合、メモリ優先の動作は、エージェントが /limpet の入力を忘れないことに依存します。SessionStart フックを設定すると、すでにインデックス化されているプロジェクトの新しいセッションはすべて、コンテキストに注入される1行のブリーフ(「このプロジェクトには limpet メモリがあります:アクティブなメモリ 13 件、古くなったメモリ 2 件…」)とともに始まり、エージェントは読み込み前にメモリを想起します。~/.claude/settings.json に追加してください。

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          { "type": "command", "command": "PATH=\"$HOME/.local/bin:$HOME/.cargo/bin:$PATH\" limpet hook" }
        ]
      }
    ]
  }
}

プロジェクトにストアがない場合、limpet hook は何も出力せず(インデックス化されたリポジトリ外のセッションはクリーンなままです)、ストアを厳密に読み取り専用で開き、常に終了コード 0 で終了します。明示的な PATH のプレフィックスが重要です。フックはログインシェルではないシェルで実行されるため、~/.local/bin や ~/.cargo/bin が含まれていないことがよくあります。また、バイナリが見つからずに黙って失敗するのは、このコマンドが決して表面化させないように設計されている種類の障害です。Windows では %USERPROFILE%\AppData\Local\Programs\limpet\limpet.exe hook を使用してください。

プロジェクトへの初期データ登録

/limpet scan は、既存の情報をもとにリポジトリのメモリを初期化します。light モード(デフォルト)ではマージコミット、タグ、README を収集し、deep ではすべてのドキュメント、本文の長いコミット、アシスタントのプロジェクトメモリディレクトリを追加します。事前のリコールで、ストアがすでに回答できる候補を除外するため、再実行時は不足分だけが追加されます。収集処理はサブエージェントで実行されるため、生の git 出力やドキュメントのダンプがメインコンテキストに入りません。戻ってくるのは精選された候補テーブルだけです。書き込み前に、2 段階で候補を承認します。確信度の高い項目はまとめて承認または却下し、判断の分かれる項目は 1 つずつ確認します。承認された各メモには origin が記録され、次回以降のスキャンで重複を検出できます。また、非公開ソースの項目は private: true を付けて保存されるため、エクスポートされることはありません。

🌳 リポジトリ全体をインデックス化し、意図的に軽量化

リポジトリ内のすべてのファイルがインデックス化され、アンカーとして指定できます。 同梱の文法に対応するファイル(PHP、JavaScript、TypeScript、Python、Rust、C/C++、Go、Java、Ruby、C#、Bash)では、関数、クラス、インポート、syntactic とラベル付けされた名前ベースの呼び出し参照、さらに継承関係(extends、implements、impl_trait、embeds、mixin)を完全に抽出し、map の系譜を通じて表示します。それ以外のすべてのファイル(.twig、.scss、.vue、.blade.php、.erb、.md、.yml、設定ファイルなど)は、コンテンツハッシュを含むファイルレベルのノードを取得します。これにより、メモのアンカーとして指定でき、ファイルが変更された時点で stale:file_edited になります。テンプレート主体のスタックでは、記憶する価値のある知識は実際にはこの領域にあります。

レガシーなエンコーディングも適切に処理します。文法に一致するファイルが有効な UTF-8 ではない場合(たとえば、古い C++ エンジンの CP949 や UTF-16 のソース)、インデックスから消えるのではなく、ファイルレベルのアンカーが維持されます。文法によってファイルのアンカー性が向上することはあっても、低下することはありません。

意図的に走査対象から除外するものは、.gitignore に含まれるすべての項目、任意の .limpetignore(gitignore 構文を使用し、git リポジトリ以外でも動作します)に含まれるすべての項目、ほぼどの環境でも生成物またはベンダー提供物となる組み込みのディレクトリ群(node_modules、vendor、target、dist、build、__pycache__、.venv/venv、Python のキャッシュ、.next/.nuxt/.svelte-kit、Pods、.gradle、bower_components、coverage、.terraform)、隠しファイルの不要な項目、*.min.* アセット、8MB を超えるファイルです。512KB を超えるソースファイルはファイルレベルでインデックス化しますが、シンボルの解析は行いません。この上限によって、生成されたバンドルから tree-sitter を保護できます。また、手書きの巨大な翻訳単位もインデックスから消えず、アンカーとして指定できます。これらの制限により、.gitignore のない大規模なベンダー提供の依存関係ツリーが CPU を占有するのを防ぎます。それ以外の項目を除外するには .limpetignore を使用してください。

LSP、型推論、公開可能な呼び出しグラフを保証する機能はありません。インデックスは、メモのアンカーポイント、無効化、リコールの局所性を提供するためのものです。同梱されているすべての文法にはテストスイート内にフィクスチャによるテストがあります。言語は数を増やすためではなく、テスト可能になった時点で追加されます。

鮮度モデル:すべてのツール呼び出しで、範囲を限定した増分スイープが実行されます(変更されたファイルは tree-sitter により数ミリ秒で再解析されます)。クエリがインデックス化の完了を待つことはありません。まだダーティな項目はエンベロープに一覧表示されます。

⚙️ リポジトリごとの設定(.limpet.json)

リポジトリのルートに置く任意の .limpet.json で、2 つの項目を調整できます。これはサイズ制限付きの単純なルックアップテーブルで、同梱されている文法に照らして検証されます。不正なファイルがあると、明示的に実行した index は無視せず、エラーで停止します。

{
  "extensions": { "inc": "cpp", "module": "php" },
  "auto_import": true
}
  • extensions は、ファイル名の拡張子を同梱されている文法(php、js、ts、py、rust、cpp、go、java、rb、cs、bash)のいずれかに対応付けます。これにより、組み込みテーブルにない拡張子でも、テンプレートを多用するスタックやレガシーなスタックからシンボルを完全に抽出できます。一致する拡張子のうち、最も長いものが優先されるため、固有の blade.php が汎用の php より優先されます。
  • auto_import(デフォルトは true)を有効にすると、初回のインデックス作成時に、コミット済みの .limpet/memory.jsonl から新しいストアにデータを取り込みます。そのため、リポジトリをクローンしたチームメイトは、追加の手順なしで共有メモリを利用できます。これは新規ストアの場合に限り、初回の 1 回だけ、limpet import と同じ保護された経路で実行されます。

移植可能な識別情報。 リポジトリのストアは、git の origin リモートがある場合はそれをキーとし、ない場合は正規化されたパスをキーとします。チェックアウトを移動したり、再クローンしたりしてもメモリは引き継がれ、異なる 2 つのリポジトリが同じストアに衝突することはありません。既存のストアは初回オープン時に自動的に移行され、誤って別のリポジトリのものと認識されることはありません。既存のストアがどのリポジトリのものか曖昧な場合は、再割り当てせず、そのまま残します。

🔒 セキュリティ方針

  • デフォルトではローカルで動作します。 インデックス作成、リコール、メモリ、UI は一切ネットワークに接続しません。テレメトリー、API キー、クラウド通信もありません。唯一の例外は、明示的に実行する limpet update です。これは HTTPS 経由でチェックサム検証済みのリリースバイナリを取得し、limpet/<version> の User-Agent 以外は送信しません。UI は 127.0.0.1 にバインドされ、埋め込みの 1 ページのみを GET で配信します。
  • シークレットは永続化されません。 remember はすべての本文とエビデンス出力をスキャンし、認証情報に該当する形式(クラウドアクセスキー、プロバイダートークン、PEM 秘密鍵ブロック、JWT)が含まれている場合は保存を拒否します。そのため、シークレットがローカルストアや共有 .limpet/memory.jsonl に入ることはありません。
  • プライベートなメモリはローカルにとどまります。 private: true を指定して保存したメモリは、プロジェクト内で通常どおりリコールされますが、export の出力には含まれません。そのため、機密性の高いコンテキストが共有 .limpet/memory.jsonl に入ることはありません。
  • シェルによる文字列展開はありません。 外部コマンド(git のみ)は引数配列で実行され、シェルに文字列が渡されることはありません。
  • パス検証。 MCP 経由で渡されるすべてのファイルパスは、リポジトリのルートに対して検証されます。絶対パスとディレクトリをさかのぼるパスは、単一のチェック箇所で拒否されます。
  • SQL はすべてパラメーター化されています。 コードベース内で、ユーザー入力を連結するクエリはありません。
  • 不正な入力があっても処理は継続します。 JSON-RPC ループは、解析エラーやハンドラーのパニックに対して JSON-RPC エラーを返し、処理を継続します。
  • install は自身の mcpServers.limpet エントリーのみを編集し、認識できない設定には手を加えません。uninstall はその変更だけを正確に元に戻します。
  • インポートは保護された経路で行われます。 チームメイトから受け取った .limpet/memory.jsonl は信頼できない入力であるため、import では remember と同じルールを適用します。シークレットは拒否されるため、ピアから受け取った場合でもストアに入ることはありません。本文のサイズは制限され、信頼度は適切な範囲に収められ、将来の日付のエントリーによってマージが汚染されることはありません。また、インポートされたアンカーハッシュはローカルコードに対して再解決されるため、偽装されたハッシュで鮮度を偽ることはできません。拒否された行は件数が記録され、黙って適用されることはありません。
  • セットアップに問題がある場合は limpet doctor を実行してください。 バイナリ、Claude Code の登録(バイナリの移動による不一致を含む)、スキルファイル、ストア、バージョンスタンプ、インデックスを確認し、各行に ok または FAIL を表示します。install と update の実行後にも自動で実行されます。

🚫 limpet ではないもの

  • 汎用の AI メモリストア、ベクトルデータベース、RAG パイプラインではありません。埋め込みも、類似性に基づく推測もありません。アンカーは決定論的な AST ハッシュであり、古くなっているかどうかはスコアではなく事実です。コードを認識しないメモリストアは、コードが変わっても気づきません。変化を検知することこそが、limpet の根本的な前提です。
  • コード検索エンジンではありません。エージェントにはすでに grep があります。
  • 呼び出しグラフの全知的な情報源ではありません。呼び出しエッジは構文に基づくものであり、そのように明示されています。
  • クラウド型メモリプラットフォームではありません。アカウントも、同期も、サーバーもありません。
  • 検索品質は書き込まれる内容に左右されます。短く、具体的で、アンカー付きのメモリはよく想起され、ツールスキーマによってエージェントがまさにそれを行うよう導かれます。

🧭 ロードマップ

ROADMAP.md では、リリース済みの内容(ポータブルなリポジトリ ID、ステータスラインの診断機能、構造的な系譜グラフ、11 言語に対応した文法の第 2 波、0.13 の鮮度チェック、0.14 の真実性レイヤー:ランキングシグナルとしての検証、書き込み時の矛盾の提示と重複の拒否、0.15 の大規模環境での鮮度チェック第 2 部:@ で指定可能な同一項目の FQN による区別、スロット優先のアンカーラダー、想起項目上の一致語句、lag-bench のウォッチャー判定、0.16 の改善ループ:admin による再検証で、再証明されたメモリをアクティブ状態に戻す機能、その裏側にあるスキーマ v8 の信頼度返還、読み取り専用の統合候補、そして macOS/Linux で古いサーバーイメージを実行中の場合に表示される診断アドバイス、0.16.1 の監査に関するフォローアップ:線形時間を保証する句読点境界でのシークレット検出、推測ではなく集計され、何も提供しなかったサーフェスからは公開されない session 台帳の数値、clippy、依存関係の勧告、宣言された MSRV に関する CI ゲート)、このリリースに含まれる内容(STABILITY.md で適用と文書化が行われている v1.0 安定性契約のコード部分、脳を模したレイアウトに改められたビジュアルメモリページ、そしてブラウザーからのすべてのリクエストが 5 秒の読み取りタイムアウトを待つのを防ぐ limpet ui の修正)、および今後の内容(契約が十分に検証された後の 1.0 タグ)をご確認ください。すべてを貫くルールは一つです。機能は、記録(limpet stats の台帳またはベンチマーク)か、誠実性の枠組みに役立つ場合にのみリリースされます。

⚖️ 依拠とライセンス

limpet は判断を支援するものであり、その代わりとなるものではありません。鮮度と信頼度のシグナルは、コード構造から算出されるヒューリスティックであり、証明ではありません。「アクティブ」なメモリは、保存された知識が今も有効であることを示す limpet にとって最善の証拠ですが、正確性や完全性を保証するものではありません。間違っていては困る情報に依拠する前に、特にセキュリティ上重要な変更や本番環境の変更では、必ず検証してください。不確実性を隠さず表面化させることが設計思想のすべてです(PHILOSOPHY.md)。そして、それによって守られるのは、提示されたフラグを確認した場合に限られます。

本ソフトウェアは「現状のまま」提供され、いかなる種類の保証もありません。また、以下のライセンスに定めるとおり、著者は本ソフトウェアの使用に関する一切の責任を負いません。

貢献を歓迎します。貢献は、プロジェクトと同じ MIT ライセンスのもとで受け入れられます(インバウンド=アウトバウンド)。プルリクエストを作成することで、貢献がこれらの条件に基づいて配布されることに同意したものとみなされます。CONTRIBUTING.md をご覧ください。

📄 ライセンス

MIT。LICENSE をご覧ください。MIT の許諾通知には、保証の否認と責任の制限が明示されています。これらの条項が、ユーザーと著者の双方を法的に保護する効力を持ちます。

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。