Magic Context存储层深度剖析:SQLite Schema、稳定项目身份与迁移机制全解
【免费下载链接】magic-contextUnbounded context. Memory that manages itself. One session, for life. The hippocampus for coding agents, part of CortexKit.项目地址: https://gitcode.com/gh_mirrors/mag/magic-context
Magic Context是 CortexKit 生态中为编码 Agent 打造的"海马体",主打"无界上下文、自管理记忆、一个会话用一生"。它的存储层全部建立在SQLite之上:一台机器共享同一个context.db,记忆按"稳定项目身份"归档,升级时通过版本栅栏(Schema Fence)+ 迁移机制安全演进。本文带你完整看懂 Magic Context 的 SQLite 表结构、项目身份算法与迁移/备份机制,无需源码基础也能读懂。
一、存储布局:一个数据库管住全部状态
Magic Context 的所有状态集中在两个 SQLite 文件里,位于同一目录:
| 文件 | 归属 | 职责 |
|---|---|---|
context.db | TypeScript 插件(所有宿主共享) | 记忆、笔记、区室(compartment)、工作区等 |
store.db | Rust 模块mc-store | 每会话的缓存状态、区室历史、审计痕迹 |
- 默认路径:
~/.local/share/cortexkit/magic-context/context.db,可用环境变量MAGIC_CONTEXT_STORAGE_DIR覆盖; - 后端自动选择:Bun 下走
bun:sqlite,Node/Electron 下走node:sqlite,行为一致; - 每个连接先设 5 秒
busy_timeout,"打开已就绪的库不拿写锁",因此多个 Agent 宿主(OpenCode、Pi、OMP)可以同时启动而互不排队。
📌 两个库是一个一致性单元:任何一侧的权威与镜像状态都引用对方,备份/回滚时必须成对操作。完整说明见官方文档 storage.md。
二、Schema 与版本栅栏:为什么升级不炸库
这是 Magic Context 存储层最"硬核"的设计,核心只有一句话:
版本必须"锁步"(lockstep),对不上就拒绝打开数据库。
关键规则:
LATEST_SUPPORTED_VERSION是唯一事实来源:定义在 storage-db.ts(当前值为94),它必须与 migrations.ts 中最新版本号相等,锁步测试schema-version-fence.test.ts强制两者同步移动;- Fail-closed(失败即关闭):如果构建能理解的版本低于库里实际版本,进程拒绝打开库并进入保护状态——每次主变换直接抛出可恢复错误,而不是让提示词"失控增长"或悄悄回退到原生压缩;
- 迁移时机守卫:若仍有运行旧版本插件的宿主进程占着库,迁移会被拒绝并记录日志,避免"新库 + 旧进程"的组合;
- 版本车道(version lanes):
<10000的版本号保留给上游 Magic Context,≥10000预留给共享context.db的分支插件,两条互不干扰,规则见 migration-version-lanes.md。
加一个新迁移的 5 步标准动作
- 在 migrations.ts 追加下一版本,并配一份
migrations-vN.test.ts; - 把
LATEST_SUPPORTED_VERSION抬到同一数字(忘了这步 = 迁移后数据库拒绝打开); - 同步更新
storage-db.ts里的全新安装 schema,让新库直接落到最终形态,无需重放全部迁移; - 用 storage-schema-helpers.ts 中的
ensureColumn/healAllNullColumns兜底:老库即使丢了迁移记录也能补齐列、回填默认值; - 若表按会话隔离,登记进
SESSION_SCOPED_TABLES,否则删除会话时该行会永久泄漏。
三、核心表速览:谁管记忆,谁管会话
Rust 侧的store.db迁移链定义在 lib.rs,从中可以摘出几张最有代表性的表:
| 表名 | 作用(一句话) |
|---|---|
mc_cache_state | 每会话的持久缓存状态,带row_version乐观并发控制 |
mc_compartments | 区室历史:会话被切成"记忆单元",含多档复述层 p1–p4 与重要度(衰减率) |
mc_memories | 项目记忆主表,UNIQUE(project_path, category, normalized_hash)去重,被替换的记忆用superseded_by_memory_id记录 |
mc_memory_mutation_log | 只追加的"变更日志":归档/删除/更新不重渲基线,而是以小 delta 补丁下发,保护提示词缓存 |
mc_user_memories | 跨项目的用户画像记忆(<user-profile>基线来源) |
mc_workspaces/mc_workspace_members | 跨项目工作区:成员项目可共享指定分类的记忆 |
mc_pass_trace/mc_chunk_transcripts | 每次变换的接收/完成/拒绝审计痕迹,可恢复的压缩转录 |
表分两类:会话级(带harness列区分宿主,如pi/opencode)与项目级(刻意跨宿主共享——从 Pi 写入的记忆,同一项目下 OpenCode 也能读到)。删除会话与"孤儿清扫"都依赖 storage-session-tables.ts 里的完整清单。
四、稳定项目身份:记忆为何不会"丢"
记忆按什么键归档?直接存路径是最朴素的答案,也是最大的坑——移动目录、符号链接、大小写差异都会让记忆"失联"。Magic Context 的答案在 project_identity.rs:
一个目录在
context.db中用一个身份而不是路径来标识:有 git 历史的检出是git:<根提交哈希>,否则是dir:<路径 MD5 前 12 位>。
这套算法的巧妙之处:
git:身份永不变化:取git rev-list --max-parents=0 HEAD的根提交哈希(多条无关历史取字典序最小),目录怎么挪、换什么名字,记忆池始终跟得上,且结果永久缓存;dir:身份每 5 分钟复检:因为目录后来可能git init成仓库,需要升级为git:身份;- 故障时的降级策略:git 临时不可用(超时、二进制缺失)时复用该目录或其同仓库祖先"最后一次成功的
git:身份",绝不落到dir:——否则会为同一个检出生成别人不会计算的新身份,记忆被拆成两个池子; - 宿主侧记忆文件:宿主每次 git 探测成功后把身份写到
context.db旁边的project-identities/边车文件中,Rust 模块直接复用,保证两条代码路径算出完全相同的值; - 家目录不算项目:
allowHomeProject关闭时直接拒绝,避免把"生活"记进记忆库。
🎯 一句话总结:身份稳定,记忆才稳定——这是"Memory that manages itself"的底层前提。
五、迁移机制:从"双库"到"单库"的一次性大手术
context.db与store.db曾经并行存两份项目记忆,靠镜像机制保持同步。如今这套镜像已退役:迁移 61(定义于 single_store_schema.rs)把所有领域表搬进context.db并删除旧表。迁移引擎实现于 single_store_migrate.rs,流程堪称教科书级:
- 先备份:两个文件都快照到备份目录,并在任何写入前打印目录位置;
- 切到 rollback-journal 模式:SQLite 只有在非 WAL 模式下才能对 ATTACH 的多个库做跨文件原子提交,这步保证"拷贝、标记、缓存重置"要么全成要么全败;
- 一个
BEGIN IMMEDIATE横跨两文件:建表 → 逐项目分类拷贝 → 重置模块缓存 → 清除镜像/权威表 →验证(包括"从两边分别渲染 m0 基线且必须逐字节一致"的渲染检查)→ 才删旧表、写入共享的迁移印章; - 任何拒绝或错误都回滚两个文件,还支持
--dry-run走完全流程后原样回退。
用户侧只需要一条命令(退出所有宿主后):
magic-context doctor single-store migrate如果两个库对"是否已迁移"说法不一,模块会以稳定的错误令牌single_store_state_split拒绝服务并给出明确指引,而不是带着脏数据继续跑。
六、备份与修复:日常运维清单
- 备份:backup-live-stores.sh 用
VACUUM INTO快照context.db和store.db——单事务内读取、不拿写锁,会话正在写入也能得到一致副本;每份快照附带完整性校验与 schema 版本,恢复时可精确匹配构建的栅栏版本; - 恢复:停掉所有占用进程 → 删除
-wal/-shm文件 → 用快照覆盖(两个库都要)→ 只启动一个宿主; - 修复:
npx @cortexkit/magic-context doctor repair-db修复损坏的context.db,动手前先把坏文件打包成.corrupt-backup-<时间戳>。
七、小结:三层防线撑起"一生的会话"
| 层 | 机制 | 解决的问题 |
|---|---|---|
| 版本层 | 栅栏 + 锁步 + 失败即关闭 | 新库旧构建互不踩坑 |
| 身份层 | git:/dir:稳定项目身份 | 记忆跨目录、跨宿主管线复用 |
| 迁移层 | 跨文件单事务 + 渲染级验证 + 全量备份 | 双库合一无数据丢失 |
想继续深入,推荐按这个顺序阅读:storage.md(存储总览)→ rust-module.md(Rust 模块与回滚)→ migrations.ts(迁移全景)。看懂这套存储层,你就理解了 Magic Context 为何敢承诺"一个会话,用一生"。
【免费下载链接】magic-contextUnbounded context. Memory that manages itself. One session, for life. The hippocampus for coding agents, part of CortexKit.项目地址: https://gitcode.com/gh_mirrors/mag/magic-context
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考