inspeximus: agent memory with provenance, GDPR erasure and a tamper-evident audit trail について
inspeximusは、記憶の訂正と監査証拠が必要な開発者向けのAIエージェント用長期記憶ライブラリ兼MCPサーバーです。署名付きハッシュチェーンで操作を記録し、検証可能な消去証明を作成しますが、証明の対象はこのストアに限られます。
主な機能
- 01キー指定の訂正で旧値を退役
- 02訂正の復元を決定として記録
- 03検証可能な対象者消去証明
- 04署名付きハッシュチェーンの操作ログ
- 05複数のエージェントフレームワーク向けアダプター
活用シーン
- 01訂正済みの事実が再び現行値になるのを防止
- 02消去請求への対応と証明の提示
- 03行動時に保持していた記憶の確認
- 04エージェントへの永続記憶の追加
MCP 対応
MCPサーバーとして、Claude Code、Cursor、Windsurf、Codex、Clineなどのクライアントに記憶機能を提供します。READMEにはLangChain、LangGraph、ADKなどのフレームワーク向けアダプターも記載されています。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
uvx inspeximusINSPEXIMUS_PATHPath to the JSON memory file the server persists to (defaults to ./inspeximus_memory.json).INSPEXIMUS_ECHO_GUARD1 (default) blocks a restated retired value from resurrecting a corrected fact; 0 = legacy keyed supersession.INSPEXIMUS_EMBED_URLOptional OpenAI-compatible /embeddings endpoint for SEMANTIC recall (e.g. http://localhost:11434/v1/embeddings for local Ollama). Unset = deterministic lexical recall.INSPEXIMUS_EMBED_MODELEmbedding model id used with INSPEXIMUS_EMBED_URL (default: text-embedding-3-small; for Ollama use e.g. nomic-embed-text).ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ツール
135掲載時のツール一覧 · 今日に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| key | any | いいえ | |
| tags | any | いいえ | |
| text | string | はい | |
| mtype | any | いいえ | |
| value | number | いいえ | |
| object | any | いいえ | |
| source | string | いいえ | |
| user_id | any | いいえ | |
| agent_id | any | いいえ | |
| reaffirm | boolean | いいえ | |
| session_id | any | いいえ | |
| derived_from | any | いいえ |
詳細
inspeximus
AI エージェントのための、改ざんを検知できる長期記憶です。事実を一度訂正すれば、古い値は無効なままです。ある人物を消去して、その証拠を示せます。エージェントが行動した時点で知っていたことを、監査担当者に提示できます。依存関係ゼロの Python ファイル1つと、MCP サーバーを備えています。
消去証明の対象はこのストアのみであり、ベクトルインデックス、プロンプトログ、バックアップは対象外です。また、これは整合性を保証する仕組みであり、コンプライアンス認証ではありません。
クイックスタート · ドキュメント · mem0 および Graphiti との比較 · mem0 からの移行 · EU AI Act および GDPR の証拠 · Claude Code、1行で設定 · 透明性ログ · PyPI
pip install "inspeximus[crypto]"
inspeximus demo # a first result: offline, touches nothing of yours
from inspeximus import Inspeximus
m = Inspeximus("memory.json")
m.remember("The staging database is db-3.internal", key="staging-db")
m.remember("The staging database is db-7.internal", key="staging-db") # a correction
m.recall("which staging database")[0]["text"] # 'The staging database is db-7.internal'
m.revert("staging-db") # and it is reversible, on purpose
memory.jsonは名前にすぎません。新しいストアは SQLite ファイルです。inspeximusまたは
sqlite3モジュールで読み込み、json.loadやcatは使わないでください。
inspeximus を選ぶ理由
エージェントが何日も稼働し、その間に保持している事実が変わる場合や、後から誰かに、何を知っていたか、何を消去したかを尋ねられる可能性がある場合にお使いください。それが設計のすべてです。
| 状況 | おすすめ |
|---|---|
| すでに訂正した値を、エージェントが自信たっぷりに繰り返し続ける | remember(key=...):訂正が優先され、古い内容を言い直しても復活せず、revert() は記録された判断になります |
| 消去する権利の行使を求められた場合、またはエージェントが行動した時点で何を知っていたか監査人に尋ねられた場合 | erasure_certificate() を伴う forget_subject()、および matches() を備えた署名付きアクション台帳 |
| Claude Code、Cursor、Windsurf、Codex、Cline を使っていて、セッション間でメモリを保持できない場合 | MCPサーバーを設定する1行 |
| フレームワーク(LangChain、LangGraph、ADK、Hermes、Haystack)を使っていて、メモリへの書き込みが行われたことを証明する手段がない場合 | アダプターとレシートチェーン |
agno は唯一、私たちが管理していないものです。 独自のクックブックに公式の統合例
cookbook/11_memory/integrations/inspeximus_integration.py
を掲載しており、2026-09-20 に
agno#10146 でマージされました。ほかに
mem0、zep、memori、dakera も掲載されています。agno 自身の README では、これを
"訂正が訂正されたまま保たれる inspeximus" と説明しています。このファイルを置く場所を私たちが作ったわけでも、管理しているわけでもありません。だからこそ、掲載する価値があります。私たちの言葉を鵜呑みにせず、読者が確認できる統合例の1つだからです。agmi も同様です。エージェントメモリの完全性を評価するスコアカードであり、メンテナーが自ら再現したうえで、私たちの3行のアダプター
agmi/adapters/inspeximus_rows.py
をagmi#1 でマージしました。
ダッシュボード付きのホステッドサービス、ドキュメントを対象としたナレッジグラフ、または会話内容の想起ベンチマークで最高スコアを求めている場合には、適したツールではありません。その分野では mem0、Zep、cognee が優れており、比較ページでは、それぞれが得意な点とそうでない点を説明しています。
検証結果
他のシステムが公表していない唯一の点、修正された事実がどのくらいの頻度で再び現れるかを測定しました。
各システムをそれぞれのネイティブ設定で、同じタスクを使って30回ずつ試しました。
| システム | 修正を保持 | 古い値を再び呼び戻す |
|---|---|---|
| inspeximus | 100% | 0% |
| Graphiti 0.x(Neo4j + OpenAI) | 86.7% | 13.3% 95% CI [3.3, 26.7] |
| mem0 2.0.11(OpenAI ネイティブ) | 53.3% | 46.7% 95% CI [30.0, 63.3] |
| inspeximus、ガード無効 | 0% | — 対照条件:ガードが機能していることを示します |
各システム n = 30。mem0 は 2.0.11(2026-07)で測定しました。mem0 は現在 2.0.18 ですが、再実行していません。バージョンを明記し、主張を現在のものとして言い換えていません。手法、未加工の配列、再実行可能なハーネス:
RAMR · echo_resistance_backends_result.json
Graphiti の行を正しく読み取ってください。そのエコー防御は失敗していません。 独自の未加工出力には、エコーが実行される前に正しく抽出された26件の修正のうち、
echo_attributable_flips: 0と記録されています。Graphiti の生物時間的な無効化処理は、そのすべてを保持しました。上記の13.3%は、エコー前の抽出漏れが4件あったことを示しています。つまり、修正がグラフに取り込まれなかったのであり、この表が扱う問題とは異なる失敗です。見出しの数値ではなく仕組みとして述べると、エコーに起因する再出現について、Graphiti のスコアは私たちと同じ 0% です。書き込み時に継承関係を保持しているためです。ここでの本当の発見は、システムを分けるのは誰がその関係を記録したかではなく、その関係が記録されているかどうかだということです。
API キーなしで3秒以内に確認できる2つの数値
2026-08-25 に Hindsight 0.9.2(vectorize-io、21k stars)および mem0 と比較して測定しました。それぞれをネイティブ設定で実行し、n=20 としました。この2つの測定には判定役が一切不要です。未加工の想起ペイロードを読み取るため、モデルの読解力に左右されません。
| inspeximus 2.21.0 | Hindsight 0.9.2 | mem0 | |
|---|---|---|---|
| 修正後の想起で、新しい値が返り、古い値は返らない | 20 / 20 | 0 / 20 | 1 / 20 |
| 同じ書き込みを2回実行 — 保存状態は同じか? | バイト単位で同一 | 20 / 20 で異なる | — |
| 実行に必要なモデル呼び出し回数 | 0 | 60 | 60 |
どちらの競合製品も修正後の値と、置き換えられた値の両方を返し、どちらを選ぶかは呼び出し元に委ねます。これは擁護できる設計です。有効性マーカー付きで古い値と新しい値を返す生物時間ストアは、正直な動作をしています。しかし、これは私たちの約束とは異なり、曖昧さの解消を誰の役割とするかという違いがあります。
1行目は無料で検証できます。キーもサーバーもネットワークも不要です。
git clone https://github.com/DanceNitra/inspeximus && cd inspeximus
python probes/integrity_bench_store_resolves.py --systems inspeximus
数ミリ秒で完了し、store-resolved=1.00 (resolved=20 both=0 stale=0 neither=0, n=20) と表示されます。,mem0 または ,hindsight を追加すると、それぞれの列を再現でき、各製品の抽出呼び出しコストが発生します。
手法、注意事項、私たちが勝っていない項目。
最下段の数値が要点です。ガードを無効にするとスコアはゼロになります。つまり、この数値は仕組みを示しており、ベンチマークが私たちに有利な結果を出したわけではありません。
EU AI Act と GDPR の証拠を標準搭載
書き込み、訂正、消去、エージェントのすべての操作について、署名付きのハッシュチェーン記録が残ります。第三者は API キーなしでオフライン検証できます。署名が誰によるものかを示すのは、読み手がオペレーターの公開鍵をピン留めし、アンカーを証人として確認した場合に限られます。証拠は現在エクスポートできます。EU AI Act の高リスク義務は 2027 年 12 月 2 日(附属書 III のシステム)および 2028 年 8 月 2 日(規制対象製品に組み込まれたシステム)から適用され、GDPR 第 17 条は 2018 年 5 月 25 日から適用されています。
| 義務 | inspeximus が保持する内容 | 読み手による確認方法 |
|---|---|---|
| EU AI Act 第 12 条、自動イベント記録 | エージェントの操作時にメモリーストアが保持していた内容を記録する署名付き操作台帳。matches() は保持されたトランスクリプトをそのエントリーに結び付けます | inspeximus actions verify、オフライン |
| 第 19 条、ログの保持 | ストアの外部に先頭が保管される追記専用の受領証チェーン。末尾が切り詰められると報告されます | verify_writes() |
| GDPR 第 17 条、消去権 | forget_subject() は、このストア内で個人に帰属するすべての記録と、それを引き継いだ要約を削除し、署名付きの内容を含まない墓標を残します。イベントジャーナル内の消去された記録のテナント ID とエージェント ID、および墓標のテナントスタンプは、ソルト付き HMAC で仮名化されます。ソルトはキーの保存場所にあるため、既知の ID から仮名を再導出できます。1 つの識別子は残ります。異議申し立てがあると、対象者の ID は <store>.objections.json に保持され、新しい記録を引き続き抑制できます | erasure_certificate()。秘密鍵なしで確認できます。作成者を確認するには expected_pubkey をピン留めし、アンカーを証人として確認してください |
| GDPR 第 15 条および第 16 条、アクセス権と訂正権 | export_subject()、および実行者と理由を記載した受領証付きの rectify() | エクスポートのマニフェストハッシュが台帳に記録されています |
| 第 26 条、導入者の義務 | deployer_report。既定では件数を記録し、レポートに個人データは含まれません | |
| 発生日時 | 第三者による RFC 3161 タイムスタンプ。inspeximus timestamp qualified は、その日時に当該認証局が EU の信頼リストに掲載されていたかどうかを示します(eIDAS 第 41 条) | 信頼リストのオフラインキャッシュ |
| 監査人への提出 | draft-sharif-agent-audit-trail-04 ファイルとしてエクスポート。Ed25519 は action_detail に格納されます | 適合する任意の検証ツール |
inspeximus compliance は、条文ごとにラベル付けされた証拠を出力します。各項目の適用範囲を含む完全な対応表は、EU AI Act evidence ページ および docs/AI_ACT.md にあります。対象範囲を一文で示すと、inspeximus coverage は、新規ストア(3.12.0)で対象となる提供者および導入者の義務 36 項目中 36 項目を網羅していることを条文ごとに示します。認証は別の当事者が行う別個の行為です。
評価者が読む文書については、intake_form() がオペレーターだけが記入できる 66 項目を一度だけ尋ねた後、assessor_pack()(3.7.0)が附属書 IV、DPIA と FRIA の付属書を含む導入者レポート、附属書 VIII のエクスポート、および監査バンドルを生成します。未回答の項目がある間は、完了したとは見なしません。
重要な30秒間
どのメモリーライブラリでも保存と取得はできます。誰も答えていないのは、保存された 事実が間違いだと判明したときに何が起きるかです。
from inspeximus import Inspeximus
m = Inspeximus("correction.json")
m.remember("The staging database is db-3.internal", key="staging-db")
m.remember("The staging database is db-7.internal", key="staging-db") # a correction
m.recall("which staging database")[0]["text"]
# 'The staging database is db-7.internal' <- the correction wins, every time
m.revert("staging-db") # and it is reversible
m.recall("which staging database")[0]["text"]
# 'The staging database is db-3.internal'
埋め込みのドリフトも、「LLMはたいてい新しいほうを選ぶ」もありません。古い値はキー単位で 退役し、その退役は監査、取り消し、証明が可能な記録として残ります。
古い値をもう一度書き込んでも、復活しません。 ここが、単なる新しさのルールでは
できない点です。同じキーのもとで db-3 を3回目に書き込んでも、現在の値は db-7 のままです。以前の値に戻すには、remember(..., reaffirm=True) を使って明示的に判断します。ガードが自ら上書き状態を解除することはありません。
キー付き書き込みの後は m.last_write["blocked"] を読み取るか、ガードが以前の値を維持した場合にIDではなく WriteBlocked エラーを返すよう、raise_on_block=True を渡してください。
キーを使う場合の制限: キーを指定せずに書き込まれた文は訂正ではなく、新しい事実なので、ガードの対象外です。パイプラインがキーなしで古い文書を再取り込みすると、そのテキストは独自の内容に基づいて競合します。どちらの挙動も
probes/does_a_restatement_take_the_key_back.py
で測定しており、1秒もかからずオフラインで実行できます。
権威のルールを有効にすると、信頼性の低い情報源が、信頼性の高い情報源を上書きしなくなります。 デフォルトでは、後から行われたキー付き書き込みが優先されます。Inspeximus(path, supersession="authority") を使うと、source={"doc": ..., "authority": 0.3} の権威が現在の値より低いキー付き書き込みは、到着時に退役し、現在の値が維持されます。その判定は記録上と m.last_write に残ります。要約は、最も権威の低い親の権威を derived_from 経由で引き継ぐため、噂を言い直しても権威を装うことはできません。権威による判定が行われるのは両方が権威を宣言している場合だけなので、既存のストアで有効にしても、書き込み側が権威を宣言し始めるまでは何も変わりません。MemTX コーパスでストアに再適用したところ、デフォルトでは318件中278件でラベル付けされた信念が取得され、権威ルールでは318件中307件で取得されました。逆の結果になったケースはありませんでした。古い書き込みの大半はすでにエコーガードで検出されており、このガードは権威に関係なく、言い直された古い値を退役させます。権威ルールが加えるのは、そのキーで一度も保持されていない値を、信頼性の低い情報源が書き込むケースへの対応です。それでも見逃す11件は、同じ権威を持つ書き込み側の間で発生する更新の競合です。どのような権威ルールでも、これは判定できません。また、知っておくべき例外が1つあります。システムが権威を最大にして登録した事実は、それより低い権威で書き込むエージェントには訂正できません。この2点は _supersede_by_key の docstring に記載されています。私たちが作成していないベンチマーク(MemTX、再適用可能な318件)では、デフォルトモードで318件中278件、supersession="authority" で318件中307件のラベル付けされた信念が取得されました。最初の数値には、1.87.0でリリースされたエコーガードがすでに含まれています。このコーパスで測定されるより前にリリースされた仕組みです。
証明を求められたとき
レシートを有効にすると、すべての書き込みがハッシュチェーンに加わります。値だけでは、誰かがライブラリに無断でファイルを編集したかどうかはわかりません。ハッシュチェーンならわかります。
from inspeximus import Inspeximus
m = Inspeximus("receipts.json", receipts=True)
m.remember("The staging database is db-3.internal", key="staging-db")
m.remember("The staging database is db-7.internal", key="staging-db")
m.verify_writes()[0] # nothing has been touched yet
# True
# now somebody edits the store directly, turning db-7 into db-9
from inspeximus import sqlite_store
items = sqlite_store.load("receipts.json")
before = sqlite_store.snapshot(items)
edited = next(r for r in items if "db-7" in r["text"])
edited["text"] = edited["text"].replace("db-7", "db-9")
sqlite_store.save("receipts.json", items, before)
Inspeximus("receipts.json", receipts=True).verify_writes()[1][0].split(": ", 1)[1]
# 'its TEXT or KEY no longer matches its write receipt (edited after write)'
チェーンのないレコードをすでに保持しているストアや、途中から始まったチェーンも、1回の呼び出しで対応できます。チェーンに記録されていない各レコードについて、現在の状態のレコードを対象にレシートが作成され、そのハッシュには backfill と記され、バッチの Merkle ルートが含まれます。その呼び出し以降の編集は、ほかの編集と同様に verify_writes() で失敗します。それより前に起きたことには、後から作成したレシートでも到達できません。
from inspeximus import Inspeximus
m = Inspeximus("older.json") # a store written with receipts off
m.remember("The on-call rota is in the wiki", key="on-call")
m.verify_writes()[1][0].split(":", 1)[0]
# 'write receipts are DISABLED'
m.enable_receipts()["anchored_records"]
# 1
m.verify_writes()[0]
# True
またはシェルから実行します:inspeximus receipts enable --backfill。CHANGELOG の 3.0.0 の項目には、私たち自身のストアでの測定結果が記載されています。
適用されなくなったキーは、プレースホルダーを書き込むのではなく retire で終了します。キー付き書き込みは置き換えを行うため、プレースホルダーを書き込むと、そのキーの新しいアクティブ値になってしまいます。retire を使うとアクティブな値がなくなり、理由とともにすべての値が history(key) に保持され、レシートチェーンにも記録されます。
from inspeximus import Inspeximus
m = Inspeximus("rota.json")
m.remember("The on-call rota is in the wiki", key="on-call")
m.retire("on-call", "the rota moved to the pager tool")
m.current("on-call")
# None
m.history("on-call")[0]["reason"]
# 'the rota moved to the pager tool'
多数のプロセス、ひとつのストア
行ライターは、行を書き込むトランザクション内で、内容を含まない行を memory_events に追加します。そのため、別のプロセスは seq によってテーブルを順に読み取り、再読み込みもブローカーも必要とせず、次の呼び出しでコミットを確認できます。current(key) は、(テナント、エージェント、キー)をキーとする L1 から繰り返しの読み取りに応答するため、あるエージェントによって初期化されたキャッシュヒットが別のエージェントに提供されることはありません。
消去時には、レコードの key がジャーナル行から削除と同じトランザクション内で取り除かれます(行自体は key_redacted の印を付けて残ります)。そのため、人を特定するキーが消去後も残ることはありません。
from inspeximus import Inspeximus
lead = Inspeximus("crew.json")
worker = Inspeximus("crew.json")
tip = worker.events_tip()
lead.remember("The plan is: ship on Friday", key="plan")
lead.publish_event("plan.updated", {"to": "worker"}, agent_id="lead")
[e["type"] for e in worker.poll_events(since_seq=tip)]
# ['record.added', 'plan.updated']
worker.current("plan")["text"]
# 'The plan is: ship on Friday'
エージェントが何をしたか、そしてその時点で何を知っていたか
監査証跡ツールは、エージェントのアクションに署名します。アクション台帳も同様に署名し、各アクションを、その時点でエージェントが保持していたメモリ、つまりストアの状態ダイジェストと、直近の想起で返された ID に結び付けます。2 つのアクションの間に事実が修正された場合、2 つのアクションには異なるダイジェストが記録されます。そのため、誰かの説明に頼らず、チェーンから、1 つ目のアクションが古い値に基づいて実行され、2 つ目が新しい値に基づいて実行されたことを確認できます。
from inspeximus import Inspeximus
from inspeximus.actions import ActionLedger
m = Inspeximus("deploys.json", receipts=True)
m.remember("The staging database is db-3.internal", key="staging-db")
led = ActionLedger(m, actor="deploy-agent")
target = m.recall("staging database")[0]["text"]
with led.action("tool:deploy", inputs={"target": target}) as a:
a.output({"deployed_to": target})
m.remember("The staging database is db-7.internal", key="staging-db") # the correction
target = m.recall("staging database")[0]["text"]
with led.action("tool:deploy", inputs={"target": target}) as a:
a.output({"deployed_to": target})
led.what_it_knew(0)["recalled_now"][0]["current"]["status"] # 'superseded'
led.what_it_knew(1)["recalled_now"][0]["current"]["status"] # 'active'
led.verify() # (True, [])
デフォルトでは内容を保存しません。入力と出力はソルト付き SHA-256 ダイジェストとして保存されます。トランスクリプトを保管したオペレーターは、引き続き led.matches(seq, inputs=prompt, output=answer) を呼び出して、モデルに渡された内容と返された内容がそれと一致するかどうかを確認できます。1 文字でも異なれば一致せず、この確認にはソルトファイルが必要なため、他の人は実行できません。ストアにレシートキーがある場合は、それを使って署名します。inspeximus actions verify はファイルをオフラインで検証します。ストアがある場合は、各エントリーの last_receipt がメモリチェーンに引き続き存在することも確認するため、書き換えられたメモリ履歴をアクション側から検出できます。INSPEXIMUS_ACTIONS=1 を設定すると、MCP サーバーはすべてのツール呼び出しを記録します。また、inspeximus.integrations.langchain.InspeximusActionCallback は LangChain のツール呼び出しとモデル呼び出しを記録します。プローブ:probes/what_the_agent_knew_when_it_acted.py。改ざん制御は 3 つあり、いずれも失敗します。
さらに 2 種類のイベントが同じチェーンを共有します。led.oversight("override", "ops-lead", refers_to=3, reason=...) は、アクションに関する人間の判断と、その判断を行った人物または役割を記録します(AI 法第 14 条および GDPR 第 22 条の記録)。参照先が解決可能である必要があり、検証ツールはその参照先を再確認します。led.disclosure("s1", "You are chatting with an AI assistant.", channel="web") は、セッションごとに第 50 条の開示を記録します。inspeximus.subject_rights.export_subject(m, "crm/alice", ledger=led) は、GDPR 第 15 条に基づくアクセス要求に対し、ソースが対象者に解決されるすべてのレコードを返します。対象者の解決方法は forget_subject とまったく同じです。また、rectify(m, key=..., text=..., actor=..., reason=..., ledger=led) は第 16 条に基づく訂正で、誰が依頼したかを記載したレシートを作成します。led.incident("...", "serious", "dpo", refers_to=[3, 4]) は、第 73 条に基づく記録を開始し、認識した時点から 15 日間の期限を設定します。incident_report(seq) は報告書のひな形です。inspeximus compliance は、検証ツールを通じて台帳からこれらすべてを読み取り、条項番号を付した 22 の管理項目に反映します。
同じ証拠から 2 つの文書が生成されます。inspeximus technical-documentation --out annex_iv.md は、第 11 条に基づく Annex IV のひな形です。ストアと台帳から、証拠で記入できるセクションを書き込み、第 13 条第 3 項 f 号の使用上の指示も含め、24 個の提供者フィールドには OPERATOR INPUT REQUIRED と記します。inspeximus deployer-report --out deployer.md は、導入者側の文書(第 26 条)です。記録された監督、インシデントと第 73 条の期限、保持している最古のログエントリーの経過期間と 6 か月の下限との比較(ログがその期間に達するまでは、まだ検証できないと報告)、開示を含みます。さらに、GDPR 第 35 条第 7 項の DPIA 付録と、それを相互参照する第 27 条第 1 項の FRIA 付録も含みます。どちらも、記入できなかったフィールドをすべて明記します。inspeximus registration-export --section A も同じ方法で、EU データベース向けの Annex VIII フィールド(第 49 条)を書き出します。
何年にもわたって保持してきた台帳は、切り捨てるのではなく、ローテーションします。inspeximus actions archive --keep-days 400 は古いエントリーを台帳の隣にあるアーカイブファイルへ移し、アーカイブ、そのハッシュ、アーカイブされた末尾を示す署名付きチェックポイントでライブファイルを開始します。チェーンは途切れず、actions verify はチェックポイントをたどってアーカイブを検証します。また、ライブファイル単体ではアーカイブ済みの範囲を検証済みとして通過させず、未検証として報告します。inspeximus actions attest --policy-days 183 --actor dpo は、台帳が記録している最古のエントリーと、Art. 19 および Art. 26(6) の6か月の最低期間が遵守されているかを示す署名付きステートメントを追加します。inspeximus actions timestamp --url https://freetsa.org/tsr は RFC 3161 認証局に末尾へのタイムスタンプ付与を依頼し、そのトークンをチェーンに組み込みます。これにより、監査担当者はそれ以前のすべての記録について第三者の時刻証明を取得でき、openssl ts -verify で検証できます。
inspeximus actions timeline --session s1
は、コンテンツを含めずに、チェーンから1つのワークフローを再構成します。各ステップと、エージェントが保持していたメモリダイジェスト、モデル、アクター、それを参照する監督またはインシデントが表示されます。inspeximus actions export-trail
は、IETF の draft-sharif-agent-audit-trail-04 形式で台帳を書き出します。この形式を読み込むツール向けに RFC 8785 に従ってハッシュチェーン化されており、--verify はその形式のファイルを検証します。inspeximus actions lifecycle substantial_modification --actor cto --note "..." は、既存システムの Art. 111(2) の適用除外を終了させる Art. 3(23) の変更を記録し、lifecycle decommission --disposition erased は、ライフサイクル終了時にメモリをどう処理したかを記録します。
CNIL の2026年のエージェント型 AI に関するノートが求めている形に合わせ、メモリをエージェントごと、プロセスごとに分割できます。inspeximus partitions open triage-2026-09-16 --kind context --max-age-days 1 --max-records 200
は、書き込みにタグが付くスコープを開きます。partitions sweep は、開いているすべてのパーティションの有効期限と上限をトゥームストーンで適用し、partitions close NAME --actor はプロセスを終了します(context パーティションは終了時にレコードを消去します)。partitions report は、現時点で有効期限を過ぎているものと、どのパーティションにも属さないメモリの量を表示します。
ストアの書き込み先
ストレージ形式を選ぶ必要はありません。新しいストアは、名前にかかわらず SQLite ファイル内の行として書き込まれます。memory.json は JSON ではないため、json.load では読み込めません。既存の JSON ストアは、このバージョンで初めて開いたときに変換されます。変換では書き込んだ内容を再読み込みし、レコード数と ID の順序の両方が維持されない場合は拒否します。また、元のファイルはストアの隣に memory.json.pre-rows.bak として残します。暗号化されたストアは、保存時暗号化がファイル全体を対象とするため、単一の暗号化済み blob のままです。
行を使うのは、以前は書き込みのたびにファイル全体を書き換えていたためです。また、ファイル全体の書き換えでは、行単位の書き込みのように、同時に書き込む別のプロセスのレコードをマージできません。
永続化書き込み1回、両形式、各30書き込みの独立した試行を3回実施
(probes/one_write_two_formats_across_store_sizes.py):
| ストア内のレコード数 | ファイル全体 | 1行 | |
|---|---|---|---|
| 1,000 | 0.0075 s | 0.0071 s | 行のほうが約1.1倍高速 |
| 10,000 | 0.0818 s | 0.0422 s | 行のほうが約1.9倍高速 |
| 30,000 | 0.2334 s | 0.1292 s | 行のほうが約1.8倍高速 |
差はファイルサイズによって生じます。ファイル全体の書き換えはファイルが大きくなるほどコストが増えますが、1行の書き込みでは増えません。そのため、レコードが増えるにつれて効果が現れます。最も小さい行の結果は、最も信頼性が低いものとして扱ってください。1,000件では両者の差が十分小さく、このプローブを別々に実行すると結果が逆転することもありました。この表の元になった実行でも、3回の試行のうち1回は逆転しました。そのため、このプローブは平均値ではなくすべての試行を報告し、傾向が安定しない場合はその旨を示します。上の表は、プローブが出力する結果ファイル(tools/sync_store_format_table.py)から生成されるため、記憶に基づく値ではなく、1回の実行で測定した値です。
同時に書き込む場合、ストア独自の StoreChangedOnDisk を無視して再試行しなかった呼び出し元は、48 プロセスでの最悪の試行で 384 件中 199 件を保存しました。一方、行ストアは、テストしたすべての並列数で、4 回中 4 回の試行ですべてのレコードを保存しました。この差の原因は呼び出し元であり、形式ではありません。エラーの指示どおりに再試行すれば、ファイル全体を保存するストアも遅れずに処理できます(probes/what_a_concurrent_writer_is_told_against_what_the_store_keeps.py)。
probes/twelve_writers_and_the_one_that_stopped_writing.py を参照してください。どちらのプローブも、こちらの測定値を引用するのではなく、実行するマシン上でファイル全体を保存する場合のベースラインを再測定します。そのため、遅いマシンでは差が小さくなり、誤った値が報告されることはありません。
アップグレードする前に、知っておくべきことが 2 つあります。
- このバージョンで書き込まれたストアは、2.26.1 以前では読み取れません。 これらのバージョンはファイルを UTF-8 としてデコードし、
UnicodeDecodeErrorを発生させます。以前のバージョンに戻すには、memory.json.pre-rows.bakをストアに上書きするように名前を変更し、古いリリースに固定してください。 - 最初の消去時に、ロールバック用のコピーが削除されます。
forget、forget_subject、forget_piiはそのコピーを削除します。このライブラリが依頼されずに作成したコピーを、個人データの削除要求後も残すことはできないためです。erasure_certificate()は、そのファイルに何が起きたかを名前で報告するため、ロールバック期間の終了が記録され、黙って過ぎることはありません。コピーを保持するには、環境変数ではなく<key home>/inspeximus/config.jsonに{"store": {"keep_conversion_backup": true}}を設定してください。この場合、証明書には、そのバックアップが消去の対象外だったデータとして記載されます。これが引き換えに受け入れる内容です。
INSPEXIMUS_STORE_FORMAT=json は、ほかのツールが直接読み取るストア向けに、古い形式を維持します。3.17.0 以降、新しいストアと、すでに JSON 形式のストアに適用されます。行ストアの場合は無視され、stderr に 1 行出力されます。また、{"store": {"format": "json"}} を <key home>/inspeximus/config.json に設定すると、すべてのストアでこの形式が固定されます。
provenance(key=...) を 1 回呼び出すだけで、残りの情報がわかります。そのキーが保持してきたすべての値と、それぞれの値を無効化したポリシー、現在の値の由来(サマリーを通じて継承した汚染も含みます)、レコードがレシートに記録された内容と依然として一致しているかどうか、そして、それらが証明しない内容を示す limits フィールドを返します。消去も同じように機能します。forget_subject() は、ある人物に帰属するすべてのメモリを、系譜を通じてその人物の情報を継承したサマリーも含めて完全に削除し、署名付きの内容を含まないトゥームストーンを残します。これにより、後から読み取る人は、改ざんではなく意図的な消去が行われたことを確認できます。erasure_certificate() を使えば、秘密鍵を持たない第三者もこの確認ができます。証明書に署名する鍵は運用者のものです。そのため、作成者を確認するには、第三者が expected_pubkey を固定し、アンカーを確認する必要があります。verify_erasure_certificate(..., require_signed=True) は、署名のない証明書を拒否します。対象となるのはこのストアのみであり、ベクトルインデックス、プロンプトログ、バックアップは対象外です。
inspeximus compliance を実行すると、条文ごとにラベル付けされた同じ証拠が、それぞれの適用範囲とともに出力されます。これは inspeximus coverage が列挙する義務であり、認証ではありません。
時計がいつ、誰のものだったかを証明する
システム内のすべての時計は監査対象の運営者に属しているため、timestamp.py は代わりに第三者から RFC 3161 トークンを取得します。eIDAS 第 41 条では、QUALIFIED タイムスタンプには表示時刻に対する反証可能な推定が認められますが、通常のタイムスタンプには認められません。トークンには、どちらであるかは記載されていません。
inspeximus timestamp trusted-lists は EU のトラステッドリストのオフラインキャッシュを構築します。また、inspeximus timestamp qualified <token> --trusted-list <cache> --when <the date it was made> は、1 つのトークンについて判定します。終了コードにより、qualified、not qualified、undetermined が区別されます。
今日の日付ではなく、トークンが作成された日付を指定してください。qualified の認定は時間とともに付与されたり、取り消されたりします。25 の地域で公開されている 1477 の qualified タイムスタンプサービスのうち、570(39%)は qualified と non-qualified の両方のステータスを経験しています。実際のオーストリアのサービスでは、証明書が同じでも日付だけを変えると、4 通りの異なる判定が返されます。
このツールが報告するのは、リストへの登録状況だけです。トラステッドリストの署名は検証せず、トークンが真正かどうかについても何も示しません(それを確認するのは verify_with_openssl であり、両方に合格する必要があります)。また、リストの最も古い記録より前の日付には、「いいえ」ではなく UNKNOWN と回答します。
適用範囲。 上記の行は、inspeximus coverage が条項ごとに示す義務です。同法の高リスクに関する義務は、単独の Annex III システムには 2027 年 12 月 2 日から、規制対象製品に組み込まれたシステムには 2028 年 8 月 2 日から適用されます。求められる証拠(第 12 条のイベントログ、第 19 条の保持、第 15 条の精度と堅牢性)は、ストアがすでに保持し、エクスポートしているものです。
docs/AI_ACT.md では、各義務をストアに対応付け、その対応付けが及ばない範囲を示しています。
読者が何も求めずに検証できるログ
ここまでの内容は、あなたが誠実である限り成り立ちます。しかし、2 つの履歴を保持し、それぞれの読者に都合のよい方を見せることは防げません。答えを提供するのも、それを書いたのも、あなた自身だからです。
そこで、tools/publish_static_log.py はログを通常のファイルとして書き出します。ヘッド、COSE キーセット、すべてのリーフハッシュ、すべてのレシート、各エントリーのテキスト、そして標準ライブラリだけで動作する verify.py です。読者は 4 つのファイルをダウンロードし、リーフ自体を使って Merkle ルートを検証します。これは証明書の透明性を迂回するものではなく、透明性の実現方法です。C2SP の static-ct-api は、API より運用コストが低く、相反する情報を提示しにくいキャッシュ可能なファイルとしてログを提供します。
私たちのログは dancenitra.github.io/inspeximus/transparency で公開されています。 各エントリーは、このプロジェクトが公開する数値を 1 つ取り上げ、その数値が登場する文と、再現するコマンドを示しています。
すべてが記録されているかどうかは、私たちが断言することではなく、あなたが検証することです。この段落は以前、それを断言していました。python tools/seed_claims_log.py --log transparency/claims.log --check はレジストリとログを照合し、まだ記録されていないものを列挙します。キーは不要で、CI はプッシュごとにこれを実行するため、記録漏れは私たちと同時にあなたにも見えるようになります。現時点では記録漏れがあります。4 つのクレームが登録されていますが、ログには記録されていません。追記には署名キーが必要で、そのキーはシーディングを実行する場所にはありません。遅れていることを明示するログこそが、この取り組みの目的です。遅れているのに完全だと説明するログこそが、防ごうとしている失敗です。
静的ログではできないことも、後から判明するのではなく、ここで述べておきます。HTTP 経由で登録を受け付けるものはありません。書き込みは署名キーがある場所で行います。ライブエンドポイントには scrapi.py が draft-ietf-scitt-scrapi-11 を提供し、deploy/ にはコンテナイメージがあります。
証人とは、自分では実行できない部分です
ログから分かるのは、内部的に整合しているということです。それがほかの誰かに見せられたものと同じログかどうかは分かりませんし、運用者がどれだけ署名しても解決しません。書き換えを検知できるのは、以前のヘッドを記憶している当事者だけです。そして、その記憶が運用者の手の届かない場所にある場合に限ります。
inspeximus witness watch がその当事者です。このコマンドは、自分が運用していないログを取得し、ヘッドから読み取るのではなくリーフからルートを再計算します。そして、現在公開されているリーフからヘッドを再構築し、最後に受け入れたヘッドと比較します。判定結果は、EXTENDS、まだ何の証明にもならないことを明言する FIRST_CONTACT、FORK、ROLLBACK、そしてログが自ら矛盾している場合の MALFORMED です。拒否した場合、記憶は更新されません。捕まえた直後に忘れてしまう証人では、次に書き換えられたログを見たときに EXTENDS と報告してしまうからです。
設定は2つのコマンドだけで完了し、最初の実行で何かに縛られることはありません。
pip install inspeximus
inspeximus witness watch --url https://dancenitra.github.io/inspeximus-log/log --state witness.json
deploy/witness-template.yml を使えば、任意のパブリックリポジトリから同じコマンドを毎日無料で実行できます。私たちのログに対して実行することは、外部の人がここでできる最も有益なことです。何かに縛られることもありません。どのエントリーが真実だと保証するのではなく、今日見た履歴が以前に見た履歴から続いているかどうかを記録するだけです。
Bitcoin アンカーをオフラインで検証する
公開される各ヘッドには OpenTimestamps のスタンプが付けられ、レシートは .ots ファイルです。通常は ots コマンドで検証しますが、このコマンドは python-bitcoinlib を取り込みます。Windows では、そのインポート時に ctypes 経由で libssl を探しに行き、証明を1バイトも読み取る前にクラッシュします。そのため、検証機能は組み込みになっています。
inspeximus ots upgrade <the .ots receipt> # which block covers it? asks the calendars
inspeximus ots verify <the stamped file> --upgrade --block-header <the 80-byte header as hex> # ANCHORED, or MISMATCH
ブロックヘッダーは、独自のノードまたは任意のエクスプローラーから取得して指定します。これによってオフラインで検証できます。ブロックの取得元は自分で選べ、データがマシンの外に出ることはありません。ネットワークを使うのは --upgrade のみで、カレンダーがすでに保持しているダイジェストについて、カレンダーに問い合わせます。
終了コード:0 は ANCHORED、1 は MISMATCH、3 は PENDING または INCOMPLETE です。カレンダーからの約束だけが含まれる証明は PENDING です。これはエラーでも合格でもないため、どちらかにまとめず、独自のコードが割り当てられています。アンカー済みの証明が示すのは、まさにこのバイト列がそのブロックの採掘前に存在していたということです。中に含まれるものが真実かどうかについては、何も示しません。
判定結果が MISMATCH で、ファイルを Windows の git checkout から取得した場合は、検証ツールが出力する改行コードについての行を確認してください。レシートは LF のバイト列に対してスタンプされているため、変換されたコピーは、誰も改ざんしていなくても一致しません。
ログを検証するための鍵を、二か所で公開
ホストされているログを検証するには、検証鍵が必要です。確認対象のホストから鍵を取得するのは、ホストにホストの確認方法を尋ねることになります。ログを書き換えられる運営者なら、その隣にある鍵も書き換えられるため、すべての署名は引き続き検証に成功します。そのため、鍵はここでも公開しています。
現在、両方のコピーは同じアカウントの GitHub 上にあります。この README と、ログの公開ミラーです。公開ミラーは、リポジトリにピン留めされた鍵を使ったワークフローによる検証後にのみ、スナップショットを公開します。これにより、二つのコピーは密かな分岐を検出できますが、GitHub や私たちに対する検証にはなりません。どちらからも独立した参照先は、生の公開鍵 9fb780dd72894867c6dac8e140cc78d755617147d20cfd26bfe557190f65ac49 で、オフラインの紙にも保管しています。
92.5.74.17.sslip.io/log+41dfe27a+AZ+3gN1yiUhnxtrI4UDMeNdVYXFH0gz9Jr/lVxkPZaxJ
この行の SHA-256:1017ff229193fa867e1f73758df24e440ebfad1710e1af49e296a5fe4f00783c
同じ行は /log/checkpoint.vkey でも配信されています。二つはバイト単位で完全に一致していなければなりません。 異なる場合は、どちらも信頼せず、issue を開いてください。41dfe27a は c2sp.org/signed-note にある4バイトの鍵 ID で、どの鍵を試すかを選ぶものであり、セキュリティ境界ではありません。
diff <(curl -s https://dancenitra.github.io/inspeximus-log/log/checkpoint.vkey) <(curl -s https://raw.githubusercontent.com/DanceNitra/inspeximus/main/README.md |
sed -n '/checkpoint-vkey:begin/,/checkpoint-vkey:end/p' | sed -n '3p')
tools/check_published_key.py がこの比較を実行し、CI でも毎日実行するため、鍵のローテーションによって二つのコピーが密かに分岐することはありません。二つのコピーがあれば、二つのシステムで二か所を書き換える必要が生じ、密かなすり替えのコストが上がります。ただし、二つとも私たちが管理しているため、私たちが信頼できるようになるわけではありません。独立性をもたらすのは、私たちが到達できないログの先頭を記憶している証人です。
次の5分間
上のデモは revert() で終わります。ここでは、それを使って何をするかを説明します。
実際のエージェントで使ってみましょう。 接続のための作業は不要です。入力時に remember、出力時に recall を使います。重要なのは鍵です。鍵があることで、後から訂正しても別の事実として追加されるのではなく、同じ事実に反映されます。
from inspeximus import Inspeximus
m = Inspeximus("memory.json")
user_id, choice, user_question = "u-1", "dark mode", "what does this user prefer"
m.remember(f"user prefers {choice}", key=f"pref::{user_id}") # correcting later needs the key
context = [hit["text"] for hit in m.recall(user_question, k=5)]
print(context[0])
# user prefers dark mode
フレームワークを使う場合は、LangChain、LangGraph、LlamaIndex、CrewAI、AutoGen、Haystack、Google ADK、OpenAI Agents、Pydantic-AI 向けのアダプターがあります。ロゴを並べるのではなく、ライブ環境へのインストールで検証済みのものと、動作しないことが記録されているものを台帳で確認できます:docs/INTEGRATIONS.md。
例を順番に試してみましょう。 どれも鍵なしでオフライン実行でき、実行内容が出力されます。
01_basics.py | キーの記憶、呼び出し、訂正、履歴の確認 |
02_correction_and_erasure.py | 訂正と消去を別々のチャネルとして扱います。それぞれ別のものだからです |
03_semantic_recall.py | お好みのエンベッダーを使えます |
06_gdpr_erasure_receipt.py | あなたを信頼していない相手に、削除が行われたことを証明します |
コードの構成を確認しましょう。 docs/CORE_MAP.md には、すべての公開メソッドと、それぞれの開始行が記載されています。AST から生成され、CI で再確認されます。
私たちを信頼せずに検証するにある二つのコマンドを使って、それから、これらを信頼するかどうかを判断してください。
使用するすべてのエージェントで共有する1つのメモリ
pip install inspeximus
inspeximus install --all
install --all(3.14.0)は、インストール済みの各エージェントを検出します。Claude Code(Claude Desktop の Code タブで実行されるコピーを含む)(3.14.4)、Codex CLI、Gemini CLI、Antigravity、Cursor、Windsurf(Devin Desktop)、Devin CLI、Cline、Hermes Agent が対象です。それぞれに MCP サーバーを登録し、すべてをユーザーレベルの1つのストアに接続するため、あるエージェントで記録した決定を、ほかのすべてのエージェントが読み取るストアに保存できます。
- エージェントごとの想起方法。 Claude Code と Hermes Agent は、フックとメモリープロバイダーを通じて想起します。Gemini CLI と Codex は、各タスクの開始時に想起するよう指示するサーバーの指示を読み取ります。Cursor、Windsurf、Devin、Cline、Antigravity では、
--allによってエージェントのルールファイルに1行追加できます(--rules yesまたは--rules no)。 - 設定はそのまま保持されます。 既存のエントリーにマージし、変更する各ファイルは事前にコピーします。エージェントがすでに異なる2つのストアを指定している場合は、処理を停止して確認を求めます。
- 成否を確認できます。 インストールの最後に、バージョンと
ARMEDまたはNOT ARMED、ストアとそのレコード数、接続されたエージェント、再起動が必要なアプリ、シールを記載した5行のブロックが表示されます。inspeximus install --checkを実行すると、ブロックが再表示され、ストアからシールが再計算されます。一致しなくなった場合は、ゼロ以外の終了コードで終了します。
Claude Desktop の macOS 用パスは Windows のレイアウトに準拠しており、Mac では測定されていません。エージェントごとの手順:docs/install/index.md。
Claude Code で使う(1行)
Claude Code 内から実行する場合、pip も設定ファイルも不要です。
/plugin marketplace add DanceNitra/inspeximus
/plugin install inspeximus@inspeximus
または、シェルから pip install inspeximus を実行した後に使います。
inspeximus install --ide claude # also: cursor, windsurf, codex, cline
どちらの方法でも、135個のツールと同じフックを備えた MCP サーバーが接続されます。次のセッションから、エージェントは直前のエージェントが下した決定を把握した状態で開始します。CLAUDE.md を編集したり、再度説明したりする必要はありません。
- SessionStart は、引き続き有効な決定を挿入します
- PostToolUse は、実際に起きたことをファイルごとに記録します
- PreToolUse は、アクションの実行前に、そのアクションに関係する決定を提示します
クリーンなプロファイルで、Claude Code CLI を使い、両方の方法で2つのセッションにわたって検証済みです。Windows の Claude デスクトップアプリの Code タブでは、3.16.2 のライブセッションで、フックによる記録がストアに保存されること、各プロンプトで想起ブロックが表示されること、MCP ツールが使えることを確認しました。Code タブは macOS では測定されていません。
フックの所要時間は、自分たちのプロジェクトストアのコピーで測定し、CHANGELOG に記録しています。67,165件のレコードを含むストアで、Read は4.96秒から0.41秒に短縮されました(3.15.1)。また、71,772件のレコードを含むストアで --archive を実行した後、プロンプトフックの中央値は6.39秒から1.82秒に短縮されました(3.16.1)。
プロジェクトストアが大きくなったとき
フックは取得したすべてのコマンドを記録するため、プロジェクトストアは毎週数千行ずつ増え、すべてのプロンプトがそれらを読み込みます。--archive を使うと、古いコマンドの記録をストアから移動し、ストアの隣に月ごとのファイルとして保存します。削除はされません。
python -P -m inspeximus.claude_code --archive --older-than 7 # what would move; writes nothing
python -P -m inspeximus.claude_code --archive --older-than 7 --apply # move it
- デフォルトでは、リコールはストアのみを読み込みます。
recall(..., include_archive=True)はアーカイブファイルも検索し、MCP のrecallツールはinclude_archiveを受け取ります。 - 消去はすべての月に適用されます。
forget、forget_subject、forget_pii、--scrub-secretsはアーカイブファイルも消去します。確認できなかったファイルがある場合は消去を拒否し、そのファイル名を示します。消去証明書には、各ファイルと、消去したレコードがそのファイルに存在しないことを確認できたかどうかが記載されます。 - ファイルは Git リポジトリに置ける程度のサイズですが、消去は Git の履歴には及びません。
--allow-git-trackedを指定しない限り、Git のワークツリー内にあるストアは拒否されます。アーカイブファイルをどこかにコミットする前に、--scrub-secretsを実行してください。 - このバージョンには制限があります。暗号化されたストアと JSON に固定されたストアは拒否されます。アーカイブファイルはプレーンな行ストアだからです。暗号化されたストアはそのまま保持されます。JSON に固定されたストアをアーカイブするには、
INSPEXIMUS_STORE_FORMATの設定を解除して一度開き、行ストアに変換してください。 - ストアには、アーカイブログのエントリー数と最後のエントリーのハッシュが記録されます。そのため、ログが切り詰められたり、単独で置き換えられたりすると検証に失敗し、復元されるまで消去がブロックされます。これにより、誤操作や単一ファイルの編集を検出できます。ストアとログの両方を編集すれば、内容を再び一致させることは可能です。ヘッドの別コピーはストアのディレクトリ外に保存されており、2.38.0 以降、レシートチェーンのヘッドがそこに保持されています(設定の
guards.heads: falseで両方を無効にできます)。同じ人物がその場所にも書き込めない限り、この編集も検出されます。そのケースを確認するには、書き込みレシート(署名付きログ)を使用します。
得られるもの
修正を第一級の操作として扱います。 remember(key=...) は、そのキーの以前の値を退役させます。revert(key) はそれを復元します。history(key) は履歴の連鎖を表示します。すべて決定的で、監査可能です。
証明可能な消去。 forget_subject() は、ある対象に帰属するすべてのメモリーをハード削除します。系譜を通じてその対象を引き継いだ要約も含まれます。そして、署名付きで内容を含まない墓標を残すため、後日の監査で 意図的に消去された のか、改ざんされた のかを判別できます。
あらゆるストアで、バイト列を読み取って削除を確認します。 delete() が成功を返すことからわかるのは、行がインデックスから消えたことだけです。その値がディスクから消えたかどうかはわかりません。消去義務において重要なのは後者です。scan_residue(root, values) は、消去されているはずの値をディレクトリ内で検索し、通常はひとまとめにされる次の3つの結果を区別します。LIVE(テーブルの行にまだ残っている)、UNRECLAIMED(バイト列は残っているものの、ストレージエンジンがまだページを再利用していないため、ライブ行には存在しない。これはエンジンの特性であり、ベンダーの欠陥ではありません)、PLAIN(ログ、トレース、バックアップファイルにまだ含まれている)。これは inspeximus に固有の機能ではありません。ベクトルデータベース、SQLite の履歴、JSONL トレース、または別のライブラリのデータディレクトリを指定すれば、そのデプロイについて結果を返します。
residue_certificate() は、これらのスキャン結果を、第三者が確認できるドキュメントにします。読み取ったすべてのファイルについて SHA-256 を記録するため、第三者が同じディレクトリを再スキャンして verify_residue_certificate() を実行すれば、申告どおりにバイト列を検索したことと、その後に内容が変更されていないことの両方を確認できます。署名はスキャナーを識別するもので、検出結果を真実にするものではありません。証拠となるのは、誰でも再実行できることです。シェルから実行するには、inspeximus residue --root DIR --value SECRET --cert-out cert.json を実行し、続けて inspeximus residue-verify cert.json --root DIR を実行します。
クリーンな結果を問題なしと判断する前に、スコープを確認してください。一致判定はリテラルで、大文字と小文字を区別するため、値を小文字にしたり、スペースを入れ直したりしたコピーは意図的に検出されません。スキャンで読み取れなかったファイルは報告され、判定は否定的なままです。「クリーン」が「そこは調べていない」という意味になることは決してありません。どちらの制限も署名付き証明書に含まれます。
保存するだけでなく、検証できる来歴。 check_sources() は各レコードの出所を再読み込みし、FRESH/DRIFTED/ORPHANED/UNCHECKABLE に加えて、意図的に分けて扱う4つのカバレッジ数値を返します。source フィールドが98.3%入力済みでも、再取得可能なのが0.01%なら、それはスキーマであって保証ではないからです。(この2つの数値は、当社が自社の本番ストアで測定したものです。)
現在の状態への適用可能性。 evaluate_applicability() が答えるのは、「この記憶は正しいか」とは別の問いです。ここで、今、アクションに利用してもよいか? 過去の証拠が完全に有効でも、もはや許可されていない場合があります。ブランチが変わった、ポリシーが変更された、テナントが異なる、期間が終了した、といった場合です。ベンダーに依存しないCMLコントラクトを実装しており、独立した2つの実装が固定フィクスチャで一致しています。
マルチテナント分離。 for_tenant("acme") は、1つの共有ストアに対するスコープ付きビューを提供します。テナントは署名対象メッセージにバインドされるため、レコードを別のテナントに移動すると検証に失敗します。
監査担当者がすでに読める形式の監査証跡。 ハッシュチェーンは、レコードが編集されていないことを証明します。しかし、第三者に対して、誰が書いたのか、何についての記録なのか、いつ書かれたのかは示しません。システムを確認する人が実際に尋ねるのは、この3点です。4つのIETF標準がこれらに答え、inspeximusは依存関係なしで4つすべてを出力します。
| 示したいこと | 成果物 | 標準 |
|---|---|---|
| このレコードがログに含まれていること | 包含レシート | RFC 9942(COSE Receipts) |
| 私がこれを述べ、これについてのものだということ | 署名付きステートメント | RFC 9943(SCITT) |
| 公開されたこれらのルールに基づくこと | 登録ポリシー。ログ自体のエントリー0として記録 | RFC 9943 s5.1.1 |
| 第三者が、この時点で確認したこと | RFC 3161タイムスタンプ | RFC 3161 |
pip install "inspeximus[crypto]"
from inspeximus import Inspeximus, new_receipt_keypair, verify_transparent_statement
secret, public = new_receipt_keypair()
m = Inspeximus("memory.json", receipts=True, receipt_key=secret)
m.remember("The staging database is db-7.internal", key="staging-db")
doc = m.transparent_statement(0, issuer="did:web:your-company.example")
# -> a COSE_Sign1 carrying your claim AND its inclusion proof, checkable by anyone
inspeximus.transparency.TransparencyService は、自身のログ内で公開するポリシーに基づき、他者のステートメントを登録します。また、python -m inspeximus.scrapi は、SCITTクライアントが利用するHTTPインターフェース(draft-ietf-scitt-scrapi-11)でそれを提供するため、ここで作成していないツールからも利用できます。
署名で得られないものも、あらかじめ明示します。 レシートが証明するのは、あるログに含まれていることです。そのログだけを人々に示したと証明することはできません。それには独立した証人が必要です。そのため、witnessed_head() はk-of-nの連署を集め、拒否をエラーではなく警報として扱います。タイムスタンプが示すのは、第三者がある時点でダイジェストを確認したことです。トークンの完全な検証は、独自実装ではなく openssl ts -verify に委ねています。「有効」と判定してしまう不完全なCMSパーサーでは、実際の検証ツールが拒否するトークンを通してしまうためです。そして、これらのどれもコンプライアンスではありません。署名付き台帳を義務付ける規制はありません。これは説明責任を果たすための証拠の品質であり、そのように一貫して表現しています。
依存関係ゼロ。 コアは1ファイルです。inspeximus/core.py をどこにコピーしても、何もインストールせずにインポートして実行できます。セマンティック検索はオプションです(embed=your_model)。字句検索のフォールバックには何も必要ありません。MCP サーバー、暗号化、フレームワークアダプターは別モジュールで、すべてオプトインです。署名(Ed25519)には pip install "inspeximus[crypto]" が必要ですが、ベースパッケージは引き続き依存関係ゼロです。
対応状況
langchain · langgraph-store · llamaindex · haystack · autogen · pydantic-ai ·
google-adk · memoryagentbench · hermes-agent
Hermes Agent では、inspeximus はシェルの Python ではなく、Hermes の実行に使う venv にインストールしてください
(方法)。Hermes は専用のインストーラーでインストールしてください。PyPI パッケージの hermes-agent は 0.19.0 で、プロバイダーを読み込みません。
最新の上流版で検証済み 14 件中 14 件、記録された不具合は 0 件です。 1 日前には 3 件に不具合があり、リストにもその旨が記載されていました。この行を信頼できるのは、それが唯一の理由です。openai-agents では SDK が型チェックする属性が欠けており、langgraph-checkpointer ではストアの単一書き込みガードがこのプロセス自身のスレッドに対して作動し、CrewAI ではストレージプロトコルが全面的に置き換えられていたため、修正ではなく 2 つ目のクラスが必要でした。
件数は、主張監査が docs/integration_conformance.json から読み取るため、この行がランナーの直近の測定結果と食い違うことはありません。
成功例だけを挙げる「対応状況」リストは、ロゴを並べただけのものです。このリストでは、実際に使い始める前に、どのアダプターが壊れるかがわかります。
テスト方法
2,600 件以上のテストと、それらを信頼できる理由となるミューテーションゲートがあります。欠陥を 175 件仕込み、175 件を検出、すり抜けたものは 0 件です。テストスイートに合格するだけでは証拠になりません。意図的に仕込んだ不具合をすべて検出するスイートこそが証拠です。
このページに記載されている数値はすべて docs/CLAIMS.md に登録されており、正確な再計算コマンドも記載されています。お手元で実行した結果と食い違う場合は、ぜひバグとして報告してください。
agmi 適合性スイートの保存時攻撃 5 種(改ざん、切り詰め、中央のエントリーの削除、並べ替え、偽造)を、攻撃者と同じ方法でストアの背後にある SQLite ファイルに対して実行します。レシートを有効にし、鍵を指定した場合、5 件中 5 件を検出し、それぞれ理由も明示されます。攻撃者がレシートのサイドカーも所持していて、ストアのディレクトリへの書き込み権限によりそれを利用でき、削除したレコードのレシートをすべて削除した場合でも、すべて検出されます。ストアはレシートを書き込むたびに、チェーンのヘッドをストアのディレクトリ外にあるユーザーの設定ディレクトリに保存し、verify_writes() はチェーンがそのヘッドより短いことを報告するためです。攻撃者が設定ディレクトリも所持している場合は、ヘッドが削除され、その場合の検出数は5 件中 4 件です。中央のエントリーを削除すると署名済みチェーンが破損しますが、末尾を切り詰めても破損しません。後者のケースには、マシンの外部に保管した anchor() と verify_consistency() が必要です。検出を行うのは監査用の呼び出しである verify_writes() です。recall() はどちらの場合も改変されたレコードを返します。レシートが無効の場合(デフォルト)、検証機能はストアが改変されているかどうかにかかわらず、その完全性を保証できません。この場合は検出ではなく、検証不能として評価されます。プローブ:
probes/five_at_rest_attacks_on_the_store_with_receipts_off_and_on.py。
私たちをうのみにせず、検証してください
2つのコマンドを実行するだけです。どちらも API キーやサービス、私たちのデータは必要ありません。
python claims_audit.py
40秒で、README、ドキュメント、サイト全体で公開しているすべての数値を読み取り、それぞれが登録されているか、ピン留めした参照先が今も解決できるか、コミット済みのコマンドで再計算できるかを報告します。最後に、問題の一覧か、次の1行が表示されます。
every published number is registered, every pin resolves, every command names a real file
件数をここに引用していないのは意図的です。監査対象のファイル内に監査自体の合計を引用すると、ドキュメントを更新するたびに数値も変わってしまいます。このセクションの初稿ではまさにそれをしてしまい、古い数値を公開しました。実行して、最新の数値を確認してください。
実行すると、いくつかの行に WITHDRAWN と表示されます。これらは私たちが公開したものの、再現できなかった数値です。削除するのではなく、その数値を否定するプローブとともに登録簿に残しています。ベンチマーク表は競合他社についての主張です。一方、登録簿は私たちについての主張であり、まず確認していただきたいのはこちらです。
python probes/integrity_bench_revert.py --systems inspeximus --judge local --n 5
無料、オフライン、決定論的で、ローカルの判定器は上の表にある OpenAI による判定の数値とは 比較できない という但し書きも自ら表示します。誠実な計測器と、見栄えのよい計測器は、同じものであるべきではありません。
ドキュメント
| プロジェクトサイト → | ベンチマーク、MCP の機能、ガバナンスに関するストーリーを紹介するガイド付きツアー |
| mem0 と Graphiti との比較 | 対照条件と誠実な評価範囲を含む、復元ベンチマークの全表 |
| Claude Code のセットアップ | 1行で実行できる MCP のインストールと、3つのフックそれぞれの機能 |
| 詳細版 | すべての仕組み、測定結果、そして失敗したもの |
| API 全体 | すべてのメソッドと、それが防ぐためにある障害 |
| 消去と GDPR | 派生サマリー全体にわたる消去権と、その証跡。実際の実行を最初から最後まで確認できる消去ページ |
| mem0 からの移行 | inspeximus import-mem0 export.json:ユーザーを主体、mem0 のタイムスタンプをイベント時刻として、メモリごとに1件のレコードを作成します。2回実行しても安全です。API の対応関係と、インポートで復元できない内容も説明します |
| 監査証跡ページ | エージェントが行動した時点で把握していた内容:署名付き台帳エントリ、トランスクリプトとの照合、IETF ドラフトのエクスポートを、実際の実行例で紹介します |
| EU AI Act の証拠ページ | 第12条のログ記録と第17条の消去を、ストアがすでに保持している内容に対応付けます。対応付けの本文は docs/AI_ACT.md にあります |
| MCP ツール | 全134件と、それぞれの用途 |
| 主張の台帳 | 公開済みのすべての数値と、それを再計算するコマンド |
| core.py の対応表 | すべての公開メソッドとその定義場所。AST から生成され、CI で検証されます |
| 実行可能な例 | コード断片ではなく、動作するスクリプト |
| フレームワークアダプター | 実環境へのインストールで検証済みのものと、動作不良として記録されているもの |
| 変更履歴 | 変更内容とその理由、私たちの誤りも含みます |
対象となる方
数分ではなく数週間にわたって動作するエージェントを構築している方です。エージェントは何かを学び、その内容はやがて変わります。設定値、ポリシー、人の好み、事実などです。致命的な失敗は、エージェントが忘れることではありません。古い答えを自信満々に覚えていることです。
このライブラリはその失敗を防ぐために作られており、私たちがベンチマークするのもそれだけです。この分野のデモの多くは書き込みを見せます。こちらが見せるのは撤回です。エージェントが評価されるのは、その操作だからです。
名前
この名前は中世の勅許状に由来します。王、司教、修道院長、または町議会は inspeximus、
「私たちは調査した」という言葉で始め、以前の文書を全文引用して、調査したことを記録しました。通常はその内容を確認し、後世の読者が確かめられるよう、結果に封印を施しました。これは写しが原本に忠実に一致していることを証明するものであり、原本が真実であることを証明するものではありません。ここでの保証も同じです。そのことは、後から気づくのではなく、provenance() の limits フィールドで確認できます。
引用
バージョンに依存しない DOI で Zenodo にアーカイブされています — 10.5281/zenodo.21708778。 機械可読なメタデータは CITATION.cff に記載されているため、GitHub の「このリポジトリを引用」ボタンから BibTeX と APA を直接取得できます。
MIT ライセンスです。成功した複製だけでなく、失敗した複製も併せて公開する自律型研究組織 Agora によって開発されました。
mcp-name: io.github.DanceNitra/inspeximus
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。