{
  "canonical_name": "rickbassham/commonplace",
  "compilation_id": "pack_6fcfe79e83054cbc8aae2b11c451de74",
  "created_at": "2026-05-13T18:10:55.633356+00:00",
  "created_by": "project-pack-compiler",
  "feedback": {
    "carrier_selection_notes": [
      "viable_asset_types=mcp_config, recipe, host_instruction, eval, preflight",
      "recommended_asset_types=mcp_config, recipe, host_instruction, eval, preflight"
    ],
    "evidence_delta": {
      "confirmed_claims": [
        "identity_anchor_present",
        "capability_and_host_targets_present",
        "install_path_declared_or_better"
      ],
      "missing_required_fields": [],
      "must_verify_forwarded": [
        "Run or inspect `npm i -g commonplace-mcp` in an isolated environment.",
        "Confirm the project exposes the claimed capability to at least one target host."
      ],
      "quickstart_execution_scope": "allowlisted_sandbox_smoke",
      "sandbox_command": "npm i -g commonplace-mcp",
      "sandbox_container_image": "node:22-slim",
      "sandbox_execution_backend": "docker",
      "sandbox_planner_decision": "deterministic_isolated_install",
      "sandbox_validation_id": "sbx_798b9fe10ca147d39381e42de902f9f3"
    },
    "feedback_event_type": "project_pack_compilation_feedback",
    "learning_candidate_reasons": [],
    "template_gaps": []
  },
  "identity": {
    "canonical_id": "project_66d2fe0c1848d38ac23b577d58220917",
    "canonical_name": "rickbassham/commonplace",
    "homepage_url": null,
    "license": "unknown",
    "repo_url": "https://github.com/rickbassham/commonplace",
    "slug": "commonplace",
    "source_packet_id": "phit_57c8dd35fb724f4ca1aedbc324bbea7e",
    "source_validation_id": "dval_6e0e02567bfa4a499e76ba80b4a1178e"
  },
  "merchandising": {
    "best_for": "需要工具连接与集成能力，并使用 mcp_host的用户",
    "github_forks": 0,
    "github_stars": 0,
    "one_liner_en": "Local-first semantic memory MCP server. A commonplace book for your agent — markdown source-of-truth, sidecar embeddings, no database.",
    "one_liner_zh": "Local-first semantic memory MCP server. A commonplace book for your agent — markdown source-of-truth, sidecar embeddings, no database.",
    "primary_category": {
      "category_id": "tool-integrations",
      "confidence": "high",
      "name_en": "Tool Integrations",
      "name_zh": "工具连接与集成",
      "reason": "matched_keywords:mcp, server, github"
    },
    "target_user": "使用 mcp_host 等宿主 AI 的用户",
    "title_en": "commonplace",
    "title_zh": "commonplace 能力包",
    "visible_tags": [
      {
        "label_en": "MCP Tools",
        "label_zh": "MCP 工具",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "product_domain-mcp-tools",
        "type": "product_domain"
      },
      {
        "label_en": "Knowledge Base Q&A",
        "label_zh": "知识库问答",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "user_job-knowledge-base-q-a",
        "type": "user_job"
      },
      {
        "label_en": "Workflow Automation",
        "label_zh": "流程自动化",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "core_capability-workflow-automation",
        "type": "core_capability"
      },
      {
        "label_en": "Node-based Workflow",
        "label_zh": "节点式流程编排",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "workflow_pattern-node-based-workflow",
        "type": "workflow_pattern"
      },
      {
        "label_en": "Local-first",
        "label_zh": "本地优先",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "selection_signal-local-first",
        "type": "selection_signal"
      }
    ]
  },
  "packet_id": "phit_57c8dd35fb724f4ca1aedbc324bbea7e",
  "page_model": {
    "artifacts": {
      "artifact_slug": "commonplace",
      "files": [
        "PROJECT_PACK.json",
        "QUICK_START.md",
        "PROMPT_PREVIEW.md",
        "HUMAN_MANUAL.md",
        "AI_CONTEXT_PACK.md",
        "BOUNDARY_RISK_CARD.md",
        "PITFALL_LOG.md",
        "REPO_INSPECTION.json",
        "REPO_INSPECTION.md",
        "CAPABILITY_CONTRACT.json",
        "EVIDENCE_INDEX.json",
        "CLAIM_GRAPH.json"
      ],
      "required_files": [
        "PROJECT_PACK.json",
        "QUICK_START.md",
        "PROMPT_PREVIEW.md",
        "HUMAN_MANUAL.md",
        "AI_CONTEXT_PACK.md",
        "BOUNDARY_RISK_CARD.md",
        "PITFALL_LOG.md",
        "REPO_INSPECTION.json"
      ]
    },
    "detail": {
      "capability_source": "Project Hit Packet + DownstreamValidationResult",
      "commands": [
        {
          "command": "npm i -g commonplace-mcp",
          "label": "Node.js / npm · 官方安装入口",
          "source": "https://github.com/rickbassham/commonplace#readme",
          "verified": true
        }
      ],
      "display_tags": [
        "MCP 工具",
        "知识库问答",
        "流程自动化",
        "节点式流程编排",
        "本地优先"
      ],
      "eyebrow": "工具连接与集成",
      "glance": [
        {
          "body": "判断自己是不是目标用户。",
          "label": "最适合谁",
          "value": "需要工具连接与集成能力，并使用 mcp_host的用户"
        },
        {
          "body": "先理解能力边界，再决定是否继续。",
          "label": "核心价值",
          "value": "Local-first semantic memory MCP server. A commonplace book for your agent — markdown source-of-truth, sidecar embeddings, no database."
        },
        {
          "body": "未完成验证前保持审慎。",
          "label": "继续前",
          "value": "publish to Doramagic.ai project surfaces"
        }
      ],
      "guardrail_source": "Boundary & Risk Card",
      "guardrails": [
        {
          "body": "Prompt Preview 只展示流程，不证明项目已安装或运行。",
          "label": "Check 1",
          "value": "不要把试用当真实运行"
        },
        {
          "body": "mcp_host",
          "label": "Check 2",
          "value": "确认宿主兼容"
        },
        {
          "body": "publish to Doramagic.ai project surfaces",
          "label": "Check 3",
          "value": "先隔离验证"
        }
      ],
      "mode": "mcp_config, recipe, host_instruction, eval, preflight",
      "pitfall_log": {
        "items": [
          {
            "body": "README/documentation is current enough for a first validation pass.",
            "category": "能力坑",
            "evidence": [
              "capability.assumptions | github_repo:1232879661 | https://github.com/rickbassham/commonplace | README/documentation is current enough for a first validation pass."
            ],
            "severity": "medium",
            "suggested_check": "将假设转成下游验证清单。",
            "title": "能力判断依赖假设",
            "user_impact": "假设不成立时，用户拿不到承诺的能力。"
          },
          {
            "body": "项目说明出现 external service/cloud/webhook/database 等运行依赖关键词。",
            "category": "运行坑",
            "evidence": [
              "packet_text.keyword_scan | github_repo:1232879661 | https://github.com/rickbassham/commonplace | matched external service / cloud / webhook / database keyword"
            ],
            "severity": "medium",
            "suggested_check": "确认是否有离线 demo、mock 数据或可替代服务。",
            "title": "运行可能依赖外部服务",
            "user_impact": "本地安装成功不等于能力可用，外部服务不可用会阻断体验。"
          },
          {
            "body": "未记录 last_activity_observed。",
            "category": "维护坑",
            "evidence": [
              "evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | last_activity_observed missing"
            ],
            "severity": "medium",
            "suggested_check": "补 GitHub 最近 commit、release、issue/PR 响应信号。",
            "title": "维护活跃度未知",
            "user_impact": "新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。"
          },
          {
            "body": "no_demo",
            "category": "安全/权限坑",
            "evidence": [
              "downstream_validation.risk_items | github_repo:1232879661 | https://github.com/rickbassham/commonplace | no_demo; severity=medium"
            ],
            "severity": "medium",
            "suggested_check": "进入安全/权限治理复核队列。",
            "title": "下游验证发现风险项",
            "user_impact": "下游已经要求复核，不能在页面中弱化。"
          },
          {
            "body": "No sandbox install has been executed yet; downstream must verify before user use.",
            "category": "安全/权限坑",
            "evidence": [
              "risks.safety_notes | github_repo:1232879661 | https://github.com/rickbassham/commonplace | No sandbox install has been executed yet; downstream must verify before user use."
            ],
            "severity": "medium",
            "suggested_check": "转成明确权限清单和安全审查提示。",
            "title": "存在安全注意事项",
            "user_impact": "用户安装前需要知道权限边界和敏感操作。"
          },
          {
            "body": "no_demo",
            "category": "安全/权限坑",
            "evidence": [
              "risks.scoring_risks | github_repo:1232879661 | https://github.com/rickbassham/commonplace | no_demo; severity=medium"
            ],
            "severity": "medium",
            "suggested_check": "把风险写入边界卡，并确认是否需要人工复核。",
            "title": "存在评分风险",
            "user_impact": "风险会影响是否适合普通用户安装。"
          },
          {
            "body": "issue_or_pr_quality=unknown。",
            "category": "维护坑",
            "evidence": [
              "evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | issue_or_pr_quality=unknown"
            ],
            "severity": "low",
            "suggested_check": "抽样最近 issue/PR，判断是否长期无人处理。",
            "title": "issue/PR 响应质量未知",
            "user_impact": "用户无法判断遇到问题后是否有人维护。"
          },
          {
            "body": "release_recency=unknown。",
            "category": "维护坑",
            "evidence": [
              "evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | release_recency=unknown"
            ],
            "severity": "low",
            "suggested_check": "确认最近 release/tag 和 README 安装命令是否一致。",
            "title": "发布节奏不明确",
            "user_impact": "安装命令和文档可能落后于代码，用户踩坑概率升高。"
          }
        ],
        "source": "ProjectPitfallLog + ProjectHitPacket + validation + community signals",
        "summary": "发现 8 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。",
        "title": "踩坑日志"
      },
      "snapshot": {
        "contributors": 1,
        "forks": 0,
        "license": "unknown",
        "note": "站点快照，非实时质量证明；用于开工前背景判断。",
        "stars": 0
      },
      "source_url": "https://github.com/rickbassham/commonplace",
      "steps": [
        {
          "body": "不安装项目，先体验能力节奏。",
          "code": "preview",
          "title": "先试 Prompt"
        },
        {
          "body": "理解输入、输出、失败模式和边界。",
          "code": "manual",
          "title": "读说明书"
        },
        {
          "body": "把上下文交给宿主 AI 继续工作。",
          "code": "context",
          "title": "带给 AI"
        },
        {
          "body": "进入主力环境前先完成安装入口与风险边界验证。",
          "code": "verify",
          "title": "沙箱验证"
        }
      ],
      "subtitle": "Local-first semantic memory MCP server. A commonplace book for your agent — markdown source-of-truth, sidecar embeddings, no database.",
      "title": "commonplace 能力包",
      "trial_prompt": "# commonplace - Prompt Preview\n\n> 复制下面这段 Prompt 到你常用的 AI，先试一次，不需要安装。\n> 它的目标是让你直接体验这个项目的服务方式，而不是阅读项目介绍。\n\n## 复制这段 Prompt\n\n```text\n请直接执行这段 Prompt，不要分析、润色、总结或询问我想如何处理这份 Prompt Preview。\n\n你现在扮演 commonplace 的“安装前体验版”。\n这不是项目介绍、不是评价报告、不是 README 总结。你的任务是让我用最小成本体验它的核心服务。\n\n我的试用任务：我想用它完成一个真实的工具连接与集成任务。\n我常用的宿主 AI：MCP Client\n\n【体验目标】\n围绕我的真实任务，现场演示这个项目如何把输入转成 示例引导, 判断线索。重点是让我感受到工作方式，而不是给我项目背景。\n\n【业务流约束】\n- 你必须像一个正在提供服务的项目能力包，而不是像一个讲解员。\n- 每一轮只推进一个步骤；提出问题后必须停下来等我回答。\n- 每一步都必须让我感受到一个具体服务动作：澄清、整理、规划、检查、判断或收尾。\n- 每一步都要说明：当前目标、你需要我提供什么、我回答后你会产出什么。\n- 不要安装、不要运行命令、不要写代码、不要声称测试通过、不要声称已经修改文件。\n- 需要真实安装或宿主加载后才能验证的内容，必须明确说“这一步需要安装后验证”。\n- 如果我说“用示例继续”，你可以用虚构示例推进，但仍然不能声称真实执行。\n\n【可体验服务能力】\n- 安装前能力预览: Local-first semantic memory MCP server. A commonplace book for your agent — markdown source-of-truth, sidecar embeddings, no database. 输入：用户任务, 当前 AI 对话上下文；输出：示例引导, 判断线索。\n\n【必须安装后才可验证的能力】\n- 命令行启动或安装流程: 项目文档中存在可执行命令，真实使用需要在本地或宿主环境中运行这些命令。 输入：终端环境, 包管理器, 项目依赖；输出：安装结果, 列表/更新/运行结果。\n\n【核心服务流】\n请严格按这个顺序带我体验。不要一次性输出完整流程：\n1. page-overview：项目概览。围绕“项目概览”模拟一次用户任务，不展示安装或运行结果。\n2. page-quickstart：快速入门与安装。围绕“快速入门与安装”模拟一次用户任务，不展示安装或运行结果。\n3. page-architecture：系统架构。围绕“系统架构”模拟一次用户任务，不展示安装或运行结果。\n4. page-embedder：嵌入模型与语义搜索。围绕“嵌入模型与语义搜索”模拟一次用户任务，不展示安装或运行结果。\n5. page-memory-format：内存格式与侧载文件。围绕“内存格式与侧载文件”模拟一次用户任务，不展示安装或运行结果。\n\n【核心能力体验剧本】\n每一步都必须按“输入 -> 服务动作 -> 中间产物”执行。不要只说流程名：\n1. page-overview\n输入：用户提供的“项目概览”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n2. page-quickstart\n输入：用户提供的“快速入门与安装”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n3. page-architecture\n输入：用户提供的“系统架构”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n4. page-embedder\n输入：用户提供的“嵌入模型与语义搜索”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n5. page-memory-format\n输入：用户提供的“内存格式与侧载文件”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n【项目服务规则】\n这些规则决定你如何服务用户。不要解释规则本身，而要在每一步执行时遵守：\n- 先确认用户任务、输入材料和成功标准，再模拟项目能力。\n- 每一步都必须形成可检查的小产物，并等待用户确认后再继续。\n- 凡是需要安装、调用工具或访问外部服务的能力，都必须标记为安装后验证。\n\n【每一步的服务约束】\n- Step 1 / page-overview：Step 1 必须围绕“项目概览”形成一个小中间产物，并等待用户确认。\n- Step 2 / page-quickstart：Step 2 必须围绕“快速入门与安装”形成一个小中间产物，并等待用户确认。\n- Step 3 / page-architecture：Step 3 必须围绕“系统架构”形成一个小中间产物，并等待用户确认。\n- Step 4 / page-embedder：Step 4 必须围绕“嵌入模型与语义搜索”形成一个小中间产物，并等待用户确认。\n- Step 5 / page-memory-format：Step 5 必须围绕“内存格式与侧载文件”形成一个小中间产物，并等待用户确认。\n\n【边界与风险】\n- 不要声称已经安装、运行、调用 API、读写本地文件或完成真实任务。\n- 安装前预览只能展示工作方式，不能证明兼容性、性能或输出质量。\n- 涉及安装、插件加载、工具调用或外部服务的能力必须安装后验证。\n\n【可追溯依据】\n这些路径只用于你内部校验或在我追问“依据是什么”时简要引用。不要在首次回复主动展开：\n- https://github.com/rickbassham/commonplace\n- https://github.com/rickbassham/commonplace#readme\n- README.md\n- package.json\n- CLAUDE.md\n- .nvmrc\n- src/index.ts\n- src/embedder/index.ts\n- src/store/memory-store.ts\n- src/server/server.ts\n- vitest.config.ts\n- tests/global-setup.ts\n\n【首次问题规则】\n- 首次三问必须先确认用户目标、成功标准和边界，不要提前进入工具、安装或实现细节。\n- 如果后续需要技术条件、文件路径或运行环境，必须等用户确认目标后再追问。\n\n首次回复必须只输出下面 4 个部分：\n1. 体验开始：用 1 句话说明你将带我体验 commonplace 的核心服务。\n2. 当前步骤：明确进入 Step 1，并说明这一步要解决什么。\n3. 你会如何服务我：说明你会先改变我完成任务的哪个动作。\n4. 只问我 3 个问题，然后停下等待回答。\n\n首次回复禁止输出：后续完整流程、证据清单、安装命令、项目评价、营销文案、已经安装或运行的说法。\n\nStep 1 / brainstorming 的二轮协议：\n- 我回答首次三问后，你仍然停留在 Step 1 / brainstorming，不要进入 Step 2。\n- 第二次回复必须产出 6 个部分：澄清后的任务定义、成功标准、边界条件、\n  2-3 个可选方案、每个方案的权衡、推荐方案。\n- 第二次回复最后必须问我是否确认推荐方案；只有我明确确认后，才能进入下一步。\n- 第二次回复禁止输出 git worktree、代码计划、测试文件、命令或真实执行结果。\n\n后续对话规则：\n- 我回答后，你先完成当前步骤的中间产物并等待确认；只有我确认后，才能进入下一步。\n- 每一步都要生成一个小的中间产物，例如澄清后的目标、计划草案、测试意图、验证清单或继续/停止判断。\n- 所有演示都写成“我会建议/我会引导/这一步会形成”，不要写成已经真实执行。\n- 不要声称已经测试通过、文件已修改、命令已运行或结果已产生。\n- 如果某个能力必须安装后验证，请直接说“这一步需要安装后验证”。\n- 如果证据不足，请明确说“证据不足”，不要补事实。\n```\n",
      "voices": [
        {
          "body": "来源平台：github。github/github_release: v0.2.1（https://github.com/rickbassham/commonplace/releases/tag/v0.2.1）；github/github_release: v0.1.0（https://github.com/rickbassham/commonplace/releases/tag/v0.1.0）；github/github_release: v0.0.1-canary.2（https://github.com/rickbassham/commonplace/releases/tag/v0.0.1-canary.2）。这些是项目级外部声音，不作为单独质量证明。",
          "items": [
            {
              "kind": "github_release",
              "source": "github",
              "title": "v0.2.1",
              "url": "https://github.com/rickbassham/commonplace/releases/tag/v0.2.1"
            },
            {
              "kind": "github_release",
              "source": "github",
              "title": "v0.1.0",
              "url": "https://github.com/rickbassham/commonplace/releases/tag/v0.1.0"
            },
            {
              "kind": "github_release",
              "source": "github",
              "title": "v0.0.1-canary.2",
              "url": "https://github.com/rickbassham/commonplace/releases/tag/v0.0.1-canary.2"
            }
          ],
          "status": "已收录 3 条来源",
          "title": "社区讨论"
        }
      ]
    },
    "homepage_card": {
      "category": "工具连接与集成",
      "desc": "Local-first semantic memory MCP server. A commonplace book for your agent — markdown source-of-truth, sidecar embeddings, no database.",
      "effort": "安装已验证",
      "forks": 0,
      "icon": "link",
      "name": "commonplace 能力包",
      "risk": "可发布",
      "slug": "commonplace",
      "stars": 0,
      "tags": [
        "MCP 工具",
        "知识库问答",
        "流程自动化",
        "节点式流程编排",
        "本地优先"
      ],
      "thumb": "gray",
      "type": "MCP 配置"
    },
    "manual": {
      "markdown": "# https://github.com/rickbassham/commonplace 项目说明书\n\n生成时间：2026-05-13 17:34:29 UTC\n\n## 目录\n\n- [项目概览](#page-overview)\n- [快速入门与安装](#page-quickstart)\n- [系统架构](#page-architecture)\n- [技术栈详解](#page-tech-stack)\n- [嵌入模型与语义搜索](#page-embedder)\n- [内存格式与侧载文件](#page-memory-format)\n- [搜索功能详解](#page-search)\n- [图功能与关系管理](#page-graph-features)\n- [存储系统](#page-storage)\n- [作用域与多存储](#page-scopes)\n\n<a id='page-overview'></a>\n\n## 项目概览\n\n### 相关页面\n\n相关主题：[快速入门与安装](#page-quickstart), [系统架构](#page-architecture)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n- [CONTRIBUTING.md](https://github.com/rickbassham/commonplace/blob/main/CONTRIBUTING.md)\n- [src/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts)\n</details>\n\n# 项目概览\n\n## 项目简介\n\nCommonplace 是一个基于 MCP（Model Context Protocol）的持久化记忆系统，旨在为 AI 代理提供跨会话的上下文记忆能力。该项目使 AI 能够记住用户的偏好、项目的架构决策、技术反馈等重要信息，从而在长时间交互中保持一致性和连续性。\n\n资料来源：[README.md:1-10]()\n\n## 核心设计原则\n\n### 记忆文件即真相\n\nCommonplace 采用 Markdown 文件作为记忆的持久化存储介质。每个记忆以 `.md` 文件形式存储，YAML frontmatter 携带结构化元数据，文件主体承载具体内容。这种设计使得记忆可以被版本控制、人类可读、手动编辑，且不依赖专有格式。\n\n资料来源：[CLAUDE.md:15-20]()\n\n### 边车文件可重建\n\n`.embedding` 等边车文件（sidecar）是从 `.md` 源文件派生的，可以随时从源码重新生成。这确保了数据的安全性——即使边车文件丢失或损坏，也能通过扫描重建索引。\n\n资料来源：[CLAUDE.md:20-22]()\n\n## 内存类型系统\n\nCommonplace 定义了四种内存类型，构成记忆分类的基础：\n\n| 类型 | 用途 | 典型场景 |\n|------|------|----------|\n| `user` | 个人规则、偏好、身份事实 | 编程语言偏好、沟通风格、联系方式 |\n| `feedback` | 来自代理行为的修正和教训 | 避免的模式、成功的策略、工作习惯 |\n| `project` | 项目特定上下文 | 架构笔记、代码规范、决策记录 |\n| `reference` | 持久化中性知识 | API 形状、公式、引用、需要按语义查询的内容 |\n\n资料来源：[README.md:45-60]()\n\n## 记忆存储架构\n\n### 双作用域设计\n\n系统支持同时加载两个独立的记忆存储：\n\n```mermaid\ngraph TD\n    A[Commonplace] --> B[用户存储]\n    A --> C[项目存储]\n    B --> D[COMMONPLACE_USER_DIR<br/>~/.commonplace/memory]\n    C --> E[COMMONPLACE_PROJECT_DIR<br/>或 .commonplace/memory]\n    \n    F[MCP roots/list检测] --> E\n    G[当前工作目录] --> E\n```\n\n- **用户存储（User Store）**：始终加载，存储跨项目共享的个人规则和反馈\n- **项目存储（Project Store）**：仅在检测到项目根目录时加载，存储项目特定的上下文\n\n资料来源：[README.md:140-165]()\n\n### 目录结构\n\n每个记忆存储遵循以下结构：\n\n```\n<store-dir>/\n├── <name>.md           # 记忆文件\n├── <name>.embedding    # 向量嵌入边车（自动生成）\n└── .index/             # 索引缓存（可选）\n```\n\n资料来源：[src/store/memory.ts:20-35]()\n\n### 记忆文件格式\n\n记忆文件采用标准 Markdown + YAML frontmatter 格式：\n\n```yaml\n---\nname: feedback_scope\ndescription: 不要单方面缩减范围\ntype: feedback\nrelations:          # 关系边（DAR-925）\n  - to: other_name\n    type: builds-on\nsupersedes:         # 替代关系\n  - old_name\n---\n<body>\n```\n\n资料来源：[src/store/memory.ts:40-60]()\n\n## 核心模块\n\n### CLI 模块\n\n入口文件 `src/index.ts` 负责命令行参数解析和子命令分发：\n\n```mermaid\ngraph LR\n    A[commonplace CLI] --> B[migrate]\n    A --> C[graph]\n    B --> D[scan - 扫描并嵌入]\n    B --> E[import - 导入外部记忆]\n    B --> F[prune - 清理悬挂引用]\n```\n\n资料来源：[src/index.ts:1-50]()\n\n### 内存存储层\n\n`MemoryStore`（`src/store/memory-store.ts`）是核心存储引擎，提供以下能力：\n\n| 方法 | 功能 |\n|------|------|\n| `scan()` | 扫描目录，检测/生成边车嵌入 |\n| `save()` | 保存新记忆 |\n| `delete()` | 删除记忆 |\n| `search()` | 语义搜索 |\n| `list()` | 列出所有记忆 |\n| `linkEdge()` | 添加记忆间关系 |\n| `unlinkEdge()` | 移除记忆间关系 |\n\n资料来源：[src/store/memory-store.ts:1-100]()\n\n### 内容哈希机制\n\n`contentSha` 函数计算记忆内容的规范哈希：\n\n```\nSHA256(`${type}\\n${name}\\n${description}\\n${body}`)\n```\n\n注意：关系字段（`relations`、`supersedes`）不参与哈希计算，添加或移除关系边不会使嵌入失效。这确保了边的修改不会触发不必要的重新嵌入。\n\n资料来源：[src/store/memory.ts:80-95]()\n\n### 提及提取\n\n`src/store/mentions.ts` 实现 `[[name]]` 语法提取：\n\n- 扫描记忆文件 body 中的 `[[name]]` 模式\n- 仅提取符合 `^[a-z0-9_]+$` 的名称\n- 通过 `MemoryGraph.addMentionsEdge` 建立提及关系\n- 可通过 `COMMONPLACE_EXTRACT_MENTIONS=false` 环境变量禁用\n\n资料来源：[src/store/mentions.ts:1-40]()\n\n### 原子写入\n\n`atomicWrite`（`src/store/atomic-write.ts`）确保写入原子性：\n\n1. 在同目录创建临时文件\n2. 写入数据\n3. 使用 `rename(2)` 原子替换目标\n4. 验证源和目标在同一文件系统\n\n资料来源：[src/store/atomic-write.ts:1-50]()\n\n## 关系图系统（DAR-925）\n\n记忆之间可以建立有向关系边：\n\n| 关系类型 | 语义 | 搜索默认包含 |\n|----------|------|--------------|\n| `related-to` | 一般关联 | 是 |\n| `builds-on` | 基于某记忆构建 | 是 |\n| `contradicts` | 与某记忆矛盾 | 否 |\n| `child-of` | 某记忆的子项 | 否 |\n| `supersedes` | 替代某旧记忆 | 否 |\n| `mentions` | 正文中提及 | 否 |\n\n`MemoryGraph` 维护内存中的邻接表，支持 BFS 遍历和路径查询。\n\n资料来源：[src/server/handlers.ts:10-25]()\n\n## MCP 工具接口\n\n系统通过 MCP 暴露四个核心工具：\n\n### memory_save\n\n保存新记忆，参数包括名称、类型、描述和内容。拒绝覆盖已有记忆，合约要求先删除再保存。\n\n### memory_search\n\n语义搜索记忆，返回按相关性排序的匹配列表。支持按类型过滤和作用域限定。\n\n### memory_list\n\n列出记忆名称，支持按类型过滤。\n\n### memory_path\n\n图遍历查询，返回两记忆间的路径。\n\n资料来源：[README.md:75-150]()\n\n## 迁移与导入\n\n### migrate 命令\n\n`commonplace migrate <dir>` 命令用于迁移现有记忆目录：\n\n1. 扫描 `.md` 文件，嵌入缺失或过时的边车\n2. 清理孤立边车（无对应 `.md` 的 `.embedding`）\n3. 可选：剪除悬挂引用（`--prune-dangling`）\n\n资料来源：[src/cli/migrate.ts:50-100]()\n\n### Claude Code 导入\n\n支持从 Claude Code 的自动记忆目录导入兼容文件：\n\n```\n~/.claude/projects/*/memory/*.md\n```\n\n导入逻辑：检测候选文件，如目标 `<name>.md` 已存在则跳过，否则复制源码并执行扫描/嵌入。\n\n资料来源：[src/cli/migrate.ts:120-160]()\n\n## 配置与部署\n\n### 环境变量\n\n| 变量 | 默认值 | 用途 |\n|------|--------|------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | 用户存储路径 |\n| `COMMONPLACE_PROJECT_DIR` | - | 项目存储路径（覆盖检测） |\n| `COMMONPLACE_MODEL_ID` | - | 指定嵌入模型 |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `true` | 启用提及提取 |\n\n资料来源：[CLAUDE.md:25-35]()\n\n### 依赖技术栈\n\n- **运行时**：Node.js 20+\n- **包管理**：pnpm\n- **嵌入引擎**：transformers.js\n- **协议**：MCP (Model Context Protocol)\n- **测试**：make test\n- **类型检查**：make typecheck\n- **构建**：make build\n\n## 开发工作流\n\n```mermaid\ngraph TD\n    A[从 main 创建功能分支] --> B[开发与测试]\n    B --> C[提交 PR]\n    C --> D[CI 检查<br/>typecheck + lint + build + test]\n    D --> E{通过?}\n    E -->|是| F[Squash 合并到 main]\n    E -->|否| B\n    F --> G[推送 tag 触发 Release]\n    G --> H[自动发布 npm 包]\n```\n\n资料来源：[CONTRIBUTING.md:1-50]()\n\n## 状态与里程碑\n\n| 阶段 | 状态 | 说明 |\n|------|------|------|\n| v0.1 | 进行中 | 基础记忆 CRUD、语义搜索 |\n| DAR-911 | 完成 | 内存文件 I/O |\n| DAR-910 | 完成 | 嵌入生成 |\n| DAR-925 | 完成 | 关系图系统 |\n| DAR-926 | 进行中 | 悬挂引用处理 |\n| DAR-927 | 完成 | 提及提取 |\n| DAR-928 | 待开始 | MCP 编辑工具 |\n\n## 快速入门\n\n1. 安装并配置 MCP 服务器\n2. 重启 Claude Code 会话\n3. 使用 `memory_save` 保存第一条记忆\n4. 通过 `memory_search` 和 `memory_list` 检索记忆\n\n资料来源：[README.md:25-40]()\n\n---\n\n**最后更新**：基于 repository main 分支，内容涵盖核心架构、存储模型、工具接口和开发流程。\n\n---\n\n<a id='page-quickstart'></a>\n\n## 快速入门与安装\n\n### 相关页面\n\n相关主题：[项目概览](#page-overview)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n- [CONTRIBUTING.md](https://github.com/rickbassham/commonplace/blob/main/CONTRIBUTING.md)\n- [package.json](https://github.com/rickbassham/commonplace/blob/main/package.json)\n- [.nvmrc](https://github.com/rickbassham/commonplace/blob/main/.nvmrc)\n</details>\n\n# 快速入门与安装\n\n## 概述\n\nCommonplace 是一个本地优先的个人知识管理工具，以 MCP（Model Context Protocol）服务器形式运行。它将笔记存储为带有 YAML 前缀的纯 Markdown 文件，嵌入向量存储在 `.embedding` 侧边文件中，语义搜索完全离线运行，底层使用 `transformers.js` + `bge-base-en-v1.5` 模型实现。\n\n本节介绍 Commonplace 的完整安装流程、系统要求、环境配置以及与 Claude Code 的集成方法。\n\n## 系统要求\n\n### Node.js 环境\n\nCommonplace 要求 Node.js 版本 **20 或更高**。项目通过 `.nvmrc` 文件声明了版本要求：\n\n```bash\n20\n```\n\n同时 `package.json` 的 `engines` 字段也做了约束声明。\n\n### 包管理器\n\n| 包管理器 | 支持状态 |\n|---------|---------|\n| pnpm | ✅ 唯一支持 |\n| npm | ❌ 不支持 |\n| yarn | ❌ 不支持 |\n\n> 资料来源：[CLAUDE.md:30]()\n\n### 技术栈\n\n| 技术 | 版本/要求 | 用途 |\n|------|----------|------|\n| TypeScript | 严格模式, ES2022 目标 | 源码编写 |\n| ESM | NodeNext 模块输出 | 模块系统 |\n| vitest | 最新版 | 单元和集成测试 |\n| @huggingface/transformers | 最新版 | 本地嵌入推理 |\n| @modelcontextprotocol/sdk | 最新版 | MCP stdio 服务器接口 |\n\n> 资料来源：[CLAUDE.md:24-37]()\n\n## 安装流程\n\n### 步骤一：克隆仓库\n\n```bash\ngit clone https://github.com/rickbassham/commonplace.git\ncd commonplace\n```\n\n### 步骤二：安装依赖\n\n```bash\npnpm install\n```\n\n### 步骤三：构建项目\n\n```bash\npnpm build\n```\n\n构建过程会：\n- 编译 TypeScript 源码到 ESM 格式\n- 输出到 `dist/` 目录\n- 生成两个可执行入口：`commonplace` 和 `commonplace-mcp`\n\n> 资料来源：[CLAUDE.md:48-50]()\n\n## Claude Code 集成配置\n\n### 添加 MCP 服务器\n\n在 Claude Code 配置中添加以下服务器配置：\n\n```json\n{\n  \"mcpServers\": {\n    \"commonplace\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/commonplace/dist/bin/commonplace-mcp.js\"]\n    }\n  }\n}\n```\n\n完成配置后，重启所有正在运行的 Claude Code 会话，四个记忆工具即可使用：\n\n- `memory_save`\n- `memory_list`\n- `memory_delete`\n- `memory_search`\n\n> 资料来源：[README.md:48-58]()\n\n## 环境变量配置\n\n### 存储路径配置\n\n| 环境变量 | 默认值 | 说明 |\n|---------|-------|------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | 用户级记忆存储路径，始终加载 |\n| `COMMONPLACE_PROJECT_DIR` | 项目根目录下的 `.commonplace/memory` | 项目级记忆存储路径，按需加载 |\n\n### 功能开关\n\n| 环境变量 | 默认值 | 说明 |\n|---------|-------|------|\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | 控制 `[[name]]` 提及提取功能，设为 `'false'` 可禁用 |\n\n> 资料来源：[CLAUDE.md:53-57]()\n\n### 记忆存储架构\n\n```mermaid\ngraph TD\n    subgraph 用户存储\n        USER_DIR[\"COMMONPLACE_USER_DIR<br/>(~/.commonplace/memory)\"]\n    end\n    \n    subgraph 项目存储\n        PROJ_DIR[\"COMMONPLACE_PROJECT_DIR<br/>(按需加载)\"]\n    end\n    \n    subgraph 记忆文件\n        MD[\"<name>.md<br/>YAML 前缀 + Markdown 正文\"]\n        EMB[\"<name>.embedding<br/>二进制嵌入向量\"]\n    end\n    \n    USER_DIR --> MD\n    PROJ_DIR --> MD\n    MD --> EMB\n```\n\n## 记忆类型系统\n\n### 四种记忆类型\n\n| 类型 | 用途 | 示例 |\n|------|------|------|\n| `user` | 个人规则、偏好和身份信息 | 工作时间偏好、写作风格 |\n| `feedback` | 修正和从以往行为中学到的教训 | 不要擅自缩减范围 |\n| `project` | 项目特定的上下文信息 | 架构笔记、代码约定 |\n| `reference` | 持久化的中立知识 | API 形状、公式、引用 |\n\n> 资料来源：[README.md:60-73]()\n\n## CLI 命令行工具\n\n### 可执行文件\n\n| 命令 | 路径 | 用途 |\n|------|------|------|\n| `commonplace` | `dist/index.js` | CLI 子命令接口 |\n| `commonplace-mcp` | `dist/bin/commonplace-mcp.js` | MCP stdio 服务器 |\n\n### 迁移命令\n\n```bash\n# 检测已知外部记忆源\ncommonplace migrate\n\n# 从指定源导入记忆\ncommonplace migrate --from claude-code\n\n# 预览模式（不写入）\ncommonplace migrate --from claude-code --dry-run\n\n# 脚本化运行\ncommonplace migrate --from claude-code --auto\n\n# 为现有记忆目录重建侧边文件\ncommonplace migrate <dir>\ncommonplace migrate <dir> --dry-run\ncommonplace migrate <dir> --prune-dangling\n```\n\n> 资料来源：[README.md:17-23]()\n\n## 验证安装\n\n### 构建验证\n\n```bash\nmake build\nmake typecheck\nmake lint\n```\n\n### 运行测试\n\n```bash\nmake test\n```\n\n### 审计依赖\n\n```bash\nmake audit\n```\n\n> 资料来源：[CONTRIBUTING.md:24-26]()\n\n## 目录结构概览\n\n```\ncommonplace/\n├── dist/                    # 构建输出\n│   ├── index.js            # CLI 入口\n│   └── bin/\n│       └── commonplace-mcp.js  # MCP 服务器入口\n├── src/\n│   ├── embedder/           # transformers.js 封装\n│   ├── store/              # Markdown + 侧边文件 I/O\n│   └── server/             # MCP 服务器处理程序\n├── package.json\n└── .nvmrc                  # Node.js 版本声明\n```\n\n## 常见问题\n\n### Q: npm 或 yarn 可以使用吗？\n\n不可以。项目仅支持 pnpm 作为包管理器。使用其他包管理器会导致依赖安装失败或构建错误。\n\n### Q: Node.js 18 可以使用吗？\n\n不可以。必须使用 Node.js 20 或更高版本。\n\n### Q: 记忆文件存储在哪里？\n\n默认情况下，用户级记忆存储在 `~/.commonplace/memory`，项目级记忆存储在项目根目录的 `.commonplace/memory` 下。\n\n### Q: 如何重建嵌入向量？\n\n使用 `commonplace migrate <dir>` 命令可重新扫描目录并重建所有 `.embedding` 侧边文件。\n\n---\n\n<a id='page-architecture'></a>\n\n## 系统架构\n\n### 相关页面\n\n相关主题：[项目概览](#page-overview), [嵌入模型与语义搜索](#page-embedder), [存储系统](#page-storage)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n- [src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n</details>\n\n# 系统架构\n\n## 概述\n\nCommonplace 是一个为 Claude Code 提供持久化记忆功能的 MCP (Model Context Protocol) 工具系统。它通过 markdown 文件存储记忆内容，支持语义搜索和关系图谱管理。资料来源：[CLAUDE.md:1]()\n\n该系统具有以下核心设计原则：\n\n- **单一真相来源** — `.md` 文件是数据的唯一真实来源，`.embedding` 等辅助文件可随时从源文件重新生成\n- **无覆盖写入** — `memory_save` 工具拒绝覆盖已有条目，必须先删除再保存\n- **双存储架构** — 支持用户级存储和项目级存储分离\n- **图关系管理** — 支持在记忆之间建立显式关系边\n\n资料来源：[CLAUDE.md:16-19]()\n\n---\n\n## 整体架构\n\n```mermaid\ngraph TB\n    subgraph \"CLI 层\"\n        CLI[命令行入口<br/>src/index.ts]\n        MIGRATE[迁移命令<br/>src/cli/migrate.ts]\n    end\n\n    subgraph \"MCP 服务器层\"\n        SERVER[MCP Server<br/>src/server/server.ts]\n        HANDLERS[请求处理器<br/>src/server/handlers.ts]\n    end\n\n    subgraph \"核心存储层\"\n        STORE[MemoryStore<br/>src/store/memory-store.ts]\n        MEMORY[Memory I/O<br/>src/store/memory.ts]\n        GRAPH[MemoryGraph<br/>关系图谱]\n        MENTIONS[Mentions 提取器<br/>src/store/mentions.ts]\n    end\n\n    subgraph \"嵌入层\"\n        EMBEDDER[Embedder<br/>src/embedder/index.ts]\n        EMBEDDINGS[.embedding 侧文件]\n    end\n\n    subgraph \"存储后端\"\n        USER_DIR[用户存储<br/>~/.commonplace/memory]\n        PROJECT_DIR[项目存储<br/>.commonplace/memory]\n    end\n\n    CLI --> MIGRATE\n    CLI --> STORE\n    SERVER --> HANDLERS\n    HANDLERS --> STORE\n    STORE --> MEMORY\n    STORE --> GRAPH\n    STORE --> MENTIONS\n    STORE --> EMBEDDER\n    EMBEDDER --> EMBEDDINGS\n    MEMORY --> USER_DIR\n    MEMORY --> PROJECT_DIR\n    GRAPH --> USER_DIR\n    GRAPH --> PROJECT_DIR\n```\n\n---\n\n## 核心组件\n\n### 1. CLI 入口层\n\n#### 命令行入口 (`src/index.ts`)\n\n负责命令解析和分发，是系统的最外层接口。\n\n**支持的子命令：**\n\n| 子命令 | 功能 | 源码位置 |\n|--------|------|----------|\n| `migrate` | 扫描、嵌入、清理记忆目录 | src/index.ts:28-50 |\n| `graph` | 图关系查询 | src/index.ts:34-42 |\n\nCLI 采用延迟加载策略：只有在确认需要执行时才构造 `Embedder` 实例，避免不必要的模型加载开销。\n\n资料来源：[src/index.ts:38-47]()\n\n```typescript\n// 延迟 embedder 工厂函数\nembedderFactory: () => new Embedder(resolveModelId(process.env))\n```\n\n#### 迁移命令 (`src/cli/migrate.ts`)\n\n提供记忆目录的维护功能：\n\n1. **扫描与嵌入** — 为缺失或过时的 `.embedding` 侧文件重新生成向量\n2. **孤立文件清理** — 移除无对应 `.md` 的 `.embedding` 文件\n3. **悬空边修剪** — 可选功能，移除指向不存在记忆的关系引用\n\n资料来源：[src/cli/migrate.ts:58-85]()\n\n---\n\n### 2. MCP 服务器层\n\n#### 服务器 (`src/server/server.ts`)\n\nMCP 服务器负责与 Claude Code 会话建立通信，提供四个核心工具：\n\n| 工具名 | 功能 |\n|--------|------|\n| `memory_save` | 保存记忆到 markdown 文件 |\n| `memory_search` | 语义搜索记忆 |\n| `memory_list` | 列出/过滤记忆 |\n| `memory_path` | 获取记忆文件路径 |\n\n资料来源：[CLAUDE.md:60-100]()\n\n#### 请求处理器 (`src/server/handlers.ts`)\n\n处理 MCP 工具调用的核心逻辑，包括：\n\n- 参数验证与类型检查\n- 搜索结果的聚合与排序\n- 默认扩展类型的配置\n\n```typescript\nexport const DEFAULT_EXPAND_TYPES: readonly EdgeType[] = ['builds-on', 'related-to'] as const;\n```\n\n资料来源：[src/server/handlers.ts:8-12]()\n\n---\n\n### 3. 核心存储层\n\n#### MemoryStore (`src/store/memory-store.ts`)\n\n系统的核心存储引擎，管理内存索引和文件系统同步。\n\n**主要职责：**\n\n- 加载与缓存记忆条目\n- 增量图索引维护\n- 原子写入操作\n- 扫描与嵌入管理\n\n**关键方法：**\n\n| 方法 | 功能 |\n|------|------|\n| `scan()` | 扫描目录，同步嵌入状态 |\n| `save()` | 保存新记忆 |\n| `delete()` | 删除记忆 |\n| `search()` | 语义向量搜索 |\n| `list()` | 列出记忆 |\n| `linkEdge()` | 添加关系边 |\n| `unlinkEdge()` | 移除关系边 |\n\n资料来源：[src/store/memory-store.ts:1-50]()\n\n#### Memory I/O (`src/store/memory.ts`)\n\n负责 markdown 文件的序列化与反序列化。\n\n**文件格式规范：**\n\n```yaml\n---\nname: memory_name\ndescription: 简短描述\ntype: user | feedback | project | reference\nrelations:       # 可选，关系列表\n  - to: other_name\n    type: builds-on\nsupersedes:      # 可选，替代列表\n  - old_name\n---\n<body>\n```\n\n**内容哈希计算：**\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${memory.description}\\n${memory.body}`, 'utf8')\n    .digest('hex');\n```\n\n注意：`contentSha` 仅基于类型、名称、描述和正文计算，**不包括** `relations` 和 `supersedes` 字段。这意味着关系的增删不会导致嵌入失效。\n\n资料来源：[src/store/memory.ts:90-97]()\n\n#### MemoryGraph (`src/store/memory-store.ts`)\n\n内存中的关系图数据结构，支持：\n\n- **边的类型**：`builds-on`、`related-to`、`contradicts`、`child-of`、`supersedes`、`mentions`\n- **BFS 遍历**：支持深度限制和边类型过滤\n- **增量更新**：通过 `addEdge()` / `removeEdge()` 增量维护\n\n#### Mentions 提取器 (`src/store/mentions.ts`)\n\n从记忆正文中提取 `[[name]]` 形式的内联引用。\n\n- 默认启用，可通过 `COMMONPLACE_EXTRACT_MENTIONS=false` 环境变量禁用\n- 仅提取符合 `[a-z0-9_]+` 命名规则的引用\n- 在 `scan()` 和 `save()` 时自动调用，结果自动写入图的 `mentions` 边\n\n资料来源：[src/store/mentions.ts:1-30]()\n\n---\n\n### 4. 嵌入层\n\n#### Embedder (`src/embedder/index.ts`)\n\n使用 Transformers.js 进行本地向量嵌入生成。\n\n**嵌入流程：**\n\n1. 接收文本内容\n2. 使用预训练模型生成向量表示\n3. 将向量序列化写入 `.embedding` 侧文件\n\n**侧文件新鲜度判断标准：**\n\n- `.embedding` 文件存在且可解码\n- `modelId` 与当前 embedder 一致\n- `dim` 维度匹配\n- `contentSha` 与源文件哈希一致\n\n任一条件不满足都会触发重新嵌入。\n\n资料来源：[src/store/memory-store.ts:180-195]()\n\n---\n\n## 双存储架构\n\n```mermaid\ngraph LR\n    subgraph \"用户存储\"\n        USER[~/.commonplace/memory]\n        USER_TYPE[user / feedback<br/>类型]\n    end\n\n    subgraph \"项目存储\"\n        PROJECT[<project>/.commonplace/memory]\n        PROJECT_TYPE[project / reference<br/>类型]\n    end\n\n    USER --> USER_TYPE\n    PROJECT --> PROJECT_TYPE\n```\n\n### 存储位置\n\n| 存储类型 | 路径 | 加载时机 |\n|----------|------|----------|\n| 用户存储 | `COMMONPLACE_USER_DIR` (默认 `~/.commonplace/memory`) | 始终加载 |\n| 项目存储 | `COMMONPLACE_PROJECT_DIR` 或 `<project-root>/.commonplace/memory` | 检测到项目根目录时加载 |\n\n### 检测优先级\n\n项目存储的路径按以下优先级确定：\n\n1. `COMMONPLACE_PROJECT_DIR` 环境变量（显式覆盖，始终优先）\n2. MCP `roots/list` 协议检测到的项目根目录\n3. 当前工作目录\n\n资料来源：[CLAUDE.md:130-150]()\n\n### 搜索行为\n\n搜索时，结果会跨两个存储聚合，按相似度降序排列。返回结果中包含 `scope: 'user' | 'project'` 字段标识来源。\n\n---\n\n## 原子写入机制\n\n```mermaid\ngraph TD\n    A[写入请求] --> B[创建临时文件<br/>`<name>.<random>.tmp`]\n    B --> C{同文件系统?}\n    C -->|否| D[抛出错误]\n    C -->|是| E[写入数据到临时文件]\n    E --> F[fsync 刷新]\n    F --> G[rename 到目标路径]\n    G --> H[完成]\n    \n    D --> I[原子性保证失败<br/>拒绝跨文件系统操作]\n```\n\n`atomicWrite` 实现通过临时文件 + rename 序列保证写入原子性，防止系统崩溃导致文件损坏。\n\n资料来源：[src/store/atomic-write.ts:1-25]()\n\n---\n\n## 内存类型体系\n\n| 类型 | 用途 | 存储位置 |\n|------|------|----------|\n| `user` | 个人规则、偏好、身份事实 | 用户存储 |\n| `feedback` | 来自以往行为的修正和经验教训 | 用户存储 |\n| `project` | 项目级上下文，如架构笔记、约定 | 项目存储 |\n| `reference` | 持久性知识，如 API 形状、公式、引用 | 项目存储 |\n\n所有四个工具都接受 `type` 参数进行过滤。\n\n资料来源：[CLAUDE.md:30-45]()\n\n---\n\n## 关系边类型\n\n| 边类型 | 语义含义 | 默认展开 |\n|--------|----------|----------|\n| `builds-on` | 基于某记忆构建 | ✓ |\n| `related-to` | 相关但不明确 | ✓ |\n| `mentions` | 正文中提及 | ✗ |\n| `supersedes` | 替代某记忆 | ✗ |\n| `contradicts` | 与某记忆矛盾 | ✗ |\n| `child-of` | 从属关系 | ✗ |\n\n`builds-on` 和 `related-to` 被设为默认展开类型，因为它们最可能提供有用的上下文。\n\n资料来源：[src/server/handlers.ts:8-12]()\n\n---\n\n## 扫描与嵌入流程\n\n```mermaid\ngraph TD\n    A[migrate 命令] --> B[遍历 .md 文件]\n    B --> C{侧文件新鲜?}\n    C -->|是| D[跳过]\n    C -->|否| E[调用 Embedder]\n    E --> F[写入 .embedding]\n    D --> G{还有文件?}\n    F --> G\n    G -->|是| B\n    G -->|否| H[孤立文件清理]\n    H --> I[输出统计报告]\n```\n\n扫描完成后会遍历目录，移除任何无对应 `.md` 的 `.embedding` 文件（孤立侧文件清理）。\n\n资料来源：[src/store/memory-store.ts:165-180]()\n\n---\n\n## 数据流向\n\n```mermaid\ngraph LR\n    A[MCP 工具调用] --> B[参数验证]\n    B --> C[MemoryStore 操作]\n    C --> D{操作类型}\n    D -->|save| E[序列化 Markdown]\n    D -->|search| F[向量搜索]\n    D -->|linkEdge| G[更新关系图]\n    E --> H[原子写入]\n    F --> I[匹配结果]\n    G --> J[图索引更新]\n    H --> K[文件系统]\n    I --> L[结果聚合]\n    J --> K\n    L --> M[返回结果]\n```\n\n---\n\n## 环境变量配置\n\n| 变量 | 默认值 | 作用 |\n|------|--------|------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | 用户存储路径 |\n| `COMMONPLACE_PROJECT_DIR` | - | 项目存储路径（覆盖检测） |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `true` | 启用 `[[name]]` 提取 |\n\n资料来源：[src/store/mentions.ts:18-20]()\n\n---\n\n## 关键设计决策\n\n### 1. 嵌入哈希稳定性\n\n`contentSha` 故意排除 `relations` 和 `supersedes` 字段。这意味着修改记忆之间的关系不会导致嵌入重新计算，保证嵌入的稳定性。\n\n资料来源：[src/store/memory.ts:82-91]()\n\n### 2. 写入安全\n\n使用原子写入（临时文件 + rename）确保数据一致性，防止崩溃导致的文件损坏。\n\n### 3. 图索引增量维护\n\n`linkEdge` 和 `unlinkEdge` 方法直接操作内存中的图结构，无需完整重新扫描目录。目录修改时间基准在操作后刷新，防止不必要的重新扫描。\n\n资料来源：[src/store/memory-store.ts:220-230]()\n\n### 4. 延迟模型加载\n\nCLI 层的 `embedderFactory` 工厂函数采用延迟实例化策略，只有在实际需要嵌入时才加载 Transformers.js 模型。\n\n资料来源：[src/index.ts:44-47]()\n\n---\n\n<a id='page-tech-stack'></a>\n\n## 技术栈详解\n\n### 相关页面\n\n相关主题：[系统架构](#page-architecture)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [package.json](https://github.com/rickbassham/commonplace/blob/main/package.json)\n- [tsconfig.json](https://github.com/rickbassham/commonplace/blob/main/tsconfig.json)\n- [tsconfig.build.json](https://github.com/rickbassham/commonplace/blob/main/tsconfig.build.json)\n- [vitest.config.ts](https://github.com/rickbassham/commonplace/blob/main/vitest.config.ts)\n- [eslint.config.js](https://github.com/rickbassham/commonplace/blob/main/eslint.config.js)\n- [src/embedder/](https://github.com/rickbassham/commonplace/blob/main/src/embedder/)\n- [src/store/](https://github.com/rickbassham/commonplace/blob/main/src/store/)\n- [src/server/](https://github.com/rickbassham/commonplace/blob/main/src/server/)\n</details>\n\n# 技术栈详解\n\n## 概述\n\nCommonplace 是一个基于 TypeScript 构建的记忆管理工具，通过 MCP（Model Context Protocol）协议与 Claude Code 等 AI 代理集成。其技术栈围绕本地向量嵌入推理、Markdown 文件存储和 MCP 协议通信三大核心能力展开。\n\n项目采用 Node.js 作为运行时环境，要求 Node >=20，代码以 ESM（ECMAScript Modules）格式输出，不使用 CommonJS。资料来源：[CLAUDE.md]()\n\n## 核心架构分层\n\n```mermaid\ngraph TD\n    subgraph \"表现层\"\n        CLI[CLI 命令行]\n        MCP[MCP 服务器]\n    end\n    \n    subgraph \"服务层\"\n        HANDLERS[MCP Handlers]\n        EMBEDDER[嵌入器]\n    end\n    \n    subgraph \"存储层\"\n        MEMORY_STORE[MemoryStore]\n        GRAPH[MemoryGraph]\n    end\n    \n    subgraph \"文件系统\"\n        MD[.md 文件]\n        EMBEDDING[.embedding 侧文件]\n    end\n    \n    CLI --> HANDLERS\n    MCP --> HANDLERS\n    HANDLERS --> EMBEDDER\n    HANDLERS --> MEMORY_STORE\n    MEMORY_STORE --> GRAPH\n    MEMORY_STORE --> MD\n    MEMORY_STORE --> EMBEDDING\n```\n\n## 编程语言与工具链\n\n### TypeScript\n\n项目使用 TypeScript 进行开发，采用严格模式（strict mode）和 ES2022 编译目标。\n\n| 配置项 | 值 |\n|--------|-----|\n| 目标版本 | ES2022 |\n| 模块系统 | ESM (NodeNext) |\n| 类型检查 | strict mode |\n| 编译输出 | ESM 格式 |\n\n资料来源：[CLAUDE.md]()\n\n### 代码质量工具\n\n| 工具 | 用途 |\n|------|------|\n| ESLint | 代码静态分析 |\n| vitest | 单元测试和集成测试 |\n| TypeScript Compiler | 类型检查与编译 |\n\n项目配置了多个 Make 目标来执行质量检查：\n\n- `make typecheck` - TypeScript 类型检查\n- `make lint` - ESLint 代码检查\n- `make test` - vitest 测试执行\n- `make build` - 项目构建\n- `make audit` - 安全审计（非阻塞）\n\n资料来源：[CONTRIBUTING.md]()\n\n## 核心依赖库\n\n### 向量嵌入推理\n\n| 依赖 | 版本 | 用途 |\n|------|------|------|\n| @huggingface/transformers | 最新 | 本地 embedding 模型推理 |\n\n`src/embedder/` 目录封装了 transformers.js 的调用，提供类型化的 `embed(text) -> Float32Array` 接口，并隔离模型加载逻辑与业务代码的耦合。\n\n```mermaid\nsequenceDiagram\n    participant 调用方\n    participant Embedder\n    participant Transformers\n    \n    调用方->>Embedder: embed(text)\n    Embedder->>Transformers: 加载模型\n    Transformers-->>Embedder: 模型就绪\n    Embedder->>Transformers: 执行推理\n    Transformers-->>Embedder: Float32Array\n    Embedder-->>调用方: 返回嵌入向量\n```\n\n资料来源：[CLAUDE.md]()\n\n### MCP 协议通信\n\n| 依赖 | 用途 |\n|------|------|\n| @modelcontextprotocol/sdk | stdio MCP 服务器实现 |\n\n`src/server/` 目录包含 MCP 工具处理器和资源处理器，负责将 MemoryStore 和 Embedder 的能力暴露给外部 MCP 客户端。\n\n项目定义了两个独立的 bin 入口：\n\n- `commonplace` -> `dist/index.js`：CLI 命令行界面\n- `commonplace-mcp` -> `dist/bin/commonplace-mcp.js`：stdio MCP 服务器\n\n资料来源：[src/index.ts]()\n\n### 文件处理\n\n| 依赖 | 用途 |\n|------|------|\n| yaml | YAML frontmatter 序列化/反序列化 |\n| crypto (内置) | SHA256 内容哈希计算 |\n| fs/promises | 原子写入文件系统操作 |\n\n## 数据存储架构\n\n### 存储目录结构\n\n```mermaid\ngraph LR\n    subgraph \"用户存储 ~/\\.commonplace/memory\"\n        MD1[name1.md]\n        EMB1[name1.embedding]\n        MD2[name2.md]\n        EMB2[name2.embedding]\n    end\n    \n    subgraph \"项目存储 \\<project\\>/\\.commonplace/memory\"\n        MD3[proj_name1.md]\n        EMB3[proj_name1.embedding]\n    end\n```\n\n### Memory 文件格式\n\n每个记忆以 Markdown 文件形式存储，包含 YAML frontmatter 和正文内容：\n\n```yaml\n---\nname: memory_name\ndescription: 描述文本\ntype: user | feedback | project | reference\nrelations:       # 可选，定义关系图\n  - to: other_name\n    type: builds-on\nsupersedes:      # 可选，定义替代关系\n  - old_name\n---\n<body>\n```\n\n记忆类型说明：\n\n| 类型 | 用途 |\n|------|------|\n| user | 个人规则、偏好和身份事实 |\n| feedback | 代理行为纠正和经验教训 |\n| project | 项目特定上下文 |\n| reference | 持久性中性知识 |\n\n资料来源：[src/store/memory.ts]()\n\n### 内容哈希机制\n\n`contentSha` 函数计算记忆内容的 SHA256 哈希值，用于判断是否需要重新生成 embedding。哈希计算范围包括：\n\n- `type`\n- `name`\n- `description`\n- `body`\n\n图关系字段（`relations`、`supersedes`）**不参与**哈希计算，确保图结构的修改不会使已有的 embedding 失效。\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${memory.description}\\n${memory.body}`, 'utf8')\n    .digest('hex');\n```\n\n资料来源：[src/store/memory.ts]()\n\n### 原子写入\n\n`src/store/atomic-write.ts` 实现了跨文件系统的原子写入保护，确保并发写入时的数据完整性：\n\n1. 在目标目录创建临时文件（`.basename.<random>.tmp`）\n2. 验证临时文件和目标目录在同一文件系统\n3. 原子重命名临时文件到目标文件\n\n资料来源：[src/store/atomic-write.ts]()\n\n## 包管理\n\n### pnpm\n\n项目使用 pnpm 作为唯一的包管理器，不支持 npm 或 yarn。\n\n```bash\n# 安装依赖\npnpm install\n\n# 添加依赖\npnpm add <package>\n\n# 运行测试\npnpm test\n```\n\n### CI 自动化\n\n项目在 Node 20 和 Node 22 两个版本上运行 CI，确保兼容性。\n\n```mermaid\ngraph LR\n    A[PR 创建] --> B[CI 触发]\n    B --> C{make typecheck}\n    B --> D{make lint}\n    B --> E{make build}\n    B --> F{make test}\n    B --> G{make audit}\n    C --> H{全部通过?}\n    D --> H\n    E --> H\n    F --> H\n    H -->|是| I[可合并]\n    H -->|否| J[阻塞合并]\n```\n\n资料来源：[CONTRIBUTING.md]()\n\n## 关键模块职责\n\n| 模块路径 | 职责 |\n|---------|------|\n| `src/embedder/` | transformers.js 封装，embedding 推理 |\n| `src/store/` | Markdown I/O，YAML frontmatter 编解码，vector index |\n| `src/server/` | MCP 协议处理器，工具/资源暴露 |\n| `src/cli/migrate.ts` | CLI 命令行参数解析和迁移逻辑 |\n| `src/index.ts` | CLI 分发器，双 bin 入口协调 |\n\n## 环境配置\n\n项目使用环境变量进行配置管理，由 DAR-913 统一管理：\n\n| 环境变量 | 说明 |\n|---------|------|\n| COMMONPLACE_USER_DIR | 用户记忆存储路径（默认 `~/.commonplace/memory`） |\n| COMMONPLACE_PROJECT_DIR | 项目记忆存储路径 |\n| COMMONPLACE_EXTRACT_MENTIONS | 是否提取 `[[name]]` 提及（默认开启） |\n\n## 测试框架\n\nvitest 用于项目的单元测试和集成测试：\n\n```typescript\n// 测试示例结构\nimport { describe, it, expect } from 'vitest';\n\ndescribe('MemoryStore', () => {\n  it('should load memories from directory', async () => {\n    // 测试逻辑\n  });\n});\n```\n\n## 总结\n\nCommonplace 的技术栈设计遵循以下原则：\n\n1. **本地优先**：使用 transformers.js 实现本地 embedding 推理，无需外部 API\n2. **简单持久化**：以 Markdown + YAML 作为存储格式，确保数据可读性和可移植性\n3. **协议解耦**：通过 MCP SDK 暴露能力，支持多种 MCP 客户端集成\n4. **类型安全**：TypeScript 严格模式配合 ESLint 确保代码质量\n\n---\n\n<a id='page-embedder'></a>\n\n## 嵌入模型与语义搜索\n\n### 相关页面\n\n相关主题：[搜索功能详解](#page-search), [系统架构](#page-architecture)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.ts)\n- [src/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n- [src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n- [CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [CHANGELOG.md](https://github.com/rickbassham/commonplace/blob/main/CHANGELOG.md)\n</details>\n\n# 嵌入模型与语义搜索\n\n## 概述\n\nCommonplace 的嵌入模型与语义搜索子系统是该应用的核心能力之一。它使 MCP 服务器能够对用户的笔记进行语义相似度搜索，而非简单的关键词匹配。整个系统完全离线运行，不依赖任何云端 API，通过本地向量计算实现语义检索。\n\n核心设计原则：\n\n- **嵌入完全本地化**：使用 `@huggingface/transformers` 库配合 `bge-base-en-v1.5` 模型\n- **边车文件（Sidecar）模式**：`.embedding` 二进制文件与 `.md` 笔记一一对应，作为派生物可随时重建\n- **内容哈希校验**：通过 `contentSha` 确保嵌入与笔记内容的一致性\n\n资料来源：[CHANGELOG.md]()\n\n## 架构概览\n\n```mermaid\ngraph TD\n    A[\"📄 Memory (.md)\"] --> B[\"contentSha() 计算哈希\"]\n    A --> C[\"序列化内存对象\"]\n    B --> D[\"嵌入模型 bge-base-en-v1.5\"]\n    C --> E[\".embedding 边车文件\"]\n    D --> E\n    E --> F[\"向量数据库\"]\n    G[\"语义搜索查询\"] --> H[\"计算查询向量\"]\n    H --> I[\"余弦相似度计算\"]\n    F --> I\n    I --> J[\"Top-K 结果排序\"]\n    J --> K[\"返回 MemorySearchMatch\"]\n```\n\n## 内存文件结构与内容哈希\n\n### YAML Frontmatter 格式\n\n每篇笔记都是一个 Markdown 文件，前置 YAML 元数据：\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: other_name\n    type: builds-on\nsupersedes:\n  - old_name\n---\n<body>\n```\n\n资料来源：[src/store/memory.ts:44-60]()\n\n### contentSha 哈希算法\n\n`contentSha` 函数计算内存内容的规范表示，用于判断边车文件是否需要重建：\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${memory.description}\\n${memory.body}`, 'utf8')\n    .digest('hex');\n```\n\n**关键设计决策**：哈希仅基于 v0.1 基线 frontmatter（`type`、`name`、`description`）和正文 `body`。图字段 `relations` 和 `supersedes` **不参与**哈希计算。\n\n> 添加或删除图关系边**不应**导致嵌入失效，这是 DAR-925 的核心设计要求。\n\n资料来源：[src/store/memory.ts:25-35]()\n\n## 边车文件（Sidecar）机制\n\n### 边车文件格式\n\n`.embedding` 是二进制文件，包含以下结构：\n\n| 字段 | 描述 |\n|------|------|\n| Magic Bytes | 格式魔数 |\n| Version | 版本号 |\n| Length | 数据长度 |\n| modelId | 使用的嵌入模型标识 |\n| dim | 向量维度 |\n| contentSha | 对应笔记的哈希值 |\n| vector | 实际的嵌入向量数据 |\n\n资料来源：[src/store/memory-store.ts:140-150]()\n\n### 边车新鲜度判断\n\n`scan()` 方法在加载时判断每个边车文件是否可复用。满足以下**全部条件**时，边车被认为是\"新鲜的\"：\n\n| 条件 | 说明 |\n|------|------|\n| 文件存在 | `.embedding` 文件存在于磁盘 |\n| 解码成功 | Magic + Version + Length 校验通过 |\n| 模型匹配 | `decoded.modelId === embedder.modelId` |\n| 维度匹配 | `decoded.dim === embedder.dim` |\n| 哈希匹配 | `decoded.contentSha === contentSha(memoryAsRead)` |\n\n任一条件不满足都会触发重新嵌入并重写边车文件。\n\n资料来源：[src/store/memory-store.ts:140-160]()\n\n### 孤立边车清理\n\n扫描完成后，`scan()` 会进行第二轮目录遍历，移除任何没有对应 `.md` 文件的 `.embedding` 孤立边车。这些孤立文件在内存索引中不可达，保留它们只会无声地积累无效数据。\n\n```typescript\n// 孤立边车计数报告\nresult.orphaned  // 被清理的孤立边车数量\n```\n\n资料来源：[src/store/memory-store.ts:175-185]()\n\n## 扫描流程（Scan Pipeline）\n\n```mermaid\nsequenceDiagram\n    participant FS as 文件系统\n    participant Store as MemoryStore\n    participant Scan as scan()\n    participant Embedder as Embedder\n    participant Sidecar as .embedding\n\n    Scan->>FS: 遍历目录中的 *.md 文件\n    Scan->>FS: 检查对应的 .embedding 边车\n    alt 边车新鲜\n        Scan->>Scan: 复用现有边车\n    else 边车过期\n        Scan->>Embedder: 调用 embed(body)\n        Embedder-->>Scan: 返回向量\n        Scan->>FS: 原子写入新边车\n    end\n    Scan->>FS: 清理孤立的 .embedding 文件\n    Scan-->>Store: 更新内存索引\n```\n\n### 扫描选项\n\n```typescript\ninterface ScanOptions {\n  /** 是否为预演模式 */\n  dryRun?: boolean;\n  /** 是否删除悬挂边 */\n  pruneDangling?: boolean;\n}\n```\n\n在 `dryRun` 模式下，孤立边车计数会报告但不实际删除。\n\n资料来源：[src/store/memory-store.ts:130-145]()\n\n## 原子写入机制\n\n嵌入向量通过原子写入操作保存到边车文件，防止并发写入导致文件损坏：\n\n```mermaid\ngraph LR\n    A[\"写入请求\"] --> B[\"生成临时文件<br/>base.<8位随机hex>.tmp\"]\n    B --> C[\"写入临时文件\"]\n    C --> D{\"写入成功?\"}\n    D--否--> E[\"删除临时文件<br/>抛出错误\"]\n    D--是--> F[\"原子重命名<br/>tmp → target\"]\n    F --> G[\"完成\"]\n```\n\n关键特性：\n\n- **文件系统检查**：验证目标目录与临时文件目录在同一文件系统（`dev` 匹配）\n- **16位熵随机数**：充足的空间避免并发冲突\n- **原子重命名**：利用操作系统原子操作保证一致性\n\n资料来源：[src/store/atomic-write.ts:1-30]()\n\n## 语义搜索实现\n\n### Top-K 余弦相似度搜索\n\n搜索流程：\n\n1. 接收用户查询文本\n2. 使用嵌入模型将查询转换为向量\n3. 在内存索引中计算所有笔记的余弦相似度\n4. 按相似度降序排列\n5. 返回前 K 条结果\n\n```typescript\ninterface MemorySearchMatch {\n  name: string;\n  type: MemoryType;\n  description: string;\n  body: string;        // 完整正文，不截断\n  score: number;       // 余弦相似度，保留3位小数\n  relations: Relation[]; // 出边关系\n}\n```\n\n资料来源：[src/server/handlers.ts:35-55]()\n\n### 搜索结果丰富化\n\n搜索结果会额外返回笔记的图关系信息，但默认只包含 `builds-on` 和 `related-to` 两种边类型：\n\n```typescript\nexport const DEFAULT_EXPAND_TYPES: readonly EdgeType[] = \n  ['builds-on', 'related-to'] as const;\n```\n\n这是经过设计的决策——这两种边类型最可能暴露对代理有用的邻近节点。其他边类型（`mentions`、`supersedes`、`contradicts`、`child-of`）需要显式 opt-in。\n\n资料来源：[src/server/handlers.ts:15-20]()\n\n### 废弃笔记排除\n\n默认情况下，被 `supersedes` 字段引用的旧笔记会被排除在搜索结果之外。搜索结果的 `relations` 数组中**不包含** `supersedes` 边，该字段仅在内存的 YAML frontmatter 中作为单向声明存在。\n\n资料来源：[src/server/handlers.ts:55-65]()\n\n## MCP 工具接口\n\n系统通过 MCP stdio 服务器暴露以下与搜索相关的工具：\n\n### memory_search\n\n语义搜索工具，返回匹配的笔记及其相似度分数。\n\n### memory_list\n\n列出所有笔记，返回名称、类型、描述信息。\n\n### memory_save\n\n保存新笔记，自动触发嵌入生成。\n\n### memory_delete\n\n删除笔记及其关联的边车文件。\n\n### memory_link / memory_unlink\n\n图关系链接工具，用于建立笔记间的 `builds-on`、`related-to`、`contradicts`、`child-of` 关系。\n\n资料来源：[src/index.ts:1-30]()\n\n## 配置与环境变量\n\n| 环境变量 | 默认值 | 用途 |\n|----------|--------|------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | 用户记忆存储根目录 |\n| `COMMONPLACE_PROJECT_DIR` | 动态检测 | 项目级记忆存储目录 |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | 是否启用 `[[name]]` 提及提取 |\n\n嵌入模型 ID 通过 `resolveModelId(process.env)` 解析，环境变量配置由 DAR-913 规范。\n\n资料来源：[src/store/mentions.ts:20-30]()\n\n## CLI 命令行接口\n\n`migrate` 子命令提供边车管理的命令行入口：\n\n| 命令 | 功能 |\n|------|------|\n| `commonplace migrate --from claude-code` | 从 Claude Code 导入记忆 |\n| `commonplace migrate --dry-run` | 预演模式，不实际写入 |\n| `commonplace migrate --scan <dir>` | 扫描目录重建边车 |\n| `commonplace migrate --prune-dangling` | 清理悬挂边 |\n\n资料来源：[src/cli/migrate.ts:1-50]()\n\n## 性能考量\n\n### 懒加载嵌入器\n\n嵌入器（Embedder）构造函数本身很轻量，真正的模型加载发生在首次 `embed()` 调用时。这使得 `migrateMain` 可以先完成参数解析和目录验证，再按需构造嵌入器。\n\n```typescript\nembedderFactory: () => new Embedder(resolveModelId(process.env))\n```\n\n### mtime 基线刷新\n\n每次边车写入后，系统会刷新目录 mtime 基线，确保后续 `search()` / `list()` 调用不会误判为需要重新扫描：\n\n```typescript\nthis.#refreshMtimeBaseline();\n```\n\n资料来源：[src/store/memory-store.ts:280-295]()\n\n## 版本历史\n\n| 版本 | 变更内容 |\n|------|----------|\n| 0.1.0 | 初始发布：本地嵌入管道、bge-base-en-v1.5 模型、`.embedding` 边车、brute-force top-k 余弦搜索 |\n\n资料来源：[CHANGELOG.md]()\n\n## 相关模块\n\n| 模块 | 职责 |\n|------|------|\n| `src/embedder/index.ts` | 嵌入模型封装、向量生成 |\n| `src/store/memory.ts` | 内存对象序列化、contentSha 计算 |\n| `src/store/memory-store.ts` | 存储抽象、scan/save/search 核心逻辑 |\n| `src/store/atomic-write.ts` | 原子文件写入 |\n| `src/server/handlers.ts` | MCP 工具处理器 |\n\n---\n\n<a id='page-memory-format'></a>\n\n## 内存格式与侧载文件\n\n### 相关页面\n\n相关主题：[存储系统](#page-storage), [搜索功能详解](#page-search)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/sidecar.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/sidecar.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n</details>\n\n# 内存格式与侧载文件\n\n## 概述\n\nCommonplace 系统中的\"内存\"(Memory)是项目的核心数据单元。每个内存以 Markdown 文件形式持久化存储，配合同名的二进制侧载文件(`.embedding`)存放嵌入向量。这种设计确保了 Markdown 文件为唯一真相来源，侧载文件可随时从源文件重新生成。\n\n系统通过 `contentSha` 哈希值实现内容变更检测，确保嵌入向量与源文件保持同步。当检测到内容变化时，系统会自动重新生成嵌入并更新侧载文件。\n\n资料来源：[src/store/memory.ts:1-30]()\n\n## 内存 Markdown 格式\n\n### 文件结构\n\n内存文件采用标准 Markdown+YAML frontmatter 格式，文件结构如下：\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: other_name\n    type: builds-on\nsupersedes:\n  - old_name\n---\n<body>\n```\n\n资料来源：[src/store/memory.ts:1-30]()\n\n### YAML Frontmatter 字段说明\n\n| 字段 | 类型 | 必需 | 说明 |\n|------|------|------|------|\n| `name` | string | 是 | 内存名称，必须匹配 `^[a-z0-9_]+$`，将成为文件名 |\n| `description` | string | 是 | 简短的人类可读描述 |\n| `type` | enum | 是 | 内存类型：`user`、`feedback`、`project`、`reference` 之一 |\n| `relations` | Relation[] | 否 | 图关系列表，支持 `builds-on`、`related-to`、`contradicts`、`child-of` |\n| `supersedes` | string[] | 否 | 被当前内存取代的其他内存名称列表 |\n\n资料来源：[src/store/memory.ts:50-80]()\n\n### Relation 对象结构\n\n```typescript\ninterface Relation {\n  to: string;      // 目标内存名称\n  type: RelationType; // builds-on | related-to | contradicts | child-of\n}\n```\n\n资料来源：[src/store/memory.ts:40-45]()\n\n### 内存类型(MemoryType)\n\n| 类型 | 用途 |\n|------|------|\n| `user` | 个人规则、偏好和身份事实 |\n| `feedback` | 来自先前代理行为的纠正和经验教训 |\n| `project` | 项目级上下文，如架构笔记、仓库约定 |\n| `reference` | 持久化、中立的知识，如 API 形状、公式、引用 |\n\n资料来源：[README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n\n### Body 内容\n\nMarkdown body 可以包含任意文本内容，支持标准 Markdown 语法。特别地，系统支持 `[[name]]` 格式的内存提及语法，用于在内存间建立隐式关系。\n\n资料来源：[src/store/mentions.ts:1-20]()\n\n## 规范化内容哈希(contentSha)\n\n### 计算范围\n\n`contentSha` 是内存内容的规范化 SHA-256 哈希值，用于检测内容变更。哈希计算范围**仅限于** v0.1 基线 frontmatter 字段：\n\n```\n${type}\\n${name}\\n${description}\\n${body}\n```\n\n**重要**：`relations` 和 `supersedes` 图字段**不参与**哈希计算。这意味着添加或删除图边不会使嵌入向量失效。\n\n资料来源：[src/store/memory.ts:70-85]()\n\n### 设计原则\n\n```\ngraph TD\n    A[内存 Markdown 文件] --> B[提取规范内容]\n    B --> C[\"type\\nname\\ndescription\\nbody\"]\n    C --> D[SHA-256 哈希]\n    D --> E[64位十六进制字符串]\n    \n    F[图字段: relations/supersedes] -.->|不参与| C\n    \n    style F fill:#ffcccc\n```\n\n这种设计确保了：\n1. 图关系的修改不会触发嵌入重新计算\n2. 仅当核心内容变化时才需要重新嵌入\n3. 侧载文件与 Markdown 保持松耦合关系\n\n资料来源：[src/store/memory.ts:75-85]()\n\n## 二进制侧载文件格式\n\n### 文件命名\n\n每个内存文件 `<name>.md` 配对一个侧载文件 `<name>.embedding`，存放在同一目录下。\n\n### Wire Format 规范\n\n侧载文件采用小端序二进制格式，结构如下：\n\n```\n偏移   大小    字段\n0      4      magic        \"CMEM\" (ASCII)\n4      1      version      0x01\n5      1      model_len    model_id 的 UTF-8 字节长度\n6      L      model_id     UTF-8 字节\n6+L    4      dim          uint32 小端序\n10+L   32     content_sha  原始 sha256 (从十六进制解码)\n42+L   D*4    vector       float32 小端序值\n```\n\n**总大小** = 42 + model_len + dim × 4 字节\n\n对于 bge-base 模型（model_id: `Xenova/bge-base-en-v1.5`，dim: 768），每个侧载文件约 3 KB。\n\n资料来源：[src/store/sidecar.ts:1-50]()\n\n### 侧载文件结构图\n\n```mermaid\ngraph LR\n    subgraph \"Binary .embedding file\"\n        A[\"magic<br/>4 bytes<br/>CMEM\"] --> B[\"version<br/>1 byte<br/>0x01\"]\n        B --> C[\"model_len<br/>1 byte\"]\n        C --> D[\"model_id<br/>L bytes<br/>UTF-8\"]\n        D --> E[\"dim<br/>4 bytes<br/>uint32 LE\"]\n        E --> F[\"content_sha<br/>32 bytes<br/>raw sha256\"]\n        F --> G[\"vector<br/>dim×4 bytes<br/>float32 LE\"]\n    end\n```\n\n资料来源：[src/store/sidecar.ts:25-45]()\n\n## 内存存储操作\n\n### MemoryStore 架构\n\n```mermaid\ngraph TD\n    subgraph \"MemoryStore\"\n        A[\"#entries[]<br/>内存索引数组\"] --> B[\"scan()\"]\n        A --> C[\"linkEdge()\"]\n        A --> D[\"unlinkEdge()\"]\n        A --> E[\"search()\"]\n    end\n    \n    F[\"文件系统<br/>*.md + *.embedding\"] --> B\n    B --> G[\"生成嵌入<br/>创建侧载\"]\n    G --> F\n    \n    H[\"MemoryGraph<br/>内存图\"] --> C\n    H --> D\n    C -->|addEdge| H\n    D -->|removeEdge| H\n```\n\n资料来源：[src/store/memory-store.ts:1-100]()\n\n### 扫描与嵌入生成\n\n`scan()` 方法执行以下操作：\n\n1. 遍历目录中所有 `.md` 文件\n2. 对每个文件，检查对应的 `.embedding` 是否可复用\n3. 满足以下条件时复用现有侧载：\n   - `.embedding` 文件存在\n   - 解码通过（magic + version + length 检查）\n   - `decoded.modelId === embedder.modelId`\n   - `decoded.dim === embedder.dim`\n   - `decoded.contentSha === contentSha(memoryAsRead)`\n\n资料来源：[src/store/memory-store.ts:80-120]()\n\n### 孤儿侧载清理\n\n扫描完成后，`scan()` 会再次遍历目录，删除任何缺少对应 `.md` 文件的 `.embedding` 孤儿文件。这防止了孤立侧载文件在磁盘上无声积累。\n\n```mermaid\ngraph TD\n    A[\"扫描完成\"] --> B{\"存在孤儿子载文件?\"}\n    B -->|是| C{\"dryRun 模式?\"}\n    C -->|是| D[\"报告孤立数量<br/>不删除\"]\n    C -->|否| E[\"删除孤儿文件\"]\n    B -->|否| F[\"扫描完成\"]\n    D --> F\n    E --> F\n```\n\n资料来源：[src/store/memory-store.ts:120-140]()\n\n### 边链接操作\n\n#### linkEdge - 添加关系\n\n```typescript\npublic async linkEdge(args: {\n  from: string;\n  to: string;\n  type: RelationType | 'supersedes';\n}): Promise<{ relations: Relation[]; supersedes: string[] }>\n```\n\n流程：\n1. 验证源内存存在\n2. 检查是否重复边\n3. 更新内存对象\n4. 通过 `atomicWrite` 写入 `.md` 文件\n5. 更新内存图 `MemoryGraph`\n6. 刷新 mtime 基线\n\n资料来源：[src/store/memory-store.ts:150-200]()\n\n#### unlinkEdge - 移除关系\n\n```typescript\npublic async unlinkEdge(args: {\n  from: string;\n  to: string;\n  type?: RelationType | 'supersedes';\n}): Promise<{ relations: Relation[]; supersedes: string[]; note?: string }>\n```\n\n- 当 `type` 省略时，移除所有从 `from` 到 `to` 的边\n- 当边不存在时为静默操作，返回 `note` 说明原因\n- 涉及原子写入和图更新\n\n资料来源：[src/store/memory-store.ts:200-260]()\n\n## 内容变更检测与重新嵌入\n\n```mermaid\nsequenceDiagram\n    participant MD as Markdown 文件\n    participant SC as Sidecar 文件\n    participant SS as MemoryStore\n    participant EMB as Embedder\n\n    SS->>MD: 读取内容\n    SS->>MD: 计算 contentSha\n    SS->>SC: 读取 sidecar\n    SC->>SS: 返回 content_sha\n    Note over SS: contentSha === content_sha?\n    \n    alt 内容一致\n        SS->>SC: 复用现有侧载\n    else 内容变更\n        SS->>EMB: 请求嵌入\n        EMB->>SS: 返回向量\n        SS->>SC: 写入新侧载\n    end\n```\n\n## 迁移工具中的扫描操作\n\n`migrate` 命令支持对现有目录执行扫描：\n\n```bash\ncommonplace migrate <dir> [--dry-run] [--prune-dangling]\n```\n\n参数说明：\n\n| 参数 | 说明 |\n|------|------|\n| `dir` | 内存目录路径 |\n| `--dry-run` | 预览模式，不实际写入 |\n| `--prune-dangling` | 清理指向不存在内存的悬空边 |\n\n资料来源：[src/cli/migrate.ts:100-150]()\n\n## 数据完整性保证\n\n| 操作 | 原子性 | 锁机制 |\n|------|--------|--------|\n| 内存写入 | `atomicWrite` (临时文件+重命名) | `acquireNameLock` |\n| 边添加/移除 | 原子写入 | 名称锁 |\n| 扫描 | 非原子 | mtime 基线避免浪费性重扫描 |\n| 孤儿清理 | `fs.unlinkSync` | - |\n\n资料来源：[src/store/memory-store.ts:180-220]()\n\n## 命名验证规则\n\n内存名称必须满足以下正则表达式：\n\n```typescript\n/^[a-z0-9_]+$/\n```\n\n- 只能包含小写字母、数字和下划线\n- 不允许路径分隔符\n- 成为文件名主干\n\n此规则确保了文件系统兼容性和 URI 安全。\n\n资料来源：[src/store/memory.ts:20-40]()\n\n---\n\n<a id='page-search'></a>\n\n## 搜索功能详解\n\n### 相关页面\n\n相关主题：[嵌入模型与语义搜索](#page-embedder), [图功能与关系管理](#page-graph-features)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n</details>\n\n# 搜索功能详解\n\n## 概述\n\nCommonplace 的搜索功能是一个本地优先的语义搜索系统，基于余弦相似度（Cosine Similarity）算法实现完全离线的向量搜索。系统使用 `@huggingface/transformers` 库和 `bge-base-en-v1.5` 模型生成嵌入向量，支持对记忆进行语义匹配检索。\n\n搜索功能的核心设计原则是**记忆文件（`.md`）是唯一真相来源**，`.embedding` 侧边文件是从记忆内容派生的，可以随时删除和重建。\n\n## 核心架构\n\n### 搜索流程图\n\n```mermaid\ngraph TD\n    A[用户发起 memory_search] --> B[解析查询参数]\n    B --> C[生成查询向量]\n    C --> D[遍历所有记忆文件]\n    D --> E[加载 .embedding 侧边文件]\n    E --> F[计算余弦相似度]\n    F --> G[按分数排序取 Top-K]\n    G --> H[合并 User/Project 商店结果]\n    H --> I[排除已废弃记忆]\n    I --> J[丰富关系图数据]\n    J --> K[返回搜索结果]\n```\n\n### 关键组件\n\n| 组件 | 文件位置 | 职责 |\n|------|----------|------|\n| Embedder | `src/store/embedder.ts` | 负责将文本转换为 768 维向量 |\n| MemoryStore | `src/store/memory-store.ts` | 管理记忆存储、扫描和搜索 |\n| MemoryGraph | `src/store/graph.ts` | 维护记忆间的图关系 |\n| Mentions | `src/store/mentions.ts` | 提取正文中 `[[name]]` 引用 |\n\n## 嵌入向量生成\n\n### 嵌入模型\n\n系统使用 `bge-base-en-v1.5` 模型作为默认嵌入模型，该模型输出 768 维的向量表示。\n\n```mermaid\ngraph LR\n    A[记忆文本] --> B[contentSha 计算]\n    B --> C[模型推理]\n    C --> D[768维向量]\n    D --> E[.embedding 侧边文件]\n```\n\n### contentSha 计算\n\n为了检测记忆内容是否发生变化，系统为每个记忆计算 SHA-256 哈希值：\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${memory.description}\\n${memory.body}`, 'utf8')\n    .digest('hex');\n```\n\n**重要设计决策**：哈希值的计算范围仅包括 `type`、`name`、`description` 和 `body` 四个字段。**图字段（`relations` 和 `supersedes`）不参与哈希计算**，这确保了添加或删除图关系不会导致嵌入向量失效。\n\n资料来源：[src/store/memory.ts:47-51](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n### 惰性重新嵌入\n\n在保存记忆时，如果 `contentSha` 与侧边文件中存储的哈希值不匹配，系统会自动触发重新嵌入：\n\n```typescript\nconst needsReembed =\n  isMissing || stale.embedding.corrupt || stale.embedding.contentShaMismatch;\n```\n\n这确保了搜索结果始终与最新的记忆内容同步。\n\n## 记忆文件结构\n\n### Markdown 格式\n\n记忆以 Markdown 文件形式存储，包含 YAML 前置数据：\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: other_name\n    type: builds-on\nsupersedes:\n  - old_name\n---\n<正文内容>\n```\n\n资料来源：[src/store/memory.ts:30-46](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n### 记忆类型\n\n| 类型 | 说明 | 适用场景 |\n|------|------|----------|\n| `user` | 个人规则和偏好 | 跨项目的通用知识 |\n| `feedback` | 纠正和经验教训 | 持久的行为调整 |\n| `project` | 项目特定上下文 | 架构笔记、代码规范 |\n| `reference` | 持久知识 | API 形状、公式、引用 |\n\n资料来源：[README.md](https://github.com/rickassham/commonplace/blob/main/README.md)\n\n## 搜索 API\n\n### memory_search 工具\n\n搜索工具是最常用的查询接口，支持以下参数：\n\n| 参数 | 类型 | 必填 | 说明 |\n|------|------|------|------|\n| `query` | string | 是 | 搜索查询文本 |\n| `type` | string | 否 | 过滤特定记忆类型 |\n| `limit` | number | 否 | 返回结果数量上限 |\n| `scope` | `user \\| project` | 否 | 指定搜索范围 |\n| `expandTypes` | string[] | 否 | 展开的边类型 |\n| `includeSuperseded` | boolean | 否 | 是否包含已废弃记忆 |\n\n### 搜索响应结构\n\n```typescript\nexport interface MemorySearchResult {\n  matches: MemorySearchMatch[];\n  query: string;\n}\n\nexport interface MemorySearchMatch {\n  name: string;\n  type: MemoryType;\n  description: string;\n  body: string;\n  score: number;  // 余弦相似度，保留3位小数\n  relations: Relation[];\n}\n```\n\n**重要约束**：根据设计规范，body 字段**永远不会被截断、摘要或转换**，调用者获得完全原始的存储内容。\n\n资料来源：[src/server/handlers.ts:35-56](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n\n## 搜索范围与合并\n\n### 双商店架构\n\nCommonplace 支持同时加载两个记忆商店：\n\n```mermaid\ngraph TD\n    A[memory_search 请求] --> B{是否指定 scope?}\n    B -->|是| C[仅搜索指定商店]\n    B -->|否| D[并行搜索两个商店]\n    C --> E[返回结果]\n    D --> F[User Store 搜索]\n    D --> G[Project Store 搜索]\n    F --> H[按分数合并排序]\n    G --> H\n    H --> I[返回合并结果]\n```\n\n### 商店位置\n\n| 商店类型 | 默认路径 | 说明 |\n|----------|----------|------|\n| User Store | `~/.commonplace/memory` | 始终加载 |\n| Project Store | `<project-root>/.commonplace/memory` | 仅在检测到项目根目录时加载 |\n\n### 检测优先级\n\n项目商店的位置按以下优先级确定：\n\n1. `COMMONPLACE_PROJECT_DIR` 环境变量（最高优先级）\n2. MCP `roots/list` 返回的项目根目录\n3. 当前工作目录\n\n## 关系图扩展\n\n### 边类型\n\n搜索结果可以包含记忆之间的关系信息，支持以下边类型：\n\n| 边类型 | 说明 | 默认展开 |\n|--------|------|----------|\n| `builds-on` | 建立于其他记忆之上 | ✓ |\n| `related-to` | 相关关系 | ✓ |\n| `mentions` | 正文中引用 | ✗ |\n| `supersedes` | 废弃替代 | ✗ |\n| `contradicts` | 矛盾关系 | ✗ |\n| `child-of` | 父子关系 | ✗ |\n\n**默认展开类型**：`builds-on` 和 `related-to` 是最可能产生有用邻居的边类型，因此默认展开。\n\n资料来源：[src/server/handlers.ts:19-25](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n\n### 废弃记忆排除\n\n默认情况下，搜索结果会排除已被废弃的记忆。通过 `supersedes` 字段，系统自动识别并过滤：\n\n```typescript\n// memory_path 工具的默认行为\nif (!includeSuperseded) {\n  results = results.filter((m) => !supersededNames.has(m.name));\n}\n```\n\n## 提及提取功能\n\n### [[name]] 语法\n\n系统支持从记忆正文中提取 `[[name]]` 格式的提及，生成隐式的关系边：\n\n```mermaid\ngraph TD\n    A[记忆正文] --> B[正则匹配 [[name]]\n    B --> C{匹配成功?}\n    C -->|是| D[提取 name]\n    C -->|否| E[跳过]\n    D --> F[调用 graph.addMentionsEdge]\n    E --> G[继续处理]\n```\n\n### 启用控制\n\n提及提取功能通过环境变量控制：\n\n- **默认状态**：启用\n- **禁用方式**：设置 `COMMONPLACE_EXTRACT_MENTIONS=false`\n\n```typescript\n// 提取受环境变量 COMMONPLACE_EXTRACT_MENTIONS 控制\nconst enabled = mentionsExtractionEnabled();\nif (enabled) {\n  const mentions = extractMentions(body);\n  for (const name of mentions) {\n    this.#graph.addMentionsEdge({ from: name, to });\n  }\n}\n```\n\n资料来源：[src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n\n## 搜索性能特性\n\n### 暴力搜索算法\n\n系统采用暴力搜索（Brute-Force）算法计算余弦相似度：\n\n```typescript\n// 伪代码示意\nfor (const memory of allMemories) {\n  const embedding = loadEmbedding(memory.embeddingPath);\n  const score = cosineSimilarity(queryEmbedding, embedding);\n  results.push({ memory, score });\n}\nreturn results.sort((a, b) => b.score - a.score).slice(0, limit);\n```\n\n### 目录扫描优化\n\nMemoryStore 维护目录修改时间基线，避免不必要的重新扫描：\n\n```typescript\n// 刷新 mtime 基线以避免浪费性重新扫描\nthis.#refreshMtimeBaseline();\n```\n\n### 原子写入保证\n\n文件写入使用原子写入模式，防止并发操作导致数据损坏：\n\n```typescript\n// 临时文件 + rename 确保写入原子性\nconst tmpName = `${base}.${randomBytes(8).toString('hex')}.tmp`;\nconst tmpPath = join(dir, tmpName);\n// ... 写入临时文件 ...\nawait fs.rename(tmpPath, target);\n```\n\n## MCP 工具注册\n\n搜索功能通过 MCP（Model Context Protocol）协议暴露给 AI 代理：\n\n```mermaid\ngraph LR\n    A[AI 代理] -->|MCP 调用| B[mcp__commonplace__memory_search]\n    B --> C[handlers.ts 分发]\n    C --> D[MemoryStore.search]\n    D --> E[返回 MemorySearchResult]\n    E --> F[AI 代理]\n```\n\n## 搜索与记忆生命周期\n\n```mermaid\ngraph LR\n    A[memory_save] --> B[写入 .md]\n    B --> C[计算 contentSha]\n    C --> D[生成嵌入向量]\n    D --> E[写入 .embedding]\n    E --> F[scan 更新索引]\n    F --> G[提取 mentions]\n    G --> H[更新关系图]\n    \n    I[memory_search] --> J[查询向量]\n    J --> K[遍历 .embedding]\n    K --> L[计算余弦相似度]\n    L --> M[合并排序结果]\n    M --> N[丰富关系数据]\n    N --> O[返回结果]\n```\n\n## 相关命令\n\n| 命令 | 说明 |\n|------|------|\n| `commonplace migrate <dir>` | 扫描并嵌入目录中的所有记忆 |\n| `commonplace migrate --from claude-code` | 从 Claude Code 导入记忆 |\n| `mcp__commonplace__memory_search` | MCP 搜索接口 |\n\n## 配置参考\n\n### 环境变量\n\n| 变量 | 默认值 | 说明 |\n|------|--------|------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | 用户记忆目录 |\n| `COMMONPLACE_PROJECT_DIR` | - | 项目记忆目录（覆盖检测） |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `true` | 启用提及提取 |\n\n### CLI 选项\n\n| 选项 | 说明 |\n|------|------|\n| `--dry-run` | 预览操作不写入文件 |\n| `--auto` | 脚本化自动运行 |\n| `--prune-dangling` | 清理悬空引用 |\n\n## 版本历史\n\n| 版本 | 日期 | 搜索相关特性 |\n|------|------|--------------|\n| 0.1.0 | 2026-05-10 | 初始发布：基础搜索、向量嵌入、图关系 |\n\n资料来源：[CHANGELOG.md](https://github.com/rickbassham/commonplace/blob/main/CHANGELOG.md)\n\n---\n\n<a id='page-graph-features'></a>\n\n## 图功能与关系管理\n\n### 相关页面\n\n相关主题：[搜索功能详解](#page-search), [内存格式与侧载文件](#page-memory-format)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/store/graph.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/graph.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n- [src/cli/graph.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/graph.ts)\n</details>\n\n# 图功能与关系管理\n\n## 概述\n\n图功能与关系管理是 Commonplace 项目中用于管理记忆（Memory）之间语义关联的核心模块。该模块基于 YAML frontmatter 中的 `relations` 和 `supersedes` 字段构建内存图，并支持从正文中提取 `[[name]]` 形式的提及关系。通过这些机制，用户可以构建记忆之间的有向图，实现知识关联、一跳扩展搜索等功能。\n\n该功能主要服务于以下场景：\n\n- 显式声明记忆之间的关系（如\"此记忆建立在另一个记忆之上\"）\n- 自动检测正文中的提及关系\n- 悬空边检测与清理\n- 图可视化与路径查询\n\n资料来源：[src/store/graph.ts:1-20]()\n\n## 数据模型\n\n### 边的类型\n\n图模块定义了六种边类型，分为两类：\n\n**授权边类型（Authored Relation Types）**\n\n| 边类型 | 说明 |\n|--------|------|\n| `related-to` | 相关关系 |\n| `builds-on` | 建立关系（继承/基于） |\n| `contradicts` | 矛盾关系 |\n| `child-of` | 子级关系 |\n\n**派生边类型（Derived Edge Types）**\n\n| 边类型 | 来源 |\n|--------|------|\n| `supersedes` | 来自 frontmatter 的 `supersedes[]` 字段 |\n| `mentions` | 来自正文 `[[name]]` 提取（DAR-927） |\n\n资料来源：[src/store/graph.ts:19-22]()\n\n```typescript\nexport type EdgeType = RelationType | 'supersedes' | 'mentions';\n```\n\n### 边接口\n\n```typescript\nexport interface Edge {\n  from: string;    // 源记忆名称\n  to: string;      // 目标记忆名称\n  type: EdgeType;  // 边类型\n}\n```\n\n### 悬空边接口\n\n当边指向的目标记忆不存在时，该边称为悬空边（Dangling Edge）：\n\n```typescript\nexport interface DanglingEdge {\n  from: string;\n  to: string;\n  type: string;  // 类型被放宽为 string，允许扩展\n}\n```\n\n资料来源：[src/store/graph.ts:24-44]()\n\n### 记忆前端matter关系字段\n\n每个记忆的 YAML frontmatter 可包含以下图字段：\n\n```yaml\n---\nname: feedback_scope\ntype: feedback\nrelations:        # DAR-925，可选，默认 []\n  - to: other_name\n    type: builds-on\nsupersedes:      # DAR-925，可选，默认 []\n  - old_name\n---\n```\n\n资料来源：[src/store/memory.ts:7-23]()\n\n### 关系解析验证\n\n`relations` 字段中的每条记录必须包含 `to` 和 `type` 两个必填键：\n\n```typescript\nconst parseRelation = (entry: unknown, ctx: string): Relation => {\n  if (!isPlainObject(entry)) {\n    throw new Error(`${ctx} must be a mapping with \\`to\\` and \\`type\\``);\n  }\n  if (!('to' in entry)) {\n    throw new Error(`${ctx} is missing required key \\`to\\``);\n  }\n  if (!('type' in entry)) {\n    throw new Error(`${ctx} is missing required key \\`type\\``);\n  }\n  const to = validateName(entry.to, `${ctx}.to`);\n  const type = entry.type;\n  if (!isRelationType(type)) {\n    throw new Error(`${ctx}.type must be one of ${RELATION_TYPES.join(', ')}`);\n  }\n  return { to, type };\n};\n```\n\n资料来源：[src/store/memory.ts:82-102]()\n\n### 内容哈希与图字段独立性\n\n内容 SHA256 仅基于 v0.1 基线字段计算：`type`、`name`、`description` 和 `body`。图字段（`relations`、`supersedes`）**不参与**哈希计算，这意味着添加或删除图边不会使对应的 embedding 失效。\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${memory.description}\\n${body}`, 'utf8')\n    .digest('hex');\n```\n\n资料来源：[src/store/memory.ts:48-55]()\n\n## 提及提取（DAR-927）\n\n### 概述\n\n`[[name]]` 提及提取器负责从记忆正文中解析所有提及的目标名称，返回去重后的集合，保持首次出现顺序。\n\n### 提取规则\n\n- 仅接受符合 `^[a-z0-9_]+$` 规则的名称（与记忆文件名命名规则一致）\n- 不符合规则的 `[[...]]` 形式会被静默忽略\n- 代码块和行内代码中的提及**不会**被特殊处理（按需求说明 #1 排除）\n\n资料来源：[src/store/mentions.ts:1-30]()\n\n### 配置\n\n提及提取由环境变量 `COMMONPLACE_EXTRACT_MENTIONS` 控制：\n\n| 值 | 行为 |\n|----|------|\n| 未设置 / `'true'` | 启用提取 |\n| `'false'` | 禁用提取 |\n\n资料来源：[src/store/mentions.ts:16-20]()\n\n### 工作流程\n\n```mermaid\ngraph TD\n    A[记忆正文] --> B{提取开关}\n    B -->|启用| C[正则匹配 [[...]]]\n    B -->|禁用| D[返回空集]\n    C --> E[提取内容]\n    E --> F{符合 NAME_PATTERN?}\n    F -->|是| G[加入结果集]\n    F -->|否| H[忽略]\n    G --> I[去重并排序]\n    H --> I\n    I --> J[返回唯一名称列表]\n    D --> J\n```\n\n## MemoryStore 关系管理\n\n### 添加关系\n\n`linkEdge` 方法用于向记忆添加新的关系边：\n\n```typescript\npublic async linkEdge(args: {\n  from: string;\n  to: string;\n  type: RelationType | 'supersedes';\n}): Promise<Memory>\n```\n\n**行为说明：**\n\n1. 验证源记忆存在\n2. 检查重复边（相同 `from`、`to`、`type` 的边已存在则报错）\n3. 更新 `relations[]` 或 `supersedes[]` 数组\n4. 通过 `atomicWrite` 原子写入 `.md` 文件\n5. 更新内存中的 entry\n6. 同步更新 `MemoryGraph`\n\n**处理逻辑：**\n\n```typescript\nconst nextRelations: Relation[] =\n  type === 'supersedes' ? entry.relations.slice() : [...entry.relations, { to, type }];\nconst nextSupersedes: string[] =\n  type === 'supersedes' ? [...entry.supersedes, to] : entry.supersedes.slice();\n```\n\n资料来源：[src/store/memory-store.ts:1-100]()\n\n### 移除关系\n\n`unlinkEdge` 方法用于移除关系边：\n\n```typescript\npublic async unlinkEdge(args: {\n  from: string;\n  to: string;\n  type?: RelationType | 'supersedes';  // 可选，不指定则移除所有类型\n}): Promise<{ relations: Relation[]; supersedes: string[]; note?: string }>\n```\n\n**行为说明：**\n\n- 当 `type` 指定时，仅移除匹配的边\n- 当 `type` 省略时，移除所有从 `from` 到 `to` 的边（无论类型）\n- 边不存在时为静默操作，返回 `note` 说明原因\n\n资料来源：[src/store/memory-store.ts:150-200]()\n\n### 原子写入保证\n\n所有图修改通过 `atomicWrite` 确保一致性：\n\n```typescript\nconst mdPath = join(this.#dir, `${from}.md`);\nconst release = await acquireNameLock(this.#dir, from);\ntry {\n  const mdBytes = Buffer.from(serializeMemory(updated), 'utf8');\n  await atomicWrite(mdPath, mdBytes);\n  // 更新内存索引...\n} finally {\n  release();\n}\n```\n\n## MCP 工具接口\n\n### memory_link\n\n建立记忆之间的边：\n\n```jsonc\n// memory_link\n{\n  \"from\": \"architecture_overview\",\n  \"to\": \"feedback_scope\",\n  \"type\": \"builds-on\"\n}\n```\n\n| 参数 | 类型 | 必填 | 说明 |\n|------|------|------|------|\n| `from` | string | 是 | 源记忆名称 |\n| `to` | string | 是 | 目标记忆名称 |\n| `type` | 边类型 | 是 | 关系类型 |\n| `scope` | `user\\|project` | 否 | 作用域 |\n\n### memory_unlink\n\n移除记忆之间的边：\n\n```jsonc\n// memory_unlink\n{\n  \"from\": \"architecture_overview\",\n  \"to\": \"feedback_scope\",\n  \"type\": \"builds-on\"  // 可选，忽略则移除所有类型\n}\n```\n\n资料来源：[src/server/handlers.ts:1-50]()\n\n### 搜索中的一跳扩展\n\n`memory_search` 工具支持 `expand: 'one-hop'` 参数，从直接命中出发扩展邻居节点：\n\n| 参数 | 默认值 | 说明 |\n|------|--------|------|\n| `expand` | `'none'` | 扩展模式：`none` 或 `one-hop` |\n| `expandTypes` | `['builds-on', 'related-to']` | 允许的边类型 |\n| `expandLimit` | `2` | 每个直接命中的最大邻居数 |\n\n```jsonc\n// 带一跳扩展的搜索\n{\n  \"query\": \"architecture\",\n  \"expand\": \"one-hop\",\n  \"expandTypes\": [\"builds-on\", \"related-to\", \"mentions\"],\n  \"expandLimit\": 3\n}\n```\n\n扩展条目携带 `via` 字段标识来源：\n\n```jsonc\n{\n  \"name\": \"neighbor_name\",\n  \"via\": {\n    \"source\": \"direct_hit_name\",\n    \"edge\": \"builds-on\"\n  }\n}\n```\n\n资料来源：[src/server/handlers.ts:60-90]()\n\n### 默认扩展类型\n\n默认仅扩展 `builds-on` 和 `related-to`，因为这两种边类型最可能产生有用的邻居。其他类型（`mentions`、`supersedes`、`contradicts`、`child-of`）需要显式 opt-in。\n\n```typescript\nexport const DEFAULT_EXPAND_TYPES: readonly EdgeType[] = ['builds-on', 'related-to'] as const;\n```\n\n资料来源：[src/server/handlers.ts:52-55]()\n\n## CLI 命令行工具\n\n### graph 子命令\n\n`commonplace graph` 命令用于可视化图结构：\n\n```bash\ncommonplace graph <name> [options]\n```\n\n| 选项 | 默认值 | 说明 |\n|------|--------|------|\n| `--depth, -d` | `1` | 遍历深度 |\n| `--types, -t` | 全部 | 逗号分隔的边类型过滤 |\n| `--direction` | `outbound` | `outbound`、`inbound` 或 `both` |\n| `--format, -f` | `mermaid` | 输出格式：`mermaid`、`json`、`dot` |\n| `--scope, -s` | 自动 | `user`、`project` 或 `both` |\n\n### 输出格式\n\n**Mermaid 格式（默认）：**\n\n````markdown\n```mermaid\nflowchart LR\n    A[architecture_overview] -->|builds-on| B[feedback_scope]\n```\n````\n\n**JSON 格式：**\n\n```json\n{\n  \"root\": \"architecture_overview\",\n  \"nodes\": [...],\n  \"edges\": [...]\n}\n```\n\n**DOT 格式：** 用于 Graphviz 工具链处理大规模图。\n\n资料来源：[src/cli/graph.ts:1-40]()\n\n### 实现细节\n\nCLI 使用与 MCP `memory_graph` 工具相同的遍历辅助函数，因此图遍历行为、循环处理、深度/类型过滤完全一致：\n\n```typescript\nconst result = await graphMain({\n  argv,\n  embedderFactory: () => new Embedder(resolveModelId(process.env)),\n  stdout: (chunk: string) => process.stdout.write(chunk),\n  stderr: (chunk: string) => process.stderr.write(chunk),\n  env: process.env,\n  cwd: process.cwd(),\n});\n```\n\n资料来源：[src/index.ts:50-65]()\n\n## 存储层架构\n\n### 双存储模式\n\nCommonplace 支持同时加载两个记忆存储：\n\n```mermaid\ngraph LR\n    subgraph 用户存储\n        U[User Memory Store]\n    end\n    subgraph 项目存储\n        P[Project Memory Store]\n    end\n    G[MemoryGraph] --- U\n    G[MemoryGraph] --- P\n```\n\n- **用户存储**：始终加载，位于 `~/.commonplace/memory`\n- **项目存储**：仅在检测到项目根目录时加载\n\n每个存储维护独立的 `#entries` 数组和 `MemoryGraph` 实例。\n\n资料来源：[src/store/memory-store.ts:1-30]()\n\n### 目录扫描与图构建\n\n在 `scan()` 和 `save()` 过程中，`MemoryStore` 调用 `extractMentions` 提取正文提及，并将其转发给 `MemoryGraph.addMentionsEdge`：\n\n```typescript\n// 伪代码示意\nfor (const memory of memories) {\n  const mentions = extractMentions(memory.body);\n  for (const name of mentions) {\n    this.#graph.addMentionsEdge({ from: memory.name, to: name });\n  }\n}\n```\n\n## 功能边界\n\n以下功能明确不在当前实现范围内：\n\n| 功能 | 负责人 |\n|------|--------|\n| 验证引用的记忆名称是否存在于磁盘（DAR-926） | 待实现 |\n| 构建内存邻接表/图（DAR-926） | 待实现 |\n| Wiki 风格反向链接渲染/自动补全 | 排除范围 |\n| 代码块/行内代码中的提及感知 | 排除范围 |\n| MCP 工具响应中的提及展示（DAR-929/DAR-932） | 待实现 |\n| 中心性/PageRank 计算（DAR-931） | 待实现 |\n| 遍历/路径查询（DAR-932） | 待实现 |\n\n资料来源：[src/store/graph.ts:6-15]()\n\n## 迁移与清理\n\n### migrate 命令的图清理\n\n`commonplace migrate` 命令在导入文件时会检测并清理悬空边：\n\n```\n  pruned:       5 dangling edges across 2 files (would be removed)\n    memory_a: 3\n    memory_b: 2\n```\n\n悬空边指向前端 matter 中声明但不存在于磁盘的目标记忆。\n\n资料来源：[src/cli/migrate.ts:1-30]()\n\n### 悬空边检测\n\n图模块暴露 `DanglingEdge` 接口用于悬空边报告：\n\n```typescript\nexport interface DanglingEdge {\n  from: string;\n  to: string;\n  type: string;\n}\n```\n\n返回时 `type` 被放宽为 `string`，以便未来支持扩展边类型。\n\n---\n\n<a id='page-storage'></a>\n\n## 存储系统\n\n### 相关页面\n\n相关主题：[内存格式与侧载文件](#page-memory-format), [作用域与多存储](#page-scopes)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.ts)\n- [src/store/graph.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/graph.ts)\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n</details>\n\n# 存储系统\n\n## 概述\n\n存储系统是 Commonplace 项目的核心模块，负责将记忆（Memory）以 Markdown 文件形式持久化到本地磁盘，同时管理向量嵌入（Embedding）sidecar 文件、图关系以及内存索引。该系统采用本地优先（Local-First）架构，所有数据存储在用户本地目录，无需云端依赖，实现了完全的离线语义搜索能力。\n\n存储系统的设计目标包括：\n\n- **文件即存储**：每个记忆是一个独立的 `.md` 文件，YAML frontmatter 存储元数据\n- **嵌入派生**：`.embedding` sidecar 文件由 `.md` 内容派生，可随时重建\n- **原子操作**：通过 temp file + rename 模式保证写操作的原子性\n- **图关系管理**：支持记忆之间的多种关系类型（builds-on、related-to 等）\n- **作用域隔离**：支持 `user` 和 `project` 两种存储作用域\n\n资料来源：[src/store/memory-store.ts:1-50]()\n\n## 架构概览\n\n```mermaid\ngraph TB\n    subgraph \"存储层 (Disk)\"\n        MD[\".md 文件<br/>YAML Frontmatter + Body\"]\n        EMB[\".embedding 文件<br/>Binary Sidecar\"]\n    end\n    \n    subgraph \"内存索引 (In-Memory)\"\n        IDX[\"#entries[]<br/>MemoryEntry 数组\"]\n        GRAPH[\"#graph<br/>MemoryGraph\"]\n    end\n    \n    subgraph \"核心模块\"\n        MS[\"MemoryStore<br/>主存储类\"]\n        AW[\"atomicWrite<br/>原子写入工具\"]\n        MEM[\"memory.ts<br/>序列化/反序列化\"]\n        MENT[\"mentions.ts<br/>提及提取器\"]\n    end\n    \n    MD --> MS\n    EMB --> MS\n    MS --> IDX\n    MS --> GRAPH\n    MS --> AW\n    MS --> MEM\n    MS --> MENT\n```\n\n## 核心组件\n\n### MemoryStore\n\n`MemoryStore` 是存储系统的主类，负责管理特定目录下的所有记忆文件。它维护两个核心内部状态：\n\n- `#entries: MemoryEntry[]` — 从磁盘扫描加载的内存索引\n- `#graph: MemoryGraph | undefined` — 可选的内存图结构\n\n资料来源：[src/store/memory-store.ts:80-85]()\n\n#### 关键方法\n\n| 方法 | 用途 |\n|------|------|\n| `save()` | 创建新记忆，写入 `.md` 和 `.embedding` |\n| `list()` | 返回所有记忆的摘要信息 |\n| `get()` | 获取单个记忆的完整内容 |\n| `delete()` | 删除记忆文件和关联的 embedding |\n| `search()` | 基于向量相似度的语义搜索 |\n| `linkEdge()` | 添加记忆间的关系边 |\n| `unlinkEdge()` | 移除记忆间的关系边 |\n| `scan()` | 重新扫描目录，更新内存索引 |\n\n资料来源：[src/store/memory-store.ts:200-450]()\n\n### Atomic Write\n\n`atomicWrite` 模块提供基于 temp file + rename 的原子写入模式，确保在写入过程中发生崩溃或断电时不会产生部分写入的损坏文件。\n\n```mermaid\nsequenceDiagram\n    participant Caller\n    participant AW as atomicWrite\n    participant FS as FileSystem\n    \n    Caller->>AW: atomicWrite(target, data)\n    AW->>AW: 生成随机 tmp 文件名<br/>base.16hexchars.tmp\n    AW->>FS: 写入 tmp 文件\n    AW->>FS: rename(tmp, target)\n    Note over FS: rename(2) 原子操作\n    AW->>Caller: 完成\n```\n\n#### 安全特性\n\n- **跨文件系统防护**：通过比较源目录和临时文件目录的 `dev` 设备号，拒绝跨文件系统重命名\n- **足够熵值**：使用 8 字节（16 十六进制字符）随机数生成临时文件名，避免并发写入冲突\n- **同目录原则**：临时文件与目标文件位于同一目录，确保 rename 操作在同一文件系统内\n\n资料来源：[src/store/atomic-write.ts:1-40]()\n\n### Memory 数据模型\n\n每个记忆由一个 Markdown 文件表示，结构如下：\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: other_name\n    type: builds-on\nsupersedes:\n  - old_name\n---\n<body>\n```\n\n#### 字段说明\n\n| 字段 | 类型 | 必需 | 说明 |\n|------|------|------|------|\n| `name` | string | 是 | 记忆名称，需匹配 `^[a-z0-9_]+$` |\n| `description` | string | 是 | 简短描述，用于搜索结果展示 |\n| `type` | MemoryType | 是 | 记忆类型：`user` \\| `feedback` \\| `project` \\| `reference` |\n| `relations` | Relation[] | 否 | 关系列表，默认空数组 |\n| `supersedes` | string[] | 否 | 被替代的记忆名称列表 |\n\n资料来源：[src/store/memory.ts:1-60]()\n\n### 记忆类型 (MemoryType)\n\n```mermaid\ngraph LR\n    A[MemoryType] --> B[\"user<br/>用户偏好规则\"]\n    A --> C[\"feedback<br/>反馈纠正\"]\n    A --> D[\"project<br/>项目上下文\"]\n    A --> E[\"reference<br/>参考知识\"]\n```\n\n| 类型 | 用途 | 使用场景 |\n|------|------|----------|\n| `user` | 个人规则、偏好、身份信息 | 跨项目适用的用户特征 |\n| `feedback` | 纠正和经验教训 | 对 agent 行为的持久修正 |\n| `project` | 项目特定上下文 | 架构笔记、代码规范、特定决策 |\n| `reference` | 持久性中性知识 | API 形状、公式、引用资料 |\n\n资料来源：[README.md:1-50]()\n\n## 图关系系统\n\n### 边类型 (RelationType)\n\n| 类型 | 说明 | 行为 |\n|------|------|------|\n| `builds-on` | 建立在另一个记忆之上 | 加入 `relations[]` |\n| `related-to` | 与另一个记忆相关 | 加入 `relations[]` |\n| `contradicts` | 与另一个记忆矛盾 | 加入 `relations[]` |\n| `child-of` | 是另一个记忆的子项 | 加入 `relations[]` |\n| `supersedes` | 替代另一个记忆 | 加入 `supersedes[]` |\n\n资料来源：[src/store/memory-store.ts:150-200]()\n\n### 关系写入流程\n\n```mermaid\ngraph TD\n    START[linkEdge from, to, type] --> CHECK{from === to?}\n    CHECK -->|是| ERR1[抛出错误:<br/>禁止自环]\n    CHECK -->|否| LOAD[从内存索引加载 from 条目]\n    LOAD --> EXISTS{to 条目存在?}\n    EXISTS -->|否| ERR2[抛出错误:<br/>目标记忆不存在]\n    EXISTS -->|是| DUPE{重复边?}\n    DUPE -->|是| ERR3[抛出错误:<br/>边已存在]\n    DUPE -->|否| BUILD[构建更新后的 Memory]\n    BUILD --> LOCK[acquireNameLock 获取锁]\n    LOCK --> WRITE[atomicWrite 写入 .md]\n    WRITE --> MUTATE[原地更新内存条目]\n    MUTATE --> GRAPH{有 #graph?}\n    GRAPH -->|是| ADD[graph.addEdge]\n    GRAPH -->|否| REFRESH[刷新 mtime 基线]\n    ADD --> REFRESH\n    REFRESH --> DONE[返回新 relations/supersedes]\n```\n\n资料来源：[src/store/memory-store.ts:280-350]()\n\n## 扫描与嵌入\n\n### Scan 流程\n\n`scan()` 方法执行完整的目录重新扫描：\n\n1. 遍历目录中所有 `.md` 文件\n2. 解析每个文件的 YAML frontmatter\n3. 检查对应的 `.embedding` sidecar 是否可复用\n4. 不可用时触发重新嵌入\n5. 清理孤立的 embedding 文件\n\n```mermaid\nflowchart TD\n    START[scan] --> SCAN[扫描目录 *.md]\n    SCAN --> LOOP{遍历每个 .md}\n    LOOP -->|有文件| READ[读取 .md]\n    READ --> PARSE[解析 frontmatter]\n    PARSE --> CHECK{sidecar 存在?}\n    CHECK -->|否| EMBED[重新嵌入]\n    CHECK -->|是| VALIDATE[验证 sidecar]\n    VALIDATE -->|有效| REUSE[复用 sidecar]\n    VALIDATE -->|无效| EMBED\n    REUSE --> NEXT[下一个文件]\n    EMBED --> WRITE[写入新 .embedding]\n    WRITE --> NEXT\n    LOOP -->|完成| ORPHAN[清理孤立 sidecar]\n    ORPHAN --> DONE[返回 ScanResult]\n```\n\n#### Sidecar 复用条件\n\n一个 `.embedding` sidecar 被认为是\"新鲜\"的，当且仅当：\n\n| 条件 | 说明 |\n|------|------|\n| 文件存在 | sidecar 文件存在 |\n| 解码有效 | magic + version + length 检查通过 |\n| 模型匹配 | `decoded.modelId === embedder.modelId` |\n| 维度匹配 | `decoded.dim === embedder.dim` |\n| SHA 匹配 | `decoded.contentSha === contentSha(memoryAsRead)` |\n\n资料来源：[src/store/memory-store.ts:400-450]()\n\n### Content SHA\n\nContent SHA 用于验证记忆内容是否发生变化，进而决定是否需要重新嵌入。计算范围仅限于 v0.1 基线 frontmatter：\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${memory.description}\\n${memory.body}`, 'utf8')\n    .digest('hex');\n```\n\n**重要**：`relations` 和 `supersedes` 图字段不参与 SHA 计算。这意味着添加或删除图关系不会使 embedding 失效。\n\n资料来源：[src/store/memory.ts:80-95]()\n\n## 搜索功能\n\n### 搜索流程\n\n```mermaid\ngraph TD\n    START[search query] --> RESCAN{需要 rescan?}\n    RESCAN -->|是| SCAN[调用 scan]\n    RESCAN -->|否| EMBED[嵌入查询文本]\n    SCAN --> EMBED\n    EMBED --> SIM[计算余弦相似度]\n    SIM --> FILTER[过滤已删除记忆]\n    FILTER --> RANK[按得分排序]\n    RANK --> EXPAND[expandRelations 扩展邻居]\n    EXPAND --> RESULT[返回结果信封]\n```\n\n### 搜索结果结构\n\n```typescript\ninterface MemorySearchResult {\n  query: string;           // 原始查询\n  memories: MemorySearchMatch[];  // 匹配结果\n  expanded: boolean;       // 是否包含扩展关系\n}\n```\n\n资料来源：[src/store/handlers.ts:50-80]()\n\n## 并发与锁定\n\n### Per-Name 锁定机制\n\n为防止并发写入同一记忆名称导致的竞态条件，系统实现了 `acquireNameLock` 机制：\n\n- 锁定粒度：每个记忆名称独立锁\n- 锁文件位置：`.locks/<name>.lock`\n- 超时回收：超过 5 秒的过期锁自动回收\n- 锁范围：覆盖 `.md` 和 `.embedding` 的完整写入过程\n\n资料来源：[src/store/memory-store.ts:500-550]()\n\n### 原子写入序列\n\n```mermaid\nsequenceDiagram\n    participant Store\n    participant Lock\n    participant AW as atomicWrite\n    participant FS\n    \n    Store->>Lock: acquireNameLock(name)\n    Lock-->>Store: release function\n    \n    Store->>AW: atomicWrite(mdPath, mdBytes)\n    AW->>FS: writeFile(tmpPath)\n    AW->>FS: rename(tmpPath, mdPath)\n    \n    Store->>AW: atomicWrite(embPath, embBytes)\n    AW->>FS: writeFile(tmpPath)\n    AW->>FS: rename(tmpPath, embPath)\n    \n    Store->>Lock: release()\n```\n\n## 作用域系统\n\n存储系统支持两种作用域（Scope），实现项目级别和用户级别的记忆隔离：\n\n```mermaid\ngraph LR\n    subgraph \"user scope\"\n        UD[~/.commonplace/]\n    end\n    subgraph \"project scope\"\n        PD[<project>/.commonplace/]\n    end\n    \n    UD --> UA[user/*.md]\n    UD --> UE[user/*.embedding]\n    PD --> PA[project/*.md]\n    PD --> PE[project/*.embedding]\n```\n\n| 作用域 | 存储路径 | 用途 |\n|--------|----------|------|\n| `user` | `~/.commonplace/` | 跨项目适用的规则、偏好 |\n| `project` | `<project>/.commonplace/` | 仅当前项目有效的上下文 |\n\n资料来源：[src/store/memory-store.ts:90-120]()\n\n## 提及提取器\n\n`mentions.ts` 模块负责从记忆正文中提取 `[[name]]` 格式的提及：\n\n- 仅识别匹配 `^[a-z0-9_]+$` 的名称\n- 返回唯一集合，按首次出现顺序排列\n- 可通过 `COMMONPLACE_EXTRACT_MENTIONS=false` 环境变量禁用\n- 在 `scan()` 和 `save()` 时自动调用\n- 提取的提及会添加到内存图的 `mentions` 边\n\n资料来源：[src/store/mentions.ts:1-50]()\n\n## 关键设计决策\n\n### 为什么不使用数据库\n\n- **简单性**：文件系统是最终的持久化介质，无需额外依赖\n- **可移植性**：记忆文件可独立使用任意文本编辑器查看和编辑\n- **可重建**：所有派生数据（embedding）可从 `.md` 重新生成\n- **版本控制**：可直接将 `.md` 文件纳入 Git 管理\n\n### Sidecar 文件策略\n\n`.embedding` 文件作为 sidecar 存在有以下优势：\n\n- 与 `.md` 文件解耦，删除 `.md` 时自动清理\n- 嵌入模型升级时可批量重新生成\n- 避免了数据库迁移的复杂性\n\n### 图字段不参与 SHA\n\n图关系（`relations`、`supersedes`）不参与 `contentSha` 计算是刻意的设计选择：\n\n> Adding or removing graph edges does not invalidate the embedding.\n\n这允许在不重新嵌入的情况下快速调整关系网络。\n\n资料来源：[src/store/memory.ts:20-30]()\n\n## 错误处理\n\n| 错误场景 | 处理方式 |\n|----------|----------|\n| 目标文件已存在 | 抛出错误，提示先删除 |\n| 源记忆不存在 | 抛出错误，阻止操作 |\n| 目标记忆不存在 | 抛出错误，阻止操作 |\n| 自环引用 | 抛出错误，禁止 |\n| 重复边 | 抛出错误，需先解绑 |\n| 磁盘读取失败 | 传播到调用方 |\n| 磁盘写入失败 | 传播到调用方 |\n\n## 相关子模块\n\n| 模块 | 职责 |\n|------|------|\n| `memory.ts` | Memory 序列化/反序列化、Content SHA 计算 |\n| `mentions.ts` | `[[name]]` 提及提取 |\n| `graph.ts` | 内存图数据结构 |\n| `atomic-write.ts` | 原子文件写入 |\n\n---\n\n<a id='page-scopes'></a>\n\n## 作用域与多存储\n\n### 相关页面\n\n相关主题：[存储系统](#page-storage)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n- [src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts)\n- [CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n</details>\n\n# 作用域与多存储\n\n## 概述\n\nCommonplace 采用**双存储架构**，支持用户级别（user）和项目级别（project）两套独立的记忆存储。这种设计允许用户在不同的项目中维护各自的上下文，同时在全局层面保留跨项目的个人规则和偏好。\n\n**核心价值：**\n\n- **持久化反馈**：跨项目积累的纠正和学习经验不会因项目切换而丢失\n- **项目隔离**：每个项目可以拥有独立的架构笔记和约定规则\n- **作用域感知**：工具调用可精确指定读写目标存储\n\n资料来源：[README.md:1-20]()\n\n## 架构设计\n\n### 双存储模型\n\n```mermaid\ngraph TD\n    subgraph 用户存储 [\"用户存储 (User Store)\"]\n        U[~/.commonplace/memory]\n        U1[用户类型记忆]\n        U2[反馈类型记忆]\n    end\n    \n    subgraph 项目存储 [\"项目存储 (Project Store)\"]\n        P[.commonplace/memory]\n        P1[项目类型记忆]\n        P2[引用类型记忆]\n    end\n    \n    subgraph MCP工具 [\"MCP 工具层\"]\n        SAVE[memory_save]\n        SEARCH[memory_search]\n        LIST[memory_list]\n        DELETE[memory_delete]\n    end\n    \n    SAVE -->|scope: user| U\n    SAVE -->|scope: project| P\n    SEARCH -->|跨存储合并| RESULT[按评分排序结果]\n    \n    style 用户存储 fill:#e1f5fe\n    style 项目存储 fill:#fff3e0\n```\n\n### 记忆类型与存储映射\n\n| 记忆类型 | 建议存储位置 | 典型用途 |\n|---------|------------|---------|\n| `user` | 用户存储 | 个人规则、偏好、身份信息 |\n| `feedback` | 用户存储 | 来自 Agent 的纠正和经验教训 |\n| `project` | 项目存储 | 架构笔记、仓库约定、特定决策 |\n| `reference` | 项目存储 | API 形状、公式、引用性知识 |\n\n资料来源：[README.md:60-75]()\n\n## 作用域检测优先级\n\n项目存储的检测按照以下优先级顺序进行，从高到低：\n\n```mermaid\ngraph LR\n    A[\"1. COMMONPLACE_PROJECT_DIR 环境变量\"] -->|最高优先级| Z[显式覆盖]\n    B[\"2. MCP roots/list 协议\"] -->|次高| P1[项目根目录]\n    C[\"3. 当前工作目录 (cwd)\"] -->|兜底| P2[自动检测]\n    \n    style A fill:#ffcdd2\n    style Z fill:#c8e6c9\n```\n\n### 优先级详情\n\n1. **环境变量 `COMMONPLACE_PROJECT_DIR`**：显式覆盖，最高优先级。路径无需预先存在，Commonplace 会自动创建所需的目录结构。\n2. **MCP `roots/list` 协议**：通过 MCP 协议发现的项目根目录。\n3. **当前工作目录**：自动检测，将 `<cwd>/.commonplace/memory` 作为项目存储路径。\n\n资料来源：[README.md:140-155]()\n\n## 存储目录结构\n\n### 用户存储\n\n默认路径：`~/.commonplace/memory`（可通过 `COMMONPLACE_USER_DIR` 覆盖）\n\n```\n~/.commonplace/memory/\n├── feedback_learned_patterns.md\n├── feedback_avoid_shrink_scope.md\n├── user_preferences.md\n└── .embeddings/\n    ├── feedback_learned_patterns.embedding\n    └── ...\n```\n\n### 项目存储\n\n项目存储位置取决于检测优先级：\n\n```\n# 方式1: 环境变量\n${COMMONPLACE_PROJECT_DIR}/memory/\n\n# 方式2: 项目根目录\n<project-root>/.commonplace/memory/\n```\n\n项目存储只在该项目被 Commonplace 加载时才会被初始化和扫描。\n\n资料来源：[CLAUDE.md:1-30]()\n\n## 工具接口中的作用域参数\n\n所有四个核心工具都接受可选的 `scope` 参数：\n\n```typescript\ninterface ToolArguments {\n  name?: string;\n  type?: 'user' | 'feedback' | 'project' | 'reference';\n  scope?: 'user' | 'project';  // 作用域参数\n  query?: string;\n  // ... 其他参数\n}\n```\n\n### 作用域行为\n\n| 操作 | `scope` 省略 | `scope: 'user'` | `scope: 'project'` |\n|-----|-------------|-----------------|-------------------|\n| **读取** | 合并两存储，按评分排序 | 仅用户存储 | 仅项目存储 |\n| **写入** | 默认写入用户存储 | 写入用户存储 | 写入项目存储 |\n\n```mermaid\ngraph TD\n    subgraph 读取流程\n        R1{scope 参数?}\n        R2[合并两存储结果]\n        R3[仅用户存储]\n        R4[仅项目存储]\n        \n        R1 -->|省略| R2\n        R1 -->|user| R3\n        R1 -->|project| R4\n    end\n    \n    subgraph 写入流程\n        W1{scope 参数?}\n        W2[写入用户存储]\n        W3[写入项目存储]\n        \n        W1 -->|省略/空| W2\n        W1 -->|project| W3\n    end\n```\n\n资料来源：[README.md:80-95]()\n\n## 搜索结果合并\n\n当 `scope` 参数省略时，搜索会跨两个存储执行，并通过向量相似度评分合并结果：\n\n```typescript\ninterface MemorySearchMatch {\n  name: string;\n  type: MemoryType;\n  description: string;\n  body: string;\n  score: number;      // 余弦相似度，保留3位小数\n  scope: 'user' | 'project';  // 结果来源标识\n}\n```\n\n**合并规则：**\n\n- 按 `score` 降序排列\n- 每个匹配结果携带 `scope` 标签，标识其来源存储\n- 项目存储的结果可能在某些查询中排名更高\n\n资料来源：[src/server/handlers.ts:1-50]()\n\n## 迁移命令与作用域\n\n`commonplace migrate` 命令支持跨作用域的记忆迁移：\n\n```bash\n# 扫描用户存储（默认）\ncommonplace migrate\n\n# 扫描指定目录\ncommonplace migrate ~/.commonplace/memory\n\n# 预演模式（不实际写入）\ncommonplace migrate ~/.commonplace/memory --dry-run\n```\n\n### 迁移操作类型\n\n| 操作 | 说明 |\n|-----|------|\n| **嵌入** | 为缺少 `.embedding` 的 `.md` 文件生成向量 |\n| **重新嵌入** | 重新生成过时的（内容哈希/模型不匹配）或损坏的 sidecar |\n| **清理孤立文件** | 删除没有对应 `.md` 的孤立 `.embedding` 文件 |\n| **修剪悬空引用** | 移除指向不存在记忆的关系和 supersedes 条目 |\n\n资料来源：[src/cli/migrate.ts:1-80]()\n\n## 环境变量配置\n\n| 变量名 | 默认值 | 说明 |\n|-------|--------|------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | 用户存储根目录 |\n| `COMMONPLACE_PROJECT_DIR` | 未设置 | 项目存储根目录（显式覆盖） |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | 启用 `[[name]]` 提及提取 |\n\n### 配置示例\n\n```bash\n# 使用自定义用户存储位置\nexport COMMONPLACE_USER_DIR=/data/commonplace/memory\n\n# 指定项目存储位置（优先级最高）\nexport COMMONPLACE_PROJECT_DIR=/workspace/my-project/.commonplace/memory\n```\n\n资料来源：[src/index.ts:1-30]()\n\n## 开发指南：记忆存储实践\n\n在开发 Commonplace 项目本身时，应遵循以下规则：\n\n```mermaid\ngraph TD\n    subgraph 记忆保存决策\n        D1{记忆范围}\n        D2[scope: user] --> U1[跨项目规则、偏好]\n        D3[scope: project] --> P1[架构笔记、仓库约定]\n        \n        D1 -->|跨项目教训| D2\n        D1 -->|特定代码库| D3\n    end\n    \n    subgraph 禁止事项\n        B1[禁止写入 harness 内置路径]\n        B2[禁止删除历史记忆]\n    end\n    \n    P1 --> B1\n```\n\n**核心原则：**\n\n- 通过 `mcp__commonplace__memory_save` 保存记忆，选择合适的 `type`\n- 通过 `mcp__commonplace__memory_search` 和 `mcp__commonplace__memory_list` 召回记忆\n- **禁止**向 `~/.claude/projects/<slug>/memory/` 写入（使用 Commonplace 产品自身）\n- **禁止**删除已有的历史记忆\n\n资料来源：[CLAUDE.md:20-45]()\n\n## 记忆文件格式与作用域\n\n每条记忆存储为独立的 Markdown 文件，带有 YAML frontmatter：\n\n```yaml\n---\nname: feedback_scope          # 记忆唯一标识\ndescription: 不要单方面缩减范围  # 简短描述\ntype: feedback                # 记忆类型\nrelations:                    # 可选：关系图边\n  - to: architecture_decision\n    type: builds-on\nsupersedes:                   # 可选：标记被替代的记忆\n  - old_scope_rule\n---\n记忆正文内容，支持 [[name]] 语法引用其他记忆。\n```\n\n**作用域隐式由文件所在目录决定**，而非 frontmatter 中的字段。\n\n资料来源：[src/store/memory.ts:1-60]()\n\n## 总结\n\n作用域与多存储系统为 Commonplace 提供了灵活的记忆组织能力：\n\n- **用户存储**（`~/.commonplace/memory`）：跨项目的个人知识和反馈\n- **项目存储**（`.commonplace/memory`）：项目特定的上下文和决策\n- **作用域感知 API**：精确控制记忆的读写目标\n- **自动合并搜索**：跨存储检索，按相关性排序\n\n---\n\n---\n\n## Doramagic 踩坑日志\n\n项目：rickbassham/commonplace\n\n摘要：发现 8 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。\n\n## 1. 能力坑 · 能力判断依赖假设\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：README/documentation is current enough for a first validation pass.\n- 对用户的影响：假设不成立时，用户拿不到承诺的能力。\n- 建议检查：将假设转成下游验证清单。\n- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。\n- 证据：capability.assumptions | github_repo:1232879661 | https://github.com/rickbassham/commonplace | README/documentation is current enough for a first validation pass.\n\n## 2. 运行坑 · 运行可能依赖外部服务\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：项目说明出现 external service/cloud/webhook/database 等运行依赖关键词。\n- 对用户的影响：本地安装成功不等于能力可用，外部服务不可用会阻断体验。\n- 建议检查：确认是否有离线 demo、mock 数据或可替代服务。\n- 防护动作：外部服务依赖未明确时，不把本地安装成功等同于能力可用。\n- 证据：packet_text.keyword_scan | github_repo:1232879661 | https://github.com/rickbassham/commonplace | matched external service / cloud / webhook / database keyword\n\n## 3. 维护坑 · 维护活跃度未知\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：未记录 last_activity_observed。\n- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。\n- 证据：evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | last_activity_observed missing\n\n## 4. 安全/权限坑 · 下游验证发现风险项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：下游已经要求复核，不能在页面中弱化。\n- 建议检查：进入安全/权限治理复核队列。\n- 防护动作：下游风险存在时必须保持 review/recommendation 降级。\n- 证据：downstream_validation.risk_items | github_repo:1232879661 | https://github.com/rickbassham/commonplace | no_demo; severity=medium\n\n## 5. 安全/权限坑 · 存在安全注意事项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：No sandbox install has been executed yet; downstream must verify before user use.\n- 对用户的影响：用户安装前需要知道权限边界和敏感操作。\n- 建议检查：转成明确权限清单和安全审查提示。\n- 防护动作：安全注意事项必须面向用户前置展示。\n- 证据：risks.safety_notes | github_repo:1232879661 | https://github.com/rickbassham/commonplace | No sandbox install has been executed yet; downstream must verify before user use.\n\n## 6. 安全/权限坑 · 存在评分风险\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：风险会影响是否适合普通用户安装。\n- 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。\n- 证据：risks.scoring_risks | github_repo:1232879661 | https://github.com/rickbassham/commonplace | no_demo; severity=medium\n\n## 7. 维护坑 · issue/PR 响应质量未知\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：issue_or_pr_quality=unknown。\n- 对用户的影响：用户无法判断遇到问题后是否有人维护。\n- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。\n- 防护动作：issue/PR 响应未知时，必须提示维护风险。\n- 证据：evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | issue_or_pr_quality=unknown\n\n## 8. 维护坑 · 发布节奏不明确\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：release_recency=unknown。\n- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。\n- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。\n- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。\n- 证据：evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | release_recency=unknown\n\n<!-- canonical_name: rickbassham/commonplace; human_manual_source: deepwiki_human_wiki -->\n",
      "markdown_key": "commonplace",
      "pages": "draft",
      "source_refs": [
        {
          "evidence_id": "github_repo:1232879661",
          "kind": "repo",
          "supports_claim_ids": [
            "claim_identity",
            "claim_distribution",
            "claim_capability"
          ],
          "url": "https://github.com/rickbassham/commonplace"
        },
        {
          "evidence_id": "art_57badb8d533b4ee293d6dfac52cf0999",
          "kind": "docs",
          "supports_claim_ids": [
            "claim_identity",
            "claim_distribution",
            "claim_capability"
          ],
          "url": "https://github.com/rickbassham/commonplace#readme"
        }
      ],
      "summary": "DeepWiki/Human Wiki 完整输出，末尾追加 Discovery Agent 踩坑日志。",
      "title": "commonplace 说明书",
      "toc": [
        "https://github.com/rickbassham/commonplace 项目说明书",
        "目录",
        "项目概览",
        "项目简介",
        "核心设计原则",
        "内存类型系统",
        "记忆存储架构",
        "核心模块",
        "Doramagic 踩坑日志"
      ]
    }
  },
  "quality_gate": {
    "blocking_gaps": [],
    "category_confidence": "medium",
    "compile_status": "ready_for_review",
    "five_assets_present": true,
    "install_sandbox_verified": true,
    "missing_evidence": [],
    "next_action": "publish to Doramagic.ai project surfaces",
    "prompt_preview_boundary_ok": true,
    "publish_status": "publishable",
    "quick_start_verified": true,
    "repo_clone_verified": true,
    "repo_commit": "bda917d02f7cf739fc731a3f895316b118ec2ba5",
    "repo_inspection_error": null,
    "repo_inspection_files": [
      "pnpm-lock.yaml",
      "package.json",
      "README.md",
      "docs/sidecar-format.md",
      "src/index.ts",
      "src/cli/migrate.ts",
      "src/cli/graph.ts",
      "src/bin/env.ts",
      "src/bin/commonplace-mcp.ts",
      "src/bin/scope.ts",
      "src/bin/boot.ts",
      "src/embedder/index.ts",
      "src/server/defaults.ts",
      "src/server/tools.ts",
      "src/server/index.ts",
      "src/server/server.ts",
      "src/server/handlers.ts",
      "src/store/mentions.ts",
      "src/store/sidecar.ts",
      "src/store/memory-store.ts",
      "src/store/graph.ts",
      "src/store/memory.ts",
      "src/store/atomic-write.ts"
    ],
    "repo_inspection_verified": true,
    "review_reasons": [],
    "tag_count_ok": true,
    "unsupported_claims": []
  },
  "schema_version": "0.1",
  "user_assets": {
    "ai_context_pack": {
      "asset_id": "ai_context_pack",
      "filename": "AI_CONTEXT_PACK.md",
      "markdown": "# commonplace-mcp - Doramagic AI Context Pack\n\n> 定位：安装前体验与判断资产。它帮助宿主 AI 有一个好的开始，但不代表已经安装、执行或验证目标项目。\n\n## 充分原则\n\n- **充分原则，不是压缩原则**：AI Context Pack 应该充分到让宿主 AI 在开工前理解项目价值、能力边界、使用入口、风险和证据来源；它可以分层组织，但不以最短摘要为目标。\n- **压缩策略**：只压缩噪声和重复内容，不压缩会影响判断和开工质量的上下文。\n\n## 给宿主 AI 的使用方式\n\n你正在读取 Doramagic 为 commonplace-mcp 编译的 AI Context Pack。请把它当作开工前上下文：帮助用户理解适合谁、能做什么、如何开始、哪些必须安装后验证、风险在哪里。不要声称你已经安装、运行或执行了目标项目。\n\n## Claim 消费规则\n\n- **事实来源**：Repo Evidence + Claim/Evidence Graph；Human Wiki 只提供显著性、术语和叙事结构。\n- **事实最低状态**：`supported`\n- `supported`：可以作为项目事实使用，但回答中必须引用 claim_id 和证据路径。\n- `weak`：只能作为低置信度线索，必须要求用户继续核实。\n- `inferred`：只能用于风险提示或待确认问题，不能包装成项目事实。\n- `unverified`：不得作为事实使用，应明确说证据不足。\n- `contradicted`：必须展示冲突来源，不得替用户强行选择一个版本。\n\n## 它最适合谁\n\n- **正在使用 Claude/Codex/Cursor/Gemini 等宿主 AI 的开发者**：README 或插件配置提到多个宿主 AI。 证据：`README.md` Claim：`clm_0002` supported 0.86\n\n## 它能做什么\n\n- **命令行启动或安装流程**（需要安装后验证）：项目文档中存在可执行命令，真实使用需要在本地或宿主环境中运行这些命令。 证据：`README.md` Claim：`clm_0001` supported 0.86\n\n## 怎么开始\n\n- `npm i -g commonplace-mcp` 证据：`README.md` Claim：`clm_0003` supported 0.86\n- `claude mcp add commonplace commonplace-mcp` 证据：`README.md` Claim：`clm_0004` supported 0.86\n\n## 继续前判断卡\n\n- **当前建议**：先做权限沙盒试用\n- **为什么**：项目存在安装命令、宿主配置或本地写入线索，不建议直接进入主力环境，应先在隔离环境试装。\n\n### 30 秒判断\n\n- **现在怎么做**：先做权限沙盒试用\n- **最小安全下一步**：先跑 Prompt Preview；若仍要安装，只在隔离环境试装\n- **先别相信**：工具权限边界不能在安装前相信。\n- **继续会触碰**：命令执行、宿主 AI 配置、本地环境或项目文件\n\n### 现在可以相信\n\n- **适合人群线索：正在使用 Claude/Codex/Cursor/Gemini 等宿主 AI 的开发者**（supported）：有 supported claim 或项目证据支撑，但仍不等于真实安装效果。 证据：`README.md` Claim：`clm_0002` supported 0.86\n- **能力存在：命令行启动或安装流程**（supported）：可以相信项目包含这类能力线索；是否适合你的具体任务仍要试用或安装后验证。 证据：`README.md` Claim：`clm_0001` supported 0.86\n- **存在 Quick Start / 安装命令线索**（supported）：可以相信项目文档出现过启动或安装入口；不要因此直接在主力环境运行。 证据：`README.md` Claim：`clm_0003` supported 0.86\n\n### 现在还不能相信\n\n- **工具权限边界不能在安装前相信。**（unverified）：MCP/tool 类项目通常会触碰文件、网络、浏览器或外部 API，必须真实检查权限和日志。\n- **真实输出质量不能在安装前相信。**（unverified）：Prompt Preview 只能展示引导方式，不能证明真实项目中的结果质量。\n- **宿主 AI 版本兼容性不能在安装前相信。**（unverified）：Claude、Cursor、Codex、Gemini 等宿主加载规则和版本差异必须在真实环境验证。\n- **不会污染现有宿主 AI 行为，不能直接相信。**（inferred）：Skill、plugin、AGENTS/CLAUDE/GEMINI 指令可能改变宿主 AI 的默认行为。 证据：`CLAUDE.md`\n- **可安全回滚不能默认相信。**（unverified）：除非项目明确提供卸载和恢复说明，否则必须先在隔离环境验证。\n- **真实安装后是否与用户当前宿主 AI 版本兼容？**（unverified）：兼容性只能通过实际宿主环境验证。\n- **项目输出质量是否满足用户具体任务？**（unverified）：安装前预览只能展示流程和边界，不能替代真实评测。\n- **安装命令是否需要网络、权限或全局写入？**（unverified）：这影响企业环境和个人环境的安装风险。 证据：`README.md`\n\n### 继续会触碰什么\n\n- **命令执行**：包管理器、网络下载、本地插件目录、项目配置或用户主目录。 原因：运行第一条命令就可能产生环境改动；必须先判断是否值得跑。 证据：`README.md`\n- **宿主 AI 配置**：Claude/Codex/Cursor/Gemini/OpenCode 等宿主的 plugin、Skill 或规则加载配置。 原因：宿主配置会改变 AI 后续工作方式，可能和用户已有规则冲突。 证据：`CLAUDE.md`\n- **本地环境或项目文件**：安装结果、插件缓存、项目配置或本地依赖目录。 原因：安装前无法证明写入范围和回滚方式，需要隔离验证。 证据：`README.md`\n- **宿主 AI 上下文**：AI Context Pack、Prompt Preview、Skill 路由、风险规则和项目事实。 原因：导入上下文会影响宿主 AI 后续判断，必须避免把未验证项包装成事实。\n\n### 最小安全下一步\n\n- **先跑 Prompt Preview**：用安装前交互式试用判断工作方式是否匹配，不需要授权或改环境。（适用：任何项目都适用，尤其是输出质量未知时。）\n- **只在隔离目录或测试账号试装**：避免安装命令污染主力宿主 AI、真实项目或用户主目录。（适用：存在命令执行、插件配置或本地写入线索时。）\n- **先备份宿主 AI 配置**：Skill、plugin、规则文件可能改变 Claude/Cursor/Codex 的默认行为。（适用：存在插件 manifest、Skill 或宿主规则入口时。）\n- **安装后只验证一个最小任务**：先验证加载、兼容、输出质量和回滚，再决定是否深用。（适用：准备从试用进入真实工作流时。）\n\n### 退出方式\n\n- **保留安装前状态**：记录原始宿主配置和项目状态，后续才能判断是否可恢复。\n- **准备移除宿主 plugin / Skill / 规则入口**：如果试装后行为异常，可以把宿主 AI 恢复到试装前状态。\n- **记录安装命令和写入路径**：没有明确卸载说明时，至少要知道哪些目录或配置需要手动清理。\n- **如果没有回滚路径，不进入主力环境**：不可回滚是继续前阻断项，不应靠信任或运气继续。\n\n## 哪些只能预览\n\n- 解释项目适合谁和能做什么\n- 基于项目文档演示典型对话流程\n- 帮助用户判断是否值得安装或继续研究\n\n## 哪些必须安装后验证\n\n- 真实安装 Skill、插件或 CLI\n- 执行脚本、修改本地文件或访问外部服务\n- 验证真实输出质量、性能和兼容性\n\n## 边界与风险判断卡\n\n- **把安装前预览误认为真实运行**：用户可能高估项目已经完成的配置、权限和兼容性验证。 处理方式：明确区分 prompt_preview_can_do 与 runtime_required。 Claim：`clm_0005` inferred 0.45\n- **命令执行会修改本地环境**：安装命令可能写入用户主目录、宿主插件目录或项目配置。 处理方式：先在隔离环境或测试账号中运行。 证据：`README.md` Claim：`clm_0006` supported 0.86\n- **待确认**：真实安装后是否与用户当前宿主 AI 版本兼容？。原因：兼容性只能通过实际宿主环境验证。\n- **待确认**：项目输出质量是否满足用户具体任务？。原因：安装前预览只能展示流程和边界，不能替代真实评测。\n- **待确认**：安装命令是否需要网络、权限或全局写入？。原因：这影响企业环境和个人环境的安装风险。\n\n## 开工前工作上下文\n\n### 加载顺序\n\n- 先读取 how_to_use.host_ai_instruction，建立安装前判断资产的边界。\n- 读取 claim_graph_summary，确认事实来自 Claim/Evidence Graph，而不是 Human Wiki 叙事。\n- 再读取 intended_users、capabilities 和 quick_start_candidates，判断用户是否匹配。\n- 需要执行具体任务时，优先查 role_skill_index，再查 evidence_index。\n- 遇到真实安装、文件修改、网络访问、性能或兼容性问题时，转入 risk_card 和 boundaries.runtime_required。\n\n### 任务路由\n\n- **命令行启动或安装流程**：先说明这是安装后验证能力，再给出安装前检查清单。 边界：必须真实安装或运行后验证。 证据：`README.md` Claim：`clm_0001` supported 0.86\n\n### 上下文规模\n\n- 文件总数：113\n- 重要文件覆盖：40/113\n- 证据索引条目：80\n- 角色 / Skill 条目：5\n\n### 证据不足时的处理\n\n- **missing_evidence**：说明证据不足，要求用户提供目标文件、README 段落或安装后验证记录；不要补全事实。\n- **out_of_scope_request**：说明该任务超出当前 AI Context Pack 证据范围，并建议用户先查看 Human Manual 或真实安装后验证。\n- **runtime_request**：给出安装前检查清单和命令来源，但不要替用户执行命令或声称已执行。\n- **source_conflict**：同时展示冲突来源，标记为待核实，不要强行选择一个版本。\n\n## Prompt Recipes\n\n### 适配判断\n\n- 目标：判断这个项目是否适合用户当前任务。\n- 预期输出：适配结论、关键理由、证据引用、安装前可预览内容、必须安装后验证内容、下一步建议。\n\n```text\n请基于 commonplace-mcp 的 AI Context Pack，先问我 3 个必要问题，然后判断它是否适合我的任务。回答必须包含：适合谁、能做什么、不能做什么、是否值得安装、证据来自哪里。所有项目事实必须引用 evidence_refs、source_paths 或 claim_id。\n```\n\n### 安装前体验\n\n- 目标：让用户在安装前感受核心工作流，同时避免把预览包装成真实能力或营销承诺。\n- 预期输出：一段带边界标签的体验剧本、安装后验证清单和谨慎建议；不含真实运行承诺或强营销表述。\n\n```text\n请把 commonplace-mcp 当作安装前体验资产，而不是已安装工具或真实运行环境。\n\n请严格输出四段：\n1. 先问我 3 个必要问题。\n2. 给出一段“体验剧本”：用 [安装前可预览]、[必须安装后验证]、[证据不足] 三种标签展示它可能如何引导工作流。\n3. 给出安装后验证清单：列出哪些能力只有真实安装、真实宿主加载、真实项目运行后才能确认。\n4. 给出谨慎建议：只能说“值得继续研究/试装”“先补充信息后再判断”或“不建议继续”，不得替项目背书。\n\n硬性边界：\n- 不要声称已经安装、运行、执行测试、修改文件或产生真实结果。\n- 不要写“自动适配”“确保通过”“完美适配”“强烈建议安装”等承诺性表达。\n- 如果描述安装后的工作方式，必须使用“如果安装成功且宿主正确加载 Skill，它可能会……”这种条件句。\n- 体验剧本只能写成“示例台词/假设流程”：使用“可能会询问/可能会建议/可能会展示”，不要写“已写入、已生成、已通过、正在运行、正在生成”。\n- Prompt Preview 不负责给安装命令；如用户准备试装，只能提示先阅读 Quick Start 和 Risk Card，并在隔离环境验证。\n- 所有项目事实必须来自 supported claim、evidence_refs 或 source_paths；inferred/unverified 只能作风险或待确认项。\n\n```\n\n### 角色 / Skill 选择\n\n- 目标：从项目里的角色或 Skill 中挑选最匹配的资产。\n- 预期输出：候选角色或 Skill 列表，每项包含适用场景、证据路径、风险边界和是否需要安装后验证。\n\n```text\n请读取 role_skill_index，根据我的目标任务推荐 3-5 个最相关的角色或 Skill。每个推荐都要说明适用场景、可能输出、风险边界和 evidence_refs。\n```\n\n### 风险预检\n\n- 目标：安装或引入前识别环境、权限、规则冲突和质量风险。\n- 预期输出：环境、权限、依赖、许可、宿主冲突、质量风险和未知项的检查清单。\n\n```text\n请基于 risk_card、boundaries 和 quick_start_candidates，给我一份安装前风险预检清单。不要替我执行命令，只说明我应该检查什么、为什么检查、失败会有什么影响。\n```\n\n### 宿主 AI 开工指令\n\n- 目标：把项目上下文转成一次对话开始前的宿主 AI 指令。\n- 预期输出：一段边界明确、证据引用明确、适合复制给宿主 AI 的开工前指令。\n\n```text\n请基于 commonplace-mcp 的 AI Context Pack，生成一段我可以粘贴给宿主 AI 的开工前指令。这段指令必须遵守 not_runtime=true，不能声称项目已经安装、运行或产生真实结果。\n```\n\n\n## 角色 / Skill 索引\n\n- 共索引 5 个角色 / Skill / 项目文档条目。\n\n- **Project Rules**（project_doc）：Project-specific rules for this codebase. Universal coding rules git practices, quality standards, task sizing, language rules, etc. are in ~/.claude/CLAUDE.md and apply automatically. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`CLAUDE.md`\n- **commonplace**（project_doc）：Commonplace is a commonplace book for your agent: a local-first store of markdown notes, each paired with a sidecar embeddings file, served to Claude Code or any MCP client over stdio. There is no database -- notes live as .md files on disk, embeddings live next to them as .embedding sidecars, and search is in-memory cosine similarity over those sidecars. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`README.md`\n- **Contributing to commonplace**（project_doc）：Thanks for your interest in contributing! This project is small and opinionated; the rules below keep the history clean and the green lights honest. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`CONTRIBUTING.md`\n- **Sidecar binary format .embedding**（project_doc）：This document specifies the on-disk wire format for the binary .embedding sidecars that pair with each memory .md file. The format is owned by DAR-910 https://linear.app/darkdragonsastro/issue/DAR-910 ; the encode and decode implementations live in src/store/sidecar.ts ../src/store/sidecar.ts . 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`docs/sidecar-format.md`\n- **Changelog**（project_doc）：All notable changes to commonplace-mcp are documented in this file. 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`CHANGELOG.md`\n\n## 证据索引\n\n- 共索引 80 条证据。\n\n- **Project Rules**（documentation）：Project-specific rules for this codebase. Universal coding rules git practices, quality standards, task sizing, language rules, etc. are in ~/.claude/CLAUDE.md and apply automatically. 证据：`CLAUDE.md`\n- **commonplace**（documentation）：Commonplace is a commonplace book for your agent: a local-first store of markdown notes, each paired with a sidecar embeddings file, served to Claude Code or any MCP client over stdio. There is no database -- notes live as .md files on disk, embeddings live next to them as .embedding sidecars, and search is in-memory cosine similarity over those sidecars. 证据：`README.md`\n- **Package**（package_manifest）：{ \"name\": \"commonplace-mcp\", \"version\": \"0.2.1\", \"description\": \"Local-first commonplace book with embedding-backed semantic search via MCP\", \"license\": \"MIT\", \"type\": \"module\", \"main\": \"dist/index.js\", \"bin\": { \"commonplace\": \"dist/index.js\", \"commonplace-mcp\": \"dist/bin/commonplace-mcp.js\" }, \"files\": \"dist/\", \"LICENSE\", \"README.md\", \"CHANGELOG.md\" , \"repository\": { \"type\": \"git\", \"url\": \"git+https://github.com/rickbassham/commonplace.git\" }, \"homepage\": \"https://github.com/rickbassham/commonplace readme\", \"bugs\": { \"url\": \"https://github.com/rickbassham/commonplace/issues\" }, \"keywords\": \"mcp\", \"model-context-protocol\", \"memory\", \"embeddings\", \"semantic-search\", \"claude\", \"ai-agent\" , \"e… 证据：`package.json`\n- **Contributing to commonplace**（documentation）：Thanks for your interest in contributing! This project is small and opinionated; the rules below keep the history clean and the green lights honest. 证据：`CONTRIBUTING.md`\n- **License**（source_file）：Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files the \"Software\" , to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 证据：`LICENSE`\n- **Sidecar binary format .embedding**（documentation）：This document specifies the on-disk wire format for the binary .embedding sidecars that pair with each memory .md file. The format is owned by DAR-910 https://linear.app/darkdragonsastro/issue/DAR-910 ; the encode and decode implementations live in src/store/sidecar.ts ../src/store/sidecar.ts . 证据：`docs/sidecar-format.md`\n- **Changelog**（documentation）：All notable changes to commonplace-mcp are documented in this file. 证据：`CHANGELOG.md`\n- **.Versionrc**（structured_config）：{ \"bumpFiles\": { \"filename\": \"package.json\", \"type\": \"json\" }, { \"filename\": \"src/server/server.ts\", \"updater\": \"scripts/server-version-updater.cjs\" } , \"header\": \" Changelog\\n\\nAll notable changes to commonplace-mcp are documented in this file.\\n\\nThe format follows Keep a Changelog https://keepachangelog.com/en/1.1.0/ ,\\nand this project adheres to Semantic Versioning https://semver.org/ .\\n\", \"types\": { \"type\": \"feat\", \"section\": \"Added\" }, { \"type\": \"fix\", \"section\": \"Fixed\" }, { \"type\": \"perf\", \"section\": \"Performance\" }, { \"type\": \"refactor\", \"section\": \"Changed\" }, { \"type\": \"revert\", \"section\": \"Reverted\" }, { \"type\": \"chore\", \"hidden\": true }, { \"type\": \"test\", \"hidden\": true }, {… 证据：`.versionrc.json`\n- **Tsconfig.Build**（structured_config）：{ \"extends\": \"./tsconfig.json\", \"compilerOptions\": { \"outDir\": \"dist\", \"rootDir\": \"src\" }, \"include\": \"src/ / \" , \"exclude\": \"node modules\", \"dist\", \"tests\", \" / .test.ts\", \"vitest.config.ts\" } 证据：`tsconfig.build.json`\n- **Tsconfig**（structured_config）：{ \"compilerOptions\": { \"target\": \"ES2022\", \"module\": \"NodeNext\", \"moduleResolution\": \"NodeNext\", \"strict\": true, \"esModuleInterop\": true, \"skipLibCheck\": true, \"forceConsistentCasingInFileNames\": true, \"resolveJsonModule\": true, \"isolatedModules\": true, \"noUncheckedIndexedAccess\": true, \"noImplicitOverride\": true, \"outDir\": \"dist\", \"declaration\": true, \"declarationMap\": true, \"sourceMap\": true, \"types\": \"node\", \"vitest/globals\" }, \"include\": \"src/ / \", \"tests/ / \", \"vitest.config.ts\" , \"exclude\": \"node modules\", \"dist\" } 证据：`tsconfig.json`\n- **Cycles 2**（structured_config）：{ \"root\": \"a\", \"depth\": 2, \"memories\": { \"name\": \"a\", \"relations\": { \"to\": \"b\", \"type\": \"related-to\" } }, { \"name\": \"b\", \"relations\": { \"to\": \"a\", \"type\": \"related-to\" } } } 证据：`tests/fixtures/graph/cycles-2.json`\n- **Cycles 3**（structured_config）：{ \"root\": \"a\", \"depth\": 3, \"memories\": { \"name\": \"a\", \"relations\": { \"to\": \"b\", \"type\": \"related-to\" } }, { \"name\": \"b\", \"relations\": { \"to\": \"c\", \"type\": \"related-to\" } }, { \"name\": \"c\", \"relations\": { \"to\": \"a\", \"type\": \"related-to\" } } } 证据：`tests/fixtures/graph/cycles-3.json`\n- **Depth 0**（structured_config）：{ \"root\": \"root\", \"depth\": 0, \"memories\": { \"name\": \"root\", \"relations\": { \"to\": \"alpha\", \"type\": \"related-to\" } }, { \"name\": \"alpha\" } } 证据：`tests/fixtures/graph/depth-0.json`\n- **Depth 1**（structured_config）：{ \"root\": \"root\", \"depth\": 1, \"memories\": { \"name\": \"root\", \"relations\": { \"to\": \"alpha\", \"type\": \"related-to\" }, { \"to\": \"beta\", \"type\": \"builds-on\" } }, { \"name\": \"alpha\", \"relations\": { \"to\": \"gamma\", \"type\": \"related-to\" } }, { \"name\": \"beta\" }, { \"name\": \"gamma\" } } 证据：`tests/fixtures/graph/depth-1.json`\n- **Depth 2**（structured_config）：{ \"root\": \"root\", \"depth\": 2, \"memories\": { \"name\": \"root\", \"relations\": { \"to\": \"alpha\", \"type\": \"related-to\" }, { \"to\": \"beta\", \"type\": \"builds-on\" } }, { \"name\": \"alpha\", \"relations\": { \"to\": \"gamma\", \"type\": \"related-to\" } }, { \"name\": \"beta\" }, { \"name\": \"gamma\" } } 证据：`tests/fixtures/graph/depth-2.json`\n- **.editorconfig**（source_file）：charset = utf-8 end of line = lf insert final newline = true trim trailing whitespace = true indent style = space indent size = 2 证据：`.editorconfig`\n- **.gitignore**（source_file）：node modules/ dist/ .embedding .DS Store .env.local 证据：`.gitignore`\n- **.nvmrc**（source_file）：24 证据：`.nvmrc`\n- **CHANGELOG.md is hand-authored Keep-a-Changelog markdown. Prettier rewraps**（source_file）：node modules/ dist/ pnpm-lock.yaml .embedding 证据：`.prettierignore`\n- **.prettierrc**（source_file）：{ \"semi\": true, \"singleQuote\": true, \"trailingComma\": \"all\", \"printWidth\": 100, \"tabWidth\": 2, \"useTabs\": false, \"endOfLine\": \"lf\" } 证据：`.prettierrc`\n- **Makefile**（source_file）：.PHONY: help install build test typecheck lint format format-check audit release release-dry 证据：`Makefile`\n- **Eslint.Config**（source_file）：// @ts-check import eslint from '@eslint/js'; import tseslint from 'typescript-eslint'; 证据：`eslint.config.js`\n- **!/usr/bin/env node**（source_file）：!/usr/bin/env node / Regenerate the DAR-933 fixture corpus snapshot files tests/fixtures/graph/ .mermaid and .dot from the spec JSONs in the same directory. Run once at fixture-add time; in CI the snapshot tests compare against these committed files. Imports the live TypeScript sources via tsx -- no make build is required before running. Earlier revisions imported from dist/ , which silently broke when the build was stale; see DAR-933 review f-3. Usage: pnpm exec tsx scripts/dar933-generate-fixtures.mjs / 证据：`scripts/dar933-generate-fixtures.mjs`\n- **!/usr/bin/env bash**（source_file）：!/usr/bin/env bash DAR-960: derive an npm dist-tag from a semver version string. Usage: scripts/derive-dist-tag.sh Example: scripts/derive-dist-tag.sh 0.1.0 - latest scripts/derive-dist-tag.sh 0.1.0-beta.1 - beta scripts/derive-dist-tag.sh 1.0.0-alpha - alpha Rule: - Input must be a MAJOR.MINOR.PATCH semver core, optionally followed by - and/or + . A leading v is rejected: the workflow strips the leading v from the git tag before invoking this script, so by the time we see the version it must be bare. - If there is no pre-release identifier, print latest . - Otherwise, print the alphabetic prefix of the first pre-release segment the part before the first . . Empty alphabetic prefix is a mal… 证据：`scripts/derive-dist-tag.sh`\n- **!/usr/bin/env bash**（source_file）：!/usr/bin/env bash DAR-955 cold-start race reproduction maintainer-only diagnostic . Triggers the race that motivated tests/global-setup.ts: when two vitest workers concurrently load transformers.js with a cold model cache, they corrupt the in-flight model.onnx and downstream parsing fails with one of: - MCP error -32000: Connection closed child process died - Load model from .../onnx/model.onnx failed: Protobuf parsing failed. - mutex lock failed libc++ abi in ORT init when files mid-write The fix is tests/global-setup.ts : serialise the download into the vitest main process before any workers fork. The boot-ordering invariants in tests/server-bin-cold-start.integration.test.ts ac-2 lock t… 证据：`scripts/reproduce-cold-start-race.sh`\n- **Server Version Updater**（source_file）：// DAR-963: commit-and-tag-version updater for src/server/server.ts. // // commit-and-tag-version walks every entry in bumpFiles and either uses a // built-in type \"json\", \"plain-text\" or a custom updater module that // exports readVersion contents and writeVersion contents, newVersion . // // For src/server/server.ts we need a scoped find/replace: ONLY the // SERVER VERSION constant should change, not any other string that // happens to look like a version. The built-in plain-text updater would // rewrite every occurrence of the current version anywhere in the file -- // brittle. A 6-line custom updater is the right shape. 证据：`scripts/server-version-updater.cjs`\n- **!/usr/bin/env bash**（source_file）：!/usr/bin/env bash DAR-914: Apply branch protection to main for the commonplace repo. This script is the reproducible source of truth for the branch protection settings -- review changes here, run the script out-of-band to apply them. CI does not run this script; a maintainer with admin rights does. Required: - gh CLI authenticated as a user with admin on the repo. - The CI workflow .github/workflows/ci.yml defines a matrix on node-version: 22, 24 and a single job named ci . The status-check contexts below \"ci 22 \" / \"ci 24 \" must match the rendered matrix-leg job names. Drift between this script and ci.yml is checked by the DAR-914 contract tests. Usage: ./scripts/setup-branch-protection.s… 证据：`scripts/setup-branch-protection.sh`\n- **!/usr/bin/env node**（source_file）：!/usr/bin/env node / Bin entry: the commonplace CLI dispatcher DAR-918, extended by DAR-961 . Subcommand surface single source of truth: USAGE in src/cli/migrate.ts : commonplace migrate detect known external memory sources commonplace migrate --from import from a known source; --dry-run / --auto supported commonplace migrate rebuild sidecars for an existing memory dir; --dry-run / --prune-dangling supported The legacy DAR-918 path rebuild sidecars for an existing dir and the DAR-961 detection / import paths share this dispatcher; the bare-bin usage message and the parser usage error message are rendered from the same exported USAGE constant so the two cannot drift. Bin convention package.j… 证据：`src/index.ts`\n- **Atomic Write.Test**（source_file）：/ DAR-923 contract tests for the atomicWrite helper. Test names mirror the contract envelope on DAR-923 round 1, approved : - ac-1: write-temp-then-rename + same-filesystem guard - ac-2: fsync semantics + descriptor lifecycle The helper writes bytes to a tmp file colocated with the target, fsyncs the tmpfile, renames over the target, then fsyncs the directory. It throws when tmpdir and target dir straddle filesystems and surfaces fsync errors. The helper exposes an internal atomicWriteHooks test seam to inject a fake fs.promises -shaped dependency. This avoids the non-configurable descriptor problem on the fs/promises namespace and lets us observe the exact fsync / rename / close call order… 证据：`tests/atomic-write.test.ts`\n- **Ci Workflow.Test**（source_file）：/ DAR-914 contract tests. Verifies the CI workflow at .github/workflows/ci.yml , the reproducible branch-protection script at scripts/setup-branch-protection.sh , and contributor documentation. The contract tests assert structural properties of the committed artifacts -- they do not invoke gh api against the live GitHub repo live state requires admin token + network access; verifying the artifact is the contract . / 证据：`tests/ci-workflow.test.ts`\n- **Derive Dist Tag.Test**（source_file）：/ DAR-960 contract tests: dist-tag derivation script. The script lives at scripts/derive-dist-tag.sh . It reads a version string the package version stripped of the leading v from the git tag and prints a single dist-tag value on stdout. The release workflow uses its stdout as the value passed to pnpm publish --tag . Living in a script rather than inline shell in the workflow makes it unit-testable -- which is exactly what this file exercises. Rule: strip the leading v the workflow does this before invoking the script -- the script itself rejects a leading v as malformed , then look at any pre-release identifier after the first - . If absent, dist-tag is latest . If present, dist-tag is the… 证据：`tests/derive-dist-tag.test.ts`\n- **Embedder.Integration.Test**（source_file）：/ DAR-912 contract integration tests. These tests load the real Xenova/bge-base-en-v1.5 model via @huggingface/transformers and run an actual embed round trip. The first run pulls weights from the HF hub ~6s cold start, see AC-2 ; subsequent runs are warm thanks to transformers.js's local cache. The wall-clock latency is intentionally NOT asserted -- AC-2's \"~6s\" is descriptive guidance, not a measurable target see contract envelope's explicit non goals . What IS asserted: - the returned vector is a Float32Array of length 768 - the vector's L2 norm is within 1e-3 of 1.0 so cosine == dot product - dim reads back as 768 and modelId round-trips - dim equals the returned vector's length after a… 证据：`tests/embedder.integration.test.ts`\n- **Embedder.Readonly Types**（source_file）：/ DAR-912: type-level guard that Embedder.modelId and Embedder.dim are declared readonly . This file is not a runtime test -- it participates in tsc --noEmit and therefore make typecheck . The // @ts-expect-error markers below FAIL the build if either property becomes assignable, which is exactly the readonly contract required by AC-1. The test runner does not execute this file; it is only here so the compiler sees the intentionally-erroneous assignments. / 证据：`tests/embedder.readonly-types.ts`\n- **Embedder.Test**（source_file）：/ DAR-912 contract tests unit . Behavioral tests for the Embedder wrapper around @huggingface/transformers . The pipeline factory is mocked so these tests run hermetically without pulling real model weights from the HF hub. The integration counterparts real model load + embed live in tests/embedder.integration.test.ts . Test names mirror the contract envelope on DAR-912 round 1, approved . / 证据：`tests/embedder.test.ts`\n- **Global Setup**（source_file）：/ Vitest globalSetup: serially warm the transformers.js model cache for the embedder used by the spawned-bin and embedder integration tests. Why this exists DAR-955 root cause The DAR-919 spawned-bin integration test was flaky on cold-cache make test runs. Surface symptoms varied: - MCP error -32000: Connection closed the bot review report on PR 15 / DAR-929 , and - a non-error CallToolResult with isError: true whose payload read Load model from .../onnx/model.onnx failed:Protobuf parsing failed. Both symptoms have the same cause: vitest defaults to running test files in parallel forked workers. Two integration tests embedder.integration.test.ts and server-bin.integration.test.ts each load… 证据：`tests/global-setup.ts`\n- **Graph Bin.Integration.Test**（source_file）：/ DAR-933 ac-1 / ac-3 / ac-6 spawned-bin coverage: prove the built commonplace bin dispatches the graph subcommand and produces a mermaid / json / dot rendering for a fixture memory dir. The in-process suite graph-cli.test.ts drives graphMain directly with a stub embedder so it can run fast. This file exists so the spawned-bin wiring -- the dispatcher's argv 0 === 'graph' short- circuit, the embedder factory, the real MemoryStore.scan cold-start -- is covered end-to-end. A missing wire would surface here as a non-zero exit or an empty stdout despite an in-process test passing. Slow on purpose: pays the real Embedder cold-start price. / 证据：`tests/graph-bin.integration.test.ts`\n- **Graph Cli.Test**（source_file）：/ DAR-933 contract tests for the commonplace graph subcommand. Test names mirror the approved contract envelope on DAR-933. The CLI surface is broken across: - argv parsing: parseGraphArgs - mermaid / json / dot renderers - dispatcher integration bare bin + unknown-subcommand error paths - end-to-end via the in-process graphMain the spawned-bin form lives in tests/graph-bin.integration.test.ts Snapshot fixtures live under tests/fixtures/graph/ ; each case has one .json describing the memories and one expected-output file per format .mermaid , .json , .dot . / 证据：`tests/graph-cli.test.ts`\n- **Graph.Test**（source_file）：/ DAR-926 contract tests. Behavioral tests for the MemoryGraph class -- an in-memory adjacency structure built from the relations and supersedes frontmatter graph fields DAR-925 layered over the MemoryStore entries DAR-916 . Test names mirror the contract envelope on DAR-926 round 1, approved . / 证据：`tests/graph.test.ts`\n- **Memory Graph.Test**（source_file）：/ DAR-925 contract tests. Behavioral tests for the relations and supersedes frontmatter graph fields layered on top of the DAR-911 memory I/O primitives: - readMemory path - { ..., relations, supersedes } - writeMemory path, memory accepts relations / supersedes - contentSha memory MUST NOT depend on relations / supersedes Test names mirror the contract envelope on DAR-925 round 1 . / 证据：`tests/memory-graph.test.ts`\n- **Memory Store Multiprocess.Test**（source_file）：/ DAR-923 contract tests for MemoryStore integration with the multi-process safety primitives: - ac-1: every .md and .embedding write goes through the atomic helper - ac-3: per-name advisory locks around save and delete - ac-4: mtime-based external-writer rescan in search and list/all Test names mirror the contract envelope on DAR-923 round 1, approved . / 证据：`tests/memory-store-multiprocess.test.ts`\n- **Memory Store Search.Test**（source_file）：/ DAR-917 contract tests. Behavioral tests for MemoryStore.search query, opts? -- brute-force top-k cosine search over the in-memory index. Vectors in the store are normalized at write time DAR-916 , so cosine reduces to a dot product. Test names mirror the contract envelope on DAR-917 round 1, approved . The Embedder dependency is stubbed no real model load so these tests run hermetically and quickly. Stubs return small deterministic vectors so dot products and ordering can be hand-computed. / 证据：`tests/memory-store-search.test.ts`\n- **Memory Store Stress.Test**（source_file）：/ DAR-923 contract tests for multi-process stress + crash safety: - ac-5: 4 child processes each saving 50 distinct memories produce 200 valid .md, .embedding pairs with no errors and no corruption. - ac-6: 2 child processes racing on the same name resolve to exactly one winner and one clear \"already exists\" / lock-busy loser, with no corruption of the winner's files. - ac-7: SIGKILL'ing a process mid-write to an existing memory leaves the prior files byte-equal, leaves no orphan tmpfile, and a fresh scan in a new process reads the prior memory without throwing. Each test orchestrates one or more child processes via node:child process running tests/fixtures/save-worker.ts under tsx. The wor… 证据：`tests/memory-store-stress.test.ts`\n- **Memory Store.Test**（source_file）：/ DAR-916 contract tests. Behavioral tests for the MemoryStore class -- the in-memory vector index backed by / .md + .embedding sidecar files. Test names mirror the contract envelope on DAR-916 round 1, approved . The Embedder dependency is stubbed no real model load so these tests run hermetically and quickly. The stub satisfies the structural contract the MemoryStore depends on: modelId , dim , and embed text . / 证据：`tests/memory-store.test.ts`\n- **Memory.Test**（source_file）：/ DAR-911 contract tests. Behavioral tests for the memory .md file I/O primitives: - readMemory path - { name, description, type, body, raw } - writeMemory path, memory - contentSha memory - 64-char lowercase sha256 hex Test names mirror the contract envelope on DAR-911 round 1 . / 证据：`tests/memory.test.ts`\n- **Mentions Store.Test**（source_file）：/ DAR-927 contract tests -- MemoryStore wiring. Behavioral tests that exercise the integration of extractMentions into MemoryStore.scan and MemoryStore.save : each extracted name becomes one mentions edge in the configured MemoryGraph , gated by the env var COMMONPLACE EXTRACT MENTIONS default on . Test names mirror the contract envelope on DAR-927 round 1, approved . / 证据：`tests/mentions-store.test.ts`\n- **Mentions.Test**（source_file）：/ DAR-927 contract tests -- pure tokenizer extractMentions . Behavioral tests for the name body-mention extractor. Test names mirror the contract envelope on DAR-927 round 1, approved . The tokenizer is a pure function over a markdown body string. It returns unique mention names in first-occurrence order, restricting matches to the same ^ a-z0-9 +$ rule used by memory file names DAR-911 / DAR-925 . / 证据：`tests/mentions.test.ts`\n- **Migrate Bin.Integration.Test**（source_file）：/ DAR-918 ac-7: spawn the built commonplace bin with the migrate subcommand and assert that: - migrate against a fixture directory produces the expected sidecars, prints a non-empty summary on stdout containing the labels 'loaded', 'embedded', 're-embedded', and 'orphaned' along with their counts, and exits 0. - migrate with no positional argument prints a usage message to stderr and exits non-zero. The build is performed by tests/scaffolding.integration.test.ts via the same make build target; we re-run it here defensively because vitest does not order test files. The bin's first invocation pays the transformers.js model load cost ~6-12s on a warm cache, longer cold . The vitest globalSetup… 证据：`tests/migrate-bin.integration.test.ts`\n- **Migrate Import.Test**（source_file）：/ DAR-961 contract tests for the auto-migration importer: - commonplace migrate no args detects Claude Code project-memory directories at ~/.claude/projects/ \\/memory/ and reports counts without writing anything. - commonplace migrate --from claude-code copies each compatible .md to / .md , then runs the existing scan/embed pass so each imported file gets its .embedding sidecar. - Conflict policy is skip-and-report default , preserving existing target files byte-identical. - --dry-run reports what would be imported without writing. Test names mirror the approved contract envelope on DAR-961. / 证据：`tests/migrate-import.test.ts`\n- **Migrate Readme.Test**（source_file）：/ DAR-961 ac-7: README sanity tests for the migration section. Asserts the migration documentation covers: - the commonplace migrate entry-point with --from claude-code , --auto , and --dry-run - the skip-and-report conflict policy - the \"Migrating from mem0 / Letta\" dual-MCP-server pattern, with an explicit note that no commonplace-side integration code is required. These are doc-drift guards rather than prose-quality assertions: each test pins one concrete claim that the issue body says must be present, so a future README rewrite that drops the claim fails the test rather than silently regressing. / 证据：`tests/migrate-readme.test.ts`\n- **Migrate Resilience.Test**（source_file）：/ DAR-966 contract tests: migrate-path resilience to permissively-formatted harness frontmatter, MEMORY.md exclusion, structured skip reasons for unrecoverable source files, and skip-and-warn semantics on MemoryStore.scan . Test names mirror the approved contract envelope on DAR-966. / 证据：`tests/migrate-resilience.test.ts`\n- **Migrate.Test**（source_file）：/ DAR-918 contract tests for runMigrate programmatic API and the argv-parsing wrapper. Test names mirror the approved contract envelope on DAR-918. / 证据：`tests/migrate.test.ts`\n- **Readme.Test**（source_file）：/ README sanity tests. Two narrow goals: 1. Catch drift between README and code: every inputSchema property of every registered MCP tool, and every COMMONPLACE env var the bin reads, must appear somewhere in the README. If a property is renamed or removed, the test fails until the README catches up. 2. Verify the verbatim install commands the publish smoke test DAR-921 depends on are present. The publish smoke test executes these strings exactly; if either drifts in the README, users will follow stale instructions. Everything else about README quality concept blurb, prose, section ordering, emoji-free, License/Contributing presence is a review-time concern, not a unit-test concern. Assertin… 证据：`tests/readme.test.ts`\n- **Release Workflow.Test**（source_file）：/ DAR-960 contract tests: release workflow YAML structure. Verifies the release workflow at .github/workflows/release.yml and the release-process docs in CONTRIBUTING.md . Mirrors the structural-assertion pattern used in tests/ci-workflow.test.ts DAR-914 : we parse the YAML with the yaml package and assert structural properties of the committed artifact rather than executing it against the live GitHub repo. / 证据：`tests/release-workflow.test.ts`\n- **Scaffolding.Integration.Test**（source_file）：/ DAR-908 contract integration tests. These shell out to make and assert exit codes / stdout for the required targets. A few targets are intentionally NOT spawned from inside vitest: - make test would recurse vitest invoking vitest . - make install mutates node modules under us mid-run. - make audit depends on the live registry and is flaky as a unit test; the recipe correctness is asserted statically. Their recipes are validated structurally in scaffolding.test.ts and operationally by CI invoking the targets directly. They are declared in the implementation envelope's untested with reasons. / 证据：`tests/scaffolding.integration.test.ts`\n- **Scaffolding.Test**（source_file）：/ DAR-908 contract tests. These tests verify the scaffolding contract: package metadata, TS/ESM config, src/ skeleton, Makefile-driven dev loop, lint/format/editor configs, license, gitignore, and the populated CLAUDE.md. They are \"unit\" in the sense of assertions over file contents on disk; a separate suite scaffolding.integration.test.ts covers the make -target integration checks. / 证据：`tests/scaffolding.test.ts`\n- **Scope.Test**（source_file）：/ DAR-924 ac-2 / ac-7: unit tests for the scope-detection function. Each detection branch env / roots / cwd / none is exercised independently of the spawned bin so the priority order can be asserted without booting a real MCP server. / 证据：`tests/scope.test.ts`\n- **Server Bin Cold Start.Integration.Test**（source_file）：/ DAR-955 cold-start invariants for the spawned-bin integration harness. Background tests/server-bin.integration.test.ts DAR-919 was flaky on make test runs from a cold transformers.js model cache: the first invocation occasionally failed with one of two surface symptoms, - MCP error -32000: Connection closed child process died , or - a CallToolResult with isError: true whose payload reads Load model from .../onnx/model.onnx failed:Protobuf parsing failed. Both symptoms have the same underlying cause: Concurrent transformers.js downloads to a shared on-disk model cache corrupt the in-flight files. Two vitest workers this file, the bin integration test, and the in-process embedder integratio… 证据：`tests/server-bin-cold-start.integration.test.ts`\n- **Server Bin Graph Wiring.Test**（source_file）：/ DAR-928 ac-5 unit-level assertion: the boot module constructs a MemoryGraph , passes it to MemoryStore { dir, embedder, graph } , and passes it to createDefaultHandlers { ..., graph } . We assert structurally on the source text. The end-to-end behavioural proof that the graph is actually wired i.e. populated by save/scan and available to link/unlink lives in server-bin-link.integration.test.ts . Note: as of DAR-924 the wiring lives in src/bin/boot.ts rather than src/bin/commonplace-mcp.ts the bin reduces to a thin shell that delegates to bootServer . The contract is unchanged -- a graph is constructed and threaded through MemoryStore + createDefaultHandlers -- just relocated. / 证据：`tests/server-bin-graph-wiring.test.ts`\n- **Server Bin Graph.Integration.Test**（source_file）：/ DAR-932 ac-7 spawned-bin integration: end-to-end coverage for memory graph and memory path against the real bin and its real MemoryGraph instance. This proves the boot path wires both per-scope graphs into the new handler factories so the running server can serve traversal queries -- a missing wire-up would surface as UnknownToolError, 'not implemented', or empty traversal results despite memory link having succeeded. Slow on purpose: pays the real Embedder cold-start price. / 证据：`tests/server-bin-graph.integration.test.ts`\n- **Server Bin Link.Integration.Test**（source_file）：/ DAR-928 bin integration test: spawn the built commonplace-mcp bin and exercise memory link / memory unlink end-to-end via real MCP stdio framing. This proves: - ac-5: the bin instantiates a MemoryGraph , wires it into both the store and the handler map, and the running server's graph is populated by scan / save verified by linking between two memory save'd entries -- a missing graph or a graph not populated by save would surface as \"target memory does not exist\" . - ac-6: round trip save A, save B, link A- B, hand-inspect A.md to verify the edge appears with valid YAML, then unlink and confirm the edge is gone and frontmatter is still valid YAML. Slow on purpose -- pays the real Embedder… 证据：`tests/server-bin-link.integration.test.ts`\n- 其余 20 条证据见 `AI_CONTEXT_PACK.json` 或 `EVIDENCE_INDEX.json`。\n\n## 宿主 AI 必须遵守的规则\n\n- **把本资产当作开工前上下文，而不是运行环境。**：AI Context Pack 只包含证据化项目理解，不包含目标项目的可执行状态。 证据：`CLAUDE.md`, `README.md`, `package.json`\n- **回答用户时区分可预览内容与必须安装后才能验证的内容。**：安装前体验的消费者价值来自降低误装和误判，而不是伪装成真实运行。 证据：`CLAUDE.md`, `README.md`, `package.json`\n\n## 用户开工前应该回答的问题\n\n- 你准备在哪个宿主 AI 或本地环境中使用它？\n- 你只是想先体验工作流，还是准备真实安装？\n- 你最在意的是安装成本、输出质量、还是和现有规则的冲突？\n\n## 验收标准\n\n- 所有能力声明都能回指到 evidence_refs 中的文件路径。\n- AI_CONTEXT_PACK.md 没有把预览包装成真实运行。\n- 用户能在 3 分钟内看懂适合谁、能做什么、如何开始和风险边界。\n\n---\n\n## Doramagic Context Augmentation\n\n下面内容用于强化 Repomix/AI Context Pack 主体。Human Manual 只提供阅读骨架；踩坑日志会被转成宿主 AI 必须遵守的工作约束。\n\n## Human Manual 骨架\n\n使用规则：这里只是项目阅读路线和显著性信号，不是事实权威。具体事实仍必须回到 repo evidence / Claim Graph。\n\n宿主 AI 硬性规则：\n- 不得把页标题、章节顺序、摘要或 importance 当作项目事实证据。\n- 解释 Human Manual 骨架时，必须明确说它只是阅读路线/显著性信号。\n- 能力、安装、兼容性、运行状态和风险判断必须引用 repo evidence、source path 或 Claim Graph。\n\n- **项目概览**：importance `high`\n  - source_paths: README.md, package.json, CLAUDE.md\n- **快速入门与安装**：importance `high`\n  - source_paths: README.md, package.json, .nvmrc\n- **系统架构**：importance `high`\n  - source_paths: CLAUDE.md, src/index.ts, src/embedder/index.ts, src/store/memory-store.ts, src/server/server.ts\n- **技术栈详解**：importance `medium`\n  - source_paths: package.json, tsconfig.json, tsconfig.build.json, vitest.config.ts, eslint.config.js\n- **嵌入模型与语义搜索**：importance `high`\n  - source_paths: src/embedder/index.ts, vitest.config.ts, tests/global-setup.ts\n- **内存格式与侧载文件**：importance `high`\n  - source_paths: docs/sidecar-format.md, src/store/memory.ts, src/store/sidecar.ts, src/store/memory-store.ts\n- **搜索功能详解**：importance `high`\n  - source_paths: README.md, src/server/defaults.ts, src/server/tools.ts, src/server/handlers.ts\n- **图功能与关系管理**：importance `medium`\n  - source_paths: src/store/graph.ts, src/store/mentions.ts, src/cli/graph.ts\n\n## Repo Inspection Evidence / 源码检查证据\n\n- repo_clone_verified: true\n- repo_inspection_verified: true\n- repo_commit: `bda917d02f7cf739fc731a3f895316b118ec2ba5`\n- inspected_files: `pnpm-lock.yaml`, `package.json`, `README.md`, `docs/sidecar-format.md`, `src/index.ts`, `src/cli/migrate.ts`, `src/cli/graph.ts`, `src/bin/env.ts`, `src/bin/commonplace-mcp.ts`, `src/bin/scope.ts`, `src/bin/boot.ts`, `src/embedder/index.ts`, `src/server/defaults.ts`, `src/server/tools.ts`, `src/server/index.ts`, `src/server/server.ts`, `src/server/handlers.ts`, `src/store/mentions.ts`, `src/store/sidecar.ts`, `src/store/memory-store.ts`\n\n宿主 AI 硬性规则：\n- 没有 repo_clone_verified=true 时，不得声称已经读过源码。\n- 没有 repo_inspection_verified=true 时，不得把 README/docs/package 文件判断写成事实。\n- 没有 quick_start_verified=true 时，不得声称 Quick Start 已跑通。\n\n## Doramagic Pitfall Constraints / 踩坑约束\n\n这些规则来自 Doramagic 发现、验证或编译过程中的项目专属坑点。宿主 AI 必须把它们当作工作约束，而不是普通说明文字。\n\n### Constraint 1: 能力判断依赖假设\n\n- Trigger: README/documentation is current enough for a first validation pass.\n- Host AI rule: 将假设转成下游验证清单。\n- Why it matters: 假设不成立时，用户拿不到承诺的能力。\n- Evidence: capability.assumptions | github_repo:1232879661 | https://github.com/rickbassham/commonplace | README/documentation is current enough for a first validation pass.\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 2: 运行可能依赖外部服务\n\n- Trigger: 项目说明出现 external service/cloud/webhook/database 等运行依赖关键词。\n- Host AI rule: 确认是否有离线 demo、mock 数据或可替代服务。\n- Why it matters: 本地安装成功不等于能力可用，外部服务不可用会阻断体验。\n- Evidence: packet_text.keyword_scan | github_repo:1232879661 | https://github.com/rickbassham/commonplace | matched external service / cloud / webhook / database keyword\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 3: 维护活跃度未知\n\n- Trigger: 未记录 last_activity_observed。\n- Host AI rule: 补 GitHub 最近 commit、release、issue/PR 响应信号。\n- Why it matters: 新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- Evidence: evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | last_activity_observed missing\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 4: 下游验证发现风险项\n\n- Trigger: no_demo\n- Host AI rule: 进入安全/权限治理复核队列。\n- Why it matters: 下游已经要求复核，不能在页面中弱化。\n- Evidence: downstream_validation.risk_items | github_repo:1232879661 | https://github.com/rickbassham/commonplace | no_demo; severity=medium\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 5: 存在安全注意事项\n\n- Trigger: No sandbox install has been executed yet; downstream must verify before user use.\n- Host AI rule: 转成明确权限清单和安全审查提示。\n- Why it matters: 用户安装前需要知道权限边界和敏感操作。\n- Evidence: risks.safety_notes | github_repo:1232879661 | https://github.com/rickbassham/commonplace | No sandbox install has been executed yet; downstream must verify before user use.\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 6: 存在评分风险\n\n- Trigger: no_demo\n- Host AI rule: 把风险写入边界卡，并确认是否需要人工复核。\n- Why it matters: 风险会影响是否适合普通用户安装。\n- Evidence: risks.scoring_risks | github_repo:1232879661 | https://github.com/rickbassham/commonplace | no_demo; severity=medium\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 7: issue/PR 响应质量未知\n\n- Trigger: issue_or_pr_quality=unknown。\n- Host AI rule: 抽样最近 issue/PR，判断是否长期无人处理。\n- Why it matters: 用户无法判断遇到问题后是否有人维护。\n- Evidence: evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | issue_or_pr_quality=unknown\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n\n### Constraint 8: 发布节奏不明确\n\n- Trigger: release_recency=unknown。\n- Host AI rule: 确认最近 release/tag 和 README 安装命令是否一致。\n- Why it matters: 安装命令和文档可能落后于代码，用户踩坑概率升高。\n- Evidence: evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | release_recency=unknown\n- Hard boundary: 不要把这个坑点包装成已解决、已验证或可忽略，除非后续验证证据明确证明它已经关闭。\n",
      "summary": "给宿主 AI 的上下文和工作边界。",
      "title": "AI Context Pack / 带给我的 AI"
    },
    "boundary_risk_card": {
      "asset_id": "boundary_risk_card",
      "filename": "BOUNDARY_RISK_CARD.md",
      "markdown": "# Boundary & Risk Card / 安装前决策卡\n\n项目：rickbassham/commonplace\n\n## Doramagic 试用结论\n\n当前结论：可以进入发布前推荐检查；首次使用仍应从最小权限、临时目录和可回滚配置开始。\n\n## 用户现在可以做\n\n- 可以先阅读 Human Manual，理解项目目的和主要工作流。\n- 可以复制 Prompt Preview 做安装前体验；这只验证交互感，不代表真实运行。\n- 可以把官方 Quick Start 命令放到隔离环境中验证，不要直接进主力环境。\n\n## 现在不要做\n\n- 不要把 Prompt Preview 当成项目实际运行结果。\n- 不要把 metadata-only validation 当成沙箱安装验证。\n- 不要把未验证能力写成“已支持、已跑通、可放心安装”。\n- 不要在首次试用时交出生产数据、私人文件、真实密钥或主力配置目录。\n\n## 安装前检查\n\n- 宿主 AI 是否匹配：mcp_host\n- 官方安装入口状态：已发现官方入口\n- 是否在临时目录、临时宿主或容器中验证：必须是\n- 是否能回滚配置改动：必须能\n- 是否需要 API Key、网络访问、读写文件或修改宿主配置：未确认前按高风险处理\n- 是否记录了安装命令、实际输出和失败日志：必须记录\n\n## 当前阻塞项\n\n- 无阻塞项。\n\n## 项目专属踩坑\n\n- 能力判断依赖假设（medium）：假设不成立时，用户拿不到承诺的能力。 建议检查：将假设转成下游验证清单。\n- 运行可能依赖外部服务（medium）：本地安装成功不等于能力可用，外部服务不可用会阻断体验。 建议检查：确认是否有离线 demo、mock 数据或可替代服务。\n- 维护活跃度未知（medium）：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 下游验证发现风险项（medium）：下游已经要求复核，不能在页面中弱化。 建议检查：进入安全/权限治理复核队列。\n- 存在安全注意事项（medium）：用户安装前需要知道权限边界和敏感操作。 建议检查：转成明确权限清单和安全审查提示。\n\n## 风险与权限提示\n\n- no_demo: medium\n\n## 证据缺口\n\n- 暂未发现结构化证据缺口。\n",
      "summary": "安装、权限、验证和推荐前风险。",
      "title": "Boundary & Risk Card / 边界与风险卡"
    },
    "human_manual": {
      "asset_id": "human_manual",
      "filename": "HUMAN_MANUAL.md",
      "markdown": "# https://github.com/rickbassham/commonplace 项目说明书\n\n生成时间：2026-05-13 17:34:29 UTC\n\n## 目录\n\n- [项目概览](#page-overview)\n- [快速入门与安装](#page-quickstart)\n- [系统架构](#page-architecture)\n- [技术栈详解](#page-tech-stack)\n- [嵌入模型与语义搜索](#page-embedder)\n- [内存格式与侧载文件](#page-memory-format)\n- [搜索功能详解](#page-search)\n- [图功能与关系管理](#page-graph-features)\n- [存储系统](#page-storage)\n- [作用域与多存储](#page-scopes)\n\n<a id='page-overview'></a>\n\n## 项目概览\n\n### 相关页面\n\n相关主题：[快速入门与安装](#page-quickstart), [系统架构](#page-architecture)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n- [CONTRIBUTING.md](https://github.com/rickbassham/commonplace/blob/main/CONTRIBUTING.md)\n- [src/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts)\n</details>\n\n# 项目概览\n\n## 项目简介\n\nCommonplace 是一个基于 MCP（Model Context Protocol）的持久化记忆系统，旨在为 AI 代理提供跨会话的上下文记忆能力。该项目使 AI 能够记住用户的偏好、项目的架构决策、技术反馈等重要信息，从而在长时间交互中保持一致性和连续性。\n\n资料来源：[README.md:1-10]()\n\n## 核心设计原则\n\n### 记忆文件即真相\n\nCommonplace 采用 Markdown 文件作为记忆的持久化存储介质。每个记忆以 `.md` 文件形式存储，YAML frontmatter 携带结构化元数据，文件主体承载具体内容。这种设计使得记忆可以被版本控制、人类可读、手动编辑，且不依赖专有格式。\n\n资料来源：[CLAUDE.md:15-20]()\n\n### 边车文件可重建\n\n`.embedding` 等边车文件（sidecar）是从 `.md` 源文件派生的，可以随时从源码重新生成。这确保了数据的安全性——即使边车文件丢失或损坏，也能通过扫描重建索引。\n\n资料来源：[CLAUDE.md:20-22]()\n\n## 内存类型系统\n\nCommonplace 定义了四种内存类型，构成记忆分类的基础：\n\n| 类型 | 用途 | 典型场景 |\n|------|------|----------|\n| `user` | 个人规则、偏好、身份事实 | 编程语言偏好、沟通风格、联系方式 |\n| `feedback` | 来自代理行为的修正和教训 | 避免的模式、成功的策略、工作习惯 |\n| `project` | 项目特定上下文 | 架构笔记、代码规范、决策记录 |\n| `reference` | 持久化中性知识 | API 形状、公式、引用、需要按语义查询的内容 |\n\n资料来源：[README.md:45-60]()\n\n## 记忆存储架构\n\n### 双作用域设计\n\n系统支持同时加载两个独立的记忆存储：\n\n```mermaid\ngraph TD\n    A[Commonplace] --> B[用户存储]\n    A --> C[项目存储]\n    B --> D[COMMONPLACE_USER_DIR<br/>~/.commonplace/memory]\n    C --> E[COMMONPLACE_PROJECT_DIR<br/>或 .commonplace/memory]\n    \n    F[MCP roots/list检测] --> E\n    G[当前工作目录] --> E\n```\n\n- **用户存储（User Store）**：始终加载，存储跨项目共享的个人规则和反馈\n- **项目存储（Project Store）**：仅在检测到项目根目录时加载，存储项目特定的上下文\n\n资料来源：[README.md:140-165]()\n\n### 目录结构\n\n每个记忆存储遵循以下结构：\n\n```\n<store-dir>/\n├── <name>.md           # 记忆文件\n├── <name>.embedding    # 向量嵌入边车（自动生成）\n└── .index/             # 索引缓存（可选）\n```\n\n资料来源：[src/store/memory.ts:20-35]()\n\n### 记忆文件格式\n\n记忆文件采用标准 Markdown + YAML frontmatter 格式：\n\n```yaml\n---\nname: feedback_scope\ndescription: 不要单方面缩减范围\ntype: feedback\nrelations:          # 关系边（DAR-925）\n  - to: other_name\n    type: builds-on\nsupersedes:         # 替代关系\n  - old_name\n---\n<body>\n```\n\n资料来源：[src/store/memory.ts:40-60]()\n\n## 核心模块\n\n### CLI 模块\n\n入口文件 `src/index.ts` 负责命令行参数解析和子命令分发：\n\n```mermaid\ngraph LR\n    A[commonplace CLI] --> B[migrate]\n    A --> C[graph]\n    B --> D[scan - 扫描并嵌入]\n    B --> E[import - 导入外部记忆]\n    B --> F[prune - 清理悬挂引用]\n```\n\n资料来源：[src/index.ts:1-50]()\n\n### 内存存储层\n\n`MemoryStore`（`src/store/memory-store.ts`）是核心存储引擎，提供以下能力：\n\n| 方法 | 功能 |\n|------|------|\n| `scan()` | 扫描目录，检测/生成边车嵌入 |\n| `save()` | 保存新记忆 |\n| `delete()` | 删除记忆 |\n| `search()` | 语义搜索 |\n| `list()` | 列出所有记忆 |\n| `linkEdge()` | 添加记忆间关系 |\n| `unlinkEdge()` | 移除记忆间关系 |\n\n资料来源：[src/store/memory-store.ts:1-100]()\n\n### 内容哈希机制\n\n`contentSha` 函数计算记忆内容的规范哈希：\n\n```\nSHA256(`${type}\\n${name}\\n${description}\\n${body}`)\n```\n\n注意：关系字段（`relations`、`supersedes`）不参与哈希计算，添加或移除关系边不会使嵌入失效。这确保了边的修改不会触发不必要的重新嵌入。\n\n资料来源：[src/store/memory.ts:80-95]()\n\n### 提及提取\n\n`src/store/mentions.ts` 实现 `[[name]]` 语法提取：\n\n- 扫描记忆文件 body 中的 `[[name]]` 模式\n- 仅提取符合 `^[a-z0-9_]+$` 的名称\n- 通过 `MemoryGraph.addMentionsEdge` 建立提及关系\n- 可通过 `COMMONPLACE_EXTRACT_MENTIONS=false` 环境变量禁用\n\n资料来源：[src/store/mentions.ts:1-40]()\n\n### 原子写入\n\n`atomicWrite`（`src/store/atomic-write.ts`）确保写入原子性：\n\n1. 在同目录创建临时文件\n2. 写入数据\n3. 使用 `rename(2)` 原子替换目标\n4. 验证源和目标在同一文件系统\n\n资料来源：[src/store/atomic-write.ts:1-50]()\n\n## 关系图系统（DAR-925）\n\n记忆之间可以建立有向关系边：\n\n| 关系类型 | 语义 | 搜索默认包含 |\n|----------|------|--------------|\n| `related-to` | 一般关联 | 是 |\n| `builds-on` | 基于某记忆构建 | 是 |\n| `contradicts` | 与某记忆矛盾 | 否 |\n| `child-of` | 某记忆的子项 | 否 |\n| `supersedes` | 替代某旧记忆 | 否 |\n| `mentions` | 正文中提及 | 否 |\n\n`MemoryGraph` 维护内存中的邻接表，支持 BFS 遍历和路径查询。\n\n资料来源：[src/server/handlers.ts:10-25]()\n\n## MCP 工具接口\n\n系统通过 MCP 暴露四个核心工具：\n\n### memory_save\n\n保存新记忆，参数包括名称、类型、描述和内容。拒绝覆盖已有记忆，合约要求先删除再保存。\n\n### memory_search\n\n语义搜索记忆，返回按相关性排序的匹配列表。支持按类型过滤和作用域限定。\n\n### memory_list\n\n列出记忆名称，支持按类型过滤。\n\n### memory_path\n\n图遍历查询，返回两记忆间的路径。\n\n资料来源：[README.md:75-150]()\n\n## 迁移与导入\n\n### migrate 命令\n\n`commonplace migrate <dir>` 命令用于迁移现有记忆目录：\n\n1. 扫描 `.md` 文件，嵌入缺失或过时的边车\n2. 清理孤立边车（无对应 `.md` 的 `.embedding`）\n3. 可选：剪除悬挂引用（`--prune-dangling`）\n\n资料来源：[src/cli/migrate.ts:50-100]()\n\n### Claude Code 导入\n\n支持从 Claude Code 的自动记忆目录导入兼容文件：\n\n```\n~/.claude/projects/*/memory/*.md\n```\n\n导入逻辑：检测候选文件，如目标 `<name>.md` 已存在则跳过，否则复制源码并执行扫描/嵌入。\n\n资料来源：[src/cli/migrate.ts:120-160]()\n\n## 配置与部署\n\n### 环境变量\n\n| 变量 | 默认值 | 用途 |\n|------|--------|------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | 用户存储路径 |\n| `COMMONPLACE_PROJECT_DIR` | - | 项目存储路径（覆盖检测） |\n| `COMMONPLACE_MODEL_ID` | - | 指定嵌入模型 |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `true` | 启用提及提取 |\n\n资料来源：[CLAUDE.md:25-35]()\n\n### 依赖技术栈\n\n- **运行时**：Node.js 20+\n- **包管理**：pnpm\n- **嵌入引擎**：transformers.js\n- **协议**：MCP (Model Context Protocol)\n- **测试**：make test\n- **类型检查**：make typecheck\n- **构建**：make build\n\n## 开发工作流\n\n```mermaid\ngraph TD\n    A[从 main 创建功能分支] --> B[开发与测试]\n    B --> C[提交 PR]\n    C --> D[CI 检查<br/>typecheck + lint + build + test]\n    D --> E{通过?}\n    E -->|是| F[Squash 合并到 main]\n    E -->|否| B\n    F --> G[推送 tag 触发 Release]\n    G --> H[自动发布 npm 包]\n```\n\n资料来源：[CONTRIBUTING.md:1-50]()\n\n## 状态与里程碑\n\n| 阶段 | 状态 | 说明 |\n|------|------|------|\n| v0.1 | 进行中 | 基础记忆 CRUD、语义搜索 |\n| DAR-911 | 完成 | 内存文件 I/O |\n| DAR-910 | 完成 | 嵌入生成 |\n| DAR-925 | 完成 | 关系图系统 |\n| DAR-926 | 进行中 | 悬挂引用处理 |\n| DAR-927 | 完成 | 提及提取 |\n| DAR-928 | 待开始 | MCP 编辑工具 |\n\n## 快速入门\n\n1. 安装并配置 MCP 服务器\n2. 重启 Claude Code 会话\n3. 使用 `memory_save` 保存第一条记忆\n4. 通过 `memory_search` 和 `memory_list` 检索记忆\n\n资料来源：[README.md:25-40]()\n\n---\n\n**最后更新**：基于 repository main 分支，内容涵盖核心架构、存储模型、工具接口和开发流程。\n\n---\n\n<a id='page-quickstart'></a>\n\n## 快速入门与安装\n\n### 相关页面\n\n相关主题：[项目概览](#page-overview)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n- [CONTRIBUTING.md](https://github.com/rickbassham/commonplace/blob/main/CONTRIBUTING.md)\n- [package.json](https://github.com/rickbassham/commonplace/blob/main/package.json)\n- [.nvmrc](https://github.com/rickbassham/commonplace/blob/main/.nvmrc)\n</details>\n\n# 快速入门与安装\n\n## 概述\n\nCommonplace 是一个本地优先的个人知识管理工具，以 MCP（Model Context Protocol）服务器形式运行。它将笔记存储为带有 YAML 前缀的纯 Markdown 文件，嵌入向量存储在 `.embedding` 侧边文件中，语义搜索完全离线运行，底层使用 `transformers.js` + `bge-base-en-v1.5` 模型实现。\n\n本节介绍 Commonplace 的完整安装流程、系统要求、环境配置以及与 Claude Code 的集成方法。\n\n## 系统要求\n\n### Node.js 环境\n\nCommonplace 要求 Node.js 版本 **20 或更高**。项目通过 `.nvmrc` 文件声明了版本要求：\n\n```bash\n20\n```\n\n同时 `package.json` 的 `engines` 字段也做了约束声明。\n\n### 包管理器\n\n| 包管理器 | 支持状态 |\n|---------|---------|\n| pnpm | ✅ 唯一支持 |\n| npm | ❌ 不支持 |\n| yarn | ❌ 不支持 |\n\n> 资料来源：[CLAUDE.md:30]()\n\n### 技术栈\n\n| 技术 | 版本/要求 | 用途 |\n|------|----------|------|\n| TypeScript | 严格模式, ES2022 目标 | 源码编写 |\n| ESM | NodeNext 模块输出 | 模块系统 |\n| vitest | 最新版 | 单元和集成测试 |\n| @huggingface/transformers | 最新版 | 本地嵌入推理 |\n| @modelcontextprotocol/sdk | 最新版 | MCP stdio 服务器接口 |\n\n> 资料来源：[CLAUDE.md:24-37]()\n\n## 安装流程\n\n### 步骤一：克隆仓库\n\n```bash\ngit clone https://github.com/rickbassham/commonplace.git\ncd commonplace\n```\n\n### 步骤二：安装依赖\n\n```bash\npnpm install\n```\n\n### 步骤三：构建项目\n\n```bash\npnpm build\n```\n\n构建过程会：\n- 编译 TypeScript 源码到 ESM 格式\n- 输出到 `dist/` 目录\n- 生成两个可执行入口：`commonplace` 和 `commonplace-mcp`\n\n> 资料来源：[CLAUDE.md:48-50]()\n\n## Claude Code 集成配置\n\n### 添加 MCP 服务器\n\n在 Claude Code 配置中添加以下服务器配置：\n\n```json\n{\n  \"mcpServers\": {\n    \"commonplace\": {\n      \"command\": \"node\",\n      \"args\": [\"/path/to/commonplace/dist/bin/commonplace-mcp.js\"]\n    }\n  }\n}\n```\n\n完成配置后，重启所有正在运行的 Claude Code 会话，四个记忆工具即可使用：\n\n- `memory_save`\n- `memory_list`\n- `memory_delete`\n- `memory_search`\n\n> 资料来源：[README.md:48-58]()\n\n## 环境变量配置\n\n### 存储路径配置\n\n| 环境变量 | 默认值 | 说明 |\n|---------|-------|------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | 用户级记忆存储路径，始终加载 |\n| `COMMONPLACE_PROJECT_DIR` | 项目根目录下的 `.commonplace/memory` | 项目级记忆存储路径，按需加载 |\n\n### 功能开关\n\n| 环境变量 | 默认值 | 说明 |\n|---------|-------|------|\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | 控制 `[[name]]` 提及提取功能，设为 `'false'` 可禁用 |\n\n> 资料来源：[CLAUDE.md:53-57]()\n\n### 记忆存储架构\n\n```mermaid\ngraph TD\n    subgraph 用户存储\n        USER_DIR[\"COMMONPLACE_USER_DIR<br/>(~/.commonplace/memory)\"]\n    end\n    \n    subgraph 项目存储\n        PROJ_DIR[\"COMMONPLACE_PROJECT_DIR<br/>(按需加载)\"]\n    end\n    \n    subgraph 记忆文件\n        MD[\"<name>.md<br/>YAML 前缀 + Markdown 正文\"]\n        EMB[\"<name>.embedding<br/>二进制嵌入向量\"]\n    end\n    \n    USER_DIR --> MD\n    PROJ_DIR --> MD\n    MD --> EMB\n```\n\n## 记忆类型系统\n\n### 四种记忆类型\n\n| 类型 | 用途 | 示例 |\n|------|------|------|\n| `user` | 个人规则、偏好和身份信息 | 工作时间偏好、写作风格 |\n| `feedback` | 修正和从以往行为中学到的教训 | 不要擅自缩减范围 |\n| `project` | 项目特定的上下文信息 | 架构笔记、代码约定 |\n| `reference` | 持久化的中立知识 | API 形状、公式、引用 |\n\n> 资料来源：[README.md:60-73]()\n\n## CLI 命令行工具\n\n### 可执行文件\n\n| 命令 | 路径 | 用途 |\n|------|------|------|\n| `commonplace` | `dist/index.js` | CLI 子命令接口 |\n| `commonplace-mcp` | `dist/bin/commonplace-mcp.js` | MCP stdio 服务器 |\n\n### 迁移命令\n\n```bash\n# 检测已知外部记忆源\ncommonplace migrate\n\n# 从指定源导入记忆\ncommonplace migrate --from claude-code\n\n# 预览模式（不写入）\ncommonplace migrate --from claude-code --dry-run\n\n# 脚本化运行\ncommonplace migrate --from claude-code --auto\n\n# 为现有记忆目录重建侧边文件\ncommonplace migrate <dir>\ncommonplace migrate <dir> --dry-run\ncommonplace migrate <dir> --prune-dangling\n```\n\n> 资料来源：[README.md:17-23]()\n\n## 验证安装\n\n### 构建验证\n\n```bash\nmake build\nmake typecheck\nmake lint\n```\n\n### 运行测试\n\n```bash\nmake test\n```\n\n### 审计依赖\n\n```bash\nmake audit\n```\n\n> 资料来源：[CONTRIBUTING.md:24-26]()\n\n## 目录结构概览\n\n```\ncommonplace/\n├── dist/                    # 构建输出\n│   ├── index.js            # CLI 入口\n│   └── bin/\n│       └── commonplace-mcp.js  # MCP 服务器入口\n├── src/\n│   ├── embedder/           # transformers.js 封装\n│   ├── store/              # Markdown + 侧边文件 I/O\n│   └── server/             # MCP 服务器处理程序\n├── package.json\n└── .nvmrc                  # Node.js 版本声明\n```\n\n## 常见问题\n\n### Q: npm 或 yarn 可以使用吗？\n\n不可以。项目仅支持 pnpm 作为包管理器。使用其他包管理器会导致依赖安装失败或构建错误。\n\n### Q: Node.js 18 可以使用吗？\n\n不可以。必须使用 Node.js 20 或更高版本。\n\n### Q: 记忆文件存储在哪里？\n\n默认情况下，用户级记忆存储在 `~/.commonplace/memory`，项目级记忆存储在项目根目录的 `.commonplace/memory` 下。\n\n### Q: 如何重建嵌入向量？\n\n使用 `commonplace migrate <dir>` 命令可重新扫描目录并重建所有 `.embedding` 侧边文件。\n\n---\n\n<a id='page-architecture'></a>\n\n## 系统架构\n\n### 相关页面\n\n相关主题：[项目概览](#page-overview), [嵌入模型与语义搜索](#page-embedder), [存储系统](#page-storage)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n- [src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n</details>\n\n# 系统架构\n\n## 概述\n\nCommonplace 是一个为 Claude Code 提供持久化记忆功能的 MCP (Model Context Protocol) 工具系统。它通过 markdown 文件存储记忆内容，支持语义搜索和关系图谱管理。资料来源：[CLAUDE.md:1]()\n\n该系统具有以下核心设计原则：\n\n- **单一真相来源** — `.md` 文件是数据的唯一真实来源，`.embedding` 等辅助文件可随时从源文件重新生成\n- **无覆盖写入** — `memory_save` 工具拒绝覆盖已有条目，必须先删除再保存\n- **双存储架构** — 支持用户级存储和项目级存储分离\n- **图关系管理** — 支持在记忆之间建立显式关系边\n\n资料来源：[CLAUDE.md:16-19]()\n\n---\n\n## 整体架构\n\n```mermaid\ngraph TB\n    subgraph \"CLI 层\"\n        CLI[命令行入口<br/>src/index.ts]\n        MIGRATE[迁移命令<br/>src/cli/migrate.ts]\n    end\n\n    subgraph \"MCP 服务器层\"\n        SERVER[MCP Server<br/>src/server/server.ts]\n        HANDLERS[请求处理器<br/>src/server/handlers.ts]\n    end\n\n    subgraph \"核心存储层\"\n        STORE[MemoryStore<br/>src/store/memory-store.ts]\n        MEMORY[Memory I/O<br/>src/store/memory.ts]\n        GRAPH[MemoryGraph<br/>关系图谱]\n        MENTIONS[Mentions 提取器<br/>src/store/mentions.ts]\n    end\n\n    subgraph \"嵌入层\"\n        EMBEDDER[Embedder<br/>src/embedder/index.ts]\n        EMBEDDINGS[.embedding 侧文件]\n    end\n\n    subgraph \"存储后端\"\n        USER_DIR[用户存储<br/>~/.commonplace/memory]\n        PROJECT_DIR[项目存储<br/>.commonplace/memory]\n    end\n\n    CLI --> MIGRATE\n    CLI --> STORE\n    SERVER --> HANDLERS\n    HANDLERS --> STORE\n    STORE --> MEMORY\n    STORE --> GRAPH\n    STORE --> MENTIONS\n    STORE --> EMBEDDER\n    EMBEDDER --> EMBEDDINGS\n    MEMORY --> USER_DIR\n    MEMORY --> PROJECT_DIR\n    GRAPH --> USER_DIR\n    GRAPH --> PROJECT_DIR\n```\n\n---\n\n## 核心组件\n\n### 1. CLI 入口层\n\n#### 命令行入口 (`src/index.ts`)\n\n负责命令解析和分发，是系统的最外层接口。\n\n**支持的子命令：**\n\n| 子命令 | 功能 | 源码位置 |\n|--------|------|----------|\n| `migrate` | 扫描、嵌入、清理记忆目录 | src/index.ts:28-50 |\n| `graph` | 图关系查询 | src/index.ts:34-42 |\n\nCLI 采用延迟加载策略：只有在确认需要执行时才构造 `Embedder` 实例，避免不必要的模型加载开销。\n\n资料来源：[src/index.ts:38-47]()\n\n```typescript\n// 延迟 embedder 工厂函数\nembedderFactory: () => new Embedder(resolveModelId(process.env))\n```\n\n#### 迁移命令 (`src/cli/migrate.ts`)\n\n提供记忆目录的维护功能：\n\n1. **扫描与嵌入** — 为缺失或过时的 `.embedding` 侧文件重新生成向量\n2. **孤立文件清理** — 移除无对应 `.md` 的 `.embedding` 文件\n3. **悬空边修剪** — 可选功能，移除指向不存在记忆的关系引用\n\n资料来源：[src/cli/migrate.ts:58-85]()\n\n---\n\n### 2. MCP 服务器层\n\n#### 服务器 (`src/server/server.ts`)\n\nMCP 服务器负责与 Claude Code 会话建立通信，提供四个核心工具：\n\n| 工具名 | 功能 |\n|--------|------|\n| `memory_save` | 保存记忆到 markdown 文件 |\n| `memory_search` | 语义搜索记忆 |\n| `memory_list` | 列出/过滤记忆 |\n| `memory_path` | 获取记忆文件路径 |\n\n资料来源：[CLAUDE.md:60-100]()\n\n#### 请求处理器 (`src/server/handlers.ts`)\n\n处理 MCP 工具调用的核心逻辑，包括：\n\n- 参数验证与类型检查\n- 搜索结果的聚合与排序\n- 默认扩展类型的配置\n\n```typescript\nexport const DEFAULT_EXPAND_TYPES: readonly EdgeType[] = ['builds-on', 'related-to'] as const;\n```\n\n资料来源：[src/server/handlers.ts:8-12]()\n\n---\n\n### 3. 核心存储层\n\n#### MemoryStore (`src/store/memory-store.ts`)\n\n系统的核心存储引擎，管理内存索引和文件系统同步。\n\n**主要职责：**\n\n- 加载与缓存记忆条目\n- 增量图索引维护\n- 原子写入操作\n- 扫描与嵌入管理\n\n**关键方法：**\n\n| 方法 | 功能 |\n|------|------|\n| `scan()` | 扫描目录，同步嵌入状态 |\n| `save()` | 保存新记忆 |\n| `delete()` | 删除记忆 |\n| `search()` | 语义向量搜索 |\n| `list()` | 列出记忆 |\n| `linkEdge()` | 添加关系边 |\n| `unlinkEdge()` | 移除关系边 |\n\n资料来源：[src/store/memory-store.ts:1-50]()\n\n#### Memory I/O (`src/store/memory.ts`)\n\n负责 markdown 文件的序列化与反序列化。\n\n**文件格式规范：**\n\n```yaml\n---\nname: memory_name\ndescription: 简短描述\ntype: user | feedback | project | reference\nrelations:       # 可选，关系列表\n  - to: other_name\n    type: builds-on\nsupersedes:      # 可选，替代列表\n  - old_name\n---\n<body>\n```\n\n**内容哈希计算：**\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${memory.description}\\n${memory.body}`, 'utf8')\n    .digest('hex');\n```\n\n注意：`contentSha` 仅基于类型、名称、描述和正文计算，**不包括** `relations` 和 `supersedes` 字段。这意味着关系的增删不会导致嵌入失效。\n\n资料来源：[src/store/memory.ts:90-97]()\n\n#### MemoryGraph (`src/store/memory-store.ts`)\n\n内存中的关系图数据结构，支持：\n\n- **边的类型**：`builds-on`、`related-to`、`contradicts`、`child-of`、`supersedes`、`mentions`\n- **BFS 遍历**：支持深度限制和边类型过滤\n- **增量更新**：通过 `addEdge()` / `removeEdge()` 增量维护\n\n#### Mentions 提取器 (`src/store/mentions.ts`)\n\n从记忆正文中提取 `[[name]]` 形式的内联引用。\n\n- 默认启用，可通过 `COMMONPLACE_EXTRACT_MENTIONS=false` 环境变量禁用\n- 仅提取符合 `[a-z0-9_]+` 命名规则的引用\n- 在 `scan()` 和 `save()` 时自动调用，结果自动写入图的 `mentions` 边\n\n资料来源：[src/store/mentions.ts:1-30]()\n\n---\n\n### 4. 嵌入层\n\n#### Embedder (`src/embedder/index.ts`)\n\n使用 Transformers.js 进行本地向量嵌入生成。\n\n**嵌入流程：**\n\n1. 接收文本内容\n2. 使用预训练模型生成向量表示\n3. 将向量序列化写入 `.embedding` 侧文件\n\n**侧文件新鲜度判断标准：**\n\n- `.embedding` 文件存在且可解码\n- `modelId` 与当前 embedder 一致\n- `dim` 维度匹配\n- `contentSha` 与源文件哈希一致\n\n任一条件不满足都会触发重新嵌入。\n\n资料来源：[src/store/memory-store.ts:180-195]()\n\n---\n\n## 双存储架构\n\n```mermaid\ngraph LR\n    subgraph \"用户存储\"\n        USER[~/.commonplace/memory]\n        USER_TYPE[user / feedback<br/>类型]\n    end\n\n    subgraph \"项目存储\"\n        PROJECT[<project>/.commonplace/memory]\n        PROJECT_TYPE[project / reference<br/>类型]\n    end\n\n    USER --> USER_TYPE\n    PROJECT --> PROJECT_TYPE\n```\n\n### 存储位置\n\n| 存储类型 | 路径 | 加载时机 |\n|----------|------|----------|\n| 用户存储 | `COMMONPLACE_USER_DIR` (默认 `~/.commonplace/memory`) | 始终加载 |\n| 项目存储 | `COMMONPLACE_PROJECT_DIR` 或 `<project-root>/.commonplace/memory` | 检测到项目根目录时加载 |\n\n### 检测优先级\n\n项目存储的路径按以下优先级确定：\n\n1. `COMMONPLACE_PROJECT_DIR` 环境变量（显式覆盖，始终优先）\n2. MCP `roots/list` 协议检测到的项目根目录\n3. 当前工作目录\n\n资料来源：[CLAUDE.md:130-150]()\n\n### 搜索行为\n\n搜索时，结果会跨两个存储聚合，按相似度降序排列。返回结果中包含 `scope: 'user' | 'project'` 字段标识来源。\n\n---\n\n## 原子写入机制\n\n```mermaid\ngraph TD\n    A[写入请求] --> B[创建临时文件<br/>`<name>.<random>.tmp`]\n    B --> C{同文件系统?}\n    C -->|否| D[抛出错误]\n    C -->|是| E[写入数据到临时文件]\n    E --> F[fsync 刷新]\n    F --> G[rename 到目标路径]\n    G --> H[完成]\n    \n    D --> I[原子性保证失败<br/>拒绝跨文件系统操作]\n```\n\n`atomicWrite` 实现通过临时文件 + rename 序列保证写入原子性，防止系统崩溃导致文件损坏。\n\n资料来源：[src/store/atomic-write.ts:1-25]()\n\n---\n\n## 内存类型体系\n\n| 类型 | 用途 | 存储位置 |\n|------|------|----------|\n| `user` | 个人规则、偏好、身份事实 | 用户存储 |\n| `feedback` | 来自以往行为的修正和经验教训 | 用户存储 |\n| `project` | 项目级上下文，如架构笔记、约定 | 项目存储 |\n| `reference` | 持久性知识，如 API 形状、公式、引用 | 项目存储 |\n\n所有四个工具都接受 `type` 参数进行过滤。\n\n资料来源：[CLAUDE.md:30-45]()\n\n---\n\n## 关系边类型\n\n| 边类型 | 语义含义 | 默认展开 |\n|--------|----------|----------|\n| `builds-on` | 基于某记忆构建 | ✓ |\n| `related-to` | 相关但不明确 | ✓ |\n| `mentions` | 正文中提及 | ✗ |\n| `supersedes` | 替代某记忆 | ✗ |\n| `contradicts` | 与某记忆矛盾 | ✗ |\n| `child-of` | 从属关系 | ✗ |\n\n`builds-on` 和 `related-to` 被设为默认展开类型，因为它们最可能提供有用的上下文。\n\n资料来源：[src/server/handlers.ts:8-12]()\n\n---\n\n## 扫描与嵌入流程\n\n```mermaid\ngraph TD\n    A[migrate 命令] --> B[遍历 .md 文件]\n    B --> C{侧文件新鲜?}\n    C -->|是| D[跳过]\n    C -->|否| E[调用 Embedder]\n    E --> F[写入 .embedding]\n    D --> G{还有文件?}\n    F --> G\n    G -->|是| B\n    G -->|否| H[孤立文件清理]\n    H --> I[输出统计报告]\n```\n\n扫描完成后会遍历目录，移除任何无对应 `.md` 的 `.embedding` 文件（孤立侧文件清理）。\n\n资料来源：[src/store/memory-store.ts:165-180]()\n\n---\n\n## 数据流向\n\n```mermaid\ngraph LR\n    A[MCP 工具调用] --> B[参数验证]\n    B --> C[MemoryStore 操作]\n    C --> D{操作类型}\n    D -->|save| E[序列化 Markdown]\n    D -->|search| F[向量搜索]\n    D -->|linkEdge| G[更新关系图]\n    E --> H[原子写入]\n    F --> I[匹配结果]\n    G --> J[图索引更新]\n    H --> K[文件系统]\n    I --> L[结果聚合]\n    J --> K\n    L --> M[返回结果]\n```\n\n---\n\n## 环境变量配置\n\n| 变量 | 默认值 | 作用 |\n|------|--------|------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | 用户存储路径 |\n| `COMMONPLACE_PROJECT_DIR` | - | 项目存储路径（覆盖检测） |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `true` | 启用 `[[name]]` 提取 |\n\n资料来源：[src/store/mentions.ts:18-20]()\n\n---\n\n## 关键设计决策\n\n### 1. 嵌入哈希稳定性\n\n`contentSha` 故意排除 `relations` 和 `supersedes` 字段。这意味着修改记忆之间的关系不会导致嵌入重新计算，保证嵌入的稳定性。\n\n资料来源：[src/store/memory.ts:82-91]()\n\n### 2. 写入安全\n\n使用原子写入（临时文件 + rename）确保数据一致性，防止崩溃导致的文件损坏。\n\n### 3. 图索引增量维护\n\n`linkEdge` 和 `unlinkEdge` 方法直接操作内存中的图结构，无需完整重新扫描目录。目录修改时间基准在操作后刷新，防止不必要的重新扫描。\n\n资料来源：[src/store/memory-store.ts:220-230]()\n\n### 4. 延迟模型加载\n\nCLI 层的 `embedderFactory` 工厂函数采用延迟实例化策略，只有在实际需要嵌入时才加载 Transformers.js 模型。\n\n资料来源：[src/index.ts:44-47]()\n\n---\n\n<a id='page-tech-stack'></a>\n\n## 技术栈详解\n\n### 相关页面\n\n相关主题：[系统架构](#page-architecture)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [package.json](https://github.com/rickbassham/commonplace/blob/main/package.json)\n- [tsconfig.json](https://github.com/rickbassham/commonplace/blob/main/tsconfig.json)\n- [tsconfig.build.json](https://github.com/rickbassham/commonplace/blob/main/tsconfig.build.json)\n- [vitest.config.ts](https://github.com/rickbassham/commonplace/blob/main/vitest.config.ts)\n- [eslint.config.js](https://github.com/rickbassham/commonplace/blob/main/eslint.config.js)\n- [src/embedder/](https://github.com/rickbassham/commonplace/blob/main/src/embedder/)\n- [src/store/](https://github.com/rickbassham/commonplace/blob/main/src/store/)\n- [src/server/](https://github.com/rickbassham/commonplace/blob/main/src/server/)\n</details>\n\n# 技术栈详解\n\n## 概述\n\nCommonplace 是一个基于 TypeScript 构建的记忆管理工具，通过 MCP（Model Context Protocol）协议与 Claude Code 等 AI 代理集成。其技术栈围绕本地向量嵌入推理、Markdown 文件存储和 MCP 协议通信三大核心能力展开。\n\n项目采用 Node.js 作为运行时环境，要求 Node >=20，代码以 ESM（ECMAScript Modules）格式输出，不使用 CommonJS。资料来源：[CLAUDE.md]()\n\n## 核心架构分层\n\n```mermaid\ngraph TD\n    subgraph \"表现层\"\n        CLI[CLI 命令行]\n        MCP[MCP 服务器]\n    end\n    \n    subgraph \"服务层\"\n        HANDLERS[MCP Handlers]\n        EMBEDDER[嵌入器]\n    end\n    \n    subgraph \"存储层\"\n        MEMORY_STORE[MemoryStore]\n        GRAPH[MemoryGraph]\n    end\n    \n    subgraph \"文件系统\"\n        MD[.md 文件]\n        EMBEDDING[.embedding 侧文件]\n    end\n    \n    CLI --> HANDLERS\n    MCP --> HANDLERS\n    HANDLERS --> EMBEDDER\n    HANDLERS --> MEMORY_STORE\n    MEMORY_STORE --> GRAPH\n    MEMORY_STORE --> MD\n    MEMORY_STORE --> EMBEDDING\n```\n\n## 编程语言与工具链\n\n### TypeScript\n\n项目使用 TypeScript 进行开发，采用严格模式（strict mode）和 ES2022 编译目标。\n\n| 配置项 | 值 |\n|--------|-----|\n| 目标版本 | ES2022 |\n| 模块系统 | ESM (NodeNext) |\n| 类型检查 | strict mode |\n| 编译输出 | ESM 格式 |\n\n资料来源：[CLAUDE.md]()\n\n### 代码质量工具\n\n| 工具 | 用途 |\n|------|------|\n| ESLint | 代码静态分析 |\n| vitest | 单元测试和集成测试 |\n| TypeScript Compiler | 类型检查与编译 |\n\n项目配置了多个 Make 目标来执行质量检查：\n\n- `make typecheck` - TypeScript 类型检查\n- `make lint` - ESLint 代码检查\n- `make test` - vitest 测试执行\n- `make build` - 项目构建\n- `make audit` - 安全审计（非阻塞）\n\n资料来源：[CONTRIBUTING.md]()\n\n## 核心依赖库\n\n### 向量嵌入推理\n\n| 依赖 | 版本 | 用途 |\n|------|------|------|\n| @huggingface/transformers | 最新 | 本地 embedding 模型推理 |\n\n`src/embedder/` 目录封装了 transformers.js 的调用，提供类型化的 `embed(text) -> Float32Array` 接口，并隔离模型加载逻辑与业务代码的耦合。\n\n```mermaid\nsequenceDiagram\n    participant 调用方\n    participant Embedder\n    participant Transformers\n    \n    调用方->>Embedder: embed(text)\n    Embedder->>Transformers: 加载模型\n    Transformers-->>Embedder: 模型就绪\n    Embedder->>Transformers: 执行推理\n    Transformers-->>Embedder: Float32Array\n    Embedder-->>调用方: 返回嵌入向量\n```\n\n资料来源：[CLAUDE.md]()\n\n### MCP 协议通信\n\n| 依赖 | 用途 |\n|------|------|\n| @modelcontextprotocol/sdk | stdio MCP 服务器实现 |\n\n`src/server/` 目录包含 MCP 工具处理器和资源处理器，负责将 MemoryStore 和 Embedder 的能力暴露给外部 MCP 客户端。\n\n项目定义了两个独立的 bin 入口：\n\n- `commonplace` -> `dist/index.js`：CLI 命令行界面\n- `commonplace-mcp` -> `dist/bin/commonplace-mcp.js`：stdio MCP 服务器\n\n资料来源：[src/index.ts]()\n\n### 文件处理\n\n| 依赖 | 用途 |\n|------|------|\n| yaml | YAML frontmatter 序列化/反序列化 |\n| crypto (内置) | SHA256 内容哈希计算 |\n| fs/promises | 原子写入文件系统操作 |\n\n## 数据存储架构\n\n### 存储目录结构\n\n```mermaid\ngraph LR\n    subgraph \"用户存储 ~/\\.commonplace/memory\"\n        MD1[name1.md]\n        EMB1[name1.embedding]\n        MD2[name2.md]\n        EMB2[name2.embedding]\n    end\n    \n    subgraph \"项目存储 \\<project\\>/\\.commonplace/memory\"\n        MD3[proj_name1.md]\n        EMB3[proj_name1.embedding]\n    end\n```\n\n### Memory 文件格式\n\n每个记忆以 Markdown 文件形式存储，包含 YAML frontmatter 和正文内容：\n\n```yaml\n---\nname: memory_name\ndescription: 描述文本\ntype: user | feedback | project | reference\nrelations:       # 可选，定义关系图\n  - to: other_name\n    type: builds-on\nsupersedes:      # 可选，定义替代关系\n  - old_name\n---\n<body>\n```\n\n记忆类型说明：\n\n| 类型 | 用途 |\n|------|------|\n| user | 个人规则、偏好和身份事实 |\n| feedback | 代理行为纠正和经验教训 |\n| project | 项目特定上下文 |\n| reference | 持久性中性知识 |\n\n资料来源：[src/store/memory.ts]()\n\n### 内容哈希机制\n\n`contentSha` 函数计算记忆内容的 SHA256 哈希值，用于判断是否需要重新生成 embedding。哈希计算范围包括：\n\n- `type`\n- `name`\n- `description`\n- `body`\n\n图关系字段（`relations`、`supersedes`）**不参与**哈希计算，确保图结构的修改不会使已有的 embedding 失效。\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${memory.description}\\n${memory.body}`, 'utf8')\n    .digest('hex');\n```\n\n资料来源：[src/store/memory.ts]()\n\n### 原子写入\n\n`src/store/atomic-write.ts` 实现了跨文件系统的原子写入保护，确保并发写入时的数据完整性：\n\n1. 在目标目录创建临时文件（`.basename.<random>.tmp`）\n2. 验证临时文件和目标目录在同一文件系统\n3. 原子重命名临时文件到目标文件\n\n资料来源：[src/store/atomic-write.ts]()\n\n## 包管理\n\n### pnpm\n\n项目使用 pnpm 作为唯一的包管理器，不支持 npm 或 yarn。\n\n```bash\n# 安装依赖\npnpm install\n\n# 添加依赖\npnpm add <package>\n\n# 运行测试\npnpm test\n```\n\n### CI 自动化\n\n项目在 Node 20 和 Node 22 两个版本上运行 CI，确保兼容性。\n\n```mermaid\ngraph LR\n    A[PR 创建] --> B[CI 触发]\n    B --> C{make typecheck}\n    B --> D{make lint}\n    B --> E{make build}\n    B --> F{make test}\n    B --> G{make audit}\n    C --> H{全部通过?}\n    D --> H\n    E --> H\n    F --> H\n    H -->|是| I[可合并]\n    H -->|否| J[阻塞合并]\n```\n\n资料来源：[CONTRIBUTING.md]()\n\n## 关键模块职责\n\n| 模块路径 | 职责 |\n|---------|------|\n| `src/embedder/` | transformers.js 封装，embedding 推理 |\n| `src/store/` | Markdown I/O，YAML frontmatter 编解码，vector index |\n| `src/server/` | MCP 协议处理器，工具/资源暴露 |\n| `src/cli/migrate.ts` | CLI 命令行参数解析和迁移逻辑 |\n| `src/index.ts` | CLI 分发器，双 bin 入口协调 |\n\n## 环境配置\n\n项目使用环境变量进行配置管理，由 DAR-913 统一管理：\n\n| 环境变量 | 说明 |\n|---------|------|\n| COMMONPLACE_USER_DIR | 用户记忆存储路径（默认 `~/.commonplace/memory`） |\n| COMMONPLACE_PROJECT_DIR | 项目记忆存储路径 |\n| COMMONPLACE_EXTRACT_MENTIONS | 是否提取 `[[name]]` 提及（默认开启） |\n\n## 测试框架\n\nvitest 用于项目的单元测试和集成测试：\n\n```typescript\n// 测试示例结构\nimport { describe, it, expect } from 'vitest';\n\ndescribe('MemoryStore', () => {\n  it('should load memories from directory', async () => {\n    // 测试逻辑\n  });\n});\n```\n\n## 总结\n\nCommonplace 的技术栈设计遵循以下原则：\n\n1. **本地优先**：使用 transformers.js 实现本地 embedding 推理，无需外部 API\n2. **简单持久化**：以 Markdown + YAML 作为存储格式，确保数据可读性和可移植性\n3. **协议解耦**：通过 MCP SDK 暴露能力，支持多种 MCP 客户端集成\n4. **类型安全**：TypeScript 严格模式配合 ESLint 确保代码质量\n\n---\n\n<a id='page-embedder'></a>\n\n## 嵌入模型与语义搜索\n\n### 相关页面\n\n相关主题：[搜索功能详解](#page-search), [系统架构](#page-architecture)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.ts)\n- [src/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n- [src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n- [CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [CHANGELOG.md](https://github.com/rickbassham/commonplace/blob/main/CHANGELOG.md)\n</details>\n\n# 嵌入模型与语义搜索\n\n## 概述\n\nCommonplace 的嵌入模型与语义搜索子系统是该应用的核心能力之一。它使 MCP 服务器能够对用户的笔记进行语义相似度搜索，而非简单的关键词匹配。整个系统完全离线运行，不依赖任何云端 API，通过本地向量计算实现语义检索。\n\n核心设计原则：\n\n- **嵌入完全本地化**：使用 `@huggingface/transformers` 库配合 `bge-base-en-v1.5` 模型\n- **边车文件（Sidecar）模式**：`.embedding` 二进制文件与 `.md` 笔记一一对应，作为派生物可随时重建\n- **内容哈希校验**：通过 `contentSha` 确保嵌入与笔记内容的一致性\n\n资料来源：[CHANGELOG.md]()\n\n## 架构概览\n\n```mermaid\ngraph TD\n    A[\"📄 Memory (.md)\"] --> B[\"contentSha() 计算哈希\"]\n    A --> C[\"序列化内存对象\"]\n    B --> D[\"嵌入模型 bge-base-en-v1.5\"]\n    C --> E[\".embedding 边车文件\"]\n    D --> E\n    E --> F[\"向量数据库\"]\n    G[\"语义搜索查询\"] --> H[\"计算查询向量\"]\n    H --> I[\"余弦相似度计算\"]\n    F --> I\n    I --> J[\"Top-K 结果排序\"]\n    J --> K[\"返回 MemorySearchMatch\"]\n```\n\n## 内存文件结构与内容哈希\n\n### YAML Frontmatter 格式\n\n每篇笔记都是一个 Markdown 文件，前置 YAML 元数据：\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: other_name\n    type: builds-on\nsupersedes:\n  - old_name\n---\n<body>\n```\n\n资料来源：[src/store/memory.ts:44-60]()\n\n### contentSha 哈希算法\n\n`contentSha` 函数计算内存内容的规范表示，用于判断边车文件是否需要重建：\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${memory.description}\\n${memory.body}`, 'utf8')\n    .digest('hex');\n```\n\n**关键设计决策**：哈希仅基于 v0.1 基线 frontmatter（`type`、`name`、`description`）和正文 `body`。图字段 `relations` 和 `supersedes` **不参与**哈希计算。\n\n> 添加或删除图关系边**不应**导致嵌入失效，这是 DAR-925 的核心设计要求。\n\n资料来源：[src/store/memory.ts:25-35]()\n\n## 边车文件（Sidecar）机制\n\n### 边车文件格式\n\n`.embedding` 是二进制文件，包含以下结构：\n\n| 字段 | 描述 |\n|------|------|\n| Magic Bytes | 格式魔数 |\n| Version | 版本号 |\n| Length | 数据长度 |\n| modelId | 使用的嵌入模型标识 |\n| dim | 向量维度 |\n| contentSha | 对应笔记的哈希值 |\n| vector | 实际的嵌入向量数据 |\n\n资料来源：[src/store/memory-store.ts:140-150]()\n\n### 边车新鲜度判断\n\n`scan()` 方法在加载时判断每个边车文件是否可复用。满足以下**全部条件**时，边车被认为是\"新鲜的\"：\n\n| 条件 | 说明 |\n|------|------|\n| 文件存在 | `.embedding` 文件存在于磁盘 |\n| 解码成功 | Magic + Version + Length 校验通过 |\n| 模型匹配 | `decoded.modelId === embedder.modelId` |\n| 维度匹配 | `decoded.dim === embedder.dim` |\n| 哈希匹配 | `decoded.contentSha === contentSha(memoryAsRead)` |\n\n任一条件不满足都会触发重新嵌入并重写边车文件。\n\n资料来源：[src/store/memory-store.ts:140-160]()\n\n### 孤立边车清理\n\n扫描完成后，`scan()` 会进行第二轮目录遍历，移除任何没有对应 `.md` 文件的 `.embedding` 孤立边车。这些孤立文件在内存索引中不可达，保留它们只会无声地积累无效数据。\n\n```typescript\n// 孤立边车计数报告\nresult.orphaned  // 被清理的孤立边车数量\n```\n\n资料来源：[src/store/memory-store.ts:175-185]()\n\n## 扫描流程（Scan Pipeline）\n\n```mermaid\nsequenceDiagram\n    participant FS as 文件系统\n    participant Store as MemoryStore\n    participant Scan as scan()\n    participant Embedder as Embedder\n    participant Sidecar as .embedding\n\n    Scan->>FS: 遍历目录中的 *.md 文件\n    Scan->>FS: 检查对应的 .embedding 边车\n    alt 边车新鲜\n        Scan->>Scan: 复用现有边车\n    else 边车过期\n        Scan->>Embedder: 调用 embed(body)\n        Embedder-->>Scan: 返回向量\n        Scan->>FS: 原子写入新边车\n    end\n    Scan->>FS: 清理孤立的 .embedding 文件\n    Scan-->>Store: 更新内存索引\n```\n\n### 扫描选项\n\n```typescript\ninterface ScanOptions {\n  /** 是否为预演模式 */\n  dryRun?: boolean;\n  /** 是否删除悬挂边 */\n  pruneDangling?: boolean;\n}\n```\n\n在 `dryRun` 模式下，孤立边车计数会报告但不实际删除。\n\n资料来源：[src/store/memory-store.ts:130-145]()\n\n## 原子写入机制\n\n嵌入向量通过原子写入操作保存到边车文件，防止并发写入导致文件损坏：\n\n```mermaid\ngraph LR\n    A[\"写入请求\"] --> B[\"生成临时文件<br/>base.<8位随机hex>.tmp\"]\n    B --> C[\"写入临时文件\"]\n    C --> D{\"写入成功?\"}\n    D--否--> E[\"删除临时文件<br/>抛出错误\"]\n    D--是--> F[\"原子重命名<br/>tmp → target\"]\n    F --> G[\"完成\"]\n```\n\n关键特性：\n\n- **文件系统检查**：验证目标目录与临时文件目录在同一文件系统（`dev` 匹配）\n- **16位熵随机数**：充足的空间避免并发冲突\n- **原子重命名**：利用操作系统原子操作保证一致性\n\n资料来源：[src/store/atomic-write.ts:1-30]()\n\n## 语义搜索实现\n\n### Top-K 余弦相似度搜索\n\n搜索流程：\n\n1. 接收用户查询文本\n2. 使用嵌入模型将查询转换为向量\n3. 在内存索引中计算所有笔记的余弦相似度\n4. 按相似度降序排列\n5. 返回前 K 条结果\n\n```typescript\ninterface MemorySearchMatch {\n  name: string;\n  type: MemoryType;\n  description: string;\n  body: string;        // 完整正文，不截断\n  score: number;       // 余弦相似度，保留3位小数\n  relations: Relation[]; // 出边关系\n}\n```\n\n资料来源：[src/server/handlers.ts:35-55]()\n\n### 搜索结果丰富化\n\n搜索结果会额外返回笔记的图关系信息，但默认只包含 `builds-on` 和 `related-to` 两种边类型：\n\n```typescript\nexport const DEFAULT_EXPAND_TYPES: readonly EdgeType[] = \n  ['builds-on', 'related-to'] as const;\n```\n\n这是经过设计的决策——这两种边类型最可能暴露对代理有用的邻近节点。其他边类型（`mentions`、`supersedes`、`contradicts`、`child-of`）需要显式 opt-in。\n\n资料来源：[src/server/handlers.ts:15-20]()\n\n### 废弃笔记排除\n\n默认情况下，被 `supersedes` 字段引用的旧笔记会被排除在搜索结果之外。搜索结果的 `relations` 数组中**不包含** `supersedes` 边，该字段仅在内存的 YAML frontmatter 中作为单向声明存在。\n\n资料来源：[src/server/handlers.ts:55-65]()\n\n## MCP 工具接口\n\n系统通过 MCP stdio 服务器暴露以下与搜索相关的工具：\n\n### memory_search\n\n语义搜索工具，返回匹配的笔记及其相似度分数。\n\n### memory_list\n\n列出所有笔记，返回名称、类型、描述信息。\n\n### memory_save\n\n保存新笔记，自动触发嵌入生成。\n\n### memory_delete\n\n删除笔记及其关联的边车文件。\n\n### memory_link / memory_unlink\n\n图关系链接工具，用于建立笔记间的 `builds-on`、`related-to`、`contradicts`、`child-of` 关系。\n\n资料来源：[src/index.ts:1-30]()\n\n## 配置与环境变量\n\n| 环境变量 | 默认值 | 用途 |\n|----------|--------|------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | 用户记忆存储根目录 |\n| `COMMONPLACE_PROJECT_DIR` | 动态检测 | 项目级记忆存储目录 |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | 是否启用 `[[name]]` 提及提取 |\n\n嵌入模型 ID 通过 `resolveModelId(process.env)` 解析，环境变量配置由 DAR-913 规范。\n\n资料来源：[src/store/mentions.ts:20-30]()\n\n## CLI 命令行接口\n\n`migrate` 子命令提供边车管理的命令行入口：\n\n| 命令 | 功能 |\n|------|------|\n| `commonplace migrate --from claude-code` | 从 Claude Code 导入记忆 |\n| `commonplace migrate --dry-run` | 预演模式，不实际写入 |\n| `commonplace migrate --scan <dir>` | 扫描目录重建边车 |\n| `commonplace migrate --prune-dangling` | 清理悬挂边 |\n\n资料来源：[src/cli/migrate.ts:1-50]()\n\n## 性能考量\n\n### 懒加载嵌入器\n\n嵌入器（Embedder）构造函数本身很轻量，真正的模型加载发生在首次 `embed()` 调用时。这使得 `migrateMain` 可以先完成参数解析和目录验证，再按需构造嵌入器。\n\n```typescript\nembedderFactory: () => new Embedder(resolveModelId(process.env))\n```\n\n### mtime 基线刷新\n\n每次边车写入后，系统会刷新目录 mtime 基线，确保后续 `search()` / `list()` 调用不会误判为需要重新扫描：\n\n```typescript\nthis.#refreshMtimeBaseline();\n```\n\n资料来源：[src/store/memory-store.ts:280-295]()\n\n## 版本历史\n\n| 版本 | 变更内容 |\n|------|----------|\n| 0.1.0 | 初始发布：本地嵌入管道、bge-base-en-v1.5 模型、`.embedding` 边车、brute-force top-k 余弦搜索 |\n\n资料来源：[CHANGELOG.md]()\n\n## 相关模块\n\n| 模块 | 职责 |\n|------|------|\n| `src/embedder/index.ts` | 嵌入模型封装、向量生成 |\n| `src/store/memory.ts` | 内存对象序列化、contentSha 计算 |\n| `src/store/memory-store.ts` | 存储抽象、scan/save/search 核心逻辑 |\n| `src/store/atomic-write.ts` | 原子文件写入 |\n| `src/server/handlers.ts` | MCP 工具处理器 |\n\n---\n\n<a id='page-memory-format'></a>\n\n## 内存格式与侧载文件\n\n### 相关页面\n\n相关主题：[存储系统](#page-storage), [搜索功能详解](#page-search)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/sidecar.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/sidecar.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n</details>\n\n# 内存格式与侧载文件\n\n## 概述\n\nCommonplace 系统中的\"内存\"(Memory)是项目的核心数据单元。每个内存以 Markdown 文件形式持久化存储，配合同名的二进制侧载文件(`.embedding`)存放嵌入向量。这种设计确保了 Markdown 文件为唯一真相来源，侧载文件可随时从源文件重新生成。\n\n系统通过 `contentSha` 哈希值实现内容变更检测，确保嵌入向量与源文件保持同步。当检测到内容变化时，系统会自动重新生成嵌入并更新侧载文件。\n\n资料来源：[src/store/memory.ts:1-30]()\n\n## 内存 Markdown 格式\n\n### 文件结构\n\n内存文件采用标准 Markdown+YAML frontmatter 格式，文件结构如下：\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: other_name\n    type: builds-on\nsupersedes:\n  - old_name\n---\n<body>\n```\n\n资料来源：[src/store/memory.ts:1-30]()\n\n### YAML Frontmatter 字段说明\n\n| 字段 | 类型 | 必需 | 说明 |\n|------|------|------|------|\n| `name` | string | 是 | 内存名称，必须匹配 `^[a-z0-9_]+$`，将成为文件名 |\n| `description` | string | 是 | 简短的人类可读描述 |\n| `type` | enum | 是 | 内存类型：`user`、`feedback`、`project`、`reference` 之一 |\n| `relations` | Relation[] | 否 | 图关系列表，支持 `builds-on`、`related-to`、`contradicts`、`child-of` |\n| `supersedes` | string[] | 否 | 被当前内存取代的其他内存名称列表 |\n\n资料来源：[src/store/memory.ts:50-80]()\n\n### Relation 对象结构\n\n```typescript\ninterface Relation {\n  to: string;      // 目标内存名称\n  type: RelationType; // builds-on | related-to | contradicts | child-of\n}\n```\n\n资料来源：[src/store/memory.ts:40-45]()\n\n### 内存类型(MemoryType)\n\n| 类型 | 用途 |\n|------|------|\n| `user` | 个人规则、偏好和身份事实 |\n| `feedback` | 来自先前代理行为的纠正和经验教训 |\n| `project` | 项目级上下文，如架构笔记、仓库约定 |\n| `reference` | 持久化、中立的知识，如 API 形状、公式、引用 |\n\n资料来源：[README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n\n### Body 内容\n\nMarkdown body 可以包含任意文本内容，支持标准 Markdown 语法。特别地，系统支持 `[[name]]` 格式的内存提及语法，用于在内存间建立隐式关系。\n\n资料来源：[src/store/mentions.ts:1-20]()\n\n## 规范化内容哈希(contentSha)\n\n### 计算范围\n\n`contentSha` 是内存内容的规范化 SHA-256 哈希值，用于检测内容变更。哈希计算范围**仅限于** v0.1 基线 frontmatter 字段：\n\n```\n${type}\\n${name}\\n${description}\\n${body}\n```\n\n**重要**：`relations` 和 `supersedes` 图字段**不参与**哈希计算。这意味着添加或删除图边不会使嵌入向量失效。\n\n资料来源：[src/store/memory.ts:70-85]()\n\n### 设计原则\n\n```\ngraph TD\n    A[内存 Markdown 文件] --> B[提取规范内容]\n    B --> C[\"type\\nname\\ndescription\\nbody\"]\n    C --> D[SHA-256 哈希]\n    D --> E[64位十六进制字符串]\n    \n    F[图字段: relations/supersedes] -.->|不参与| C\n    \n    style F fill:#ffcccc\n```\n\n这种设计确保了：\n1. 图关系的修改不会触发嵌入重新计算\n2. 仅当核心内容变化时才需要重新嵌入\n3. 侧载文件与 Markdown 保持松耦合关系\n\n资料来源：[src/store/memory.ts:75-85]()\n\n## 二进制侧载文件格式\n\n### 文件命名\n\n每个内存文件 `<name>.md` 配对一个侧载文件 `<name>.embedding`，存放在同一目录下。\n\n### Wire Format 规范\n\n侧载文件采用小端序二进制格式，结构如下：\n\n```\n偏移   大小    字段\n0      4      magic        \"CMEM\" (ASCII)\n4      1      version      0x01\n5      1      model_len    model_id 的 UTF-8 字节长度\n6      L      model_id     UTF-8 字节\n6+L    4      dim          uint32 小端序\n10+L   32     content_sha  原始 sha256 (从十六进制解码)\n42+L   D*4    vector       float32 小端序值\n```\n\n**总大小** = 42 + model_len + dim × 4 字节\n\n对于 bge-base 模型（model_id: `Xenova/bge-base-en-v1.5`，dim: 768），每个侧载文件约 3 KB。\n\n资料来源：[src/store/sidecar.ts:1-50]()\n\n### 侧载文件结构图\n\n```mermaid\ngraph LR\n    subgraph \"Binary .embedding file\"\n        A[\"magic<br/>4 bytes<br/>CMEM\"] --> B[\"version<br/>1 byte<br/>0x01\"]\n        B --> C[\"model_len<br/>1 byte\"]\n        C --> D[\"model_id<br/>L bytes<br/>UTF-8\"]\n        D --> E[\"dim<br/>4 bytes<br/>uint32 LE\"]\n        E --> F[\"content_sha<br/>32 bytes<br/>raw sha256\"]\n        F --> G[\"vector<br/>dim×4 bytes<br/>float32 LE\"]\n    end\n```\n\n资料来源：[src/store/sidecar.ts:25-45]()\n\n## 内存存储操作\n\n### MemoryStore 架构\n\n```mermaid\ngraph TD\n    subgraph \"MemoryStore\"\n        A[\"#entries[]<br/>内存索引数组\"] --> B[\"scan()\"]\n        A --> C[\"linkEdge()\"]\n        A --> D[\"unlinkEdge()\"]\n        A --> E[\"search()\"]\n    end\n    \n    F[\"文件系统<br/>*.md + *.embedding\"] --> B\n    B --> G[\"生成嵌入<br/>创建侧载\"]\n    G --> F\n    \n    H[\"MemoryGraph<br/>内存图\"] --> C\n    H --> D\n    C -->|addEdge| H\n    D -->|removeEdge| H\n```\n\n资料来源：[src/store/memory-store.ts:1-100]()\n\n### 扫描与嵌入生成\n\n`scan()` 方法执行以下操作：\n\n1. 遍历目录中所有 `.md` 文件\n2. 对每个文件，检查对应的 `.embedding` 是否可复用\n3. 满足以下条件时复用现有侧载：\n   - `.embedding` 文件存在\n   - 解码通过（magic + version + length 检查）\n   - `decoded.modelId === embedder.modelId`\n   - `decoded.dim === embedder.dim`\n   - `decoded.contentSha === contentSha(memoryAsRead)`\n\n资料来源：[src/store/memory-store.ts:80-120]()\n\n### 孤儿侧载清理\n\n扫描完成后，`scan()` 会再次遍历目录，删除任何缺少对应 `.md` 文件的 `.embedding` 孤儿文件。这防止了孤立侧载文件在磁盘上无声积累。\n\n```mermaid\ngraph TD\n    A[\"扫描完成\"] --> B{\"存在孤儿子载文件?\"}\n    B -->|是| C{\"dryRun 模式?\"}\n    C -->|是| D[\"报告孤立数量<br/>不删除\"]\n    C -->|否| E[\"删除孤儿文件\"]\n    B -->|否| F[\"扫描完成\"]\n    D --> F\n    E --> F\n```\n\n资料来源：[src/store/memory-store.ts:120-140]()\n\n### 边链接操作\n\n#### linkEdge - 添加关系\n\n```typescript\npublic async linkEdge(args: {\n  from: string;\n  to: string;\n  type: RelationType | 'supersedes';\n}): Promise<{ relations: Relation[]; supersedes: string[] }>\n```\n\n流程：\n1. 验证源内存存在\n2. 检查是否重复边\n3. 更新内存对象\n4. 通过 `atomicWrite` 写入 `.md` 文件\n5. 更新内存图 `MemoryGraph`\n6. 刷新 mtime 基线\n\n资料来源：[src/store/memory-store.ts:150-200]()\n\n#### unlinkEdge - 移除关系\n\n```typescript\npublic async unlinkEdge(args: {\n  from: string;\n  to: string;\n  type?: RelationType | 'supersedes';\n}): Promise<{ relations: Relation[]; supersedes: string[]; note?: string }>\n```\n\n- 当 `type` 省略时，移除所有从 `from` 到 `to` 的边\n- 当边不存在时为静默操作，返回 `note` 说明原因\n- 涉及原子写入和图更新\n\n资料来源：[src/store/memory-store.ts:200-260]()\n\n## 内容变更检测与重新嵌入\n\n```mermaid\nsequenceDiagram\n    participant MD as Markdown 文件\n    participant SC as Sidecar 文件\n    participant SS as MemoryStore\n    participant EMB as Embedder\n\n    SS->>MD: 读取内容\n    SS->>MD: 计算 contentSha\n    SS->>SC: 读取 sidecar\n    SC->>SS: 返回 content_sha\n    Note over SS: contentSha === content_sha?\n    \n    alt 内容一致\n        SS->>SC: 复用现有侧载\n    else 内容变更\n        SS->>EMB: 请求嵌入\n        EMB->>SS: 返回向量\n        SS->>SC: 写入新侧载\n    end\n```\n\n## 迁移工具中的扫描操作\n\n`migrate` 命令支持对现有目录执行扫描：\n\n```bash\ncommonplace migrate <dir> [--dry-run] [--prune-dangling]\n```\n\n参数说明：\n\n| 参数 | 说明 |\n|------|------|\n| `dir` | 内存目录路径 |\n| `--dry-run` | 预览模式，不实际写入 |\n| `--prune-dangling` | 清理指向不存在内存的悬空边 |\n\n资料来源：[src/cli/migrate.ts:100-150]()\n\n## 数据完整性保证\n\n| 操作 | 原子性 | 锁机制 |\n|------|--------|--------|\n| 内存写入 | `atomicWrite` (临时文件+重命名) | `acquireNameLock` |\n| 边添加/移除 | 原子写入 | 名称锁 |\n| 扫描 | 非原子 | mtime 基线避免浪费性重扫描 |\n| 孤儿清理 | `fs.unlinkSync` | - |\n\n资料来源：[src/store/memory-store.ts:180-220]()\n\n## 命名验证规则\n\n内存名称必须满足以下正则表达式：\n\n```typescript\n/^[a-z0-9_]+$/\n```\n\n- 只能包含小写字母、数字和下划线\n- 不允许路径分隔符\n- 成为文件名主干\n\n此规则确保了文件系统兼容性和 URI 安全。\n\n资料来源：[src/store/memory.ts:20-40]()\n\n---\n\n<a id='page-search'></a>\n\n## 搜索功能详解\n\n### 相关页面\n\n相关主题：[嵌入模型与语义搜索](#page-embedder), [图功能与关系管理](#page-graph-features)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n</details>\n\n# 搜索功能详解\n\n## 概述\n\nCommonplace 的搜索功能是一个本地优先的语义搜索系统，基于余弦相似度（Cosine Similarity）算法实现完全离线的向量搜索。系统使用 `@huggingface/transformers` 库和 `bge-base-en-v1.5` 模型生成嵌入向量，支持对记忆进行语义匹配检索。\n\n搜索功能的核心设计原则是**记忆文件（`.md`）是唯一真相来源**，`.embedding` 侧边文件是从记忆内容派生的，可以随时删除和重建。\n\n## 核心架构\n\n### 搜索流程图\n\n```mermaid\ngraph TD\n    A[用户发起 memory_search] --> B[解析查询参数]\n    B --> C[生成查询向量]\n    C --> D[遍历所有记忆文件]\n    D --> E[加载 .embedding 侧边文件]\n    E --> F[计算余弦相似度]\n    F --> G[按分数排序取 Top-K]\n    G --> H[合并 User/Project 商店结果]\n    H --> I[排除已废弃记忆]\n    I --> J[丰富关系图数据]\n    J --> K[返回搜索结果]\n```\n\n### 关键组件\n\n| 组件 | 文件位置 | 职责 |\n|------|----------|------|\n| Embedder | `src/store/embedder.ts` | 负责将文本转换为 768 维向量 |\n| MemoryStore | `src/store/memory-store.ts` | 管理记忆存储、扫描和搜索 |\n| MemoryGraph | `src/store/graph.ts` | 维护记忆间的图关系 |\n| Mentions | `src/store/mentions.ts` | 提取正文中 `[[name]]` 引用 |\n\n## 嵌入向量生成\n\n### 嵌入模型\n\n系统使用 `bge-base-en-v1.5` 模型作为默认嵌入模型，该模型输出 768 维的向量表示。\n\n```mermaid\ngraph LR\n    A[记忆文本] --> B[contentSha 计算]\n    B --> C[模型推理]\n    C --> D[768维向量]\n    D --> E[.embedding 侧边文件]\n```\n\n### contentSha 计算\n\n为了检测记忆内容是否发生变化，系统为每个记忆计算 SHA-256 哈希值：\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${memory.description}\\n${memory.body}`, 'utf8')\n    .digest('hex');\n```\n\n**重要设计决策**：哈希值的计算范围仅包括 `type`、`name`、`description` 和 `body` 四个字段。**图字段（`relations` 和 `supersedes`）不参与哈希计算**，这确保了添加或删除图关系不会导致嵌入向量失效。\n\n资料来源：[src/store/memory.ts:47-51](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n### 惰性重新嵌入\n\n在保存记忆时，如果 `contentSha` 与侧边文件中存储的哈希值不匹配，系统会自动触发重新嵌入：\n\n```typescript\nconst needsReembed =\n  isMissing || stale.embedding.corrupt || stale.embedding.contentShaMismatch;\n```\n\n这确保了搜索结果始终与最新的记忆内容同步。\n\n## 记忆文件结构\n\n### Markdown 格式\n\n记忆以 Markdown 文件形式存储，包含 YAML 前置数据：\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: other_name\n    type: builds-on\nsupersedes:\n  - old_name\n---\n<正文内容>\n```\n\n资料来源：[src/store/memory.ts:30-46](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n### 记忆类型\n\n| 类型 | 说明 | 适用场景 |\n|------|------|----------|\n| `user` | 个人规则和偏好 | 跨项目的通用知识 |\n| `feedback` | 纠正和经验教训 | 持久的行为调整 |\n| `project` | 项目特定上下文 | 架构笔记、代码规范 |\n| `reference` | 持久知识 | API 形状、公式、引用 |\n\n资料来源：[README.md](https://github.com/rickassham/commonplace/blob/main/README.md)\n\n## 搜索 API\n\n### memory_search 工具\n\n搜索工具是最常用的查询接口，支持以下参数：\n\n| 参数 | 类型 | 必填 | 说明 |\n|------|------|------|------|\n| `query` | string | 是 | 搜索查询文本 |\n| `type` | string | 否 | 过滤特定记忆类型 |\n| `limit` | number | 否 | 返回结果数量上限 |\n| `scope` | `user \\| project` | 否 | 指定搜索范围 |\n| `expandTypes` | string[] | 否 | 展开的边类型 |\n| `includeSuperseded` | boolean | 否 | 是否包含已废弃记忆 |\n\n### 搜索响应结构\n\n```typescript\nexport interface MemorySearchResult {\n  matches: MemorySearchMatch[];\n  query: string;\n}\n\nexport interface MemorySearchMatch {\n  name: string;\n  type: MemoryType;\n  description: string;\n  body: string;\n  score: number;  // 余弦相似度，保留3位小数\n  relations: Relation[];\n}\n```\n\n**重要约束**：根据设计规范，body 字段**永远不会被截断、摘要或转换**，调用者获得完全原始的存储内容。\n\n资料来源：[src/server/handlers.ts:35-56](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n\n## 搜索范围与合并\n\n### 双商店架构\n\nCommonplace 支持同时加载两个记忆商店：\n\n```mermaid\ngraph TD\n    A[memory_search 请求] --> B{是否指定 scope?}\n    B -->|是| C[仅搜索指定商店]\n    B -->|否| D[并行搜索两个商店]\n    C --> E[返回结果]\n    D --> F[User Store 搜索]\n    D --> G[Project Store 搜索]\n    F --> H[按分数合并排序]\n    G --> H\n    H --> I[返回合并结果]\n```\n\n### 商店位置\n\n| 商店类型 | 默认路径 | 说明 |\n|----------|----------|------|\n| User Store | `~/.commonplace/memory` | 始终加载 |\n| Project Store | `<project-root>/.commonplace/memory` | 仅在检测到项目根目录时加载 |\n\n### 检测优先级\n\n项目商店的位置按以下优先级确定：\n\n1. `COMMONPLACE_PROJECT_DIR` 环境变量（最高优先级）\n2. MCP `roots/list` 返回的项目根目录\n3. 当前工作目录\n\n## 关系图扩展\n\n### 边类型\n\n搜索结果可以包含记忆之间的关系信息，支持以下边类型：\n\n| 边类型 | 说明 | 默认展开 |\n|--------|------|----------|\n| `builds-on` | 建立于其他记忆之上 | ✓ |\n| `related-to` | 相关关系 | ✓ |\n| `mentions` | 正文中引用 | ✗ |\n| `supersedes` | 废弃替代 | ✗ |\n| `contradicts` | 矛盾关系 | ✗ |\n| `child-of` | 父子关系 | ✗ |\n\n**默认展开类型**：`builds-on` 和 `related-to` 是最可能产生有用邻居的边类型，因此默认展开。\n\n资料来源：[src/server/handlers.ts:19-25](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n\n### 废弃记忆排除\n\n默认情况下，搜索结果会排除已被废弃的记忆。通过 `supersedes` 字段，系统自动识别并过滤：\n\n```typescript\n// memory_path 工具的默认行为\nif (!includeSuperseded) {\n  results = results.filter((m) => !supersededNames.has(m.name));\n}\n```\n\n## 提及提取功能\n\n### [[name]] 语法\n\n系统支持从记忆正文中提取 `[[name]]` 格式的提及，生成隐式的关系边：\n\n```mermaid\ngraph TD\n    A[记忆正文] --> B[正则匹配 [[name]]\n    B --> C{匹配成功?}\n    C -->|是| D[提取 name]\n    C -->|否| E[跳过]\n    D --> F[调用 graph.addMentionsEdge]\n    E --> G[继续处理]\n```\n\n### 启用控制\n\n提及提取功能通过环境变量控制：\n\n- **默认状态**：启用\n- **禁用方式**：设置 `COMMONPLACE_EXTRACT_MENTIONS=false`\n\n```typescript\n// 提取受环境变量 COMMONPLACE_EXTRACT_MENTIONS 控制\nconst enabled = mentionsExtractionEnabled();\nif (enabled) {\n  const mentions = extractMentions(body);\n  for (const name of mentions) {\n    this.#graph.addMentionsEdge({ from: name, to });\n  }\n}\n```\n\n资料来源：[src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n\n## 搜索性能特性\n\n### 暴力搜索算法\n\n系统采用暴力搜索（Brute-Force）算法计算余弦相似度：\n\n```typescript\n// 伪代码示意\nfor (const memory of allMemories) {\n  const embedding = loadEmbedding(memory.embeddingPath);\n  const score = cosineSimilarity(queryEmbedding, embedding);\n  results.push({ memory, score });\n}\nreturn results.sort((a, b) => b.score - a.score).slice(0, limit);\n```\n\n### 目录扫描优化\n\nMemoryStore 维护目录修改时间基线，避免不必要的重新扫描：\n\n```typescript\n// 刷新 mtime 基线以避免浪费性重新扫描\nthis.#refreshMtimeBaseline();\n```\n\n### 原子写入保证\n\n文件写入使用原子写入模式，防止并发操作导致数据损坏：\n\n```typescript\n// 临时文件 + rename 确保写入原子性\nconst tmpName = `${base}.${randomBytes(8).toString('hex')}.tmp`;\nconst tmpPath = join(dir, tmpName);\n// ... 写入临时文件 ...\nawait fs.rename(tmpPath, target);\n```\n\n## MCP 工具注册\n\n搜索功能通过 MCP（Model Context Protocol）协议暴露给 AI 代理：\n\n```mermaid\ngraph LR\n    A[AI 代理] -->|MCP 调用| B[mcp__commonplace__memory_search]\n    B --> C[handlers.ts 分发]\n    C --> D[MemoryStore.search]\n    D --> E[返回 MemorySearchResult]\n    E --> F[AI 代理]\n```\n\n## 搜索与记忆生命周期\n\n```mermaid\ngraph LR\n    A[memory_save] --> B[写入 .md]\n    B --> C[计算 contentSha]\n    C --> D[生成嵌入向量]\n    D --> E[写入 .embedding]\n    E --> F[scan 更新索引]\n    F --> G[提取 mentions]\n    G --> H[更新关系图]\n    \n    I[memory_search] --> J[查询向量]\n    J --> K[遍历 .embedding]\n    K --> L[计算余弦相似度]\n    L --> M[合并排序结果]\n    M --> N[丰富关系数据]\n    N --> O[返回结果]\n```\n\n## 相关命令\n\n| 命令 | 说明 |\n|------|------|\n| `commonplace migrate <dir>` | 扫描并嵌入目录中的所有记忆 |\n| `commonplace migrate --from claude-code` | 从 Claude Code 导入记忆 |\n| `mcp__commonplace__memory_search` | MCP 搜索接口 |\n\n## 配置参考\n\n### 环境变量\n\n| 变量 | 默认值 | 说明 |\n|------|--------|------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | 用户记忆目录 |\n| `COMMONPLACE_PROJECT_DIR` | - | 项目记忆目录（覆盖检测） |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `true` | 启用提及提取 |\n\n### CLI 选项\n\n| 选项 | 说明 |\n|------|------|\n| `--dry-run` | 预览操作不写入文件 |\n| `--auto` | 脚本化自动运行 |\n| `--prune-dangling` | 清理悬空引用 |\n\n## 版本历史\n\n| 版本 | 日期 | 搜索相关特性 |\n|------|------|--------------|\n| 0.1.0 | 2026-05-10 | 初始发布：基础搜索、向量嵌入、图关系 |\n\n资料来源：[CHANGELOG.md](https://github.com/rickbassham/commonplace/blob/main/CHANGELOG.md)\n\n---\n\n<a id='page-graph-features'></a>\n\n## 图功能与关系管理\n\n### 相关页面\n\n相关主题：[搜索功能详解](#page-search), [内存格式与侧载文件](#page-memory-format)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/store/graph.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/graph.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n- [src/cli/graph.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/graph.ts)\n</details>\n\n# 图功能与关系管理\n\n## 概述\n\n图功能与关系管理是 Commonplace 项目中用于管理记忆（Memory）之间语义关联的核心模块。该模块基于 YAML frontmatter 中的 `relations` 和 `supersedes` 字段构建内存图，并支持从正文中提取 `[[name]]` 形式的提及关系。通过这些机制，用户可以构建记忆之间的有向图，实现知识关联、一跳扩展搜索等功能。\n\n该功能主要服务于以下场景：\n\n- 显式声明记忆之间的关系（如\"此记忆建立在另一个记忆之上\"）\n- 自动检测正文中的提及关系\n- 悬空边检测与清理\n- 图可视化与路径查询\n\n资料来源：[src/store/graph.ts:1-20]()\n\n## 数据模型\n\n### 边的类型\n\n图模块定义了六种边类型，分为两类：\n\n**授权边类型（Authored Relation Types）**\n\n| 边类型 | 说明 |\n|--------|------|\n| `related-to` | 相关关系 |\n| `builds-on` | 建立关系（继承/基于） |\n| `contradicts` | 矛盾关系 |\n| `child-of` | 子级关系 |\n\n**派生边类型（Derived Edge Types）**\n\n| 边类型 | 来源 |\n|--------|------|\n| `supersedes` | 来自 frontmatter 的 `supersedes[]` 字段 |\n| `mentions` | 来自正文 `[[name]]` 提取（DAR-927） |\n\n资料来源：[src/store/graph.ts:19-22]()\n\n```typescript\nexport type EdgeType = RelationType | 'supersedes' | 'mentions';\n```\n\n### 边接口\n\n```typescript\nexport interface Edge {\n  from: string;    // 源记忆名称\n  to: string;      // 目标记忆名称\n  type: EdgeType;  // 边类型\n}\n```\n\n### 悬空边接口\n\n当边指向的目标记忆不存在时，该边称为悬空边（Dangling Edge）：\n\n```typescript\nexport interface DanglingEdge {\n  from: string;\n  to: string;\n  type: string;  // 类型被放宽为 string，允许扩展\n}\n```\n\n资料来源：[src/store/graph.ts:24-44]()\n\n### 记忆前端matter关系字段\n\n每个记忆的 YAML frontmatter 可包含以下图字段：\n\n```yaml\n---\nname: feedback_scope\ntype: feedback\nrelations:        # DAR-925，可选，默认 []\n  - to: other_name\n    type: builds-on\nsupersedes:      # DAR-925，可选，默认 []\n  - old_name\n---\n```\n\n资料来源：[src/store/memory.ts:7-23]()\n\n### 关系解析验证\n\n`relations` 字段中的每条记录必须包含 `to` 和 `type` 两个必填键：\n\n```typescript\nconst parseRelation = (entry: unknown, ctx: string): Relation => {\n  if (!isPlainObject(entry)) {\n    throw new Error(`${ctx} must be a mapping with \\`to\\` and \\`type\\``);\n  }\n  if (!('to' in entry)) {\n    throw new Error(`${ctx} is missing required key \\`to\\``);\n  }\n  if (!('type' in entry)) {\n    throw new Error(`${ctx} is missing required key \\`type\\``);\n  }\n  const to = validateName(entry.to, `${ctx}.to`);\n  const type = entry.type;\n  if (!isRelationType(type)) {\n    throw new Error(`${ctx}.type must be one of ${RELATION_TYPES.join(', ')}`);\n  }\n  return { to, type };\n};\n```\n\n资料来源：[src/store/memory.ts:82-102]()\n\n### 内容哈希与图字段独立性\n\n内容 SHA256 仅基于 v0.1 基线字段计算：`type`、`name`、`description` 和 `body`。图字段（`relations`、`supersedes`）**不参与**哈希计算，这意味着添加或删除图边不会使对应的 embedding 失效。\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${memory.description}\\n${body}`, 'utf8')\n    .digest('hex');\n```\n\n资料来源：[src/store/memory.ts:48-55]()\n\n## 提及提取（DAR-927）\n\n### 概述\n\n`[[name]]` 提及提取器负责从记忆正文中解析所有提及的目标名称，返回去重后的集合，保持首次出现顺序。\n\n### 提取规则\n\n- 仅接受符合 `^[a-z0-9_]+$` 规则的名称（与记忆文件名命名规则一致）\n- 不符合规则的 `[[...]]` 形式会被静默忽略\n- 代码块和行内代码中的提及**不会**被特殊处理（按需求说明 #1 排除）\n\n资料来源：[src/store/mentions.ts:1-30]()\n\n### 配置\n\n提及提取由环境变量 `COMMONPLACE_EXTRACT_MENTIONS` 控制：\n\n| 值 | 行为 |\n|----|------|\n| 未设置 / `'true'` | 启用提取 |\n| `'false'` | 禁用提取 |\n\n资料来源：[src/store/mentions.ts:16-20]()\n\n### 工作流程\n\n```mermaid\ngraph TD\n    A[记忆正文] --> B{提取开关}\n    B -->|启用| C[正则匹配 [[...]]]\n    B -->|禁用| D[返回空集]\n    C --> E[提取内容]\n    E --> F{符合 NAME_PATTERN?}\n    F -->|是| G[加入结果集]\n    F -->|否| H[忽略]\n    G --> I[去重并排序]\n    H --> I\n    I --> J[返回唯一名称列表]\n    D --> J\n```\n\n## MemoryStore 关系管理\n\n### 添加关系\n\n`linkEdge` 方法用于向记忆添加新的关系边：\n\n```typescript\npublic async linkEdge(args: {\n  from: string;\n  to: string;\n  type: RelationType | 'supersedes';\n}): Promise<Memory>\n```\n\n**行为说明：**\n\n1. 验证源记忆存在\n2. 检查重复边（相同 `from`、`to`、`type` 的边已存在则报错）\n3. 更新 `relations[]` 或 `supersedes[]` 数组\n4. 通过 `atomicWrite` 原子写入 `.md` 文件\n5. 更新内存中的 entry\n6. 同步更新 `MemoryGraph`\n\n**处理逻辑：**\n\n```typescript\nconst nextRelations: Relation[] =\n  type === 'supersedes' ? entry.relations.slice() : [...entry.relations, { to, type }];\nconst nextSupersedes: string[] =\n  type === 'supersedes' ? [...entry.supersedes, to] : entry.supersedes.slice();\n```\n\n资料来源：[src/store/memory-store.ts:1-100]()\n\n### 移除关系\n\n`unlinkEdge` 方法用于移除关系边：\n\n```typescript\npublic async unlinkEdge(args: {\n  from: string;\n  to: string;\n  type?: RelationType | 'supersedes';  // 可选，不指定则移除所有类型\n}): Promise<{ relations: Relation[]; supersedes: string[]; note?: string }>\n```\n\n**行为说明：**\n\n- 当 `type` 指定时，仅移除匹配的边\n- 当 `type` 省略时，移除所有从 `from` 到 `to` 的边（无论类型）\n- 边不存在时为静默操作，返回 `note` 说明原因\n\n资料来源：[src/store/memory-store.ts:150-200]()\n\n### 原子写入保证\n\n所有图修改通过 `atomicWrite` 确保一致性：\n\n```typescript\nconst mdPath = join(this.#dir, `${from}.md`);\nconst release = await acquireNameLock(this.#dir, from);\ntry {\n  const mdBytes = Buffer.from(serializeMemory(updated), 'utf8');\n  await atomicWrite(mdPath, mdBytes);\n  // 更新内存索引...\n} finally {\n  release();\n}\n```\n\n## MCP 工具接口\n\n### memory_link\n\n建立记忆之间的边：\n\n```jsonc\n// memory_link\n{\n  \"from\": \"architecture_overview\",\n  \"to\": \"feedback_scope\",\n  \"type\": \"builds-on\"\n}\n```\n\n| 参数 | 类型 | 必填 | 说明 |\n|------|------|------|------|\n| `from` | string | 是 | 源记忆名称 |\n| `to` | string | 是 | 目标记忆名称 |\n| `type` | 边类型 | 是 | 关系类型 |\n| `scope` | `user\\|project` | 否 | 作用域 |\n\n### memory_unlink\n\n移除记忆之间的边：\n\n```jsonc\n// memory_unlink\n{\n  \"from\": \"architecture_overview\",\n  \"to\": \"feedback_scope\",\n  \"type\": \"builds-on\"  // 可选，忽略则移除所有类型\n}\n```\n\n资料来源：[src/server/handlers.ts:1-50]()\n\n### 搜索中的一跳扩展\n\n`memory_search` 工具支持 `expand: 'one-hop'` 参数，从直接命中出发扩展邻居节点：\n\n| 参数 | 默认值 | 说明 |\n|------|--------|------|\n| `expand` | `'none'` | 扩展模式：`none` 或 `one-hop` |\n| `expandTypes` | `['builds-on', 'related-to']` | 允许的边类型 |\n| `expandLimit` | `2` | 每个直接命中的最大邻居数 |\n\n```jsonc\n// 带一跳扩展的搜索\n{\n  \"query\": \"architecture\",\n  \"expand\": \"one-hop\",\n  \"expandTypes\": [\"builds-on\", \"related-to\", \"mentions\"],\n  \"expandLimit\": 3\n}\n```\n\n扩展条目携带 `via` 字段标识来源：\n\n```jsonc\n{\n  \"name\": \"neighbor_name\",\n  \"via\": {\n    \"source\": \"direct_hit_name\",\n    \"edge\": \"builds-on\"\n  }\n}\n```\n\n资料来源：[src/server/handlers.ts:60-90]()\n\n### 默认扩展类型\n\n默认仅扩展 `builds-on` 和 `related-to`，因为这两种边类型最可能产生有用的邻居。其他类型（`mentions`、`supersedes`、`contradicts`、`child-of`）需要显式 opt-in。\n\n```typescript\nexport const DEFAULT_EXPAND_TYPES: readonly EdgeType[] = ['builds-on', 'related-to'] as const;\n```\n\n资料来源：[src/server/handlers.ts:52-55]()\n\n## CLI 命令行工具\n\n### graph 子命令\n\n`commonplace graph` 命令用于可视化图结构：\n\n```bash\ncommonplace graph <name> [options]\n```\n\n| 选项 | 默认值 | 说明 |\n|------|--------|------|\n| `--depth, -d` | `1` | 遍历深度 |\n| `--types, -t` | 全部 | 逗号分隔的边类型过滤 |\n| `--direction` | `outbound` | `outbound`、`inbound` 或 `both` |\n| `--format, -f` | `mermaid` | 输出格式：`mermaid`、`json`、`dot` |\n| `--scope, -s` | 自动 | `user`、`project` 或 `both` |\n\n### 输出格式\n\n**Mermaid 格式（默认）：**\n\n````markdown\n```mermaid\nflowchart LR\n    A[architecture_overview] -->|builds-on| B[feedback_scope]\n```\n````\n\n**JSON 格式：**\n\n```json\n{\n  \"root\": \"architecture_overview\",\n  \"nodes\": [...],\n  \"edges\": [...]\n}\n```\n\n**DOT 格式：** 用于 Graphviz 工具链处理大规模图。\n\n资料来源：[src/cli/graph.ts:1-40]()\n\n### 实现细节\n\nCLI 使用与 MCP `memory_graph` 工具相同的遍历辅助函数，因此图遍历行为、循环处理、深度/类型过滤完全一致：\n\n```typescript\nconst result = await graphMain({\n  argv,\n  embedderFactory: () => new Embedder(resolveModelId(process.env)),\n  stdout: (chunk: string) => process.stdout.write(chunk),\n  stderr: (chunk: string) => process.stderr.write(chunk),\n  env: process.env,\n  cwd: process.cwd(),\n});\n```\n\n资料来源：[src/index.ts:50-65]()\n\n## 存储层架构\n\n### 双存储模式\n\nCommonplace 支持同时加载两个记忆存储：\n\n```mermaid\ngraph LR\n    subgraph 用户存储\n        U[User Memory Store]\n    end\n    subgraph 项目存储\n        P[Project Memory Store]\n    end\n    G[MemoryGraph] --- U\n    G[MemoryGraph] --- P\n```\n\n- **用户存储**：始终加载，位于 `~/.commonplace/memory`\n- **项目存储**：仅在检测到项目根目录时加载\n\n每个存储维护独立的 `#entries` 数组和 `MemoryGraph` 实例。\n\n资料来源：[src/store/memory-store.ts:1-30]()\n\n### 目录扫描与图构建\n\n在 `scan()` 和 `save()` 过程中，`MemoryStore` 调用 `extractMentions` 提取正文提及，并将其转发给 `MemoryGraph.addMentionsEdge`：\n\n```typescript\n// 伪代码示意\nfor (const memory of memories) {\n  const mentions = extractMentions(memory.body);\n  for (const name of mentions) {\n    this.#graph.addMentionsEdge({ from: memory.name, to: name });\n  }\n}\n```\n\n## 功能边界\n\n以下功能明确不在当前实现范围内：\n\n| 功能 | 负责人 |\n|------|--------|\n| 验证引用的记忆名称是否存在于磁盘（DAR-926） | 待实现 |\n| 构建内存邻接表/图（DAR-926） | 待实现 |\n| Wiki 风格反向链接渲染/自动补全 | 排除范围 |\n| 代码块/行内代码中的提及感知 | 排除范围 |\n| MCP 工具响应中的提及展示（DAR-929/DAR-932） | 待实现 |\n| 中心性/PageRank 计算（DAR-931） | 待实现 |\n| 遍历/路径查询（DAR-932） | 待实现 |\n\n资料来源：[src/store/graph.ts:6-15]()\n\n## 迁移与清理\n\n### migrate 命令的图清理\n\n`commonplace migrate` 命令在导入文件时会检测并清理悬空边：\n\n```\n  pruned:       5 dangling edges across 2 files (would be removed)\n    memory_a: 3\n    memory_b: 2\n```\n\n悬空边指向前端 matter 中声明但不存在于磁盘的目标记忆。\n\n资料来源：[src/cli/migrate.ts:1-30]()\n\n### 悬空边检测\n\n图模块暴露 `DanglingEdge` 接口用于悬空边报告：\n\n```typescript\nexport interface DanglingEdge {\n  from: string;\n  to: string;\n  type: string;\n}\n```\n\n返回时 `type` 被放宽为 `string`，以便未来支持扩展边类型。\n\n---\n\n<a id='page-storage'></a>\n\n## 存储系统\n\n### 相关页面\n\n相关主题：[内存格式与侧载文件](#page-memory-format), [作用域与多存储](#page-scopes)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.ts)\n- [src/store/graph.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/graph.ts)\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n</details>\n\n# 存储系统\n\n## 概述\n\n存储系统是 Commonplace 项目的核心模块，负责将记忆（Memory）以 Markdown 文件形式持久化到本地磁盘，同时管理向量嵌入（Embedding）sidecar 文件、图关系以及内存索引。该系统采用本地优先（Local-First）架构，所有数据存储在用户本地目录，无需云端依赖，实现了完全的离线语义搜索能力。\n\n存储系统的设计目标包括：\n\n- **文件即存储**：每个记忆是一个独立的 `.md` 文件，YAML frontmatter 存储元数据\n- **嵌入派生**：`.embedding` sidecar 文件由 `.md` 内容派生，可随时重建\n- **原子操作**：通过 temp file + rename 模式保证写操作的原子性\n- **图关系管理**：支持记忆之间的多种关系类型（builds-on、related-to 等）\n- **作用域隔离**：支持 `user` 和 `project` 两种存储作用域\n\n资料来源：[src/store/memory-store.ts:1-50]()\n\n## 架构概览\n\n```mermaid\ngraph TB\n    subgraph \"存储层 (Disk)\"\n        MD[\".md 文件<br/>YAML Frontmatter + Body\"]\n        EMB[\".embedding 文件<br/>Binary Sidecar\"]\n    end\n    \n    subgraph \"内存索引 (In-Memory)\"\n        IDX[\"#entries[]<br/>MemoryEntry 数组\"]\n        GRAPH[\"#graph<br/>MemoryGraph\"]\n    end\n    \n    subgraph \"核心模块\"\n        MS[\"MemoryStore<br/>主存储类\"]\n        AW[\"atomicWrite<br/>原子写入工具\"]\n        MEM[\"memory.ts<br/>序列化/反序列化\"]\n        MENT[\"mentions.ts<br/>提及提取器\"]\n    end\n    \n    MD --> MS\n    EMB --> MS\n    MS --> IDX\n    MS --> GRAPH\n    MS --> AW\n    MS --> MEM\n    MS --> MENT\n```\n\n## 核心组件\n\n### MemoryStore\n\n`MemoryStore` 是存储系统的主类，负责管理特定目录下的所有记忆文件。它维护两个核心内部状态：\n\n- `#entries: MemoryEntry[]` — 从磁盘扫描加载的内存索引\n- `#graph: MemoryGraph | undefined` — 可选的内存图结构\n\n资料来源：[src/store/memory-store.ts:80-85]()\n\n#### 关键方法\n\n| 方法 | 用途 |\n|------|------|\n| `save()` | 创建新记忆，写入 `.md` 和 `.embedding` |\n| `list()` | 返回所有记忆的摘要信息 |\n| `get()` | 获取单个记忆的完整内容 |\n| `delete()` | 删除记忆文件和关联的 embedding |\n| `search()` | 基于向量相似度的语义搜索 |\n| `linkEdge()` | 添加记忆间的关系边 |\n| `unlinkEdge()` | 移除记忆间的关系边 |\n| `scan()` | 重新扫描目录，更新内存索引 |\n\n资料来源：[src/store/memory-store.ts:200-450]()\n\n### Atomic Write\n\n`atomicWrite` 模块提供基于 temp file + rename 的原子写入模式，确保在写入过程中发生崩溃或断电时不会产生部分写入的损坏文件。\n\n```mermaid\nsequenceDiagram\n    participant Caller\n    participant AW as atomicWrite\n    participant FS as FileSystem\n    \n    Caller->>AW: atomicWrite(target, data)\n    AW->>AW: 生成随机 tmp 文件名<br/>base.16hexchars.tmp\n    AW->>FS: 写入 tmp 文件\n    AW->>FS: rename(tmp, target)\n    Note over FS: rename(2) 原子操作\n    AW->>Caller: 完成\n```\n\n#### 安全特性\n\n- **跨文件系统防护**：通过比较源目录和临时文件目录的 `dev` 设备号，拒绝跨文件系统重命名\n- **足够熵值**：使用 8 字节（16 十六进制字符）随机数生成临时文件名，避免并发写入冲突\n- **同目录原则**：临时文件与目标文件位于同一目录，确保 rename 操作在同一文件系统内\n\n资料来源：[src/store/atomic-write.ts:1-40]()\n\n### Memory 数据模型\n\n每个记忆由一个 Markdown 文件表示，结构如下：\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: other_name\n    type: builds-on\nsupersedes:\n  - old_name\n---\n<body>\n```\n\n#### 字段说明\n\n| 字段 | 类型 | 必需 | 说明 |\n|------|------|------|------|\n| `name` | string | 是 | 记忆名称，需匹配 `^[a-z0-9_]+$` |\n| `description` | string | 是 | 简短描述，用于搜索结果展示 |\n| `type` | MemoryType | 是 | 记忆类型：`user` \\| `feedback` \\| `project` \\| `reference` |\n| `relations` | Relation[] | 否 | 关系列表，默认空数组 |\n| `supersedes` | string[] | 否 | 被替代的记忆名称列表 |\n\n资料来源：[src/store/memory.ts:1-60]()\n\n### 记忆类型 (MemoryType)\n\n```mermaid\ngraph LR\n    A[MemoryType] --> B[\"user<br/>用户偏好规则\"]\n    A --> C[\"feedback<br/>反馈纠正\"]\n    A --> D[\"project<br/>项目上下文\"]\n    A --> E[\"reference<br/>参考知识\"]\n```\n\n| 类型 | 用途 | 使用场景 |\n|------|------|----------|\n| `user` | 个人规则、偏好、身份信息 | 跨项目适用的用户特征 |\n| `feedback` | 纠正和经验教训 | 对 agent 行为的持久修正 |\n| `project` | 项目特定上下文 | 架构笔记、代码规范、特定决策 |\n| `reference` | 持久性中性知识 | API 形状、公式、引用资料 |\n\n资料来源：[README.md:1-50]()\n\n## 图关系系统\n\n### 边类型 (RelationType)\n\n| 类型 | 说明 | 行为 |\n|------|------|------|\n| `builds-on` | 建立在另一个记忆之上 | 加入 `relations[]` |\n| `related-to` | 与另一个记忆相关 | 加入 `relations[]` |\n| `contradicts` | 与另一个记忆矛盾 | 加入 `relations[]` |\n| `child-of` | 是另一个记忆的子项 | 加入 `relations[]` |\n| `supersedes` | 替代另一个记忆 | 加入 `supersedes[]` |\n\n资料来源：[src/store/memory-store.ts:150-200]()\n\n### 关系写入流程\n\n```mermaid\ngraph TD\n    START[linkEdge from, to, type] --> CHECK{from === to?}\n    CHECK -->|是| ERR1[抛出错误:<br/>禁止自环]\n    CHECK -->|否| LOAD[从内存索引加载 from 条目]\n    LOAD --> EXISTS{to 条目存在?}\n    EXISTS -->|否| ERR2[抛出错误:<br/>目标记忆不存在]\n    EXISTS -->|是| DUPE{重复边?}\n    DUPE -->|是| ERR3[抛出错误:<br/>边已存在]\n    DUPE -->|否| BUILD[构建更新后的 Memory]\n    BUILD --> LOCK[acquireNameLock 获取锁]\n    LOCK --> WRITE[atomicWrite 写入 .md]\n    WRITE --> MUTATE[原地更新内存条目]\n    MUTATE --> GRAPH{有 #graph?}\n    GRAPH -->|是| ADD[graph.addEdge]\n    GRAPH -->|否| REFRESH[刷新 mtime 基线]\n    ADD --> REFRESH\n    REFRESH --> DONE[返回新 relations/supersedes]\n```\n\n资料来源：[src/store/memory-store.ts:280-350]()\n\n## 扫描与嵌入\n\n### Scan 流程\n\n`scan()` 方法执行完整的目录重新扫描：\n\n1. 遍历目录中所有 `.md` 文件\n2. 解析每个文件的 YAML frontmatter\n3. 检查对应的 `.embedding` sidecar 是否可复用\n4. 不可用时触发重新嵌入\n5. 清理孤立的 embedding 文件\n\n```mermaid\nflowchart TD\n    START[scan] --> SCAN[扫描目录 *.md]\n    SCAN --> LOOP{遍历每个 .md}\n    LOOP -->|有文件| READ[读取 .md]\n    READ --> PARSE[解析 frontmatter]\n    PARSE --> CHECK{sidecar 存在?}\n    CHECK -->|否| EMBED[重新嵌入]\n    CHECK -->|是| VALIDATE[验证 sidecar]\n    VALIDATE -->|有效| REUSE[复用 sidecar]\n    VALIDATE -->|无效| EMBED\n    REUSE --> NEXT[下一个文件]\n    EMBED --> WRITE[写入新 .embedding]\n    WRITE --> NEXT\n    LOOP -->|完成| ORPHAN[清理孤立 sidecar]\n    ORPHAN --> DONE[返回 ScanResult]\n```\n\n#### Sidecar 复用条件\n\n一个 `.embedding` sidecar 被认为是\"新鲜\"的，当且仅当：\n\n| 条件 | 说明 |\n|------|------|\n| 文件存在 | sidecar 文件存在 |\n| 解码有效 | magic + version + length 检查通过 |\n| 模型匹配 | `decoded.modelId === embedder.modelId` |\n| 维度匹配 | `decoded.dim === embedder.dim` |\n| SHA 匹配 | `decoded.contentSha === contentSha(memoryAsRead)` |\n\n资料来源：[src/store/memory-store.ts:400-450]()\n\n### Content SHA\n\nContent SHA 用于验证记忆内容是否发生变化，进而决定是否需要重新嵌入。计算范围仅限于 v0.1 基线 frontmatter：\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${memory.description}\\n${memory.body}`, 'utf8')\n    .digest('hex');\n```\n\n**重要**：`relations` 和 `supersedes` 图字段不参与 SHA 计算。这意味着添加或删除图关系不会使 embedding 失效。\n\n资料来源：[src/store/memory.ts:80-95]()\n\n## 搜索功能\n\n### 搜索流程\n\n```mermaid\ngraph TD\n    START[search query] --> RESCAN{需要 rescan?}\n    RESCAN -->|是| SCAN[调用 scan]\n    RESCAN -->|否| EMBED[嵌入查询文本]\n    SCAN --> EMBED\n    EMBED --> SIM[计算余弦相似度]\n    SIM --> FILTER[过滤已删除记忆]\n    FILTER --> RANK[按得分排序]\n    RANK --> EXPAND[expandRelations 扩展邻居]\n    EXPAND --> RESULT[返回结果信封]\n```\n\n### 搜索结果结构\n\n```typescript\ninterface MemorySearchResult {\n  query: string;           // 原始查询\n  memories: MemorySearchMatch[];  // 匹配结果\n  expanded: boolean;       // 是否包含扩展关系\n}\n```\n\n资料来源：[src/store/handlers.ts:50-80]()\n\n## 并发与锁定\n\n### Per-Name 锁定机制\n\n为防止并发写入同一记忆名称导致的竞态条件，系统实现了 `acquireNameLock` 机制：\n\n- 锁定粒度：每个记忆名称独立锁\n- 锁文件位置：`.locks/<name>.lock`\n- 超时回收：超过 5 秒的过期锁自动回收\n- 锁范围：覆盖 `.md` 和 `.embedding` 的完整写入过程\n\n资料来源：[src/store/memory-store.ts:500-550]()\n\n### 原子写入序列\n\n```mermaid\nsequenceDiagram\n    participant Store\n    participant Lock\n    participant AW as atomicWrite\n    participant FS\n    \n    Store->>Lock: acquireNameLock(name)\n    Lock-->>Store: release function\n    \n    Store->>AW: atomicWrite(mdPath, mdBytes)\n    AW->>FS: writeFile(tmpPath)\n    AW->>FS: rename(tmpPath, mdPath)\n    \n    Store->>AW: atomicWrite(embPath, embBytes)\n    AW->>FS: writeFile(tmpPath)\n    AW->>FS: rename(tmpPath, embPath)\n    \n    Store->>Lock: release()\n```\n\n## 作用域系统\n\n存储系统支持两种作用域（Scope），实现项目级别和用户级别的记忆隔离：\n\n```mermaid\ngraph LR\n    subgraph \"user scope\"\n        UD[~/.commonplace/]\n    end\n    subgraph \"project scope\"\n        PD[<project>/.commonplace/]\n    end\n    \n    UD --> UA[user/*.md]\n    UD --> UE[user/*.embedding]\n    PD --> PA[project/*.md]\n    PD --> PE[project/*.embedding]\n```\n\n| 作用域 | 存储路径 | 用途 |\n|--------|----------|------|\n| `user` | `~/.commonplace/` | 跨项目适用的规则、偏好 |\n| `project` | `<project>/.commonplace/` | 仅当前项目有效的上下文 |\n\n资料来源：[src/store/memory-store.ts:90-120]()\n\n## 提及提取器\n\n`mentions.ts` 模块负责从记忆正文中提取 `[[name]]` 格式的提及：\n\n- 仅识别匹配 `^[a-z0-9_]+$` 的名称\n- 返回唯一集合，按首次出现顺序排列\n- 可通过 `COMMONPLACE_EXTRACT_MENTIONS=false` 环境变量禁用\n- 在 `scan()` 和 `save()` 时自动调用\n- 提取的提及会添加到内存图的 `mentions` 边\n\n资料来源：[src/store/mentions.ts:1-50]()\n\n## 关键设计决策\n\n### 为什么不使用数据库\n\n- **简单性**：文件系统是最终的持久化介质，无需额外依赖\n- **可移植性**：记忆文件可独立使用任意文本编辑器查看和编辑\n- **可重建**：所有派生数据（embedding）可从 `.md` 重新生成\n- **版本控制**：可直接将 `.md` 文件纳入 Git 管理\n\n### Sidecar 文件策略\n\n`.embedding` 文件作为 sidecar 存在有以下优势：\n\n- 与 `.md` 文件解耦，删除 `.md` 时自动清理\n- 嵌入模型升级时可批量重新生成\n- 避免了数据库迁移的复杂性\n\n### 图字段不参与 SHA\n\n图关系（`relations`、`supersedes`）不参与 `contentSha` 计算是刻意的设计选择：\n\n> Adding or removing graph edges does not invalidate the embedding.\n\n这允许在不重新嵌入的情况下快速调整关系网络。\n\n资料来源：[src/store/memory.ts:20-30]()\n\n## 错误处理\n\n| 错误场景 | 处理方式 |\n|----------|----------|\n| 目标文件已存在 | 抛出错误，提示先删除 |\n| 源记忆不存在 | 抛出错误，阻止操作 |\n| 目标记忆不存在 | 抛出错误，阻止操作 |\n| 自环引用 | 抛出错误，禁止 |\n| 重复边 | 抛出错误，需先解绑 |\n| 磁盘读取失败 | 传播到调用方 |\n| 磁盘写入失败 | 传播到调用方 |\n\n## 相关子模块\n\n| 模块 | 职责 |\n|------|------|\n| `memory.ts` | Memory 序列化/反序列化、Content SHA 计算 |\n| `mentions.ts` | `[[name]]` 提及提取 |\n| `graph.ts` | 内存图数据结构 |\n| `atomic-write.ts` | 原子文件写入 |\n\n---\n\n<a id='page-scopes'></a>\n\n## 作用域与多存储\n\n### 相关页面\n\n相关主题：[存储系统](#page-storage)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n- [src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n- [src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts)\n- [CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n</details>\n\n# 作用域与多存储\n\n## 概述\n\nCommonplace 采用**双存储架构**，支持用户级别（user）和项目级别（project）两套独立的记忆存储。这种设计允许用户在不同的项目中维护各自的上下文，同时在全局层面保留跨项目的个人规则和偏好。\n\n**核心价值：**\n\n- **持久化反馈**：跨项目积累的纠正和学习经验不会因项目切换而丢失\n- **项目隔离**：每个项目可以拥有独立的架构笔记和约定规则\n- **作用域感知**：工具调用可精确指定读写目标存储\n\n资料来源：[README.md:1-20]()\n\n## 架构设计\n\n### 双存储模型\n\n```mermaid\ngraph TD\n    subgraph 用户存储 [\"用户存储 (User Store)\"]\n        U[~/.commonplace/memory]\n        U1[用户类型记忆]\n        U2[反馈类型记忆]\n    end\n    \n    subgraph 项目存储 [\"项目存储 (Project Store)\"]\n        P[.commonplace/memory]\n        P1[项目类型记忆]\n        P2[引用类型记忆]\n    end\n    \n    subgraph MCP工具 [\"MCP 工具层\"]\n        SAVE[memory_save]\n        SEARCH[memory_search]\n        LIST[memory_list]\n        DELETE[memory_delete]\n    end\n    \n    SAVE -->|scope: user| U\n    SAVE -->|scope: project| P\n    SEARCH -->|跨存储合并| RESULT[按评分排序结果]\n    \n    style 用户存储 fill:#e1f5fe\n    style 项目存储 fill:#fff3e0\n```\n\n### 记忆类型与存储映射\n\n| 记忆类型 | 建议存储位置 | 典型用途 |\n|---------|------------|---------|\n| `user` | 用户存储 | 个人规则、偏好、身份信息 |\n| `feedback` | 用户存储 | 来自 Agent 的纠正和经验教训 |\n| `project` | 项目存储 | 架构笔记、仓库约定、特定决策 |\n| `reference` | 项目存储 | API 形状、公式、引用性知识 |\n\n资料来源：[README.md:60-75]()\n\n## 作用域检测优先级\n\n项目存储的检测按照以下优先级顺序进行，从高到低：\n\n```mermaid\ngraph LR\n    A[\"1. COMMONPLACE_PROJECT_DIR 环境变量\"] -->|最高优先级| Z[显式覆盖]\n    B[\"2. MCP roots/list 协议\"] -->|次高| P1[项目根目录]\n    C[\"3. 当前工作目录 (cwd)\"] -->|兜底| P2[自动检测]\n    \n    style A fill:#ffcdd2\n    style Z fill:#c8e6c9\n```\n\n### 优先级详情\n\n1. **环境变量 `COMMONPLACE_PROJECT_DIR`**：显式覆盖，最高优先级。路径无需预先存在，Commonplace 会自动创建所需的目录结构。\n2. **MCP `roots/list` 协议**：通过 MCP 协议发现的项目根目录。\n3. **当前工作目录**：自动检测，将 `<cwd>/.commonplace/memory` 作为项目存储路径。\n\n资料来源：[README.md:140-155]()\n\n## 存储目录结构\n\n### 用户存储\n\n默认路径：`~/.commonplace/memory`（可通过 `COMMONPLACE_USER_DIR` 覆盖）\n\n```\n~/.commonplace/memory/\n├── feedback_learned_patterns.md\n├── feedback_avoid_shrink_scope.md\n├── user_preferences.md\n└── .embeddings/\n    ├── feedback_learned_patterns.embedding\n    └── ...\n```\n\n### 项目存储\n\n项目存储位置取决于检测优先级：\n\n```\n# 方式1: 环境变量\n${COMMONPLACE_PROJECT_DIR}/memory/\n\n# 方式2: 项目根目录\n<project-root>/.commonplace/memory/\n```\n\n项目存储只在该项目被 Commonplace 加载时才会被初始化和扫描。\n\n资料来源：[CLAUDE.md:1-30]()\n\n## 工具接口中的作用域参数\n\n所有四个核心工具都接受可选的 `scope` 参数：\n\n```typescript\ninterface ToolArguments {\n  name?: string;\n  type?: 'user' | 'feedback' | 'project' | 'reference';\n  scope?: 'user' | 'project';  // 作用域参数\n  query?: string;\n  // ... 其他参数\n}\n```\n\n### 作用域行为\n\n| 操作 | `scope` 省略 | `scope: 'user'` | `scope: 'project'` |\n|-----|-------------|-----------------|-------------------|\n| **读取** | 合并两存储，按评分排序 | 仅用户存储 | 仅项目存储 |\n| **写入** | 默认写入用户存储 | 写入用户存储 | 写入项目存储 |\n\n```mermaid\ngraph TD\n    subgraph 读取流程\n        R1{scope 参数?}\n        R2[合并两存储结果]\n        R3[仅用户存储]\n        R4[仅项目存储]\n        \n        R1 -->|省略| R2\n        R1 -->|user| R3\n        R1 -->|project| R4\n    end\n    \n    subgraph 写入流程\n        W1{scope 参数?}\n        W2[写入用户存储]\n        W3[写入项目存储]\n        \n        W1 -->|省略/空| W2\n        W1 -->|project| W3\n    end\n```\n\n资料来源：[README.md:80-95]()\n\n## 搜索结果合并\n\n当 `scope` 参数省略时，搜索会跨两个存储执行，并通过向量相似度评分合并结果：\n\n```typescript\ninterface MemorySearchMatch {\n  name: string;\n  type: MemoryType;\n  description: string;\n  body: string;\n  score: number;      // 余弦相似度，保留3位小数\n  scope: 'user' | 'project';  // 结果来源标识\n}\n```\n\n**合并规则：**\n\n- 按 `score` 降序排列\n- 每个匹配结果携带 `scope` 标签，标识其来源存储\n- 项目存储的结果可能在某些查询中排名更高\n\n资料来源：[src/server/handlers.ts:1-50]()\n\n## 迁移命令与作用域\n\n`commonplace migrate` 命令支持跨作用域的记忆迁移：\n\n```bash\n# 扫描用户存储（默认）\ncommonplace migrate\n\n# 扫描指定目录\ncommonplace migrate ~/.commonplace/memory\n\n# 预演模式（不实际写入）\ncommonplace migrate ~/.commonplace/memory --dry-run\n```\n\n### 迁移操作类型\n\n| 操作 | 说明 |\n|-----|------|\n| **嵌入** | 为缺少 `.embedding` 的 `.md` 文件生成向量 |\n| **重新嵌入** | 重新生成过时的（内容哈希/模型不匹配）或损坏的 sidecar |\n| **清理孤立文件** | 删除没有对应 `.md` 的孤立 `.embedding` 文件 |\n| **修剪悬空引用** | 移除指向不存在记忆的关系和 supersedes 条目 |\n\n资料来源：[src/cli/migrate.ts:1-80]()\n\n## 环境变量配置\n\n| 变量名 | 默认值 | 说明 |\n|-------|--------|------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | 用户存储根目录 |\n| `COMMONPLACE_PROJECT_DIR` | 未设置 | 项目存储根目录（显式覆盖） |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | 启用 `[[name]]` 提及提取 |\n\n### 配置示例\n\n```bash\n# 使用自定义用户存储位置\nexport COMMONPLACE_USER_DIR=/data/commonplace/memory\n\n# 指定项目存储位置（优先级最高）\nexport COMMONPLACE_PROJECT_DIR=/workspace/my-project/.commonplace/memory\n```\n\n资料来源：[src/index.ts:1-30]()\n\n## 开发指南：记忆存储实践\n\n在开发 Commonplace 项目本身时，应遵循以下规则：\n\n```mermaid\ngraph TD\n    subgraph 记忆保存决策\n        D1{记忆范围}\n        D2[scope: user] --> U1[跨项目规则、偏好]\n        D3[scope: project] --> P1[架构笔记、仓库约定]\n        \n        D1 -->|跨项目教训| D2\n        D1 -->|特定代码库| D3\n    end\n    \n    subgraph 禁止事项\n        B1[禁止写入 harness 内置路径]\n        B2[禁止删除历史记忆]\n    end\n    \n    P1 --> B1\n```\n\n**核心原则：**\n\n- 通过 `mcp__commonplace__memory_save` 保存记忆，选择合适的 `type`\n- 通过 `mcp__commonplace__memory_search` 和 `mcp__commonplace__memory_list` 召回记忆\n- **禁止**向 `~/.claude/projects/<slug>/memory/` 写入（使用 Commonplace 产品自身）\n- **禁止**删除已有的历史记忆\n\n资料来源：[CLAUDE.md:20-45]()\n\n## 记忆文件格式与作用域\n\n每条记忆存储为独立的 Markdown 文件，带有 YAML frontmatter：\n\n```yaml\n---\nname: feedback_scope          # 记忆唯一标识\ndescription: 不要单方面缩减范围  # 简短描述\ntype: feedback                # 记忆类型\nrelations:                    # 可选：关系图边\n  - to: architecture_decision\n    type: builds-on\nsupersedes:                   # 可选：标记被替代的记忆\n  - old_scope_rule\n---\n记忆正文内容，支持 [[name]] 语法引用其他记忆。\n```\n\n**作用域隐式由文件所在目录决定**，而非 frontmatter 中的字段。\n\n资料来源：[src/store/memory.ts:1-60]()\n\n## 总结\n\n作用域与多存储系统为 Commonplace 提供了灵活的记忆组织能力：\n\n- **用户存储**（`~/.commonplace/memory`）：跨项目的个人知识和反馈\n- **项目存储**（`.commonplace/memory`）：项目特定的上下文和决策\n- **作用域感知 API**：精确控制记忆的读写目标\n- **自动合并搜索**：跨存储检索，按相关性排序\n\n---\n\n---\n\n## Doramagic 踩坑日志\n\n项目：rickbassham/commonplace\n\n摘要：发现 8 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。\n\n## 1. 能力坑 · 能力判断依赖假设\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：README/documentation is current enough for a first validation pass.\n- 对用户的影响：假设不成立时，用户拿不到承诺的能力。\n- 建议检查：将假设转成下游验证清单。\n- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。\n- 证据：capability.assumptions | github_repo:1232879661 | https://github.com/rickbassham/commonplace | README/documentation is current enough for a first validation pass.\n\n## 2. 运行坑 · 运行可能依赖外部服务\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：项目说明出现 external service/cloud/webhook/database 等运行依赖关键词。\n- 对用户的影响：本地安装成功不等于能力可用，外部服务不可用会阻断体验。\n- 建议检查：确认是否有离线 demo、mock 数据或可替代服务。\n- 防护动作：外部服务依赖未明确时，不把本地安装成功等同于能力可用。\n- 证据：packet_text.keyword_scan | github_repo:1232879661 | https://github.com/rickbassham/commonplace | matched external service / cloud / webhook / database keyword\n\n## 3. 维护坑 · 维护活跃度未知\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：未记录 last_activity_observed。\n- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。\n- 证据：evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | last_activity_observed missing\n\n## 4. 安全/权限坑 · 下游验证发现风险项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：下游已经要求复核，不能在页面中弱化。\n- 建议检查：进入安全/权限治理复核队列。\n- 防护动作：下游风险存在时必须保持 review/recommendation 降级。\n- 证据：downstream_validation.risk_items | github_repo:1232879661 | https://github.com/rickbassham/commonplace | no_demo; severity=medium\n\n## 5. 安全/权限坑 · 存在安全注意事项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：No sandbox install has been executed yet; downstream must verify before user use.\n- 对用户的影响：用户安装前需要知道权限边界和敏感操作。\n- 建议检查：转成明确权限清单和安全审查提示。\n- 防护动作：安全注意事项必须面向用户前置展示。\n- 证据：risks.safety_notes | github_repo:1232879661 | https://github.com/rickbassham/commonplace | No sandbox install has been executed yet; downstream must verify before user use.\n\n## 6. 安全/权限坑 · 存在评分风险\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：风险会影响是否适合普通用户安装。\n- 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。\n- 证据：risks.scoring_risks | github_repo:1232879661 | https://github.com/rickbassham/commonplace | no_demo; severity=medium\n\n## 7. 维护坑 · issue/PR 响应质量未知\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：issue_or_pr_quality=unknown。\n- 对用户的影响：用户无法判断遇到问题后是否有人维护。\n- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。\n- 防护动作：issue/PR 响应未知时，必须提示维护风险。\n- 证据：evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | issue_or_pr_quality=unknown\n\n## 8. 维护坑 · 发布节奏不明确\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：release_recency=unknown。\n- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。\n- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。\n- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。\n- 证据：evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | release_recency=unknown\n\n<!-- canonical_name: rickbassham/commonplace; human_manual_source: deepwiki_human_wiki -->\n",
      "summary": "DeepWiki/Human Wiki 完整输出，末尾追加 Discovery Agent 踩坑日志。",
      "title": "Human Manual / 人类版说明书"
    },
    "pitfall_log": {
      "asset_id": "pitfall_log",
      "filename": "PITFALL_LOG.md",
      "markdown": "# Pitfall Log / 踩坑日志\n\n项目：rickbassham/commonplace\n\n摘要：发现 8 个潜在踩坑项，其中 0 个为 high/blocking；最高优先级：能力坑 - 能力判断依赖假设。\n\n## 1. 能力坑 · 能力判断依赖假设\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：README/documentation is current enough for a first validation pass.\n- 对用户的影响：假设不成立时，用户拿不到承诺的能力。\n- 建议检查：将假设转成下游验证清单。\n- 防护动作：假设必须转成验证项；没有验证结果前不能写成事实。\n- 证据：capability.assumptions | github_repo:1232879661 | https://github.com/rickbassham/commonplace | README/documentation is current enough for a first validation pass.\n\n## 2. 运行坑 · 运行可能依赖外部服务\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：项目说明出现 external service/cloud/webhook/database 等运行依赖关键词。\n- 对用户的影响：本地安装成功不等于能力可用，外部服务不可用会阻断体验。\n- 建议检查：确认是否有离线 demo、mock 数据或可替代服务。\n- 防护动作：外部服务依赖未明确时，不把本地安装成功等同于能力可用。\n- 证据：packet_text.keyword_scan | github_repo:1232879661 | https://github.com/rickbassham/commonplace | matched external service / cloud / webhook / database keyword\n\n## 3. 维护坑 · 维护活跃度未知\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：未记录 last_activity_observed。\n- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。\n- 建议检查：补 GitHub 最近 commit、release、issue/PR 响应信号。\n- 防护动作：维护活跃度未知时，推荐强度不能标为高信任。\n- 证据：evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | last_activity_observed missing\n\n## 4. 安全/权限坑 · 下游验证发现风险项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：下游已经要求复核，不能在页面中弱化。\n- 建议检查：进入安全/权限治理复核队列。\n- 防护动作：下游风险存在时必须保持 review/recommendation 降级。\n- 证据：downstream_validation.risk_items | github_repo:1232879661 | https://github.com/rickbassham/commonplace | no_demo; severity=medium\n\n## 5. 安全/权限坑 · 存在安全注意事项\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：No sandbox install has been executed yet; downstream must verify before user use.\n- 对用户的影响：用户安装前需要知道权限边界和敏感操作。\n- 建议检查：转成明确权限清单和安全审查提示。\n- 防护动作：安全注意事项必须面向用户前置展示。\n- 证据：risks.safety_notes | github_repo:1232879661 | https://github.com/rickbassham/commonplace | No sandbox install has been executed yet; downstream must verify before user use.\n\n## 6. 安全/权限坑 · 存在评分风险\n\n- 严重度：medium\n- 证据强度：source_linked\n- 发现：no_demo\n- 对用户的影响：风险会影响是否适合普通用户安装。\n- 建议检查：把风险写入边界卡，并确认是否需要人工复核。\n- 防护动作：评分风险必须进入边界卡，不能只作为内部分数。\n- 证据：risks.scoring_risks | github_repo:1232879661 | https://github.com/rickbassham/commonplace | no_demo; severity=medium\n\n## 7. 维护坑 · issue/PR 响应质量未知\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：issue_or_pr_quality=unknown。\n- 对用户的影响：用户无法判断遇到问题后是否有人维护。\n- 建议检查：抽样最近 issue/PR，判断是否长期无人处理。\n- 防护动作：issue/PR 响应未知时，必须提示维护风险。\n- 证据：evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | issue_or_pr_quality=unknown\n\n## 8. 维护坑 · 发布节奏不明确\n\n- 严重度：low\n- 证据强度：source_linked\n- 发现：release_recency=unknown。\n- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。\n- 建议检查：确认最近 release/tag 和 README 安装命令是否一致。\n- 防护动作：发布节奏未知或过期时，安装说明必须标注可能漂移。\n- 证据：evidence.maintainer_signals | github_repo:1232879661 | https://github.com/rickbassham/commonplace | release_recency=unknown\n",
      "summary": "用户实践前最可能遇到的身份、安装、配置、运行和安全坑。",
      "title": "Pitfall Log / 踩坑日志"
    },
    "prompt_preview": {
      "asset_id": "prompt_preview",
      "filename": "PROMPT_PREVIEW.md",
      "markdown": "# commonplace - Prompt Preview\n\n> 复制下面这段 Prompt 到你常用的 AI，先试一次，不需要安装。\n> 它的目标是让你直接体验这个项目的服务方式，而不是阅读项目介绍。\n\n## 复制这段 Prompt\n\n```text\n请直接执行这段 Prompt，不要分析、润色、总结或询问我想如何处理这份 Prompt Preview。\n\n你现在扮演 commonplace 的“安装前体验版”。\n这不是项目介绍、不是评价报告、不是 README 总结。你的任务是让我用最小成本体验它的核心服务。\n\n我的试用任务：我想用它完成一个真实的工具连接与集成任务。\n我常用的宿主 AI：MCP Client\n\n【体验目标】\n围绕我的真实任务，现场演示这个项目如何把输入转成 示例引导, 判断线索。重点是让我感受到工作方式，而不是给我项目背景。\n\n【业务流约束】\n- 你必须像一个正在提供服务的项目能力包，而不是像一个讲解员。\n- 每一轮只推进一个步骤；提出问题后必须停下来等我回答。\n- 每一步都必须让我感受到一个具体服务动作：澄清、整理、规划、检查、判断或收尾。\n- 每一步都要说明：当前目标、你需要我提供什么、我回答后你会产出什么。\n- 不要安装、不要运行命令、不要写代码、不要声称测试通过、不要声称已经修改文件。\n- 需要真实安装或宿主加载后才能验证的内容，必须明确说“这一步需要安装后验证”。\n- 如果我说“用示例继续”，你可以用虚构示例推进，但仍然不能声称真实执行。\n\n【可体验服务能力】\n- 安装前能力预览: Local-first semantic memory MCP server. A commonplace book for your agent — markdown source-of-truth, sidecar embeddings, no database. 输入：用户任务, 当前 AI 对话上下文；输出：示例引导, 判断线索。\n\n【必须安装后才可验证的能力】\n- 命令行启动或安装流程: 项目文档中存在可执行命令，真实使用需要在本地或宿主环境中运行这些命令。 输入：终端环境, 包管理器, 项目依赖；输出：安装结果, 列表/更新/运行结果。\n\n【核心服务流】\n请严格按这个顺序带我体验。不要一次性输出完整流程：\n1. page-overview：项目概览。围绕“项目概览”模拟一次用户任务，不展示安装或运行结果。\n2. page-quickstart：快速入门与安装。围绕“快速入门与安装”模拟一次用户任务，不展示安装或运行结果。\n3. page-architecture：系统架构。围绕“系统架构”模拟一次用户任务，不展示安装或运行结果。\n4. page-embedder：嵌入模型与语义搜索。围绕“嵌入模型与语义搜索”模拟一次用户任务，不展示安装或运行结果。\n5. page-memory-format：内存格式与侧载文件。围绕“内存格式与侧载文件”模拟一次用户任务，不展示安装或运行结果。\n\n【核心能力体验剧本】\n每一步都必须按“输入 -> 服务动作 -> 中间产物”执行。不要只说流程名：\n1. page-overview\n输入：用户提供的“项目概览”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n2. page-quickstart\n输入：用户提供的“快速入门与安装”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n3. page-architecture\n输入：用户提供的“系统架构”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n4. page-embedder\n输入：用户提供的“嵌入模型与语义搜索”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n5. page-memory-format\n输入：用户提供的“内存格式与侧载文件”相关信息。\n服务动作：模拟项目在这一步的核心判断和整理方式。\n中间产物：一个可检查的小结果。\n\n【项目服务规则】\n这些规则决定你如何服务用户。不要解释规则本身，而要在每一步执行时遵守：\n- 先确认用户任务、输入材料和成功标准，再模拟项目能力。\n- 每一步都必须形成可检查的小产物，并等待用户确认后再继续。\n- 凡是需要安装、调用工具或访问外部服务的能力，都必须标记为安装后验证。\n\n【每一步的服务约束】\n- Step 1 / page-overview：Step 1 必须围绕“项目概览”形成一个小中间产物，并等待用户确认。\n- Step 2 / page-quickstart：Step 2 必须围绕“快速入门与安装”形成一个小中间产物，并等待用户确认。\n- Step 3 / page-architecture：Step 3 必须围绕“系统架构”形成一个小中间产物，并等待用户确认。\n- Step 4 / page-embedder：Step 4 必须围绕“嵌入模型与语义搜索”形成一个小中间产物，并等待用户确认。\n- Step 5 / page-memory-format：Step 5 必须围绕“内存格式与侧载文件”形成一个小中间产物，并等待用户确认。\n\n【边界与风险】\n- 不要声称已经安装、运行、调用 API、读写本地文件或完成真实任务。\n- 安装前预览只能展示工作方式，不能证明兼容性、性能或输出质量。\n- 涉及安装、插件加载、工具调用或外部服务的能力必须安装后验证。\n\n【可追溯依据】\n这些路径只用于你内部校验或在我追问“依据是什么”时简要引用。不要在首次回复主动展开：\n- https://github.com/rickbassham/commonplace\n- https://github.com/rickbassham/commonplace#readme\n- README.md\n- package.json\n- CLAUDE.md\n- .nvmrc\n- src/index.ts\n- src/embedder/index.ts\n- src/store/memory-store.ts\n- src/server/server.ts\n- vitest.config.ts\n- tests/global-setup.ts\n\n【首次问题规则】\n- 首次三问必须先确认用户目标、成功标准和边界，不要提前进入工具、安装或实现细节。\n- 如果后续需要技术条件、文件路径或运行环境，必须等用户确认目标后再追问。\n\n首次回复必须只输出下面 4 个部分：\n1. 体验开始：用 1 句话说明你将带我体验 commonplace 的核心服务。\n2. 当前步骤：明确进入 Step 1，并说明这一步要解决什么。\n3. 你会如何服务我：说明你会先改变我完成任务的哪个动作。\n4. 只问我 3 个问题，然后停下等待回答。\n\n首次回复禁止输出：后续完整流程、证据清单、安装命令、项目评价、营销文案、已经安装或运行的说法。\n\nStep 1 / brainstorming 的二轮协议：\n- 我回答首次三问后，你仍然停留在 Step 1 / brainstorming，不要进入 Step 2。\n- 第二次回复必须产出 6 个部分：澄清后的任务定义、成功标准、边界条件、\n  2-3 个可选方案、每个方案的权衡、推荐方案。\n- 第二次回复最后必须问我是否确认推荐方案；只有我明确确认后，才能进入下一步。\n- 第二次回复禁止输出 git worktree、代码计划、测试文件、命令或真实执行结果。\n\n后续对话规则：\n- 我回答后，你先完成当前步骤的中间产物并等待确认；只有我确认后，才能进入下一步。\n- 每一步都要生成一个小的中间产物，例如澄清后的目标、计划草案、测试意图、验证清单或继续/停止判断。\n- 所有演示都写成“我会建议/我会引导/这一步会形成”，不要写成已经真实执行。\n- 不要声称已经测试通过、文件已修改、命令已运行或结果已产生。\n- 如果某个能力必须安装后验证，请直接说“这一步需要安装后验证”。\n- 如果证据不足，请明确说“证据不足”，不要补事实。\n```\n",
      "summary": "不安装项目也能感受能力节奏的安全试用 Prompt。",
      "title": "Prompt Preview / 安装前试用 Prompt"
    },
    "quick_start": {
      "asset_id": "quick_start",
      "filename": "QUICK_START.md",
      "markdown": "# Quick Start / 官方入口\n\n项目：rickbassham/commonplace\n\n## 官方安装入口\n\n### Node.js / npm · 官方安装入口\n\n```bash\nnpm i -g commonplace-mcp\n```\n\n来源：https://github.com/rickbassham/commonplace#readme\n\n## 来源\n\n- repo: https://github.com/rickbassham/commonplace\n- docs: https://github.com/rickbassham/commonplace#readme\n",
      "summary": "从项目官方 README 或安装文档提取的开工入口。",
      "title": "Quick Start / 官方入口"
    }
  },
  "validation_id": "dval_6e0e02567bfa4a499e76ba80b4a1178e"
}
