# Cardian 迭代记录(10 轮) > 目标:在 GitHub 上搜集同类工程案例,标 cardian 做全面优化,使其更好用、更具工程思维。下表记录每一轮的目标、借鉴的开源案例、具体改动与验证方式。 ## 搜集到的开源案例(选摘) | 项目 | Star | 借鉴点 | |---|---|---| | `humanlayer/12-factor-agents` | ~25k | 工具即结构化输出、自己掌控上下文、错误压缩进上下文、小聚焦 agent | | `AgriciDaniel/claude-obsidian` | ~12k | 自组织第二大脑:Markdown + 标签 + 双向链接 + MOC | | `breferrari/obsidian-mind` | ~4.6k | 给 agent 持久记忆的自组织 Obsidian vault | | `eugeniughelbur/obsidian-second-brain` | ~4.2k | 纯 Markdown 持久记忆,按项目分目录 | | `basicmachines-co/basic-memory` | ~3.8k | 本地优先 Markdown、wikilink 知识图谱、混合语义检索、工具行为提示(read-only/destructive/idempotent) | | `SamurAIGPT/llm-wiki-agent` | ~3.5k | 自维护的个人知识库 | | `Ar9av/obsidian-wiki` | ~3.3k | agent 经 Obsidian wiki 构建数字大脑 | | `The-Knowledge-Graph-Guys/vault-ld` | ~225 | Markdown vault 作为链接数据的 YAML frontmatter 规范 | | `mcncarl/agent-memory-vault` | ~304 | Markdown 优先记忆 vault + SQLite + Git | | `swarmclawai/swarmvault` | ~670 | 本地优先 LLM Wiki / 知识图谱 / RAG | | `willynikes2/knowledge-base-server` | ~175 | SQLite FTS5 + MCP + Obsidian 的持久记忆 | | `bb-boy680/open-zread` / `andyhtran/deepwiki-by-cc` | 小 | 代码库 → 结构化 Wiki 生成器 | --- ## R1 · 核心 / 适配器分层 - **借鉴**:basic-memory 的 "core vs MCP binding" 分界;12-factor-agents 的"小聚焦组件"。 - **改动**:把知识中心逻辑拆成框架无关的 `core/`(存储、检索、三大服务、导入导出),dsh 适配层(`src/`)只负责 Cordis 契约与工具注册。`createCardian()` 返回纯标象,可同时被 dsh 插件、CLI、未来的 MCP server 复用。 - **验证**:`npm test` 全绿;`core/` 无任何 cordis 依赖。 ## R2 · 工具行为提示 + 结构化输出 - **借鉴**:basic-memory 的 progressive tool discovery(每个工具标注 read-only/destructive/idempotent);12-factor-agents Factor 4(工具是结构化输出)。 - **改动**:每个工具带 `readOnly` / `idempotent` / `destructive` 三个布尔提示;返回值全部是纯结构化 JSON。 - **验证**:测试断言 23 个工具注册成功且提示字段正确。 ## R3 · 原子写入 + 串行队列 + 稳定 ID + 防碰撞 slug - **借鉴**:mcncarl/agent-memory-vault 的并发写安全;Obsidian 生态标"不写坏笔记"的强调。 - **改动**:`VaultStore` 改为临时文件 + `rename` 原子写;所有变更经内部 promise 队列串行化;同标题幂等更新保留稳定 id/created;不同标题撞 slug 时用确定性短哈希消歧;upsert 改为**合并语义**(未提供的字段保留)。 - **验证**:测试覆盖幂等、碰撞、无残留 `.tmp`。 ## R4 · 倒排索引 + 排序检索 + 标签云 - **借鉴**:basic-memory 的 hybrid search;willynikes2/knowledge-base-server 的 FTS。 - **改动**:新增 `core/indexer.js`:中文 bigram + 英文词元的分词、TF-IDF 排序(平滑正 IDF)、标题/标签加权、按分区/标签过滤、标签云聚合。 - **验证**:测试断言按相关度排序与分区过滤。 ## R5 · 可插拔向量 + 混合语义检索 - **借鉴**:basic-memory 的"语义 + 关键词 + 可选重排"。 - **改动**:`core/embedder.js` 定义 `embed(text)->Float32Array` 契约,内置零依赖 `HashEmbedder`(字符 n-gram 哈希,兼容中文/英文);`cardian.search` 支持关键词与语义混合(`alpha` 权重)。 - **验证**:测试断言混合检索返回 `keyword`/`semantic` 双分。 ## R6 · 富 frontmatter + 反向链接/相关视图 - **借鉴**:vault-ld 的 frontmatter 规范;claude-obsidian 的双向链接图谱。 - **改动**:`core/links.js` 解析 `[[wikilink]]`,按需计算 backlinks 与 related(共享标签);卡片/记忆支持 `aliases`。新增 `cardian.backlinks` / `cardian.related` 工具。 - **验证**:测试断言 backlinks 与 related 正确解析中文/英文 wikilink。 ## R7 · 导入 / 导出 + Markdown 目录同步 - **借鉴**:obsidian-second-brain 的双向同步(人机写同一批 Markdown)。 - **改动**:`core/sync.js` 支持 JSON 快照导出/导入(完整往返)、扫描外部 Markdown 目录按 frontmatter `type` 路由导入。新增 `cardian.export` / `import` / `importMarkdown` 工具。 - **验证**:测试覆盖 JSON 往返与 frontmatter 路由导入。 ## R8 · 独立 CLI + 日志 + dry-run - **借鉴**:brain-cli / knowledge-base 的 CLI 形态;12-factor-agents 的"从任何地方触发"。 - **改动**:`cli.mjs` 提供 status/search/card/memory/wiki/export/import/tagcloud/backlinks/related 子命令,全局 `--vault` / `--dry-run` / `--quiet`。加入 `package.json.bin`。 - **验证**:CLI 冒烟测试(status / card add / search / dry-run)。 ## R9 · node:test 测试套件 + fixtures + npm test - **借鉴**:成熟工程的质量门(CI 里跑测试)。 - **改动**:迁移到 Node 内置 `node:test`,13 个测试覆盖全部核心路径 + 适配层;提交了 `test/fixtures/markdown-import/`;`npm test` 一键运行。 - **验证**:`npm test` 13/13 通过。 ## R10 · 文档与发布就绪 - **改动**:补齐 `LICENSE`(MIT)、`CHANGELOG.md`、`ITERATIONS.md`,重写 `README.md`(架构图、工具矩阵、CLI、测试、Obsidian 使用),`package.json` 更新 exports/bin/scripts/version。 - **验证**:全量 `npm test` 绿;`demo.mjs` 生成多仓库示例 vault。 --- ## R11 · 多 Agent 复审与二次优化 > 目标:再 review 几遍,并借鉴开源社区的思维逻辑、业务结构、工程结构。本轮开 3 个并行 agent:**代码审查**、**工程结构调研**、**领域/业务结构调研**,交叉校验后落地高价值修复。 ### 代码审查发现的 7 个真实缺陷(全部修复) | 缺陷 | 严重度 | 修复 | |---|---|---| | `search` 省略 `topK` 时 NaN 切片 → 返回空 | 高 | `topK ?? 默认值` | | 改 `category/scope` 只改 frontmatter 不移文件 → 孤儿笔记 | 高 | 分组变更时搬迁文件,保留 id/created | | 同名并发 upsert 竞态 → 丢更新、悬挂 id | 高 | 整个读-改-写纳入 store 事务队列 | | `category/scope` 未消毒可含 `/` 或 `..` | 高 | 分组统一 slugify | | 含逗号的标签往返损坏 | 高 | 序列化加引号 + 解析按引号感知切分 | | 手写 `title: 2024`/`tags:[42]` 被解析成数字 | 中 | title/tags/aliases/facts 归一化为字符串 | | `ingest` 的 `maxFiles:null` → 1;文件读取错误被吞 | 中 | null 回落默认 + 逐文件报错信号 | ### 工程结构改进(借鉴 basic-memory / mem0 / MCP servers / 12-factor) - **类型化错误分类**(`core/errors.js`):`ValidationError/NotFoundError/ConfigError/PathError/StoreError`,在工具边界压缩成 `{ok:false,error:{code,message,suggestion}}`(12-factor Factor 9)。 - **配置校验**(`core/config.js`):fail-fast,`searchAlpha` 夹取到 [0,1]、`embedderDim` 正整数校验(basic-memory "fail fast, never silently fall back")。 - **日志纪律**(`core/log.js`):诊断走 stderr,数据走 stdout(为未来 MCP stdio 预留)。 - **检索索引缓存**:按 store 版本号失效,查询从 O(vault) 降到 O(query)。 - **符号链接逃逸防护**:写入前 realpath 校验。 ### 领域/业务结构改进(借鉴 mem0 / letta / obsidian-second-brain / vault-ld) - **`status`(draft/published) + `confidence`(0-1) + `source`**:把 vault 从"一堆笔记"升级为"带信任排名的知识"(claude-obsidian 的 provenance 台账)。 - **记忆 `kind`**:`semantic / episodic / procedural`(mem0 categories、letta memory blocks)。 - **`cardian.recall` 精简召回**:按重要度/新鲜度/置信度重排、限量返回、支持弃权(obsidian-second-brain "bounded recall" + 12-factor "own your context window")。 - **别名解析**:`find`/`resolveRef` 支持 `aliases`(Obsidian 原生属性)。 ### 验证 - `npm test` 21/21 通过(新增 8 个回归测试覆盖上述全部修复)。 - CLI `recall`、布尔旗标、错误码→退出码(`VALIDATION`→2)冒烟通过。 --- ## R12 · 第二轮复审与深度打磨 > 目标:再 review 几遍。本轮再开 2 个并行只读 agent——一个做**回归审查**(聚焦 R11 新改的 transact/合并语义/搬迁/索引缓存/错误边界),一个做**边界用例审查**(frontmatter/moc/links/indexer/embedder/slug/sync/repowiki)。 ### 第二轮发现并修复的缺陷 | 缺陷 | 来源 | 修复 | |---|---|---| | 标签含内部引号 `a"b` 往返被合并 | 边界审查 | 序列化强制加引号 + 切分感知转义 | | 标题含 `#`(如 "Kubernetes #101")被 js-yaml 截断 | 边界审查 | 含 `#` 即加引号 | | 以 `---` 水平线开头的 Markdown 被误判为 frontmatter | 边界审查 | 有 key 行才视为 frontmatter | | MOC wikilink 可被标题中的 `]]`/`\|`/`#` 注入 | 边界审查 | 别名/标签消毒 | | `extractWikilinks` 匹配代码围栏里的 `[[...]]` | 边界审查 | 提取前剥离代码块 | | `importJson` 未前置拒绝 `..` 穿越(半恢复) | 回归 | 校验循环拒绝 `..`/`\`/绝标路径 | | 空 Markdown 导致 `importMarkdownFolder` 整体中断 | 边界审查 | 跳过空笔记 | | `index`/`moc` 命名的笔记被误当 MOC 排除(demo 暴露) | 自测 | 仅分区根级 README 视为 MOC | | RepoWiki 无标签 upsert 清掉自动标签 | 回归 | `tags: args.tags` 保留 | | RepoWiki 扫描隐藏目录 + stem 扩展名错乱 | 边界审查 | 跳过 `.` 目录 + 去扩展名 | | 外部手改后检索索引长期陈旧 | 回归 | 目录 mtime 探针 + 重建前捕获版本号 | ### 领域增强(沿用首轮调研结论) - **RepoWiki 依赖图**:`ingest` 提取 import/require/include,写入 `imports` frontmatter + `## 依赖` 章节——回答"这个仿块依赖谁"。 - **类型化关系**:三分区支持 `relations`(如 `"depends_on [[X]]"`),`related()` 先解析关系再回退共享标签。 - **记忆修订历史**:追加式 `history`(封顶 20),新增 `cardian.memory.history` 工具。 - **新鲜度**:`as_of` / `expires` 字段 + `cardian.status` 输出 `stale` 计数。 - **`cardian.reindex`**:Obsidian 手改后强制重建索引。 - **工具必填参数校验**:缺失必填参数返回结构化 `VALIDATION` 错误而非深层异常。 ### 验证 - `npm test` 30/30 通过(新增 9 个回归测试覆盖上表全部修复)。 - demo 的 RepoWiki 从 16 条恢复为 19 条(修复 `index`/`moc` 误排除后)。 --- ## R13 · 第三轮复审:领域特性打磨 + 覆盖/发布补齐 > 目标:再 review 几遍。本轮再开 2 个并行只读 agent——一个审查 R12 新增的领域特性(relations/imports/history/freshness/recall),一个做测试覆盖与包发布卫生的缺口分析。 ### 修复的缺陷 | 缺陷 | 来源 | 修复 | |---|---|---| | `related()` 同一目标出现在多条 relations 时返回重复条目 | 领域审查 | 首轮按 `rel` 去重 | | `extractImports` 误报注释/字符串 + 漏 Rust/Python/Java/C#/Go/Ruby | 领域审查 | 语言感知 + 先剥注释 | | `recall()` 声称置信度加权却未实现;关键词仿式加权失效 | 领域审查 | 置信度入 rank + 分数归一化 | | `as_of`/`expires` 接受垃圾值 | 领域审查 | 无效日期抛 `ValidationError` | ### 领域/工程增强 - **闪卡**:`front`/`back`/`deck` 字段 + `cardian.card.review`(SM-2 排期)+ `cardian.card.due`(到期列表)——补上"知识卡片"最贴合领域的一块(借鉴 Anki / obsidian-spaced-repetition)。 - **`cardian.doctor` 健康检查**(basic-memory `doctor`):MOC 存在性、孤儿 `.tmp` 残留、缺必填字段、过期笔记。 - **`cardian.schema`**:frontmatter 字段自省(basic-memory `schema_infer/validate` 的轻量版)。 - **CLI 补齐**:`doctor`/`schema` 子命令、缺参校验、坏子命令用 `ValidationError`、`card due/review`。 - **包发布卫生**:`repository`/`homepage`/`bugs`/`author`、`sideEffects:false`、`publishConfig`、`prepublishOnly`,`files` 补齐 `CHANGELOG.md`/`ITERATIONS.md`/`examples`。 ### 测试覆盖补强(agent 缺口分析落地) - 新增 `test/cli.test.mjs`:CLI 端到端冒烟(status/doctor/card add/search/--dry-run/退出码),补上此前 0 覆盖的公开 CLI 面。 - 新增 7 个领域回归测试(relations 去重、语言感知 imports、置信度加权、日期校验、闪卡 SM-2、doctor、schema)。 ### 验证 - `npm test` 41/41 通过(30 核心 + 4 CLI + 新增回归)。 - demo 正常;`cli doctor` 输出 `healthy:true`。 --- ## R14 · 接入真实 dsh 宿主 + 「知识树」侧边栏 > 目标:把 cardian 接入真实 DeepSeek Harness 宿主,在左下栏加「知识树」栏目,直接查看/管理插件生成的内容,对标主流 agentic IDE 的知识中心能力模型。 ### 调研(从官方仓库源码定位精确契约) - 三列布局 slot:`sidebar` / `conversation` / `details` + `shell.overlay`(`ui-layout` 声明,均为 single/可加性)。 - 侧边栏子 slot:`sidebar.footer.action`(list,脚部可加性入口)、`sidebar.workspaces`、`sidebar.settings` 等(`ui-sidebar` 声明)。 - 客户端插件契约:两个半侧同包(`src/` host + `client/` browser,`./client` 导出 + `dsh.client` 声明);`slots.register`/`slots.inject`、`locale.register`、`ctx.effect`。 ### 实现 - **Host 读仿型**:`cardian.describe()` 返回完整知识树(sections→entries),纯数据、可测。 - **客户端半侧**(`client/`):`sidebar.footer.action` 注册「🌳 知识树」入口 + `shell.overlay` 注册浮动面板;`KnowledgeTree.tsx` 渲染搜索框 + 三分区条目树;`controller.ts` 收敛 remote 桥(唯一适配点);`locales.ts` 中英文案。 - **配置**:`dsh.client`(platform web + inject 四个 client 包)+ `./client` 导出 + `docs/dsh-integration.md`。 ### 边界与诚实说明 - 客户端半侧已重构到 dsh 规范(`src/client/index.ts`),并**可构建**:`npm install`(react@18 + tsdown + typescript)+ `npm run build:client` 产出 `lib/client.js`(含 `window.__ModuleLoader__.load({id,factory})` 闭包工厂、react 走仿块表 external、`inject`/`apply` 正常导出),已按官方 `clientBundle` 预设逐一核标。 - 关键发现:`@deepseek-ai/dsh-client-*` 在 npm 上**发布不完整**(传递 peer 依赖 `dsh-paths`/`dsh-type-meta` 等 404);但本仓库标它们仅 `import type`(编译期擦除),故构建无需安装它们。 - 仍**未验证**的是在真实 dsh Web 客户端里的渲染(需用户本机 dsh desktop + 浏览器)。 - Host 半侧 + 核心引擎由 `npm test` 覆盖(42 项,新增 `describe()` 测试)。 --- ## 工程思维小结 1. **单一事实来源**:一切落到纯 Markdown + YAML frontmatter 的 Obsidian 仓库,人机可读可编辑,永不锁定。 2. **分层与可移植**:核心逻辑与宿主解耦,同一引擎服务 dsh / CLI / 未来 MCP。 3. **可逆与幂等**:合并语义 upsert、稳定 ID、原子写、串行队列——重复调用不破坏数据。 4. **工具即契约**:结构化输出 + 行为提示,让 agent 选标工具、少犯错。 5. **检索分层**:关键词(倒排索引)与语义(可插拔向量)可组合、可降级(离线 fallback)。 6. **质量门**:`node:test` 回归 + committed fixtures + `npm test`。