Skip to main content
Glama
moonandecho

origin-memorycore

by moonandecho

origin-memorycore

English | 简体中文

MemoryCore は LLM エージェントのためのメモリガバナンス層です。

エージェントはメモリを急速に蓄積します — 好み、事実、決定などです。維持されないメモリは静かに劣化します:重複が蓄積し、古い事実が残り続け、ホット層が満杯になって書き込みを拒否し始めます。MemoryCore はそれを防ぎます。

2層メモリシステムとして機能します:

  • ホット層 — 頻繁に使用される行動知識(好み、ルール、修正)を高速なローカルファイルに保持し、常にコンテキスト内に置きます。

  • コールド層 — 低頻度の事実を自動的にマイグレーションし、プロセス内 SQLite エンジン(または設定すればリモートメモリサービス)に保存します。

この2層の間で、ガバナンスコアがメモリを健全に保ちます:

  • 書き込み時重複排除 — 類似した事実は保存前にマージされ、重複しません。

  • 容量制御 — ソフト/ハードしきい値がホット層が満杯になる前にオーバーフローをトリガーするため、書き込みを拒否することはありません。

  • コールド層ガバナンス — 定期的な重複排除/クリーンアップパスにより、コールド層は成長しても検索可能な状態を保ちます。

  • ごみ箱 — 削除されたエントリには30日間の猶予期間があり、ごみ箱内のエントリを呼び戻すと復活します。

結果として、ホット層は予算内に収まり、コールド層は検索可能な状態を維持し、エージェントがどれだけ蓄積してもメモリは管理可能な状態を保ちます。

MCP(Model Context Protocol)streamable-http / stdio 標準に基づいて構築されています。あらゆる MCP クライアントで動作し、Hermes Agent でテストされています。

機能

  • メモリガバナンス(中核) — コールド層のデータ整合性を保護する3層構造:

    • コールド書き込み重複排除:コールド層への書き込み前に、セマンティックリコール + LLM ジャッジが重複をチェックし、冗長なエントリを作成せずに既存のエントリを更新します。

    • 容量ハードゲート:コールド層はソフト制限(6000エントリ、メンテナンスパスを1回トリガー)とハード制限(10000エントリ、メンテナンスループを強制)を適用し、無制限の成長を防ぎます。

    • ごみ箱 (trash_store.py):削除されたコールド層エントリは、30日間の有効期限付きで ~/.memorycore/trash.json に移動されます。新しいセマンティックエビデンスでごみ箱内のエントリを呼び戻すと復元されます(「呼び戻して復活」)。

  • コールド/ホットルーティング — すべての書き込みは分類されます:高重要度または好みに似たもの → ホット(ローカル);低頻度の事実 → コールド(リモート);古いステータスレコード → 破棄。

  • 6ステップオーバーフロー — 容量ベースライン → 重複排除 → 古いデータのフィルタリング → マージ → 安全な書き込み(コールドを先に、その後ローカルを削除) → 検証。

  • コールド層メンテナンス — 重複排除マージ、古いデータのクリーンアップ、競合解決、埋め込み整合性チェック。

  • 容量制御 — ソフトしきい値(書き込み前に1回オーバーフロー)/ ハードしきい値(オーバーフローを強制)/ ターゲット比率。デフォルト:5000文字制限の 60% / 80% / 40%。

  • グレースフルデグラデーション — コールド層に到達できませんか?書き込みは明示的に失敗し(静かに破棄されることはありません)、オーバーフローはローカルエントリを保持し、ヘルスチェックは cold.error 付きでローカルステータスを返します。

  • コアの変更ゼロ — ドロップインコンパニオンとして設計されており、エージェントの組み込みメモリツールはそのまま動作し続けます。

Related MCP server: AI Long-Term Memory MCP Server

アーキテクチャ

┌─────────────────────────────── Mac / local ──────────────────────────────┐
│  LLM agent (e.g. Hermes)                                                 │
│    │  MCP client                                                         │
│    ▼                                                                     │
│  MemoryCore MCP server                                                   │
│    ├─ local_store.py        hot tier: MEMORY.md / USER.md (chars-based)  │
│    ├─ classifier.py         cold/hot/stale routing rules                 │
│    ├─ overflow.py           six-step overflow                            │
│    ├─ maintenance.py        cold-tier governance                         │
│    └─ cold_store_client.py  →  LocalBackend (SQLite, in-process)         │
│                               or RemoteBackend (MCP streamable-http)     │
└──────────────────────────────────────────────────────────────────────────┘
                     LocalBackend: mnemosyne-memory (in-process engine)
                     RemoteBackend: remote MCP memory service

Optional (Hermes Agent only): hermes-plugin/memorycore-prefetch
  ┌───────────────────────────────────────────────────────────────────────┐
  │ MemoryProvider plugin (single-model qwen3, enabled by default)        │
  │   system_prompt_block → static index (always active)                  │
  │   prefetch → ColdStoreClient.recall_results(top_k=20)                 │
  │            → dense ranking → session + hot-tier dedup → top-5         │
  │   Disable: MEMORYCORE_PREFETCH_ENABLED=0                              │
  └───────────────────────────────────────────────────────────────────────┘

クイックスタート

前提条件

  • ollama — 埋め込み API(インストール: https://ollama.com)

  • qwen3-embedding:0.6b — 推奨埋め込みモデル(1024次元)

# Install ollama (macOS/Linux)
curl -fsSL https://ollama.com/install.sh | sh

# Pull the embedding model
ollama pull qwen3-embedding:0.6b

インストールと実行

pip install "origin-memorycore @ git+https://github.com/moonandecho/origin-memorycore.git"

# That's it! MemoryCore runs with ollama for embeddings:
#   - Hot tier:  MEMORY.md / USER.md (default ~/.hermes/memories)
#   - Cold tier: SQLite via mnemosyne-memory (default ~/.memorycore/data/)
#   - Embedding: qwen3-embedding:0.6b via ollama (http://localhost:11434/v1)
python -m memorycore.server          # stdio transport (default)

データディレクトリ構成(すべて ~/.memorycore/ 配下):

~/.memorycore/
├── data/          # SQLite database (MNEMOSYNE_DATA_DIR)
└── ...

MNEMOSYNE_DATA_DIR で上書きします。

モデル切り替え

デフォルトの埋め込みモデルは qwen3-embedding:0.6b(1024次元)です。環境変数を設定することで任意の ollama モデルを使用できます:

export MEMORYCORE_EMBED_URL="http://localhost:11434/v1"
export MEMORYCORE_EMBED_MODEL="nomic-embed-text"   # or your preferred model

または、OpenAI 互換の埋め込み API を指定できます:

export MEMORYCORE_EMBED_URL="https://api.openai.com/v1"
export MEMORYCORE_EMBED_MODEL="text-embedding-3-small"

MCP クライアントに登録します(Hermes Agent の config.yaml の例):

mcp_servers:
  memorycore:
    command: python
    args: ["-m", "memorycore.server"]

リモートモード(オプション)

ローカルエンジンの代わりに共有リモート Mnemosyne MCP サービスを使用したい場合は、MEMORYCORE_COLD_BACKEND=remote を設定します:

export MEMORYCORE_COLD_BACKEND=remote
export MNEMOSYNE_URL="http://your-memory-service:9000/mcp"
python -m memorycore.server

公開されるツール:

ツール

目的

memorycore_store_fact(content, importance, scope, target)

統合書き込みエントリ:コールド / ホット / 古いデータにルーティング

memorycore_recall(query, top_k)

コールド層のメモリを積極的に呼び戻します(読み取り専用、ターンごとのプリフェッチを補完)

memorycore_trigger_overflow(target)

6ステップオーバーフローを実行。ターゲット ≤40%

memorycore_run_cold_storage_maintenance()

コールド層ガバナンスパス

memorycore_get_memory_usage()

ホット層の使用量 + コールド層の統計 + しきい値

Hermes 統合 — ターンごとのプリフェッチ

MCP サーバーはクライアント非依存です。Hermes Agent には、デュアルチャネルのコールド層アクセスを提供するオプションのコンパニオンプラグインがあります:

デュアルチャネル設計

  • 静的インデックスチャネル(常時アクティブ、オーバーヘッドゼロ) — 利用可能なトピックを列挙したシステムプロンプトブロック(MEMORYCORE_INDEX_TOPICS で設定可能、カンマ区切り)。オンデマンドリコールに memorycore_recall(query) を使用するようガイドします。

  • ターンごとプリフェッチチャネル(デフォルトで有効) — 毎ターンコールド層を呼び戻し、密スコアでランク付けし、トップ5をコンテキストに注入します。これにより、エージェントは話す前に関連コンテンツを「思い出します」。無効にするには MEMORYCORE_PREFETCH_ENABLED=0 を設定し、オンデマンドリコールのみを使用します。

プリフェッチパイプライン

query → preprocess → cold-tier recall (20 candidates)
  → dense ranking (qwen3) → top-5
  → session dedup → hot-tier dedup → inject into context

MemoryCore はシングルモデル qwen3 アーキテクチャ(リランカーなし)を使用します。qwen3 の密スコアはバッチ内の相対ランキングに使用されます。絶対しきい値はありません。密スコアによるトップ5の候補が、重複排除後に常に注入されます。

グレースフルデグラデーション

ollama に到達できない場合(未インストール、未実行、モデル未プル)、プリフェッチは静かに空文字列を返します。会話はメモリを注入せずに進行し、ユーザーにエラーは表示されません。DEBUG レベルのログがプローブ失敗を記録します。

デプロイ(Hermes Agent)

# 1. install origin-memorycore (provides the cold tier + ColdStoreClient)
pip install "origin-memorycore @ git+https://github.com/moonandecho/origin-memorycore.git"

# 2. put the plugin in Hermes' user plugin dir
mkdir -p ~/.hermes/plugins
cp -r hermes-plugin/memorycore-prefetch ~/.hermes/plugins/

# 3. activate (takes effect next session)
hermes config set memory.provider memorycore-prefetch

デプロイ後の3つのポスチャ:

ポスチャ

設定

動作

デフォルト(推奨)

追加設定なし

静的インデックス + トップ5注入によるターンごとプリフェッチ

オンデマンドのみ

MEMORYCORE_PREFETCH_ENABLED=0

静的インデックスのみ。エージェントは memorycore_recall でコールド層をクエリ

カスタム埋め込み

MEMORYCORE_EMBED_URL + MEMORYCORE_EMBED_MODEL

別の ollama インスタンスまたは OpenAI 互換 API を指定

プラグイン設定

変数

デフォルト

説明

MEMORYCORE_PREFETCH_ENABLED

(未設定)

0 に設定するとターンごとのプリフェッチを無効化

MEMORYCORE_EMBED_URL

http://localhost:11434/v1

Ollama または OpenAI 互換の埋め込み API ベース URL

MEMORYCORE_EMBED_MODEL

qwen3-embedding:0.6b

埋め込みモデル名(1024次元を推奨)

MEMORYCORE_INDEX_TOPICS

(未設定)

システムプロンプトのインデックスブロック用のカンマ区切りトピック

要件と注意事項:

  • Hermes 固有:プラグインは Hermes ランタイムモジュール(agent.memory_provider)をインポートするため、スタンドアロンパッケージとしては動作しません。これは MemoryCore の Hermes 統合側です。詳細: hermes-plugin/memorycore-prefetch/README.md。

  • すべてのリコールは5秒のタイムアウトを維持します。失敗は静かに空の注入にデグラデーションし、会話をブロックすることはありません。

ホット層ガバナンス

ホット層(MEMORY.md / USER.md)は毎ターンコンテキストに注入されるため、小さく最新の状態を保つ必要があります。MemoryCore は6ステップオーバーフローの上に3つのメカニズムを重ね、履歴レコードが蓄積されるのではなく決定論的に退役するようにします:

ホット層メタデータエージング

  • サイドカーメタデータ:MEMORY.meta.json / USER.meta.json は .md ファイルの隣に配置され、エントリ内容の SHA-256 をキーとします。アトミック書き込みとファイルロックによりプロセス間でも安全です。§区切りの .md 形式は変更されないため、ホストのメモリツールは変更なく動作し続けます。

  • すべてのエントリは state(過去の決定 / ステータスレコード)または rule(教訓 / 好み)にタイプ付けされます:

    • state:書き込みから7日後にコールド層へ退役します(設定可能:STATE_TTL_DAYS)

    • rule:経過日数では退役しません。更新がないまま30日経過すると、長いエントリ(>200文字)が LLM 圧縮候補になります(設定可能:RULE_COMPRESS_DAYS)。ルールはまた、以下の無効化シグナルラダーを通じて持続可能な出口を得ます。アクティブな好みを誤って退役させることはありません。

  • エントリの内容が変わるとキーも変わります。次のリコンサイルで新しい内容が再タイプ付けされ、孤立したキーはガベージコレクションされます。

デュアル書き込みエントリガバナンス

  • store_fact 書き込みエントリ:完了した決定/ステータスレコードのように見える内容(日付と完了マーカー(例:拍板/已配置)、行動指示なし)は、直接コールド層にルーティングされます。ホット層には入りません。

  • プラグイン on_memory_write 直接書き込みチャネル:組み込みメモリツールの追加/置換のたびに、エントリは即座にタイプ付けされます。state エントリはバックグラウンドでコールド層にマイグレーションします(重複排除 → コールド書き込み確認 → ホットから削除。コールド失敗時はエントリが state スタンプ付きで7日間のバックストップとして残ります)。これは使用量しきい値とは独立して動作します。単一のワーカースレッドが境界のあるキュー(サイズ128)を処理します。キューが満杯の場合は書き込みがスキップされ、次のオーバーフローリコンサイルがバックストップとしてスタンプします。

メタデータ優先オーバーフロー

各オーバーフロー実行はまずメタデータをリコンサイルし(未タイプのレガシーエントリをスタンプ、孤立をガベージコレクション)、その後メタデータに基づいてエントリを退役させます。キーワードは未タイプのエントリのフォールバックとしてのみ残ります。サイドカーの障害はキーワードパスにデグラデーションし、オーバーフローをブロックすることはありません。

ルール無効化シグナル(階層的保護)

純粋な rule エントリで構成されたホット層は設計上出口がありません(「好みを沈めない」)。そのため、編集されない短いルールは永遠に残り、最終的に層を満杯にしてしまいます。MemoryCore はプレッシャーラダーでそのギャップを埋めます:各オーバーフロー実行は実際の使用量(ベースライン)を測定し、プレッシャーが上昇するにつれてより深い出口を開きます(レスポンス)。5つの観測可能なシグナルが適格性と順序を決定し、プレッシャーが行動するかどうかを決定します:

シグナル

監視対象

アクション

S1 アイドル時間

サイドカー内の updated_at

圧縮(30日)とスタブシンク(45日)の対象判定ゲート

S2 完了再チェック

埋め込み日付が60日以上+完了マーカー2つ以上+行動語ゼロ

rule と誤って型付けされた履歴レコードは state に付け替えられる → 通常の7日TTLシンクへ

S3 同一トピックのクラスタリング

語彙的類似度(+任意の埋め込みチャネル)

同一トピックのエントリは1つに統合される。統合後の長いエントリは後で圧縮候補になる

S4 トピックアクティビティ

ローカルクエリアクティビティログ(プリフェッチ/リコール、45日間ローリング、任意)+LLM休眠判定

強制圧力下の休眠Bクラスルール:全文をコールド層へ(先に確認)、≤40文字のポインタスタブはホットに残る

S5 層間冗長性

コールド層のリコール一致

同等のコールドコピーがすでに存在する → ホットコピーを破棄(情報損失ゼロ)

階層型保護: Aクラスのメタルール(行動・相互作用・文章スタイルの規範)、レッドラインルール、重要度 ≥ 0.9 のエントリは決して S2/S4/S5 を受けない。これらはマージまたは圧縮のみ行われる。スタブポインタには独自のライフサイクルがある(強制圧力下では最古優先GC。コールド層には決して触れない)。そのためポインタが層を再び満たすことはない。すべての退出は コールドライトファースト である。ローカルエントリが変更されるのはコールド層が確認した後だけであり、失敗した場合は元の状態が維持される。シグナルが利用できない場合(アクティビティログなし、LLMキーなし)、ラダーは推測せずに以前の動作に劣化する。

定数(memorycore/core/config.py): RULE_RETYPE_DAYS=60、RULE_STUB_IDLE_DAYS=45、ACTIVITY_WINDOW_DAYS=30、MAX_STUB_PER_RUN=3、STUB_MAX_CHARS=40、IMPORTANCE_PROTECT=0.9。

ヘルスチェック: memorycore_memory_audit

ホット層の全エントリを、その型、経過時間、退避計画、keep/sink分類とともに一覧表示する読み取り専用ツール。シンク対象が見つからないオーバーフローを診断するための可観測性の要です。

スケールテストと最適化の結果

MemoryCore は、コールド層1万エントリ規模でストレステストとリコール最適化が行われました(隔離されたテスト環境、本番データへの接触ゼロ、再現可能な結果)。

書き込みと容量

メトリクス

結果

書き込みスループット

10kエントリを467秒、約21.4エントリ/秒(埋め込み処理がボトルネック)

データベースサイズ

300MB / 10kエントリ

メモリ使用量

プロセスRSS +19MBのみ、全体を通じてフラット — リークの兆候なし

クエリレイテンシ — top_k=5 で中央値48ms。1万エントリ規模は100エントリ規模と同等であり、レイテンシの劣化はありません。

リコール品質 — 3つの検証項目:

  1. 完全一致(セルフリコール): 20/20 が top-1 にヒット — 完全一致は依然として機能。

  2. ノイズ拒否(無関係なクエリ): top-1 の dense スコア平均 0.056、ほとんどが 0.0 を返す — 無関係なコンテンツが結果に漏れることはほぼない。

  3. 短いクエリのリコール(改善前 → 改善後) — 主要な最適化の成果:

段階

短いクエリのヒット率

改善前

0/8

改善後

5/8(62.5%)

最適化した内容: トピック密度が高いと、固定の候補切り詰め k=max(top_k, 20) によって詳細な記憶が候補プールから押し出され、短いクエリでそれらをリコールできませんでした。この修正では、候補切り詰めを k=max(top_k*4, 300) に拡大し、リコールの入口で内部の候補を展開してから返却を切り詰めます。これにより、すべてのリコール経路(ターンごとのプリフェッチ+オンデマンドリコール)が1つの修正で恩恵を受けます。修正はリコール段階だけに限定されており、ランキングロジックには触れず、動作は予測可能で元に戻せます。

注: テストは合成10kエントリのデータベース(80件の「ゴールデン」メモリ+日誌口調の9920件のフィラーメモリ、本番と同じ設定)で実施しました。本番データには触れていません。

sqlite-vec ユーザーへの注意

Mnemosyne のコールド層で sqlite-vec ベクトルインデックスを有効にする場合、beam.py の _wm_vec_search_sqlite は生の類似度計算式 sim = 1 - distance / (2 * EMBEDDING_DIM) を使用しており、これが float32 距離を約1.0に潰してしまうため、動的しきい値が実質的に役に立たなくなります(すべての結果が通過する)。

パッチ: float32 ブランチでは、式を sim = 1 - d² / 2 に置き換えてください。これにより、正規化されたベクトルに対して正確なコサイン類似度が得られ、しきい値の正しい動作が回復します。

コールドストア契約

以下の5つのMCPツールを公開するサービスは、コールド層として機能できます。

ツール

意味

remember(content, importance, scope)

メモリを保存し、memory_id を返す

recall(query, top_k)

意味的リコール

update(memory_id, content)

既存メモリをマージ更新

forget(memory_id)

メモリを削除

stats()

total + 埋め込み整合性

完全な契約とリファレンスクライアントについては examples/cold-store-contract.md を参照してください。

設定

環境変数

デフォルト

意味

MEMORYCORE_COLD_BACKEND

local

コールド層バックエンド: local(インプロセス)または remote(MCP)

MNEMOSYNE_URL

(空)

コールド層MCPエンドポイント(remote モードで必須)

MNEMOSYNE_DATA_DIR

~/.memorycore/data

ローカルSQLiteデータディレクトリ

MEMORYCORE_EMBED_URL

http://localhost:11434/v1

Ollama または OpenAI 互換の埋め込みAPIベースURL

MEMORYCORE_EMBED_MODEL

qwen3-embedding:0.6b

埋め込みモデル名(1024次元)

MEMORY_DIR

~/.hermes/memories

ホット層ディレクトリ(MEMORY.md / USER.md)

ACTIVITY_LOG_ENABLED

1

トピックアクティビティシグナル用のクエリアクティビティログ。0 にするとログとS4スタブシンクが完全に無効になる

MNEMOSYNE_TIMEOUT

10.0

コールド層リクエストタイムアウト(リモートモード、秒)

容量定数は memorycore/core/config.py にあります(CHAR_LIMIT_*、SOFT_THRESHOLD、HARD_THRESHOLD、TARGET_RATIO)。

動作の仕組み

  1. 書き込み — store_fact はコンテンツを分類します:

    • 重要度 ≥ 0.8 またはホットキーワードに一致 → ホット、ローカルに保持

    • 失効マーカー(短いエントリ、例: "已修复 / fixed") → 破棄(移行しない)

    • それ以外 → コールド、リモートサービスに直接書き込み

  2. オーバーフロー — ホット層の使用量がソフトしきい値を超えると、オーバーフローが低頻度エントリをコールド層へ移行します。ハードしきい値では、ターゲット以下になるまで強制オーバーフローします。順序は常に コールドに先に書き込み、確認してからローカルを削除 であり、コールド層が失敗しても何も失われません。

  3. メンテナンス — コールド層への定期的なパスで、重複のマージ、失効エントリの削除、競合の解決、埋め込み整合性の検証を行います。

ライセンス

MIT © 2026 moonandecho

サードパーティライセンス

  • mnemosyne-memory — MIT, AxDSan 作。LocalBackend が使用するインプロセスメモリエンジン。

  • MCP Python SDK — MIT。

  • ollama — MIT。ローカル埋め込みAPIサーバー。

  • qwen3-embedding — Apache-2.0, Alibaba Cloud 作。デフォルトの埋め込みモデル(同梱されていません。ollama 経由で取得)。

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    A
    maintenance
    Open-source AI memory layer for LLM agents. Importance scoring, temporal decay, hierarchical memory (facts, summaries, themes), YMYL prioritization, and active retrieval with contradiction detection. Supports OpenAI, Anthropic, Ollama. Local-first with SQLite + FAISS.
    51 PyPI
    49
    Apache 2.0
  • A
    license
    A
    quality
    D
    maintenance
    Provides persistent, self-optimizing memory for AI agents, enabling them to remember preferences and context across sessions and share knowledge across multiple agents.
    4
    7 npm
    ISC