数据库架构¶
Claude-Mem 使用 SQLite 3 及其 bun:sqlite 原生模块进行持久化存储,并使用 FTS5 进行全文搜索。
数据库位置¶
路径:~/.claude-mem/claude-mem.db
数据库使用 SQLite 的 WAL(预写日志)模式以支持并发读写。
数据库实现¶
主要实现:bun:sqlite(原生 SQLite 模块) - 由 SessionStore 和 SessionSearch 使用 - 格式:同步 API,性能更佳 - 注意:Database.ts(使用 bun:sqlite)是遗留代码
核心表¶
1. sdk_sessions¶
跟踪进行中及已完成的会话。
CREATE TABLE sdk_sessions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sdk_session_id TEXT UNIQUE NOT NULL,
claude_session_id TEXT,
project TEXT NOT NULL,
prompt_counter INTEGER DEFAULT 0,
status TEXT NOT NULL DEFAULT 'active',
created_at TEXT NOT NULL,
created_at_epoch INTEGER NOT NULL,
completed_at TEXT,
completed_at_epoch INTEGER,
last_activity_at TEXT,
last_activity_epoch INTEGER
);
索引:
- claude_session_id 上的 idx_sdk_sessions_claude_session
- project 上的 idx_sdk_sessions_project
- status 上的 idx_sdk_sessions_status
- created_at_epoch DESC 上的 idx_sdk_sessions_created_at
2. observations¶
具有层级结构的单次工具执行记录。
CREATE TABLE observations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
sdk_session_id TEXT NOT NULL,
claude_session_id TEXT,
project TEXT NOT NULL,
prompt_number INTEGER,
tool_name TEXT NOT NULL,
correlation_id TEXT,
-- Hierarchical fields
title TEXT,
subtitle TEXT,
narrative TEXT,
text TEXT,
facts TEXT,
concepts TEXT,
type TEXT,
files_read TEXT,
files_modified TEXT,
created_at TEXT NOT NULL,
created_at_epoch INTEGER NOT NULL,
FOREIGN KEY (sdk_session_id) REFERENCES sdk_sessions(sdk_session_id)
);
观察类型:
- decision - 架构或设计决策
- bugfix - 缺陷修复与更正
- feature - 新功能或新能力
- refactor - 代码重构与清理
- discovery - 对代码库的认知发现
- change - 常规变更与修改
索引:
- session_id 上的 idx_observations_session
- sdk_session_id 上的 idx_observations_sdk_session
- project 上的 idx_observations_project
- tool_name 上的 idx_observations_tool_name
- created_at_epoch DESC 上的 idx_observations_created_at
- type 上的 idx_observations_type
3. session_summaries¶
AI 生成的会话摘要(每个会话可有多条)。
CREATE TABLE session_summaries (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sdk_session_id TEXT NOT NULL,
claude_session_id TEXT,
project TEXT NOT NULL,
prompt_number INTEGER,
-- Summary fields
request TEXT,
investigated TEXT,
learned TEXT,
completed TEXT,
next_steps TEXT,
notes TEXT,
created_at TEXT NOT NULL,
created_at_epoch INTEGER NOT NULL,
FOREIGN KEY (sdk_session_id) REFERENCES sdk_sessions(sdk_session_id)
);
索引:
- sdk_session_id 上的 idx_session_summaries_sdk_session
- project 上的 idx_session_summaries_project
- created_at_epoch DESC 上的 idx_session_summaries_created_at
4. user_prompts¶
原始用户提示词,支持 FTS5 搜索(自 v4.2.0 起)。
CREATE TABLE user_prompts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
sdk_session_id TEXT NOT NULL,
claude_session_id TEXT,
project TEXT NOT NULL,
prompt_number INTEGER,
prompt_text TEXT NOT NULL,
created_at TEXT NOT NULL,
created_at_epoch INTEGER NOT NULL,
FOREIGN KEY (sdk_session_id) REFERENCES sdk_sessions(sdk_session_id)
);
索引:
- sdk_session_id 上的 idx_user_prompts_sdk_session
- project 上的 idx_user_prompts_project
- created_at_epoch DESC 上的 idx_user_prompts_created_at
5. tool_uses¶
原始工具 I/O 的持久化备份索引(schema v51)。它从同一摄取汇聚点写入——该汇聚点也为观察生成器供数——因此能捕获相同的调用,而无需新增第二条捕获路径。
CREATE TABLE tool_uses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
tool_use_id TEXT NOT NULL,
content_session_id TEXT NOT NULL,
memory_session_id TEXT,
session_db_id INTEGER,
project TEXT NOT NULL,
platform_source TEXT NOT NULL DEFAULT 'claude',
tool_name TEXT NOT NULL,
tool_input TEXT,
tool_response TEXT,
cwd TEXT,
prompt_number INTEGER,
agent_type TEXT,
agent_id TEXT,
observation_id INTEGER,
or_generation_id TEXT,
or_session_id TEXT,
content_hash TEXT,
created_at TEXT NOT NULL,
created_at_epoch INTEGER NOT NULL,
UNIQUE(content_session_id, tool_use_id)
);
存在原因:pending_messages 是生成队列——行会被认领、汇总并删除,因此一旦观察已生成,原始工具载荷便无法恢复。tool_uses 是可在队列清理后依然存留的持久化侧索引,get_tool_uses MCP 工具(渐进式披露层 4)读取的正是该表。
并非会话记录存储:磁盘上的 JSONL 转录记录及转录监视器仍是会话历史的主干。此表只是工具主体的引用型索引,仅此而已。
幂等性:UNIQUE(content_session_id, tool_use_id) 意味着重放的 PostToolUse(钩子重试、转录重新扫描)会更新该行而不是重复插入。observation_id 在生成之后才关联,一旦设置便不会被覆盖。
载荷上限:tool_input / tool_response 在 64 KB 处截断,并附带 …[truncated: N bytes] 标记。content_hash 基于截断前的原始载荷计算。
成本列:故意不设置。or_generation_id 和 or_session_id 是可空连接键,指向 OpenRouter 的支出记录行;金额存放在那一行中,绝不会出现在这里。
索引:project、memory_session_id、content_session_id、session_db_id、tool_name、created_at_epoch、observation_id、or_generation_id
遗留表¶
- sessions:遗留会话跟踪(v3.x)
- memories:遗留压缩记忆块(v3.x)
- overviews:遗留会话摘要(v3.x)
FTS5 全文搜索¶
SQLite FTS5(全文搜索)虚拟表可对观测记录和会话摘要执行快速全文搜索。用户提示通过子串匹配(LIKE)进行搜索,没有 FTS 索引。
FTS5 虚拟表¶
observations_fts¶
CREATE VIRTUAL TABLE observations_fts USING fts5(
title,
subtitle,
narrative,
text,
facts,
concepts,
content='observations',
content_rowid='id'
);
session_summaries_fts¶
CREATE VIRTUAL TABLE session_summaries_fts USING fts5(
request,
investigated,
learned,
completed,
next_steps,
notes,
content='session_summaries',
content_rowid='id'
);
自动同步¶
FTS5 表通过触发器保持同步。更新触发器仅在写入索引列时触发,因此维护性更新(同步修订、项目合并、内容哈希)永远不会触及索引。每次索引更新都会追加一条删除标记以及该行文本的重新插入,因此未限定列的更新触发器会在每次此类写入时增大索引:
-- Insert trigger example
CREATE TRIGGER observations_ai AFTER INSERT ON observations BEGIN
INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts)
VALUES (new.id, new.title, new.subtitle, new.narrative, new.text, new.facts, new.concepts);
END;
-- Update trigger example (fires only when an indexed column is written)
CREATE TRIGGER observations_au
AFTER UPDATE OF title, subtitle, narrative, text, facts, concepts ON observations BEGIN
INSERT INTO observations_fts(observations_fts, rowid, title, subtitle, narrative, text, facts, concepts)
VALUES('delete', old.id, old.title, old.subtitle, old.narrative, old.text, old.facts, old.concepts);
INSERT INTO observations_fts(rowid, title, subtitle, narrative, text, facts, concepts)
VALUES (new.id, new.title, new.subtitle, new.narrative, new.text, new.facts, new.concepts);
END;
-- Delete trigger example
CREATE TRIGGER observations_ad AFTER DELETE ON observations BEGIN
INSERT INTO observations_fts(observations_fts, rowid, title, subtitle, narrative, text, facts, concepts)
VALUES('delete', old.id, old.title, old.subtitle, old.narrative, old.text, old.facts, old.concepts);
END;
FTS5 查询语法¶
FTS5 支持丰富的查询语法:
- 简单:
"error handling" - AND(与):
"error" AND "handling" - OR(或):
"bug" OR "fix" - NOT(非):
"bug" NOT "feature" - 短语:
'exact phrase' - 列:
title:"authentication"
安全性¶
自 v4.2.3 起,所有 FTS5 查询都会正确转义以防止 SQL 注入:
- 双引号会被转义:query.replace(/"/g, '""')
- 全面测试套件包含 332 项注入攻击测试
数据库类¶
SessionStore¶
针对会话、观测、摘要和用户提示的 CRUD 操作。
位置:src/services/sqlite/SessionStore.ts
方法:
- createSession()
- getSession()
- updateSession()
- createObservation()
- getObservations()
- createSummary()
- getSummaries()
- createUserPrompt()
SessionSearch¶
FTS5 全文搜索,提供 8 种专用搜索方法。
位置:src/services/sqlite/SessionSearch.ts
方法:
- searchObservations() - 在观测记录中进行全文搜索
- searchSessions() - 在会话摘要中进行全文搜索
- searchUserPrompts() - 在用户提示中进行全文搜索
- findByConcept() - 按概念标签查找
- findByFile() - 按文件引用查找
- findByType() - 按观测类型查找
- getRecentContext() - 获取最近的会话上下文
- advancedSearch() - 组合筛选
迁移¶
数据库模式通过 src/services/sqlite/migrations.ts 中的迁移进行管理。
迁移历史:
- 迁移 001:初始模式(sessions、memories、overviews、diagnostics、transcript_events)
- 迁移 002:分层记忆字段(title、subtitle、facts、concepts、files_touched)
- 迁移 003:SDK 会话和观测
- 迁移 004:会话摘要
- 迁移 005:多提示词会话(prompt_counter、prompt_number)
- 迁移 006:FTS5 虚拟表和触发器
- 迁移 007-010:各项改进及用户提示表
- 迁移 051:tool_uses 持久化原始工具 I/O 索引
性能注意事项¶
- 索引:所有外键和频繁查询的列均已建立索引
- FTS5:全文搜索明显快于 LIKE 查询
- 触发器:自动同步开销极小
- 连接池:bun:sqlite 高效地复用连接
- 同步 API:bun:sqlite 使用同步 API 以获得更好的性能
故障排除¶
常见问题及解决方案请参阅 故障排除 - 数据库问题。
本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 cl/claude-mem