KEPTA — the memory for AI systems について
KEPTAは、AIシステム、スクリプト、Pythonプロジェクト向けのローカル暗号化メモリレイヤーです。共有ナレッジベースはハイブリッド検索と時間に基づく履歴を備え、クラウドやアカウントなしで複数の方法から利用できます。
主な機能
- 01ローカル暗号化ナレッジベース
- 02全文検索とベクトル検索の併用
- 03ナレッジグラフとローカル再ランキング
- 04時間情報を含む事実と履歴
- 05PDF、Markdown、テキスト、JSONの取り込み
- 06MCPツール、HTTP API、Pythonクライアント
活用シーン
- 01複数のAIクライアントで永続メモリを共有
- 02取り込んだ文書やチャット履歴を検索
- 03過去の特定日時に知っていた情報を確認
MCP 対応
検索、保存、更新、削除、一覧表示、関連付け、統合、忘却を行う8つのMCPツールを提供します。サーバーはstdioとStreamable HTTPに対応します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
KEPTA — AI システムのためのメモリ
AI はすべてを忘れます。チャットを始めるたびに、ゼロからのスタートです。
KEPTA がその問題を解決します。あらゆる AI が読み書きできる、ローカルで暗号化された一つのメモリです。Claude、Cursor、Gemini CLI、Cline、あらゆる MCP クライアント、HTTP 経由のスクリプトに対応します。クラウド不要。アカウント不要。あなたが所有する一つのファイルです。
AI システムが学習したことはすべて、あなたのコンピューター上の暗号化されたナレッジベースに保存されます。そして、コンテキストがどれほど増えても、あらゆる AI がミリ秒単位で記憶を呼び戻せます。ドキュメント、決定事項、クライアントの知識、チャット履歴全体を記憶し、関連付け、矛盾を見つけ、更新します。失われることはありません。
このリポジトリは、ソースを公開したコアです(BUSL-1.1 — すべての行を公開し、各リリースから4年後にAGPL-3.0-or-laterへ移行します)。メモリエンジン、MCP サーバー、HTTP APIに加えて、Pythonクライアントも含まれます。PythonクライアントはMITライセンスのため、あらゆるPythonプロジェクトに組み込めます。メモリを賢くする機能はすべて、この無料エンジンに含まれています。メモリ内にプランの違いはありません。何かを販売するために機能を制限することもありません。
質問、セキュリティに関するご意見、ベンチマークへの批評はこちら → ディスカッション
flowchart LR
subgraph Apps["Your AI apps — every client, one memory"]
direction TB
A["Claude Desktop · Claude Code"]
B["Cursor · Gemini CLI<br/>Cline · Codex · Zed"]
C["Your scripts"]
end
subgraph KEPTA["KEPTA — this repository"]
direction TB
M["MCP server<br/>8 tools · stdio + Streamable HTTP"]
G["HTTP API · 32 routes<br/>Python client · CLI"]
E["Memory engine<br/>hybrid retrieval: FTS5 + vectors + graph<br/>RRF fusion → local rerank"]
end
D[("One encrypted file<br/>SQLCipher 4 · AES-256<br/>~/.kepta/kepta.db")]
K["OS keychain<br/>the key never leaves"]
A --> M
B --> M
C --> G
G --> E
M --> E
E --> D
D -.-> K
⚡ あらゆる AI クライアントを、1つのコマンドで
インストール先のマシンに Node 22.13以降(package.json → engines)が必要です。npmはNode 22、24、26向けのSQLiteプリビルドバイナリを用意しています。
npx -y kepta-mcp demo # six scenes in a throwaway database — nothing of yours is touched
npx -y kepta-mcp setup # connects Claude Desktop, Claude Code, Cursor, Windsurf, VS Code, Gemini CLI, Cline and Roo Code
npx -y kepta-mcp remember "Client Miller signs renewals in December." # write a note from the terminal, no AI client needed
npx -y kepta-mcp recall "who signs renewals" # read it back: 1 match — ranked by relevance
npx -y kepta-mcp stats # size, encryption state, top tags
npx -y kepta-mcp timeline "miller" # what was true, and when
npx -y kepta-mcp import chatgpt <export-folder> # bring your ChatGPT history with you (export → extract → import)
次の2行がそのまま示す内容です — 2026年10月10日にレジストリから取得したkepta-mcp 3.2.0、使い捨てのHOME、空のメモリの場合です。
$ npx -y kepta-mcp remember "Client Miller signs renewals in December."
✓ remembered — Client Miller signs renewals in December.
type: semantic · id: k-mv2mghs9-fdf75c17
$ npx -y kepta-mcp recall "who signs renewals"
1 match — ranked by relevance
1. Client Miller signs renewals in December. · semantic · today
Client Miller signs renewals in December.
#remember
ノートとは、メモリに保存される1つの項目です。rememberで手動で書き込み、AIクライアントはmemory_saveツールを通じて同じ種類のノートを書き込みます。AIに覚えておく価値のあることを伝えて、記録される様子を確かめてください。詳細はクイックスタートをご覧ください。
🖥️ または、デスクトップアプリをダウンロード
コア自体にウィンドウはありません。インターフェースは AI クライアントです。 ウィンドウが必要な場合は、無料のデスクトップアプリをご利用ください。同じエンジン、同じ暗号化ファイル、同じキーを使い、このリポジトリのリリースからダウンロードできます。チームや組織向けには、契約に基づく KEPTA Enterprise があります。この3文がすべての回答です。ここにあるすべてのドキュメントで、同じ説明をしています。
このアプリでは、メモリブラウザー、取得元を確認できるハイブリッド検索、ナレッジグラフ、タイムトラベル、ドシエ、メモリを読み込むチャットを利用できます。最新リリースからお使いの Mac 用の DMG(Apple Silicon または Intel)をダウンロードし、Applications にドラッグしてください。ビルドはアドホック署名で、公証されていないため、macOS が初回に一度だけ確認を求めます。回避方法は2つあり、どちらもすべての macOS バージョンで利用できます。xattr -dr com.apple.quarantine /Applications/KEPTA.app を実行するか、システム設定 → プライバシーとセキュリティ → KEPTA のメッセージ → このまま開くを選択してください。一度行えば、以降は必要ありません。古いガイドには右クリック → 開くと書かれていますが、Apple は macOS 15 でこの方法を廃止しており、現在のシステムでは何も起きません。(このリポジトリから起動するものにはウィンドウがありません。npm run dev は HTTP API とその POST /mcp を起動します。これはお使いのマシン上で動作するサービスであり、インターフェースではありません。)
このアプリは、このリポジトリにあるほかのすべてと同様に無料です。KEPTA Enterprise(チームおよびテナントのメモリ、監査チェーン、人的レビュー、指定時点への復旧)は契約に基づくライセンスです。— LinkedIn でご連絡ください。
🧠 ひとつのエンジン。無料。あらゆる AI に。
KEPTA は特定のアプリに組み込まれた機能ではありません。あらゆるモデル、アプリ、コンテキストウィンドウを超えて使い続けられるメモリレイヤーです。3つの方法で、同じ暗号化ファイルにアクセスできます。
| 接続方法 | 利用するもの |
|---|---|
| MCP — 8つのツール、stdio(npm バイナリとコンテナ)+ Streamable HTTP(このリポジトリをソースから実行) | すべての MCP クライアント:Claude、Cursor、Gemini CLI、Cline、Codex、Zed、お使いのエージェント |
| HTTP API — 32のルート、ループバックのみ | スクリプト、cron ジョブ、エージェントチーム、自動化 |
Python — pip install kepta、標準ライブラリのみ | あらゆる Python プロジェクトへの組み込み |
無料とは、本当に無料ということです。 €0で永久に利用でき、アカウント、ライセンスキー、1日の利用上限、メモリ内のプラン階層、後から販売するためのロック機能はありません。私たちが作れる最高のメモリエンジンを無料で提供することが目的です。この説明は料金についてであり、容量についてではありません。1台のマシンでは、アクティブなノートが KEPTA_MAX_ACTIVE 件(デフォルトは 5000、server.ts → maxActiveMemories())に達すると、ローカル API は新しいノートの受け付けを停止します。これはエージェントが暴走してメモリをノートで埋め尽くすのを防ぐブレーキであり、ペイウォールではありません。この変数の値を増やせばよく、ほかに変更はありません。無料のコアにロックされた機能はありません。このような設定項目についてはすべて、SECURITY.mdを参照してください。
チームや組織 — チームで共有するメモリ、集中管理ポリシー、MDM、組織全体の監査が必要な場合は、KEPTA Enterprise をリクエストしてください。料金をいただくのは調整機能だけで、メモリの品質ではありません。→ LinkedIn でご連絡ください
⚡ クイックスタート
AI アプリを接続する
npx -y kepta-mcp setup
お使いのコンピューターにある Claude Desktop、Claude Code、Cursor、Windsurf、VS Code、Gemini CLI、Cline、Roo Code を検出し、KEPTA を追加します。アプリごとに確認し(--yes を付けるとすべて接続します)、変更する各ファイルのバックアップを保持し、ほかの項目には手を加えません。Zed、Codex CLI、Continue には、貼り付けるための正確な設定スニペットを表示します(設定形式の変更が速すぎるため、外部から対応するのが難しいためです)。その他の MCP クライアントの場合:
{
"mcpServers": {
"kepta": {
"command": "npx",
"args": ["-y", "kepta-mcp"]
}
}
}
8つのツール:memory_search、memory_save、memory_update、memory_delete、memory_list、memory_graph、memory_consolidate、memory_forget。
HTTP API
git clone https://github.com/DamianTodorovic/kepta.git
cd kepta && npm install && npm run dev
# → http://127.0.0.1:3000
# save a note
curl -s localhost:3000/api/memory -H 'Content-Type: application/json' \
-d '{"title":"Client Miller","content":"Billed quarterly.","tags":["client"]}'
# search
curl -s "localhost:3000/api/memories/search?q=how+does+miller+pay"
Docker(MCP サーバーのみ)
npm installを実行する前に、クリーンなクローンからイメージをビルドしてください。ビルドコンテキストにmacOS用にビルドされたnode_modulesが含まれると、Linuxのビルドが失敗します(ERR_DLOPEN_FAILED)。2026年10月12日時点のこの状態での計測結果(docs/belege/r1/kontext-groesse-2128.log.txt):同じフォルダーのビルドコンテキストは180 MBで、そのうち169 MBがnode_modulesです。追跡対象ファイルだけなら4 MBです。(現在の.dockerignoreではnode_modulesとビルド成果物をコンテキストから除外しています。これが手元のチェックアウトに反映されるまでは、クリーンなクローンを使うのが安全です。)
git clone https://github.com/DamianTodorovic/kepta.git && cd kepta
docker build -t kepta-mcp .
# A container has no keychain, so the database key is not optional here: it has
# to come from the environment. Generate it ONCE and keep it — it is the only way
# back into the volume.
KEPTA_DB_KEY=$(openssl rand -hex 32)
docker run --rm -i -e KEPTA_DB_KEY="$KEPTA_DB_KEY" -v kepta-data:/data kepta-mcp
**キーがなければ、ファイルは作成されません。**実際の値を渡してください。64文字の16進数で、openssl rand -hex 32で一度だけ生成し、シークレットを保管している場所に保存してください。コンテナーはキーチェーンにフォールバックできないため、KEPTA_DB_KEYがない場合、新しいナレッジベースは作成されません。KEPTAはゼロ以外の終了コードで停止し、代わりに何をすべきかを示します。同じ値を、その後の起動時にも毎回渡す必要があります。2回目に新しくopenssl rand -hex 32を実行すると、ボリュームに対応しないキーになり、こちらも何も変更せずに停止します。平文データベースにする唯一の方法は、それを明示するスイッチKEPTA_ENCRYPTION=offです。
古いビルドについて読む人向けに、移行期間の説明をひとつ。コードにこのルールが加わる前は、使用できない値(ガイドからコピーしたプレースホルダー、短すぎる値、16進数ではない値)でも失敗しませんでした。KEPTAは1行出力した後、データベースを平文で作成し、終了コード0で終了していました。kepta.dbの先頭がバイト列SQLite format 3なら、それが起きたということです。そのファイルは、読み取り権限のある誰でも読めます。バージョンを確認し、キーを再設定するか、ボリュームを交換してください。ルールの全容はSECURITY.mdを参照してください。
CI、サーバー、その他すべてのヘッドレス起動
CIランナーにもキーチェーンがないため、キーはシークレットとして渡します。ジョブごとではなく一度だけ生成してください。そうしないと、実行のたびに新しい空のメモリーが作られます。
# GitHub Actions, one step. The secret holds the 64 hex characters from `openssl rand -hex 32`.
- run: KEPTA_DB_KEY="${{ secrets.KEPTA_DB_KEY }}" npx -y kepta-mcp stats
このリポジトリで計測された、注意すべき点は3つです。
- 空の値は「キーなし」ではありません。
KEPTA_DB_KEY=""は破棄され、実行時にキーチェーンを探しにいきます。自分のマシンでは、触れるつもりのなかったキーチェーンのエントリーを読み込むことになります。起動前に変数が空でないことを確認し、テンプレートの誤りで""にならないようにしてください。 - **プレースホルダーも値です。**ガイドから
<64-hex>形式のトークンをコピーするのは、空の値を渡すのと同じです。 - **ログに記録されたコマンドライン上のキーは、公開されたキーです。**環境ファイルまたはランナーのシークレット機構を使って渡してください。CIが出力するシェル履歴には記録しないでください。
実行時にキーをまったく取得できない場合、正しい結果は上記のとおりです。データベースは作成されず、ゼロ以外の終了コードで終了し、KEPTA_DB_KEYについて説明が表示されます。平文のナレッジベースを作成して成功扱いになるCIを防ぐためのルールです。既定値と各変数の読み込み元を含む、すべての変数の一覧はdocs/ENVIRONMENT.mdを参照してください。
✨ 内容
| 🔍 ハイブリッド検索 | BM25 全文検索+ベクトル類似度(Ollama)+ナレッジグラフを、RRF で統合し、ローカルで再ランキングします。この3つの要素は同等の強さではありません。このリポジトリで測定した数値を、下の図の下に示しています |
| 🔐 保存時の暗号化 | SQLCipher 4:AES-256 と、WAL を含むすべてのページに対する HMAC-SHA512。キーは OS のキーチェーン(macOS Keychain、Windows DPAPI、Linux Secret Service)に保存されます |
| 🕐 タイムトラベル | 有効期間(valid_from / valid_to)と asOf クエリに対応しています。「3月3日時点で、私は何を知っていましたか?」 |
| ♻️ 矛盾ではなく、置き換え | 新しい事実が古い事実を置き換え(superseded_by)、履歴は保持されます |
| 🔗 MCP を第一に | 8つのツール。API と MCP でコードパスを共通化し、エージェントはどのクライアントと同等の品質を得られます |
| 📄 ファイルのインポート | PDF(文字マップ付きの pdf.js)、[[wiki links]] に対応した Markdown、テキスト、JSON |
| 📊 評価 | 固定コーパス(58件のノート/45件のクエリ)に対する npm run eval:Hit@1、Recall@5(上限あり)、MRR。語彙ベースのみ、オフライン、決定論的です。意図的に recall と呼んでいます。スクリプトは上位5件に含まれるヒット数を min(5, relevant) で割ります(scripts/eval.ts の evaluate():hitsIn5 / Math.min(5, Math.max(1, relevant.length)))。これは5件の精度ではなく、回答セットのどれだけを取得できたかを測定します。npx tsx scripts/ablation.ts は、同じコーパスとローカル Ollama の埋め込みを使って、各検索要素を他の要素と比較し、P@5 には共通の分母5を使用します(scripts/ablation.ts:46)。ノートは同じでも指標は異なり、数値を相互に比較することはできません |
クエリが答えを見つける仕組み
flowchart TD
Q(["Your query"]) --> A["FTS5 · BM25<br/>lexical search"]
Q --> B["Vector KNN<br/>local embeddings (Ollama)"]
Q --> C["Entity match<br/>knowledge graph"]
A --> R["Reciprocal Rank Fusion<br/>k = 60"]
B --> R
C --> R
R --> BO["Recency + confidence boost"]
BO --> T{"Temporal state?"}
T -->|expired| X5["score × 0.5"]
T -->|superseded| X4["score × 0.4"]
T -->|valid| K1["unchanged"]
X5 & X4 & K1 --> R2["Local reranker<br/>term coverage · phrases · title · tags<br/>max boost +0.25 — no network"]
R2 --> OUT(["Top-k, ranked by relevance"])
各要素単独の価値 — この状態で npx tsx scripts/ablation.ts を実行し、58件のノート/45件のクエリ、ローカル Ollama を使用して、2026年10月12日に同一条件で3回測定しました(docs/belege/r1/ablation-2326.log.txt):Hit@1 は、全文検索のみで71%、全文検索 +グラフで71%(+0ポイント)、全文検索 +ベクトルで78%、**3要素すべてで76%**です。グラフ要素単独では11%に達します。正確に読み取ってください。答えを支えているのは全文検索で、7ポイントを上乗せするのはベクトル要素です。また、モデルを必要とするのはこの要素だけです。このコーパスでは、グラフ要素はランキングを向上させません。全文検索とベクトル検索の組み合わせに追加すると、2ポイント低下します。グラフ要素はエンティティと GET /api/graph のためにあり、勝利のためではありません。3つが同等の強みだと主張するのは、このリポジトリ自身のスクリプトと矛盾する数値を売り込むことになります。
🖥️ HTTP API(32 個のルートパス)
異なるパスは32個です。各 HTTP メソッドを個別に数えると35個のエンドポイントになります。これは、/api/memories、/api/settings、/mcp のようなパスが2種類のメソッドに応答するためです。どちらの数も server.ts 自体に基づいており、tests/doku-zahlen.test.ts はパスを数えます。そのため、既存のパスに新しいメソッドを追加すると2つ目の数だけが増え、新しいパスを追加すると両方の数が増えます。
| 分野 | ルート |
|---|---|
| メモリー | GET/POST /api/memories、POST /api/memory、DELETE /api/memories/:id、POST /api/memories/:id/restore、POST /api/memories/bulk-delete、POST /api/memories/bulk-restore、POST /api/memories/reclassify、POST /api/memories/import |
| 検索とグラフ | GET /api/memories/search、POST /api/search、GET /api/graph、GET /api/graph/bild |
| インポート/エクスポート | POST /api/import/markdown、POST /api/export/markdown |
| 受信箱 | GET /api/inbox/status、POST /api/inbox/scan |
| デバイス同期 | POST /api/sync/export、POST /api/sync/import、GET /api/sync/journal |
| 暗号化と修復 | GET /api/health(encryption の状態を含む)、POST /api/repair/imports |
| MCP | POST /mcp、GET /mcp、GET /api/mcp/tools、POST /api/mcp/search、POST /api/mcp/save、POST /api/mcp/consolidate、POST /api/mcp/forget、GET /api/tools、POST /api/embed |
| システム | GET /api/settings、PUT /api/settings、GET /api/storage-info、GET /api/activity |
すべてのルートは 127.0.0.1 のみで待ち受け、レート制限、Helmet、入力検証を適用します。
この API は、このリポジトリから実行するサーバーです(npm run dev、または npm run build && npm start)。公開されている npm バイナリと Docker コンテナは、stdio 経由でのみ MCP と通信します。POST /mcp が応答するのはこのサーバー上であり、npx kepta-mcp からではありません。
ループバックはデフォルトであり、保証ではありません。KEPTA_HOST を設定すると、同じ認証なしの API がそのアドレスにバインドされ、ネットワーク上のすべてのマシンがあなたのメモリーを読み取り、削除できるようになります。これを設定する代わりに何をすべきかは、SECURITY.md に記載されています。
API がデータを破棄する前に求めるもの
スクリプトが把握しておくべき 5 つの動作です。どれも、以前のデフォルト設定では、入力ミスひとつでデータが失われかねなかったために追加されました。
POST /api/memories/importでmode:"replace"を指定する場合は、confirm:"replace"が必要です。 これがないと、呼び出しは400を返し、何も起こりません。以前は、1 行の呼び出しでナレッジベース全体が永久に失われていました。消去の前に、コアは<data folder>/backup/kepta-pre-replace-<timestamp>.dbに暗号化されたスナップショットを書き込み、レスポンスのbackupPathにそのパスを返します。dryRun: trueを指定すると、変更を加えずにaffected: { active, trashed }を事前に確認できます。使用可能なノートがないペイロード(空の配列、またはコンテンツのないノート)は400で拒否されます。以前、すべてを消去したのはこのケースでした。復元するには、.dbファイルを空のデータフォルダーにkepta.dbとして置き、同じキーで起動します。スナップショットは、確認済みの置き換えごとに 1 つずつ、そのまま保存されます。backup/の整理はコアではなく、利用者が行ってください。DELETE /api/memories/:id?permanent=は厳密です。 指定できる値は1、0、true、false、またはパラメーターなし(=ゴミ箱へ移動)のみです。Trueも含め、それ以外はすべて400となり、削除は行われません。?permanent=1&permanent=0も400になります。GET /api/settingsはシークレットの値を返さなくなりました。key、api_key、token、secret、password、passwort、passphrase、schluesselで終わるキーとai_settingsの値は、{ gesetzt: true, ende: "…最後の 4 文字…" }として返されます。8 文字未満の場合はendeがなく、削除済みのエントリはレスポンスに含まれません。書き込みは引き続きPUTで行い、値全体は暗号化されたデータベース内に保存されます。UI ではgesetztとendeを表示し、値そのものは決して表示しないでください。- エラーレスポンスは JSON です。 スタックトレース、絶対パス、送信した本文のエコーは含まれません。
413では上限と受信したサイズ(limitBytes、receivedBytes)が示されます。不正な本文には、それを繰り返さずに400が返されます。また、500以上の場合、実際の理由はレスポンスではなくサーバーログに記録されます。 POST /api/repair/importsの上限は 16 kb です。 以前から上限は宣言されていましたが、適用されておらず、900 KB のデータも通っていました。現在は上限を超えると413になります。このルートに関するほかの変更はありません。
1 行ずつ触れておくべき小さな変更が 2 つあります。~/.kepta/inbox/ 内のシンボリックリンクはインポートされません。元の場所に残り、POST /api/inbox/scan は skipped: [{ file, reason }] に報告します(リンクだけで、エージェントが参照するメモリーに読み取り可能なファイルを取り込めてしまっていました)。また、GET /api/graph には上限があります。エンティティは最大 500 件、関係は最大 2000 件です(src/core/store.ts、getGraph())。いずれの上限の前にも ORDER BY はないため、どれが返るかは重要度ではなく行の順序で決まり、大規模なストアでは中心的な用語が含まれないことがあります。さらに、エッジからは分からないこともあります。レスポンス内の関係には validFrom と validTo が含まれますが、コアの書き込み処理では両方とも空のままです(addRelation は期間を指定せずに呼び出されるため、デフォルトの null がそのまま使われます)。このグラフを描画するクライアントは、期限切れの主張と有効な主張を区別できません。そのように区別できるかのように扱ってはいけません。
GET /api/graph/bild — 切り捨てた内容を示すエンドポイント
GET /api/graph はそのままです。外部のエージェントがその構造を前提に実装しているためです。画像ルートは、その正直な兄弟です。graf-2 の契約に従い、sicht、entitaet、tiefe、knoten、kanten、layout を返します。意図的に width/height は含みません。位置はワールド単位で返され、welt.groesse はこの画像の一辺です。最低値は 1000 で、ストックに応じて増加し、力の法則に基づいて計算され、応答ごとに報告されます(src/core/graf-vertrag.ts)。welt.nullpunkt はそのワールドの左下隅です。レイアウトの状態 5 以降、位置は各軸で nullpunkt + [0, welt.groesse] の範囲内にありますが、必ずしも 0 から始まるとは限りません。追加されたノートによって、ビット単位で完全に固定されたノードをすべて同じ位置に保ったまま、以前の画像の最低値を超えて拡大することがあるためです。見栄えのよい 0 を保つために画像を平行移動すると、それらのノードがすべて動いてしまいます。そのためクライアントは (x - welt.nullpunkt.x) / welt.groesse をマッピングし、min(width, height) に合わせて拡大縮小します。ウィンドウサイズがレイアウト計算に入ることはありません。ハードコードされた 1000 で割ること、または最低値が 0 だと仮定することは、レンダラーがしてはならない唯一のことです。ノートが 3 000 件あると、ワールドの幅は約 2 500 単位になり、画像は空のキャンバスに対して 5 分の 1 の大きさの雲のように表示されてしまいます。計算した内容と表示内容が異なる場合は、応答自身が kuerzung でそのことを示します。適用された上限、残りの量(uebrig)、削減した理由(grund:knoten、kanten、paarBudget、tiefe、privat、papierkorb)、除外された非公開およびゴミ箱内の項目数(名前ではなく数値のみ)、孤立したノードとエッジ、そして単一の vollständig フラグです。ETag と If-None-Match を使えば、再計算せずに 304 が返されます。画像がストア全体を表しているかどうかをクライアントが知る必要がある場合、確認すべきフィールドはこれです。GET /api/graph ではわかりません。
コアがノードの円を互いに分離するようになりました(LAYOUT_VERSION 5)。描画前にノードの円同士が重ならないようにストックをレイアウトします。27 個の概念について、ノード数 400/1 500/3 000 で測定した結果は、交差するペアが0 件でした。コア独自の上限なしの規則 r = 6 + 2,4·√grad と、サーフェス側の規則 min(18, 4 + log2(1+grad)·2,2) の両方で数えています(tests/graf-ruhe.test.ts。今回と同じフィールドを、この状態より前の状態で、Stand 4 独自のソース(git show 6ae32d3:src/core/graf-kraft.ts)を使って実行した場合、コアの規則では重なるペアが 37/935/7 134 件、サーフェス側の規則では 15/443/5 236 件あり、ワールドの枠上に配置される地点は 36/221/818 件でした。この実行結果は docs/belege/nacht-12-10/vorher-gleich-12-10.log.txt に記録されています。このファイルはプロジェクトの資料と一緒に保管され、公開パッケージには含まれません。また、同じフィールドをそのコミットでレイアウトすれば、数値を再現できます)。空白を増やすことでこの判定を取り繕うことがないよう、2 つの数値も維持しており、どちらもサイズ区分ごとにテストで確認されます。測定日時は 2026-10-12 14:44 で、静穏性プローブが落ち着いていると判定したマシンでの結果です。
- 順序: 実際のエッジの中央値は 283 / 385 / 571 ワールド単位、ランダムなペアの中央値は 427 / 572 / 817 で、比率は 0,662 / 0,674 / 0,699 です。このリポジトリが読みやすさの基準としてすでに使っている 0,8 を下回っています(
tests/ui/graph.test.ts、実行ログ:docs/belege/nacht-12-10/ruhe-mit-anteil-1444.log.txt)。 - スケール: 描画される最小の円盤は、画像のワールド辺の 0,769 % / 0,572 % / 0,368 % を占めます(半径 10,16 WE、ワールド辺 1 321 / 1 775 / 2 759 WE)。これは 0,3 % 以上を保つ必要があります。この基準は、現在最も密度の高いフィールドを描画する際に 0,414 % となる、独自の描画面を基に測定したものです(ワールド辺は
kepta-app/src/lib/graphLayout.ts:521、半径はsrc/components/KnowledgeGraph.tsx:1418)。比率だけでは、ワールド全体が一様に広がったケースを検出できません。却下されたあるバリアントでは、ワールド辺が 19 684 のときにペア数が 0 となり、比率は基準を下回る 0,721 でしたが、円盤の占める割合はわずか 0,052 % でした(実行ログ:docs/belege/nacht-12-10/kleinste-scheibe-2007.log.txt。ヘッダーにあるとおり、18:07:18 UTC に独立した実行として開始されています。1 回の実行で半径と辺を測り、辺をbild-guete.json[28]と照合しています)。これはクライアントで正規化されると、画像ではなくほこりのようなものです。
🐍 Python クライアント
このマシンで KEPTA が実行中であることが前提です。デスクトップアプリを起動するか、このリポジトリで npm run dev を実行してください。pip install kepta で導入されるのはクライアントであり、サーバーではありません。また、AI クライアントが起動する stdio サーバーの npx kepta-mcp は、HTTP ポートをまったく開かないため、このクライアントが接続する相手ではありません。
pip install kepta
from kepta import KeptaClient
kepta = KeptaClient()
kepta.save("Carbonara", "Guanciale, pecorino, egg yolk. No cream.", tags=["cooking"])
for hit in kepta.search("carbonara without cream"):
print(f"{hit.score:.2f} {hit.memory.title}")
依存関係はありません。Python 標準ライブラリのみを使用します。
上記の例は、飾りではなく実測値です。デフォルトモデル(nomic-embed-text)では、search("carbonara without cream") により、そのメモが最初に表示され、ベクトル類似度は 0.75 になります。同じモデルでは、メモと単語が一つも共通しない言い換えは見つけられません。search("what do I cook with pasta") では、レシピの類似度は 0.51 となり、ベクトルの下限である 0.58(src/core/engine.ts、VECTOR_FLOOR)を下回ります。一方、「Pasta」という単語を含むだけのメモが 0.59 で上位になります。このケースで答えを返すのは全文検索です。質問とメモが共有する唯一の単語に一致するためです。python/README.md では、この制限と、それを改善するために必要なことを説明しています。
🏗️ アーキテクチャ
src/core/ memory engine (store, search, encryption, MCP protocol)
server.ts HTTP API (Express, 32 routes)
src/mcp-server.ts MCP stdio server (npx kepta-mcp) and the CLI (npx kepta-mcp)
src/ui/graph.ts the graph builder behind the CLI and the demo — `GET /api/graph` reads `store.getGraph` directly instead. No UI: the core has no window of its own, the interface is your AI client, and for a window there is the free desktop app in this repository's releases
npm/ source of the npm package (kepta-mcp)
Dockerfile container for the MCP server
python/ Python client (PyPI: kepta)
scripts/ eval, benchmark, repair
tools/ benchmark harnesses (LongMemEval, latency)
docs/ environment variables and the words the API uses
tests/ Vitest suite with CI-enforced coverage thresholds
HTTP API と MCP サーバーで同じコードパスを使用するため、エージェントは API を直接呼び出す場合と同じ結果を得られます。
🔧 環境変数
KEPTA が環境から読み取るすべての変数と、それぞれのデフォルト値、変更内容、変更した場合に起こりうる問題は、docs/ENVIRONMENT.md の 1 つの表にまとめられています。特に重要な 3 つを簡単に説明します。
KEPTA_MAX_ACTIVE | ローカル API が 429 を返すまでに受け付けるアクティブなメモの数です(デフォルトは 5000)。ライセンス上限ではなく、暴走したエージェントを制御するための制限です。値を上げても、それ以外は何も変わりません。 |
KEPTA_HOST | バインドするアドレスです。デフォルトは 127.0.0.1 です。ここにネットワークアドレスを指定すると、そのネットワークに対して認証なしの API が公開され、ループバックの保証が失われます。代わりに、独自の認証機能を備えたリバースプロキシを使用してください。 |
KEPTA_ENCRYPTION | off にすると、確認なしでデータベースが平文で書き込まれます。生の SQLite が必要なスクリプト向けの設定であり、キーの問題を解決するために使うものではありません。 |
API とこれらのドキュメントで使われる用語(note、memory、scope、dry-run、supersede、key と restore の 2 つの意味)は、docs/WORDS.md でまとめて説明しています。
🔐 暗号化
ナレッジベースは SQLCipher 4 データベースです。AES-256 による暗号化と、WAL を含むすべてのページに対する HMAC-SHA512 を使用します。256 ビットのランダムキーは、macOS Keychain、Windows DPAPI、Linux Secret Service のいずれかのオペレーティングシステムのキーリングに保存されます。キーリングのないサーバーやコンテナーでは、KEPTA_DB_KEY に 64 桁の 16 進数を設定してください。openssl rand -hex 32 で一度生成し、大切に保管します。
バイトレベルでの動作は、主張ではなく実測で確認できます。レジストリの kepta-mcp 3.2.0 からメモをひとつ書き込み、2026-10-10 に一時的な HOME を使ったところ、~/.kepta/kepta.db の先頭 16 バイトは 85 95 55 36 a3 ab f4 02 4c 6c f0 5c 0f 0b 4c 69 でした。SQLite format 3 ではなく、ファイル内のどこにもメモのテキストの痕跡はありません。どのストアでも、もちろんお使いのものでも、head -c 16 ~/.kepta/kepta.db がテストのすべてです。
ルール:キーがなければ、ファイルも作りません。 KEPTA がナレッジベースを作成しようとして、キーを安全な場所に保存できない場合(キーリングがない、承認を拒否された、CI の環境変数が空など)、ファイルは作成しません。終了コード 0 以外で停止し、解決方法(KEPTA_DB_KEY、または本当に平文を使いたい場合は KEPTA_ENCRYPTION=off)を示します。暗号化されないデータベースへ何も通知せずにフォールバックするのが以前の動作であり、このルールはその問題をなくすためのものです。既存のファイルを開く動作に変更はありません。既存のファイルでキーがない、または間違っている場合は、これまでも停止し、何も変更しませんでした。決定日:これは 2026-10-10 に決定され、現在コードに反映中です。これより前のビルドは、使用できない値でも平文を書き込み、終了コード 0 で終了します。古いリリースを使っている場合は、この記述を鵜呑みにせず、実際にテストしてください。
平文にする方法はひとつだけです。意図して有効にする必要があります。KEPTA_ENCRYPTION=off です。これは、インスペクターや一度限りの移行スクリプトなど、生の SQLite を読み取る必要のあるツール向けであり、パフォーマンス切り替え用ではありません。また、キーの問題を解決する方法でもありません(暗号化されたファイルに対して使うと、ファイルを読み取れないというエラーになります)。コンテナーを起動するために、これを使わないでください。その用途には KEPTA_DB_KEY を使います。暗号化の対象と対象外、およびキーのコピーを保管する方法については、SECURITY.md を参照してください。
🧪 品質
Vitest と v8 カバレッジによるテスト 1045 件(85 ファイル、2026-10-13 に計測)。これは実行時に収集され、実行できたケース数です。ソースに it.skip として記述されたケースは件数から除外されます。一方、実行中に静穏性プローブが実行を拒否したケースは件数に含まれます。どちらも同じランナー上の同じツリーだからです(scripts/test-bericht.mjs に理由を記載しています。この環境では、あるコミットでタイミングに関する 3 件のケースが実行を拒否され、次のコミットでは実行されました。周囲の状況で変わる数は、数とは言えません)。npm test はその実行の JSON レポートを書き出し、続いて node scripts/doku-check.mjs が両方の README の数値をその数に厳密に一致させます。tests/doku-zahlen.test.ts は同じレポートを参照し、信頼できない場合(レポートがない、テストスイートより古い、部分的な実行で書き出された場合)は、引き出しから値を取り出して照合するのではなく、比較を拒否します。カバレッジのしきい値は CI のゲートです。いずれかを下回るコミットがあると、CI は失敗します。さらに、固定コーパスを使った検索評価(Hit@1、上限付き Recall@5、MRR)、検索経路ごとのアブレーションテスト、暗号化評価、コアアーキテクチャの境界テストもあります。
カバレッジのしきい値(CI で適用)
| 対象 | 行 | 関数 | 分岐 | ステートメント |
|---|---|---|---|---|
| カバレッジ対象範囲全体 — CI で固定 | ≥ 70 % | ≥ 72 % | ≥ 56 % | ≥ 66 % |
src/core — CI で固定 | ≥ 87 % | ≥ 89 % | ≥ 74 % | ≥ 85 % |
計測対象範囲は src/core/** と server.ts(vitest.config.ts)です。製品であるヘッドレスコアが対象です。tools/、scripts/、npm/、python/ にはそれぞれ独自のテストスイートがありますが、しきい値は設定されていないため、これらの割合には含まれません。
レイテンシ — 計測結果を公開
1 台のノート PC(Apple M4)での検索時間の中央値です。各実行結果は tools/latenz/ergebnisse/ にコミットされています。メモリ 100,000 件では中央値 46.6 ms(p95 87.6 ms、tools/latenz/ergebnisse/latenz-100k-fts-2026-10-01.json)、メモリ 1,000,000 件では中央値 276.5 ms(tools/latenz/ergebnisse/latenz-1m-fts-2026-10-01.json)です。次の 3 つの条件は記録自体に含まれており、数値と合わせて確認する必要があります。計測では暗号化を無効にし、決定論的なスタブの埋め込み器を使用しています。そのことは konfiguration.verschluesselung と konfiguration.embedder に記載されています。また、どちらの計測でも konfiguration.vektorChunks は 20000 です。tools/latenz/bench.ts:38 ではベクトル処理部分を min(20_000, N) に固定しているため、100 万件のメモリでの中央値も、100,000 件の場合と同じ 20,000 チャンクで計測されています。つまり、これはベクトル処理部分を上限付きにした計測であり、その規模のメモリをすべて埋め込み処理したストアでの計測ではありません。すべてのノートがベクトルを持つストアでは、この数値が示すより検索が遅くなります。どの程度遅くなるかは、このリポジトリではまだ計測結果が公開されておらず、計測結果の一覧を掲載している tools/latenz/README.md には 20,000 チャンクという条件が記載されています。ディスク上のファイルは常に SQLCipher-4 で暗号化されていますが、この 2 つの中央値には暗号化のコストは含まれていません。
ベンチマーク記録 — LongMemEval-S、完全公開
KEPTA は、ベンチマークの結果を単一の代表値ではなく、質問ごとの生データとして公開しています。すべての実行で、500 件すべての質問記録をこのリポジトリにコミットしています。保存先は tools/longmemeval/ergebnisse/ です。各記録には、ID、種類とスキル、判定者の評価、検索で返されたメモの数、取得したコンテキストのうちどれが回答を裏付けたか、そして参照回答が一字一句そのまま含まれていたかが記載されています。質問と回答のテキストはリポジトリに含まれていません。SHA-256 を各記録に含めた、固定された上流データセットから取得します。データセットは固定(LongMemEval-S、500 問、SHA 固定)、判定者も固定されており、ローカルで完全に再現できます。詳しくは tools/longmemeval/README.md をご覧ください。
この一連の結果は質問ごとの生データとしてコミットされていますが、現在の測定値ではないため、ここではスコアを記載していません。そのフォルダーにあるすべての記録で kepta_version が 2.13.2 から 2.13.22 の範囲にある一方(grep -h kepta_version tools/longmemeval/ergebnisse/*.json)、このリポジトリで公開しているのは 3.4.0 です。この二つは一文の中で併せて述べるべきもので、意味することは一つです。記録は実行時のエンジンに対して有効なままであり、新しい実行なしにバージョン番号が変わっても 3.4.0 について何も示しません。以前のパーセンテージが再び有効になるわけでも、無効になるわけでもありません。この一連の処理を公開中のエンジンで再実行するまでは、数値は記録に残し、論文には載せません。変わらない点もあります。判定者はどちらもローカルで実行されます(継続性の系列では qwen2.5:3b、後続の実行では Q4 の qwen2.5:14b を使用し、いずれもコンシューマー向け GPU 上で実行)。クラウドはゼロ、ファインチューニングも行わず、両方の処理チェーンの全ステップが同じフォルダーに実行記録として保存されています。
この指標が測定するもの — 他の指標と比較する前にお読みください。 これはエンドツーエンドの回答精度ではなく、コンテキストの十分性を測定するものです。ローカルの判定者(qwen2.5:14b、temperature 0、プロンプト v1)が、取得したコンテキストに参照回答が含まれているかを評価します。処理には生成用 LLM は含まれず、PARTIAL 判定は 0.5 点として数えます。また、この実行では質問の 29.8 % が、判定者を一度も呼び出さずに決定論的な完全一致で解決されました(tools/longmemeval/README.md、104 行目)。Zep が公表している 63.8 % は、クラウド LLM が評価した、生成パイプライン全体の回答精度です。関連する証拠ではありますが、同じ指標ではありません。両方の数値とこの違いは、引用した論文に明記されています。さらに、はっきり述べておくべき注意点があります。この系列のすべての調整項目(topk、--temporal、--zeitsplit、HyDE、判定者のサイズ)は、同じ 500 問を使って選択されています。そのため、この系列の数値は学習データ内の値であり、上方に偏っています。未使用のホールドアウト分割では、まだ実行していません。質問ごとの生データをすべて公開しているのは、まさにその内容を確認していただくためです。ここでの説明も含め、ぜひ検証してください。
👋 KEPTA の開発者
KEPTA は、ドイツを拠点とする小さなチーム、Damian Todorovic と Emil Wagner が開発し、開発の様子を公開しています。ご質問やアイデア、チーム向けの Enterprise に関するお問い合わせ、あるいは今後の展開を追いたい方は、LinkedIn でご連絡ください。
📄 ライセンス
BUSL 1.1 — ソース公開ですが、OSI 承認のオープンソースではありません。すべてのコードを公開しており、自組織内での本番利用は常に許可されています。ホステッドサービスとして提供する権利は留保され、各バージョンはリリースから 4 年後に AGPL-3.0-or-later に切り替わります。npm パッケージ kepta-mcp にはこのリポジトリと同じライセンスが適用されますが、python/ 以下の Python クライアントは MIT ライセンスのままです。そのため、あらゆる Python プロジェクトに組み込めます。チームおよび組織向けの KEPTA Enterprise は契約に基づいてライセンスされます — LinkedIn でご連絡ください。
このリポジトリが提供するもの、提供しないもの。 ソース公開のコアはメモリエンジンです。ストレージ、検索、MCP を、すべての AI に無料で提供します。フォークは正当な利用方法ですが、フォークを KEPTA として提示することはできません。KEPTA の名称とブランドは Damian Todorovic に帰属します。フォークして、開発に利用し、独自の製品として公開できます。ただし、別の名称を使用し、このエンジンをホステッドサービスとして提供せず、バージョンの変更日が到来した際には、加えたすべての変更を AGPL-3.0-or-later に切り替えてください。非公開のメモは、あらゆる AI チャネルから保護されます — private はエージェントに対する開示ルールであり、自分のマシン上で実行されるプログラムから守るためのものではありません(SECURITY.md)。
KEPTA — あらゆる AI が読み書きする、ローカルで暗号化されたひとつのメモリ。ローカル、暗号化、無料。サブスクリプションも、アカウントも、言い訳も不要です。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。