Hermes-compatible memory / skills / session / prompt layer for AI agents (MoonBit native + JS)
Dependencies
Note: This project is named mnemo (short for mnemonic). The hermes-agent upstream is still called hermes.
# Prerequisites: Node.js 24+, pnpm, moon, just
pnpm install
just test # proto 280 + moonbit 121 + adapters 10 = all green (411)
just build-dist # dist/src.js を生成 (adapters が src.cjs として参照)just test-proto # proto vitest (280 件、うち 135 が goldens-lint)
just goldens # proto で golden JSON を再生成 (45 ファイル)
just test-mbt # MoonBit inline tests on JS backend (121 件)
just test-adapters # MCP server (7) + pi extension (3) adapter testsjust test の実行順は test-proto → goldens → test-mbt → build-dist → test-adapters です。 goldens を更新してから MoonBit 側をテストしないとパリティがずれ、adapters は build-dist した src.js を参照します。
# Nix 利用者(推奨)— `nix develop` が sqlite + NIX_LDFLAGS を設定
nix develop
just test-mbt-native # 116/121 tests green (JS-only Promise concurrency excluded)
# 手動設定
# Linux: sudo apt-get install libsqlite3-dev
# macOS: xcode-select --install もしくは brew install sqlite
just build-native # MoonBit native compile
just test-mbt-native # native test runner| Tool | 説明 |
|---|---|
| memory_add | MEMORY.md / USER.md に新しいエントリを追加する |
| memory_replace | 既存エントリをキーで置換する |
| memory_remove | エントリをキーで削除する (複数ヒットは ambiguous_match で拒否) |
| memory_read | MEMORY.md または USER.md の全エントリを読む |
| skills_list | platform / available_tools / disabled[] でフィルタしたスキル一覧を返す |
| skill_view | 単一スキルのフルコンテンツ (frontmatter + 本文) を返す |
| session_create | 新しいセッションを作成する |
| session_append | セッションにメッセージを追記する |
| session_get | セッション ID でセッションとメッセージを取得する |
| session_list | セッション一覧を返す (最新順) |
| session_search | FTS5 全文検索 + 並列 LLM 要約 (proto / MoonBit 双方で concurrency 3) |
| session_resolve | セッション ID prefix (UUID 先頭 8 字など) からフル ID を解決する |
| prompt_build | identity → memory → user → skills → context → SOUL の順で system prompt を構築する (disabled_skills[] 対応) |
# ローカル開発:
claude mcp add mnemo -- node /path/to/adapters/mcp-server/bin/mnemo-mcp
# 公開後 (予定):
claude mcp add mnemo -- npx -y @mizchi/mnemo-mcp{
"pi": {
"extensions": ["/path/to/adapters/pi-extension/src/index.ts"]
}
}| 変数 | デフォルト | 説明 |
|---|---|---|
| MNEMO_HOME | ~/.mnemo | memories・skills・sessions.db のルートディレクトリ |
| MNEMO_CONTRACT_DIR | — | adapter から contract/ を参照するときのパス (通常は自動解決) |
| OPENROUTER_API_KEY | — | LLM 要約を有効化する場合の API キー |
| MNEMO_SUMMARIZER_API_KEY | — | OPENROUTER_API_KEY の代替 |
| MNEMO_SUMMARIZER_MODEL | — | 要約に使う LLM モデル名 (OpenRouter 形式、例 openai/gpt-4o-mini) |
| MNEMO_SEARCH_CONCURRENCY | 3 | session_search の並列 LLM 要約数 (1-5、proto + MoonBit) |
| MNEMO_LOCK_STALE_TTL_MS | 30000 | memories/.writing sentinel が stale と判定されるまでの ms |
| ファイル | 内容 |
|---|---|
| docs/ARCHITECTURE.md | 3 層構造・サブシステム詳細・MoonBit JS 橋渡し |
| docs/PARITY_AUDIT.md | hermes 再現率の詳細 (機能ごとの対応状況) |
| docs/MOONBIT_GOTCHAS.md | MoonBit API 差分・既知の制限 |
| docs/superpowers/specs/ | 設計仕様 |
| docs/superpowers/plans/ | Phase 別実装計画 (Phase 0–10)。Phase 11-12 は個別 commit としてのみ |
| Tag | 内容 |
|---|---|
| ermes-phase1-memory | MemoryStore (MEMORY.md / USER.md) |
| ermes-phase2-skills | SkillsStore (SKILL.md + frontmatter) |
| ermes-phase3-sessiondb | SessionDB (node:sqlite, FTS5) |
| ermes-phase5-prompt-builder | PromptBuilder (identity → SOUL) |
| ermes-phase6-adapters | MCP server + pi extension adapters |
| ermes-phase8-async | async/await 移行 (moonbitlang/async) |
| ermes-phase9-safety | セキュリティパターン + FTS5 sanitize |
| ermes-phase9-complete | parity 完成 (safety + LLM + WAL + schema) |
| ermes-phase10-complete | model guidance + Int64 統一 + session_resolve + LICENSE/docs/CI |
git tag | grep -E "^(ermes|mnemo)-"contract/ ← single source of truth
tool-schemas/ ← 13 tool の JSON Schema
file-formats/ ← MEMORY.md / USER.md / SKILL.md エンコード仕様
sql/schema.sql ← SessionDB DDL + migrations/
security/ ← インジェクション検出パターン (13 項目)
goldens/ ← proto が生成する fixture JSON (45 ファイル)
proto/ ← Node.js/TS throwaway (golden 生成専用)
src/ ← MoonBit 本番実装 (native + JS)
*.mbt ← cross-target コア (memory / skills / session_db /
search_core / prompt / security / fts5 / goldens)
*_js.mbt ← JS backend 固有 (lock / memory_store / async_utils / hello)
*_native.mbt ← native backend 固有 (同上、extern "C" via native_stub.c)
mnemo_api.mbt ← Node.js adapter glue (JS-only)
session_search.mbt ← Promise.all LLM orchestration (JS-only)
native_stub.c ← POSIX primitives (O_EXCL / stat mtime / fsync+rename)
dist/src.js ← moon build --target js --release 出力
npm 配布時は adapters/*/dist/src.cjs にリネームコピー
adapters/
mcp-server/ ← @mizchi/mnemo-mcp (Claude Code, JS 専用)
pi-extension/ ← @mizchi/mnemo-pi (pi-mono, JS 専用)async fn MemoryStore::remove(self : MemoryStore, target : Target, old_substring : String) -> OpResultasync fn MemoryStore::replace(self : MemoryStore, target : Target, old_substring : String, new_content : String) -> OpResultpub struct MsgForFormat {
role : String
content : String
tool_name : String
tool_calls : String
}pub struct MsgRow {
id : Int
role : String
content : String
tool_name : String
reasoning_details : String?
codex_reasoning_items : String?
}pub struct SearchResult {
session_id : String
when : String
source : String
model : String
summary : String
}pub struct SessionRow {
id : String
source : String
user_id : String?
model : String?
system_prompt : String
parent_session_id : String?
started_at : Int64
ended_at : Int64?
end_reason : String?
message_count : Int
input_tokens : Int
output_tokens : Int
cache_read_tokens : Int
cache_write_tokens : Int
title : String?
}pub struct SessionSearchResponse {
ok : Bool
query : String
results : Array[SearchResult]
count : Int
sessions_searched : Int
}pub struct SkillEntry {
name : String
skill_name : String
description : String
category : String
content : String
frontmatter : SkillFrontmatter
}fn _stmt_buffer_init() -> Unitasync fn append_message(sdb : SessionDb, session_id : String, role : String, timestamp : Int64, content? : String?, tool_name? : String?, token_count? : Int?, reasoning_details? : String?, codex_reasoning_items? : String?) -> Intasync fn create_session(sdb : SessionDb, source : String, system_prompt : String, model? : String?, user_id? : String?, parent_session_id? : String?) -> Stringlet default_lock_stale_ttl_ms : Intfn list_sessions(sdb : SessionDb, limit? : Int, offset? : Int, source? : String) -> (Array[SessionRow], Int)fn sanitize_fts5_query(q : String) -> Stringasync fn session_search(sdb : SessionDb, query : String, limit? : Int, role_filter? : String?) -> SessionSearchResponsefn skills_store_build_prompt(store : SkillsStore, available_tools : Array[String]?, platform_hint : String?, disabled? : Array[String]) -> Stringfn skills_store_list(store : SkillsStore, available_tools : Array[String]?, platform_hint : String?, available_toolsets? : Array[String]?, disabled? : Array[String]) -> Array[SkillEntry]async fn sleep_ms(ms : Int) -> Unitfn truncate_around_matches(full_text : String, query : String, max_chars? : Int) -> Stringasync fn[T] with_lock(path : String, f : async () -> T) -> THermes-compatible memory / skills / session / prompt layer for AI agents (MoonBit native + JS)
Dependencies