summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-07-04 19:19:00 +0900
committertanaka takashi <isazaka@gmail.com>2026-07-04 19:19:00 +0900
commitdda043b0ec9d8d9e5da7fe51fc48791086417a9b (patch)
tree58bff8830ebd8047048bbe32fe1c5b69de630bf1
parentaba6f5cf8001d23c99960f42143890644b7af36f (diff)
ドキュメント更新
-rw-r--r--README.md205
-rw-r--r--docs/mcp.md390
2 files changed, 519 insertions, 76 deletions
diff --git a/README.md b/README.md
index bf935e0..e86c8f9 100644
--- a/README.md
+++ b/README.md
@@ -1,128 +1,181 @@
-# tiny-convmem-mcp
+# Tiny ConvMem MCP
-LLMの会話メッセージをローカルの追記ログへ保存する、Windows向けC17製MCP
-サーバです。書込みと削除はディスクへの同期完了後に成功を返し、プロセス再起動時は
-ログまたはsnapshotから状態を復旧します。
+Tiny ConvMem MCPは、LLMとの会話をローカル環境へ保存し、あとから検索・参照できる
+MCPサーバーです。
-## 必要環境
+会話メッセージをsession単位で蓄積し、本文やタグから検索したり、関連する前後の会話を
+取り出したりできます。データは指定したdirectory内に保存され、外部databaseやnetwork
+serviceを必要としません。
+
+現行versionはWindows x64をサポートしています。将来的には、Linux対応も想定しています。
+
+## 主な特徴
+
+- **ローカル完結:** 会話データを指定したdirectoryへ保存
+- **永続的な記憶:** MCP hostやPCを再起動しても保存内容を復元
+- **文脈を含む検索:** 本文、summary、tagを検索し、前後のメッセージやrelationも取得
+- **構造化metadata:** 記憶の種類、tier、importance、tag、summary、relationを保持
+- **安全な更新:** revisionを使った競合検出付きのメッセージ更新
+- **耐障害性:** append-only log、CRC検証、snapshot fallback、書込み完了前のdisk flush
+- **バックアップ:** JSONL形式のtransactional importとatomic export
+- **軽量な実装:** C17で実装されたstdio MCPサーバー
+
+## 動作環境
- Windows x64
-- Visual Studio Community 2026(Desktop development with C++)
+- Visual Studio Community 2026
+ - `Desktop development with C++` workload
- CMake 4.3以降
- Git
-- vcpkg(PATHから実行可能であること)
+- vcpkg(`PATH`から実行可能であること)
+
+## ビルド
-## ビルドとテスト
+repositoryをcloneし、submoduleを取得してからbootstrap scriptを実行します。
```powershell
git submodule update --init --recursive
-.\scripts\bootstrap.ps1 -Configuration Debug
+.\scripts\bootstrap.ps1 -Configuration Release
```
-手動実行する場合は次のとおりです。
+生成される実行ファイル:
+
+```text
+build\windows-vs2026\src\Release\tiny-convmem-mcp.exe
+```
+
+手動でbuildする場合:
```powershell
$config = vcpkg z-print-config | ConvertFrom-Json
$env:VCPKG_ROOT = $config.'vcpkg-root'
+
cmake --preset windows-vs2026
-cmake --build --preset windows-vs2026-debug
-ctest --preset windows-vs2026-debug
+cmake --build --preset windows-vs2026-release
+ctest --preset windows-vs2026-release
```
-AddressSanitizer構成は独立した`build/windows-vs2026-asan`を使用します。
+## MCPクライアントへの登録
-```powershell
-cmake --preset windows-vs2026-asan
-cmake --build --preset windows-vs2026-asan
-ctest --preset windows-vs2026-asan
-```
+MCPクライアントのstdio server設定へ、実行ファイルと保存先を登録します。設定形式は
+クライアントによって異なりますが、一般的なJSONの例は次のとおりです。
-単体テストにはUTF-8/UTF-16、unaligned binary codec、allocation失敗、short I/Oと
-操作別I/O失敗が含まれます。自前関数とテストの対応は
-[function coverage map](tests/function-coverage.md)を参照してください。
+```json
+{
+ "mcpServers": {
+ "tiny-convmem": {
+ "command": "C:\\path\\to\\tiny-convmem-mcp.exe",
+ "args": ["--data-dir", "C:\\path\\to\\conversation-memory"]
+ }
+ }
+}
+```
-## 起動
+`--data-dir`は必須です。相対pathも利用できますが、MCP hostの起動directoryに左右されない
+絶対pathを推奨します。同じdata directoryを複数processから同時に開くことはできません。
-保存先は必ず明示します。相対パスも使用できます。同じdata directoryを使用する
-プロセスの二重起動は拒否されます。
+手動で起動する場合:
```powershell
-.\build\windows-vs2026\src\Debug\tiny-convmem-mcp.exe --data-dir .\data
+.\tiny-convmem-mcp.exe --data-dir .\conversation-memory
```
-stdoutはMCP JSON-RPC専用、stderrは診断専用です。
+標準入力と標準出力はMCP JSON-RPC専用です。診断messageは標準error出力へ送られます。
## MCP tools
-- `write_message`: 再起動後も利用する会話メッセージを同期永続化
-- `read_messages`: 履歴、session一覧、前後・relation文脈、versioned JSONL exportをviewで取得
-- `search_messages`: content・summary・tagsを検索し、filterとscore内訳を返す
-- `update_message`: IDと作成情報を保ったまま本文またはmetadataを差分更新
-- `delete_message`: メッセージをread/searchから即時除外(物理除去はrebuild後)
-- `rebuild_index`: 保守時にStoreをcompactし、snapshotとメモリindexを再構築
-- `get_system_health`: 永続化・復旧問題の診断に必要なStore状態と件数を取得
+| Tool | 用途 |
+|---|---|
+| `write_message` | session、role、contentと任意metadataを新しいメッセージとして保存します。 |
+| `read_messages` | session履歴、session一覧、対象メッセージ前後の文脈を取得します。 |
+| `search_messages` | content、summary、tagを検索し、score内訳や任意の前後文脈を返します。 |
+| `update_message` | IDや作成日時を維持したまま、本文またはmetadataを更新します。 |
+| `delete_message` | メッセージをread/search結果から除外します。物理除去はrebuild後です。 |
+| `rebuild_index` | logをcompactし、snapshotとmemory indexを再構築します。 |
+| `get_system_health` | 件数、file size、recovery状態、I/O、推定memory使用量を返します。 |
+
+主なmetadata:
-ツール結果はMCP TextContent内のJSON文字列です。入力schema、サイズ制限、エラーコード
-および物理フォーマットは[設計書](docs/Design.md)を参照してください。
-既知の設計上限と将来対応事項は[設計書](docs/Design.md#12-将来対応事項)にまとめています。
+- `tags`: 検索や分類に使うtag
+- `memory_tier`: `short` / `mid` / `long`
+- `memory_kind`: `conversation` / `episode` / `semantic` / `procedure` / `preference` / `summary`
+- `importance`: 0~100
+- `summary`: 要約文
+- `relations`, `source_message_ids`: メッセージ間の関係
-## 永続化と復旧
+toolの入力parameter、response形式、filter、viewの詳細は
+[MCP Tool Reference](docs/mcp.md)を参照してください。実際の入力schemaはMCPの`tools/list`からも
+取得できます。
-`active.log` はversion付きlittle-endianレコード、payload CRC32、単調sequenceを持ちます。
-v2はv1 PUT/DELを読取り可能で、UPDATEは変更fieldだけを追記します。
-PUT/DELはsys層のdurability flushが成功するまで`OK`を返しません。末尾で中断したレコード
-だけは正常境界まで自動切詰めし、途中のCRC不一致はデータを保存したまま起動を拒否します。
+## バックアップと復元
-`rebuild_index` は新しいgeneration markerを持つログを作成後、同じgenerationとログoffsetを
-記録した `snapshot.bin` を置換します。起動時に両者が一致するとsnapshotをロードし、後続
-レコードだけを再生します。不一致または不正なsnapshotは変更せず、ログ全体を再生します。
+serverを停止した状態でJSONLへexportできます。
-削除は呼出時には論理削除です。元本文が `active.log` から除去されるのはcompaction成功時で、
-SSD、バックアップ等からの安全消去は保証しません。`memory_tier` は初期版では属性であり、
-自動要約・昇格・破棄を行いません。
+```powershell
+.\tiny-convmem-mcp.exe --data-dir .\conversation-memory `
+ --export .\backup.jsonl
+```
-## セキュリティとバックアップ
+特定sessionだけをexportする場合:
-data directory、snapshot、active log、JSONL exportはすべて平文であり、接続済みのstdio
-hostは全tool権限を持ちます。CRC32は偶発的な破損検出用で、悪意ある改変の認証では
-ありません。取得内容はprompt injectionを含み得るため、host側で命令として信頼しないでください。
+```powershell
+.\tiny-convmem-mcp.exe --data-dir .\conversation-memory `
+ --export .\session-backup.jsonl --session my-session
+```
-data directoryとexport先は専用Windowsアカウントだけが読めるACLにします。
+backupをimportする場合:
```powershell
-icacls .\data /inheritance:r /grant:r "$env:USERNAME:(OI)(CI)F"
+.\tiny-convmem-mcp.exe --data-dir .\restored-memory `
+ --import .\backup.jsonl --policy overwrite
```
-exportは元データと同じ機密区分で保管してください。暗号化が必要ならBitLocker等の上位暗号化
-filesystemを使用します。削除やcompactionはfilesystem、SSD、既存backupからのsecure eraseを
-保証しません。
+`--policy reject`を指定すると、同じmessage IDの重複をrejectできます。importは全recordを
+検証してstaging logへ書き、完了後にだけ保存先を置換します。
-## 容量とメモリ予算
+## データとセキュリティ
-importは1行`1 MiB + 4096 bytes`、100,000 record、decode後合計4 GiBが上限です。
-2-pass importは本文全件を保持せず、compact ID indexと最大1行だけをメモリに保持します。
-全件検証とstaging logのflushが成功した場合だけ`active.log`を置換します。
-`get_system_health.memory_estimate`はstore entry、本文、metadata、search、history、relation indexの
-確保量概算を返します。allocator overhead等は含まないため、実working setには余裕を持たせて
-ください。現行v1はlive corpusをメモリに保持し、retentionやdisk-backed bodyは実装しません。
+`active.log`、`snapshot.bin`、JSONL backupは平文です。会話に機密情報が含まれる場合は、
+data directoryとbackupへ適切なWindows ACLを設定し、必要に応じてBitLockerなどの暗号化された
+filesystemを使用してください。
-## mcpcの管理
+```powershell
+icacls .\conversation-memory /inheritance:r /grant:r "$env:USERNAME:(OI)(CI)F"
+```
+
+注意事項:
-mcpc submoduleはコミット `4025fddfedcfa7573803a47236b147733fcb3c07` に固定しています。
-固定版tool APIではoptional/object/array schemaとcallback contextを表現できないため、
-プロジェクト側MCP互換境界がmcpc同梱のmjson parserを利用してraw argumentsとschemaを扱います。
-submoduleのソースは変更しません。詳細は[src/mcp/README.md](src/mcp/README.md)を参照してください。
+- CRC32は偶発的な破損を検出するもので、悪意ある改変を防ぐ認証機能ではありません。
+- 接続したMCP hostは保存、読取り、更新、削除、maintenanceを実行できます。
+- 削除後も、compact前のlogや既存backup、filesystem履歴にデータが残る場合があります。
+- 保存したcontentやmetadataを命令として信頼するかどうかはMCP host側の責任です。
-## コーディングスタイル
+## 現在の制約
-プロジェクト所有のCソースとヘッダーは、リポジトリ直下の
-[`.clang-format`](.clang-format)に従います。制御文には常に波括弧を付け、1行には
-1つのstatementだけを記述します。`third_party/` は整形対象外です。
+- 現行versionはWindows x64のみを正式サポートしています。Linux対応は将来予定です。
+- 単一process、単一writerを対象としています。
+- live corpusと検索indexはmemory上に保持されるため、必要memoryは保存量に比例します。
+- 自動保存判断、自動要約、retention、tierの自動移動、利用頻度による強化・減衰は行いません。
+- import上限は100,000 record、1行あたり約1 MiB、decode後合計4 GiBです。
-Visual Studio同梱のclang-formatを使う場合は、PowerShellで次のように整形できます。
+詳しい設計、物理format、回復動作、将来対応事項は[Design.md](docs/Design.md)にあります。
+
+## 開発者向けテスト
```powershell
-$formatter = 'C:\Program Files\Microsoft Visual Studio\18\Community\VC\Tools\Llvm\x64\bin\clang-format.exe'
-$files = rg --files src tests -g '*.c' -g '*.h'
-& $formatter -i --style=file $files
+cmake --build --preset windows-vs2026-debug
+ctest --preset windows-vs2026-debug
+
+cmake --preset windows-vs2026-asan
+cmake --build --preset windows-vs2026-asan
+ctest --preset windows-vs2026-asan
```
+
+関数とtestの対応は[function coverage map](tests/function-coverage.md)を参照してください。
+
+## ライセンス
+
+このprojectは[MIT License](LICENSE)で提供されます。
+
+third-party componentにはそれぞれのライセンスが適用されます。詳細は`third_party/`配下の
+licenseおよびupstream情報を参照してください。
diff --git a/docs/mcp.md b/docs/mcp.md
new file mode 100644
index 0000000..639946f
--- /dev/null
+++ b/docs/mcp.md
@@ -0,0 +1,390 @@
+# MCP Tool Reference
+
+Tiny ConvMem MCPが公開する7つのtoolの仕様をまとめる。実際のJSON SchemaはMCPの
+`tools/list`からも取得できる。
+
+## 共通仕様
+
+### Tool result
+
+toolのapplication responseは、MCP `TextContent.text`に格納された**JSON文字列**である。
+呼出側はTextContentを取得した後、その`text`をJSONとしてparseする。
+
+成功例:
+
+```json
+{"status":"OK"}
+```
+
+application errorではMCP tool resultの`isError`がtrueになり、`text`は次の形式になる。
+
+```json
+{
+ "status": "ERROR",
+ "error": {
+ "code": "VALIDATION_ERROR",
+ "message": "invalid arguments"
+ }
+}
+```
+
+主なerror code:
+
+| Code | 意味 |
+|---|---|
+| `VALIDATION_ERROR` | parameter、JSON文字列、値域が不正 |
+| `NOT_FOUND` | 対象messageまたはcontextが存在しない |
+| `CONFLICT` | `expected_revision`が現在のrevisionと一致しない |
+| `BUSY` | resourceが使用中 |
+| `IO_ERROR` | logの書込み、flush、置換などに失敗 |
+| `CORRUPT_STORE` | 永続化dataの整合性error |
+| `INTERNAL_ERROR` | allocationや内部状態のerror |
+
+### Message object
+
+各toolが返すmessageは次の形式である。
+
+```json
+{
+ "message_id": "01ARZ3NDEKTSV4RRFFQ69G5FAV",
+ "session_id": "conversation-1",
+ "timestamp": 1720843200000,
+ "role": "user",
+ "content": "Remember this",
+ "revision": 1,
+ "updated_at": 1720843200000,
+ "metadata": {
+ "tool_call_id": "optional",
+ "tags": ["project", "decision"],
+ "memory_tier": "short",
+ "memory_kind": "conversation",
+ "importance": 50,
+ "summary": "optional summary",
+ "relations": [
+ {"type": "derived_from", "message_id": "01ARZ3NDEKTSV4RRFFQ69G5FAW"}
+ ],
+ "source_message_ids": ["01ARZ3NDEKTSV4RRFFQ69G5FAW"]
+ }
+}
+```
+
+`tool_call_id`と`summary`は未設定時に省略される。その他のmetadata fieldは空配列やdefault値を
+含めて出力される。
+
+### Metadata JSON
+
+`write_message.metadata_json`、`update_message.metadata_json`はJSON objectを表す文字列である。
+MCP arguments内では次のように渡す。
+
+```json
+{
+ "metadata_json": "{\"tags\":[\"project\"],\"memory_kind\":\"semantic\",\"importance\":80}"
+}
+```
+
+| Field | 型・制限 | Default |
+|---|---|---|
+| `tool_call_id` | string、最大256 UTF-8 bytes | 未設定 |
+| `tags` | string配列、最大32件、各128 bytes、空文字不可 | `[]` |
+| `memory_tier` | `short` / `mid` / `long` / `discard` | `short` |
+| `memory_kind` | `conversation` / `episode` / `semantic` / `procedure` / `preference` / `summary` | `conversation` |
+| `importance` | integer、0~100 | `50` |
+| `summary` | string、最大4096 bytes。空文字は未設定扱い | 未設定 |
+| `relations` | 最大32件の`{"type", "message_id"}` | `[]` |
+| `source_message_ids` | 26文字ULIDの配列、最大64件 | `[]` |
+
+relation typeは`depends_on`、`derived_from`、`supersedes`、`related_to`のいずれかである。
+
+## `write_message`
+
+新しいmessageを生成し、diskへflushしてから成功を返す。
+
+### Input
+
+| Parameter | 必須 | 型 | 説明 |
+|---|---:|---|---|
+| `session_id` | Yes | string | 1~256 UTF-8 bytes |
+| `role` | Yes | string | `user` / `assistant` / `system` |
+| `content` | Yes | string | 1 byte~1 MiBのUTF-8 text |
+| `metadata_json` | No | string | Metadata JSON。defaultは`{}` |
+
+### Output
+
+```json
+{"status":"OK","message":{...Message object...}}
+```
+
+`message_id`、`timestamp`、`updated_at`はserverが生成し、初期`revision`は1となる。
+
+## `update_message`
+
+messageのidentity、session、role、作成時刻を維持し、contentまたはmetadataを更新する。
+
+### Input
+
+| Parameter | 必須 | 型 | 説明 |
+|---|---:|---|---|
+| `message_id` | Yes | string | 対象の26文字ULID |
+| `content` | No | string | 新しいcontent。最大1 MiB |
+| `metadata_json` | No | string | 更新するmetadata fieldを含むJSON文字列 |
+| `expected_revision` | No | integer | 1以上。現在値と違う場合は`CONFLICT` |
+
+`content`と`metadata_json`の少なくとも一方が必要である。`metadata_json`に含まれないfieldは
+維持される。同じ値への更新はno-opとなり、`changed`はfalse、revisionとlogは変更されない。
+
+### Output
+
+```json
+{"status":"OK","changed":true,"message":{...Message object...}}
+```
+
+## `read_messages`
+
+`view`によりhistory、context、sessionsの3種類を返す。`view`省略時は`history`。
+
+### 共通Input
+
+| Parameter | 必須 | 型 | 説明 |
+|---|---:|---|---|
+| `view` | No | string | `history` / `context` / `sessions` |
+| `limit` | No | integer | 1~1000、default 100 |
+| `cursor` | No | string | 前回responseの`nextCursor`。内容はopaque |
+
+responseは約8 MiBのbudget内で打ち切られる場合がある。
+
+### `history` view
+
+session内のlive messageを作成順に返す。
+
+追加parameter:
+
+| Parameter | 必須 | 型 | 説明 |
+|---|---:|---|---|
+| `session_id` | Yes | string | 対象session、最大256 bytes |
+
+```json
+{
+ "history": [{...Message object...}],
+ "nextCursor": "optional opaque cursor"
+}
+```
+
+続きを読む場合は同じ`session_id`と`nextCursor`を渡す。
+
+### `context` view
+
+指定message、同一sessionの前後message、relation graphを返す。
+
+追加parameter:
+
+| Parameter | 必須 | 型 | Default | 説明 |
+|---|---:|---|---:|---|
+| `message_id` | Yes | string | — | 対象の26文字ULID |
+| `before` | No | integer | 1 | 同一sessionから前に返す件数、0~10 |
+| `after` | No | integer | 1 | 同一sessionから後に返す件数、0~10 |
+| `relation_depth` | No | integer | 1 | relation traversal depth、0~2 |
+| `relation_types_json` | No | string | 全type | relation type配列を表すJSON文字列 |
+
+`relation_types_json`の例:
+
+```json
+{"relation_types_json":"[\"derived_from\",\"supersedes\"]"}
+```
+
+```json
+{
+ "message": {...Message object...},
+ "chronological_context": {
+ "before": [{...Message object...}],
+ "after": [{...Message object...}]
+ },
+ "relations": [
+ {
+ "type": "derived_from",
+ "direction": "outgoing",
+ "depth": 1,
+ "message": {...Message object...}
+ }
+ ],
+ "session": {"session_id":"conversation-1","message_count":12},
+ "truncated": false
+}
+```
+
+削除済みrelation先では`message`の代わりに`message_id`と`"status":"deleted"`が返る。
+最大50 message相当またはresponse budget到達時は`truncated`がtrueになる。
+
+### `sessions` view
+
+session一覧を時刻とIDの安定順序でpage取得する。`session_id`は使用しない。
+
+```json
+{
+ "sessions": [
+ {
+ "session_id": "conversation-1",
+ "message_count": 12,
+ "kind_counts": {
+ "conversation": 8,
+ "episode": 1,
+ "semantic": 2,
+ "procedure": 0,
+ "preference": 0,
+ "summary": 1
+ },
+ "representative_summary": "latest summary or content",
+ "started_at": 1720843200000,
+ "last_message_at": 1720846800000
+ }
+ ],
+ "nextCursor": "optional opaque cursor"
+}
+```
+
+## `search_messages`
+
+content、summary、tagsを検索し、scoreの高い順に返す。同scoreではimportance等がtie-breakに
+使われる。search自体はmessageやaccess履歴を書き換えない。
+
+### Input
+
+| Parameter | 必須 | 型 | Default | 説明 |
+|---|---:|---|---:|---|
+| `query` | Yes | string | — | 1~4096 UTF-8 bytes |
+| `session_id` | No | string | 全session | 指定sessionだけを検索 |
+| `filters_json` | No | string | `{}` | filter objectを表すJSON文字列 |
+| `min_importance` | No | integer | 0 | 0~100 |
+| `context_size` | No | integer | 0 | 各結果の前後message数、0~3 |
+| `limit` | No | integer | 20 | 1~100 |
+
+`filters_json`の形式:
+
+```json
+{
+ "kinds": ["semantic", "preference"],
+ "tiers": ["mid", "long"],
+ "tags": ["project", "confirmed"]
+}
+```
+
+argumentsとして渡す場合はescapeした文字列にする。
+
+```json
+{
+ "query": "database decision",
+ "filters_json": "{\"kinds\":[\"semantic\"],\"tags\":[\"project\"]}",
+ "min_importance": 60,
+ "context_size": 1,
+ "limit": 10
+}
+```
+
+`kinds`と`tiers`は各配列内でOR、category間はANDとなる。`tags`は指定した全tagを持つmessage
+だけが一致する。
+
+### Output
+
+```json
+{
+ "results": [
+ {
+ ...Message object fields...,
+ "score": 1.0,
+ "score_breakdown": {"content":1.0,"summary":0.0,"tags":0.0},
+ "matched_fields": ["content"],
+ "relation_count": 0,
+ "context_preview": {
+ "before": [{...Message object...}],
+ "after": [{...Message object...}]
+ }
+ }
+ ]
+}
+```
+
+`context_preview`は`context_size > 0`の場合だけ出力される。response budgetへ到達すると、
+`limit`未満でも後続結果が省略される。
+
+## `delete_message`
+
+messageを論理削除し、直ちにread/search対象から除外する。
+
+### Input
+
+| Parameter | 必須 | 型 | 説明 |
+|---|---:|---|---|
+| `message_id` | Yes | string | canonical 26文字ULID |
+| `session_id` | No | string | 一致する場合だけ削除するsession guard |
+
+### Output
+
+削除した場合:
+
+```json
+{"status":"OK"}
+```
+
+対象なし、削除済み、またはsession guard不一致の場合:
+
+```json
+{"status":"NOT_FOUND"}
+```
+
+`NOT_FOUND`はapplication errorではない。本文がlogから物理的に除去されるのは
+`rebuild_index`成功後である。
+
+## `rebuild_index`
+
+parameterなし。live messageだけでlogをcompactし、snapshotとmemory indexを再構築する。
+同期処理のため、完了まで他requestを処理しない。
+
+```json
+{
+ "status": "OK",
+ "messages_indexed": 120,
+ "records_removed": 35,
+ "bytes_before": 1048576,
+ "bytes_after": 524288
+}
+```
+
+## `get_system_health`
+
+parameterなし。永続化状態、logical I/O counter、memory estimateを返す。
+
+```json
+{
+ "status": "OK",
+ "format_version": 2,
+ "log_size": 524288,
+ "snapshot_size": 262144,
+ "active_messages": 120,
+ "deleted_messages": 3,
+ "last_sequence": 150,
+ "update_records": 12,
+ "dead_bytes": 4096,
+ "memory_estimate": {
+ "total_bytes": 2097152,
+ "store_entries_bytes": 32768,
+ "body_bytes": 524288,
+ "metadata_bytes": 65536,
+ "search_index_bytes": 1048576,
+ "history_index_bytes": 131072,
+ "relation_index_bytes": 65536
+ },
+ "io": {
+ "write_bytes": 1048576,
+ "write_calls": 80,
+ "flush_calls": 20,
+ "truncate_calls": 0,
+ "replace_calls": 1
+ },
+ "recovered_tail": false,
+ "snapshot_valid": true,
+ "last_error": ""
+}
+```
+
+`status`は`last_error`が空なら`OK`、診断messageが残っていれば`DEGRADED`となる。
+`memory_estimate`はprojectが管理する主要allocationの概算で、runtimeやallocator overheadは
+含まない。