{
  "canonical_name": "rickbassham/commonplace",
  "compilation_id": "pack_2d395e29e43b45658e53084415466fc7",
  "created_at": "2026-05-18T04:26:28.421958+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": "Security & Permissions",
        "label_zh": "安全审查与权限治理",
        "source": "repo_evidence_project_characteristics",
        "tag_id": "product_domain-security-permissions",
        "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": [
        "安全审查与权限治理",
        "知识库问答",
        "流程自动化",
        "节点式流程编排",
        "本地优先"
      ],
      "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> Copy the prompt below into your AI host before installing anything.\n> Its purpose is to let you safely feel the project's workflow, not to claim the project has already run.\n\n## Copy this prompt\n\n```text\nYou are using an independent Doramagic capability pack for rickbassham/commonplace.\n\nProject:\n- Name: commonplace\n- Repository: https://github.com/rickbassham/commonplace\n- Summary: Local-first semantic memory MCP server. A commonplace book for your agent — markdown source-of-truth, sidecar embeddings, no database.\n- Host target: mcp_host\n\nGoal:\nHelp me evaluate this project for the following task without installing it yet: Local-first semantic memory MCP server. A commonplace book for your agent — markdown source-of-truth, sidecar embeddings, no database.\n\nBefore taking action:\n1. Restate my task, success standard, and boundary.\n2. Identify whether the next step requires tools, browser access, network access, filesystem access, credentials, package installation, or host configuration.\n3. Use only the Doramagic Project Pack, the upstream repository, and the source-linked evidence listed below.\n4. If a real command, install step, API call, file write, or host integration is required, mark it as \"requires post-install verification\" and ask for approval first.\n5. If evidence is missing, say \"evidence is missing\" instead of filling the gap.\n\nPreviewable capabilities:\n- Capability 1: Local-first semantic memory MCP server. A commonplace book for your agent — markdown source-of-truth, sidecar embeddings, no database.\n\nCapabilities that require post-install verification:\n- Capability 1: Use the source-backed project context to guide one small, checkable workflow step.\n\nCore service flow:\n1. introduction: Introduction to Commonplace. Produce one small intermediate artifact and wait for confirmation.\n2. quickstart: Quick Start Guide. Produce one small intermediate artifact and wait for confirmation.\n3. system-architecture: System Architecture. Produce one small intermediate artifact and wait for confirmation.\n4. memory-data-model: Memory Data Model. Produce one small intermediate artifact and wait for confirmation.\n5. memory-types-taxonomy: Memory Types Taxonomy. Produce one small intermediate artifact and wait for confirmation.\n\nSource-backed evidence to keep in mind:\n- https://github.com/rickbassham/commonplace\n- https://github.com/rickbassham/commonplace#readme\n- README.md\n- CLAUDE.md\n- src/index.ts\n- package.json\n- src/embedder/index.ts\n- src/store/memory-store.ts\n- src/server/index.ts\n- src/server/server.ts\n\nFirst response rules:\n1. Start Step 1 only.\n2. Explain the one service action you will perform first.\n3. Ask exactly three questions about my target workflow, success standard, and sandbox boundary.\n4. Stop and wait for my answers.\n\nStep 1 follow-up protocol:\n- After I answer the first three questions, stay in Step 1.\n- Produce six parts only: clarified task, success standard, boundary conditions, two or three options, tradeoffs for each option, and one recommendation.\n- End by asking whether I confirm the recommendation.\n- Do not move to Step 2 until I explicitly confirm.\n\nConversation rules:\n- Advance one step at a time and wait for confirmation after each small artifact.\n- Write outputs as recommendations or planned checks, not as completed execution.\n- Do not claim tests passed, files changed, commands ran, APIs were called, or the project was installed.\n- If the user asks for execution, first provide the sandbox setup, expected output, rollback, and approval checkpoint.\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": [
        "安全审查与权限治理",
        "知识库问答",
        "流程自动化",
        "节点式流程编排",
        "本地优先"
      ],
      "thumb": "gray",
      "type": "MCP 配置"
    },
    "manual": {
      "markdown": "# https://github.com/rickbassham/commonplace 项目说明书\n\n生成时间：2026-05-18 04:25:02 UTC\n\n## 目录\n\n- [Introduction to Commonplace](#introduction)\n- [Quick Start Guide](#quickstart)\n- [System Architecture](#system-architecture)\n- [Project Structure](#project-structure)\n- [Memory Data Model](#memory-data-model)\n- [Memory Types Taxonomy](#memory-types-taxonomy)\n- [Memory Store](#memory-store)\n- [Embedding System](#embedding-system)\n- [Semantic Search](#semantic-search)\n- [Graph Features](#graph-features)\n- [MCP Tool Reference](#mcp-tool-reference)\n- [Server Handlers](#server-handlers)\n\n<a id='introduction'></a>\n\n## Introduction to Commonplace\n\n### 相关页面\n\n相关主题：[Quick Start Guide](#quickstart), [System Architecture](#system-architecture), [Memory Data Model](#memory-data-model)\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- [src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.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/store/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n- [CHANGELOG.md](https://github.com/rickbassham/commonplace/blob/main/CHANGELOG.md)\n- [CONTRIBUTING.md](https://github.com/rickbassham/commonplace/blob/main/CONTRIBUTING.md)\n</details>\n\n# Introduction to Commonplace\n\nCommonplace is a local-first personal knowledge management system that functions as an MCP (Model Context Protocol) server. It enables AI agents to persistently store, retrieve, and reason about notes using semantic search, all without requiring external API calls or cloud services. 资料来源：[README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n\n## Overview\n\nCommonplace operates as a flat directory of Markdown files with YAML frontmatter. Each note is a plain `.md` file, and embeddings are stored in `.embedding` sidecar files generated locally using `transformers.js`. This architecture ensures that:\n\n- **Notes are human-readable and portable** — since memories are plain Markdown files, they can be edited, backed up, or version-controlled using standard tools.\n- **Embeddings are derived, not the source of truth** — `.embedding` files are regenerable from `.md` files at any time and may be deleted or rebuilt without data loss. 资料来源：[CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"MCP Client Layer\"\n        A[\"Claude Code / AI Agent\"]\n    end\n    \n    subgraph \"MCP Server Layer\"\n        B[\"commonplace MCP Server<br/>stdio interface\"]\n    end\n    \n    subgraph \"Store Layer\"\n        C[\"MemoryStore<br/>src/store/memory-store.ts\"]\n        D[\"MemoryGraph<br/>Graph relationships\"]\n        E[\"Embedder<br/>transformers.js + bge-base-en-v1.5\"]\n    end\n    \n    subgraph \"Filesystem Layer\"\n        F[\"COMMONPLACE_USER_DIR<br/>~/.commonplace\"]\n        G[\"COMMONPLACE_PROJECT_DIR<br/>.commonplace\"]\n    end\n    \n    A -->|\"MCP Protocol\"| B\n    B --> C\n    C --> D\n    C --> E\n    C --> F\n    C --> G\n    \n    F -.->|\"user scope\"| C\n    G -.->|\"project scope\"| C\n```\n\n### Key Components\n\n| Component | File | Responsibility |\n|-----------|------|-----------------|\n| MCP Server | `src/server/handlers.ts` | Handles MCP protocol communication, registers tools |\n| MemoryStore | `src/store/memory-store.ts` | Manages CRUD operations, scanning, searching |\n| MemoryGraph | `src/store/memory-store.ts` | In-memory graph for relations and mentions |\n| Embedder | `src/store/embedder.ts` | Local embedding generation via transformers.js |\n| Memory I/O | `src/store/memory.ts` | Parses/serializes `.md` files with YAML frontmatter |\n| Atomic Write | `src/store/atomic-write.ts` | Safe file writes to prevent corruption |\n| Mentions | `src/store/mentions.ts` | Extracts `[[name]]` references from body content |\n\n## Memory Model\n\n### Memory Types\n\nMemories are classified into a four-element taxonomy defined at 资料来源：[README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n\n| Type | Purpose | Example |\n|------|---------|---------|\n| `user` | Personal rules, preferences, identity facts about the human operator | Coding style preferences, work schedule |\n| `feedback` | Corrections and lessons learned from prior agent behavior | \"Don't shrink scope unilaterally\" |\n| `project` | Per-project context like architecture notes, repo conventions | API conventions, decision records |\n| `reference` | Durable, neutral knowledge: API shapes, formulas, citations | Library documentation, formulas |\n\n### Memory File Format\n\nA memory is a Markdown file with YAML frontmatter:\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: scope_management\n    type: builds-on\nsupersedes:\n  - old_scope_note\n---\n<Body content here. Can contain [[other_memory_name]] mentions.>\n```\n\n**Frontmatter Fields:**\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `name` | string | Yes | Memory identifier matching `^[a-z0-9_]+$` |\n| `description` | string | Yes | Brief summary of the memory |\n| `type` | enum | Yes | One of: `user`, `feedback`, `project`, `reference` |\n| `relations` | array | No | List of `{to, type}` edges to other memories |\n| `supersedes` | array | No | List of memory names this memory replaces |\n\nThe `contentSha` is computed from `${type}\\n${name}\\n${description}\\n${body}` — graph fields do not affect the hash, so adding or removing edges does not invalidate embeddings. 资料来源：[src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n### Relation Types\n\nGraph edges support the following relation types 资料来源：[src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts):\n\n| Relation Type | Description |\n|---------------|-------------|\n| `builds-on` | This memory extends or depends on another |\n| `related-to` | Tangentially connected memories |\n| `contradicts` | This memory opposes another |\n| `child-of` | This memory is a sub-component of another |\n| `mentions` | Body contains `[[name]]` reference |\n\n## MCP Tools\n\nCommonplace exposes the following tools via MCP protocol 资料来源：[CHANGELOG.md](https://github.com/rickbassham/commonplace/blob/main/CHANGELOG.md):\n\n### memory_save\n\nSaves a memory as a Markdown file with YAML frontmatter and generates an embedding sidecar. Refuses to overwrite existing entries.\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `name` | string | Yes | Memory name, must match `^[a-z0-9_]+$` |\n| `type` | enum | Yes | One of the four memory types |\n| `description` | string | Yes | Brief description |\n| `body` | string | Yes | Full memory content |\n| `scope` | enum | No | `'user'` (default) or `'project'` |\n\n### memory_list\n\nReturns all memories of a given type.\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `type` | enum | Yes | Filter by memory type |\n| `scope` | enum | No | `'user'`, `'project'`, or both (default) |\n\n### memory_delete\n\nRemoves a memory and its embedding sidecar.\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `name` | string | Yes | Memory name to delete |\n| `scope` | enum | No | `'user'` (default) or `'project'` |\n\n### memory_search\n\nPerforms semantic search across memories using cosine similarity.\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `query` | string | Yes | Natural language query |\n| `type` | enum | No | Filter by memory type |\n| `limit` | number | No | Maximum results (default: 5) |\n| `scope` | enum | No | `'user'`, `'project'`, or both (default) |\n\n### memory_link\n\nCreates a directed edge between two memories.\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `from` | string | Yes | Source memory name |\n| `to` | string | Yes | Target memory name |\n| `type` | enum | Yes | One of: `builds-on`, `related-to`, `contradicts`, `child-of` |\n| `scope` | enum | No | `'user'` (default) or `'project'` |\n\n### memory_unlink\n\nRemoves an edge between two memories.\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `from` | string | Yes | Source memory name |\n| `to` | string | Yes | Target memory name |\n| `type` | enum | No | Specific edge type to remove; omit to remove all |\n\n## CLI Commands\n\nThe `commonplace` CLI provides additional management functions 资料来源：[src/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n\n### migrate\n\nThe `migrate` command handles embedding sidecar management and migration between systems.\n\n```\ncommonplace migrate <dir> [--dry-run] [--prune-dangling]\n```\n\n**Functions:**\n\n1. **Embeds** any `.md` whose `.embedding` sidecar is missing\n2. **Re-embeds** any `.md` whose sidecar is stale (contentSha, modelId, or dim mismatch)\n3. **Removes** orphaned `.embedding` files whose matching `.md` is gone\n4. **Prunes** dangling edges when `--prune-dangling` is specified\n\n### Import from Claude Code\n\n```\ncommonplace migrate --from claude-code        # import memories\ncommonplace migrate --from claude-code --dry-run  # preview import\n```\n\nImport copies compatible `.md` files from Claude Code's auto-memory locations (`~/.claude/projects/*/memory/*.md`) into `COMMONPLACE_USER_DIR`.\n\n**Conflict Policy:** Skip and report — if a memory already exists, the source is skipped without overwrite. Use `--dry-run` to preview conflicts.\n\n## Scopes and Directory Structure\n\nCommonplace supports two independent scopes 资料来源：[src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts):\n\n```mermaid\ngraph LR\n    A[\"~/.commonplace<br/>COMMONPLACE_USER_DIR\"] <--> B[\"Cross-project memories<br/>user scope\"]\n    C[\".commonplace<br/>COMMONPLACE_PROJECT_DIR\"] <--> D[\"Project-specific memories<br/>project scope\"]\n```\n\n| Scope | Directory | Contents |\n|-------|-----------|----------|\n| `user` | `~/.commonplace/` | Cross-project memories (preferences, general feedback) |\n| `project` | `.commonplace/` | Per-project memories (conventions, decisions) |\n\nWhen `scope` is omitted on tool calls, reads merge across both stores while writes default to `user`.\n\n## Search Behavior\n\nSearch results include 资料来源：[src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts):\n\n| Field | Description |\n|-------|-------------|\n| `name` | Memory identifier |\n| `type` | Memory type |\n| `description` | Brief summary |\n| `body` | Full body content (never truncated) |\n| `score` | Cosine similarity, rounded to 3 decimals |\n| `relations` | Outgoing graph edges from this memory |\n\n**Expand Types:** By default, search enriches results with `builds-on` and `related-to` neighbors. Pass `expandTypes: ['supersedes']` to include superseded entries explicitly.\n\n**Supersedes Handling:** Entries listed in another memory's `supersedes` field are excluded by default from search results. Pass `excludeSuperseded: false` to include them.\n\n## [[name]] Mentions\n\nBody mentions are extracted using a regex tokenizer 资料来源：[src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts):\n\n- Only `<name>` tokens matching `^[a-z0-9_]+$` are recognized\n- Mentions are added as directed edges in the MemoryGraph\n- Extraction is controlled by `COMMONPLACE_EXTRACT_MENTIONS` env var (default: on)\n\nMentions are **not**:\n- Rendered as wiki-style links\n- Aware of code fences or inline code blocks (intentional)\n- Surfaced through MCP tool responses (DAR-929/DAR-932)\n\n## Installation and Setup\n\nAfter installing Commonplace:\n\n```bash\nnpm install -g commonplace\n# or\npnpm add -g commonplace\n```\n\nConfigure Claude Code to use the MCP server by adding to your settings. After restarting Claude Code sessions, the four memory tools become available. 资料来源：[README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n\n## Workflow Summary\n\n```mermaid\ngraph TD\n    A[\"Agent starts task\"] --> B[\"memory_search or memory_list\"]\n    B --> C{\"Results found?\"}\n    C -->|Yes| D[\"Use memory content\"]\n    C -->|No| E[\"Gather new information\"]\n    E --> F[\"memory_save<br/>with appropriate type\"]\n    F --> G[\"Embedding generated<br/>and stored\"]\n    D --> H[\"Complete task\"]\n    G --> H\n```\n\n## Contributing\n\nThis project follows a squash-merge workflow with the following requirements 资料来源：[CONTRIBUTING.md](https://github.com/rickbassham/commonplace/blob/main/CONTRIBUTING.md):\n\n1. Branch from `main` with descriptive names\n2. No direct pushes to `main` — all changes via PR\n3. CI must pass: `make typecheck`, `make lint`, `make build`, `make test`\n4. All PR conversations must be resolved before merge\n5. Squash-merge only to keep history linear\n\nThe project dogfoods Commonplace for its own memory — developers are encouraged to use `mcp__commonplace__memory_save` for cross-project and project-specific lessons. 资料来源：[CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n\n---\n\n<a id='quickstart'></a>\n\n## Quick Start Guide\n\n### 相关页面\n\n相关主题：[Introduction to Commonplace](#introduction), [MCP Tool Reference](#mcp-tool-reference)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [CONTRIBUTING.md](https://github.com/rickbassham/commonplace/blob/main/CONTRIBUTING.md)\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/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n</details>\n\n# Quick Start Guide\n\nWelcome to **Commonplace** — a persistent, embeddable memory system for AI agents that operates on plain markdown files with YAML frontmatter.\n\n## Prerequisites\n\nBefore getting started, ensure your environment meets the following requirements:\n\n| Requirement | Version | Notes |\n|-------------|---------|-------|\n| Node.js | 20 or 22 | CI runs on both versions |\n| pnpm | latest | Package manager for this project |\n| Claude Code | compatible | For MCP tool integration |\n\n资料来源：[CONTRIBUTING.md:1-20]()\n\n## Installation\n\n### From Source\n\nClone the repository and install dependencies:\n\n```bash\ngit clone https://github.com/rickbassham/commonplace.git\ncd commonplace\npnpm install\n```\n\n### Build the Project\n\n```bash\nmake build\n```\n\nThis compiles the TypeScript source and prepares the CLI binary.\n\n资料来源：[CONTRIBUTING.md:22-30]()\n\n## Core Concepts\n\n### Memory Types\n\nEvery memory in Commonplace has a `type` field that categorizes its content:\n\n| Type | Purpose | Example |\n|------|---------|---------|\n| `user` | Personal rules, preferences, identity facts | `preferred_code_style`, `keyboard_shortcuts` |\n| `feedback` | Corrections and lessons learned | `dont_shrink_scope_unilaterally`, `verify_api_response` |\n| `project` | Per-project context, architecture, conventions | `monorepo_structure`, `db_schema_notes` |\n| `reference` | Durable neutral knowledge, API docs | `openapi_spec_location`, `rate_limit_formulas` |\n\n资料来源：[README.md:1-20]()\n\n### Memory Scopes\n\nCommonplace supports two parallel memory stores:\n\n```mermaid\ngraph TD\n    A[Claude Code Session] --> B{Scope Selection}\n    B -->|user| C[User Store]\n    B -->|project| D[Project Store]\n    C --> E[~/.commonplace/memory]\n    D --> F[COMMONPLACE_PROJECT_DIR<br/>or<br/>.commonplace/memory]\n    \n    style C fill:#e1f5fe\n    style D fill:#fff3e0\n```\n\n| Scope | Location | Use Case |\n|-------|----------|----------|\n| `user` | `~/.commonplace/memory` (default) | Cross-project memories, personal preferences |\n| `project` | Project root `.commonplace/memory` | Repository-specific context |\n\n资料来源：[README.md:45-70]()\n\n### Memory File Structure\n\nEach memory is stored as a markdown file with YAML frontmatter:\n\n```yaml\n---\nname: my_memory_name\ndescription: Brief description of this memory\ntype: feedback\nrelations:\n  - to: other_memory\n    type: builds-on\nsupersedes:\n  - old_memory_name\n---\nBody content goes here. Can contain [[wiki-links]] to other memories.\n```\n\n资料来源：[src/store/memory.ts:35-55]()\n\n## CLI Commands\n\n### Migrate Command\n\nThe `commonplace migrate` command manages your memory directory:\n\n```bash\n# Scan and embed all memories\ncommonplace migrate <dir>\n\n# Preview changes without writing\ncommonplace migrate <dir> --dry-run\n\n# Remove dangling references\ncommonplace migrate <dir> --prune-dangling\n```\n\n#### Migration Workflow\n\n```mermaid\ngraph TD\n    A[commonplace migrate <dir>] --> B{Orphan Detection}\n    B -->|Sidecar exists<br/>no .md file| C[Clean up orphan]\n    B -->|.md exists<br/>no sidecar| D[Embed memory]\n    B -->|Sidecar stale| E[Re-embed memory]\n    B -->|Both fresh| F[Mark unchanged]\n    \n    C --> G[Report: orphaned]\n    D --> H[Report: embedded]\n    E --> I[Report: re-embedded]\n    F --> J[Report: loaded]\n    \n    style G fill:#c8e6c9\n    style H fill:#c8e6c9\n    style I fill:#c8e6c9\n    style J fill:#c8e6c9\n```\n\n资料来源：[src/cli/migrate.ts:50-85]()\n\n### Import from Claude Code\n\nImport memories from Claude Code's auto-memory directories:\n\n```bash\n# Detect candidates\ncommonplace migrate --from claude-code\n\n# Perform import\ncommonplace migrate --from claude-code --auto\n```\n\nThe import:\n1. Scans `~/.claude/projects/*/memory/*.md` for candidates\n2. Copies compatible files to your user store (skips if target exists)\n3. Runs embed pass on newly imported files\n\n资料来源：[src/cli/migrate.ts:120-180]()\n\n## MCP Tool Reference\n\nAfter installation, four tools become available in Claude Code:\n\n### memory_save\n\nSave a new memory:\n\n```json\n{\n  \"name\": \"my_memory\",\n  \"type\": \"project\",\n  \"body\": \"Detailed content here...\"\n}\n```\n\n### memory_search\n\nSearch memories by semantic similarity:\n\n```json\n{\n  \"query\": \"scope handshake\",\n  \"limit\": 3,\n  \"type\": \"feedback\"\n}\n```\n\n### memory_list\n\nList all memories, optionally filtered:\n\n```json\n{\n  \"type\": \"reference\",\n  \"includeSuperseded\": false\n}\n```\n\n### memory_link / memory_unlink\n\nCreate or remove relationships between memories:\n\n```json\n// memory_link\n{\n  \"from\": \"architecture_overview\",\n  \"to\": \"feedback_scope\",\n  \"type\": \"builds-on\"\n}\n```\n\n资料来源：[README.md:100-200]()\n\n## Search and Expansion\n\n### One-Hop Expansion\n\nWhen searching, you can expand results to include connected memories:\n\n```mermaid\ngraph LR\n    A[Query] --> B[Direct Hits]\n    B --> C{expand: 'one-hop'}\n    C -->|Enabled| D[Outbound Edges]\n    D --> E[Neighbors]\n    C -->|Disabled| F[Direct Only]\n    \n    E -.->|via: {source, edge}| B\n```\n\n| Parameter | Values | Default | Description |\n|-----------|--------|---------|-------------|\n| `expand` | `none`, `one-hop` | `none` | Expansion mode |\n| `expandTypes` | edge types array | `['builds-on', 'related-to']` | Which edges to follow |\n| `expandLimit` | integer | `2` | Max neighbors per hit |\n\n资料来源：[README.md:180-220]()\n\n## Development Workflow\n\n### Make Targets\n\n| Target | Purpose |\n|--------|---------|\n| `make typecheck` | Run TypeScript type checking |\n| `make lint` | Run ESLint |\n| `make build` | Compile TypeScript to JavaScript |\n| `make test` | Run test suite |\n| `make audit` | Security audit (non-blocking) |\n\n### Branch Strategy\n\n1. Branch from `main` with a descriptive name\n2. Open a PR against `main`\n3. Ensure CI passes before merge\n4. Squash-merge to keep history linear\n\n资料来源：[CONTRIBUTING.md:5-35]()\n\n## Configuration\n\n### Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | User memory store location |\n| `COMMONPLACE_PROJECT_DIR` | (project root) | Project memory store override |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | Enable `[[name]]` extraction |\n\n资料来源：[src/store/mentions.ts:10-25]()\n\n## Troubleshooting\n\n### Embedding Sidecars\n\nThe `.embedding` sidecar files are derived and regenerable. If embeddings seem stale:\n\n```bash\n# Rebuild all embeddings\ncommonplace migrate <dir>\n```\n\n### Dangling References\n\nIf memories reference names that no longer exist:\n\n```bash\n# Preview dangling removal\ncommonplace migrate <dir> --dry-run --prune-dangling\n\n# Execute cleanup\ncommonplace migrate <dir> --prune-dangling\n```\n\n资料来源：[src/cli/migrate.ts:60-80]()\n\n## See Also\n\n- [Memory Store Architecture](../architecture/memory-store.md) — Detailed internal design\n- [MCP Integration](../integration/mcp-tools.md) — Tool contracts and responses\n- [Contributing Guide](../contributing/CONTRIBUTING.md) — Development standards\n\n---\n\n<a id='system-architecture'></a>\n\n## System Architecture\n\n### 相关页面\n\n相关主题：[Project Structure](#project-structure), [Embedding System](#embedding-system), [Memory Store](#memory-store)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.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/store/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.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- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n\nNote: `src/embedder/index.ts`, `src/server/index.ts`, and `src/server/server.ts` were referenced but not included in the provided context.\n\n</details>\n\n# System Architecture\n\n## Overview\n\nCommonplace is a persistent memory system for AI agents that stores contextual knowledge as markdown files with YAML frontmatter. The system provides semantic search across memories using embeddings, a graph-based relationship model for linking related memories, and a dual-store architecture supporting both user-level and project-level contexts.\n\nThe architecture is designed around the principle that **markdown files are the source of truth** — `.embedding` sidecar files are derived and regenerable at any time. 资料来源：[CLAUDE.md]()\n\n## Core Components\n\n| Component | File | Purpose |\n|-----------|------|---------|\n| MemoryStore | `src/store/memory-store.ts` | Central store managing in-memory index, file I/O, search, and graph edges |\n| Memory I/O | `src/store/memory.ts` | YAML frontmatter parsing, serialization, content hashing |\n| Atomic Write | `src/store/atomic-write.ts` | Safe file writes via temp-file + rename pattern |\n| Mentions Extractor | `src/store/mentions.ts` | Extracts `[[name]]` references from memory bodies |\n| MCP Server | `src/server/handlers.ts` | Tool handlers exposing memory operations via Model Context Protocol |\n| CLI Entry | `src/index.ts` | Command-line interface dispatcher |\n\n## Memory Model\n\n### Data Structure\n\nEach memory is a markdown file with the following structure:\n\n```yaml\n---\nname: memory_name\ndescription: Brief description\ntype: user | feedback | project | reference\nrelations:           # DAR-925, optional\n  - to: other_name\n    type: builds-on\nsupersedes:          # DAR-925, optional\n  - old_name\n---\n<body content>\n```\n\nThe `contentSha` is computed from the canonical form `${type}\\n${name}\\n${description}\\n${body}` — intentionally excluding graph fields (`relations`, `supersedes`) so adding or removing edges does not invalidate embeddings. 资料来源：[src/store/memory.ts:30-35]()\n\n### Memory Types\n\n| Type | Purpose |\n|------|---------|\n| `user` | Personal rules, preferences, identity facts about the human operator |\n| `feedback` | Corrections and lessons learned from prior agent behaviour |\n| `project` | Per-project context (architecture notes, repo conventions) |\n| `reference` | Durable, neutral knowledge (API shapes, formulas, citations) |\n\n资料来源：[README.md]()\n\n## Dual-Store Architecture\n\nCommonplace loads up to two memory stores side by side:\n\n```mermaid\ngraph TD\n    subgraph User_Store[\"User Store (always loaded)\"]\n        U[~/.commonplace/memory]\n    end\n    \n    subgraph Project_Store[\"Project Store (conditional)\"]\n        P[.commonplace/memory in project root]\n    end\n    \n    MS[MemoryStore instances]\n    Search[Search merges across both stores]\n    \n    U --> MS\n    P --> MS\n    MS --> Search\n```\n\n### Store Detection Priority\n\n1. `COMMONPLACE_PROJECT_DIR` env var (explicit override, always wins)\n2. MCP `roots/list` response for project root detection\n3. Current working directory traversal\n\n资料来源：[README.md]()\n\n### Scope Behavior\n\n- **Reads** merge hits across both stores by descending score\n- **Writes** default to `user` scope when `scope` argument is omitted\n- Search results carry a `scope: 'user' | 'project'` tag identifying the source store\n\n## MemoryStore Architecture\n\n### Core Responsibilities\n\nThe `MemoryStore` class is the central orchestrator responsible for:\n\n1. **Indexing** — maintaining an in-memory array of memory entries\n2. **File I/O** — reading/writing `.md` files with YAML frontmatter\n3. **Embedding** — coordinating with the embedder for semantic search\n4. **Graph edges** — managing `relations[]` and `supersedes[]` arrays\n5. **Caching** — detecting directory changes to avoid redundant rescans\n\n资料来源：[src/store/memory-store.ts]()\n\n### Scan and Cache Invalidation\n\nThe `scan()` method rebuilds the in-memory index by walking the directory. Sidecar freshness is determined by:\n\n```mermaid\ngraph TD\n    A[Check .embedding exists] --> B{Decode success?}\n    B -->|No| C[Re-embed]\n    B -->|Yes| D{modelId matches?}\n    D -->|No| C\n    D -->|Yes| E{dim matches?}\n    E -->|No| C\n    E -->|Yes| F{contentSha matches?}\n    F -->|No| C\n    F -->|Yes| G[Sidecar is fresh, reuse]\n    \n    C --> H[Write new .embedding sidecar]\n    G --> I[Use existing sidecar]\n```\n\nReuse criteria per memory:\n- `.embedding` file exists and decodes (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:60-75]()\n\n### Orphan Cleanup (DAR-918)\n\nAfter the per-`.md` pass, `scan()` walks the directory again and removes any `.embedding` file whose matching `<name>.md` is missing. This prevents dead weight accumulation from deleted memories.\n\n```mermaid\ngraph LR\n    A[Scan directory] --> B[Find all .md files]\n    A --> C[Find all .embedding files]\n    B --> D[Build .md set]\n    C --> E[For each .embedding]\n    E --> F{basename.md exists?}\n    F -->|No| G[Delete orphan sidecar]\n    F -->|Yes| H[Keep sidecar]\n```\n\n## Graph System (DAR-925)\n\n### Edge Types\n\n| Type | Storage Location | Behavior |\n|------|------------------|----------|\n| `related-to` | `relations[]` | Deduped by `(to, type)` |\n| `builds-on` | `relations[]` | Deduped by `(to, type)` |\n| `contradicts` | `relations[]` | Deduped by `(to, type)` |\n| `child-of` | `relations[]` | Deduped by `(to, type)` |\n| `supersedes` | `supersedes[]` | Deduped by name |\n| `mentions` | Auto-extracted | From `[[name]]` body tokens |\n\n资料来源：[src/server/handlers.ts:20-30]()\n\n### Edge Operations\n\nThe `MemoryStore` provides two primary graph mutation methods:\n\n**`linkEdge(from, to, type)`**\n- Validates: no self-edges, both memories loaded, no duplicate edges\n- Writes source `.md` through `atomicWrite`\n- Updates in-memory entry in place\n- Calls `MemoryGraph.addEdge()` incrementally\n\n资料来源：[src/store/memory-store.ts:linkEdge-method]()\n\n**`unlinkEdge(from, to, type?)`**\n- Removes matching entry from `relations[]` or `supersedes[]`\n- When `type` omitted, removes ALL edges from → to\n- No-op if edge doesn't exist\n\n### Default Expand Types\n\nWhen searching with graph expansion, the default edge types are `['builds-on', 'related-to']`. Other types require explicit 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:15-20]()\n\n## Atomic Write System (DAR-923)\n\n### Pattern\n\nThe atomic write uses a tmpfile + rename sequence:\n\n1. Generate tmp name: `<basename>.<8-hex-chars>.tmp`\n2. Write data to tmp file in same directory\n3. Rename tmp → target (atomic on same filesystem)\n\n### Safety Guards\n\n```mermaid\ngraph TD\n    A[atomicWrite called] --> B{Same filesystem?}\n    B -->|No| C[Throw: cross-fs rename not atomic]\n    B -->|Yes| D[Write to tmp file]\n    D --> E[Rename tmp → target]\n    E --> F[Release tmp file handle]\n    G[On error] --> H[Cleanup tmp file]\n```\n\n**Cross-filesystem guard**: The implementation stats both the target directory and tmpfile directory, requiring matching `dev` (device number). 资料来源：[src/store/atomic-write.ts]()\n\n### Advisory Locking\n\nMemory operations acquire a proper-lockfile lock before writing:\n\n- Lock target: `<dir>/.locks/<name>.lock`\n- `stale: 5000` — orphaned locks from crashed processes are reclaimed after 5 seconds\n- `realpath: false` — works even when target file doesn't exist yet\n- `ELOCKED` error translated to: `MemoryStore: lock for memory '<name>' is busy`\n\n资料来源：[src/store/memory-store.ts:acquireNameLock]()\n\n## Embedding Pipeline\n\n### Mentions Extraction (DAR-927)\n\nThe `[[name]]` tokenizer extracts unique mention targets from memory bodies:\n\n```typescript\nexport const extractMentions = (body: string): string[]\n```\n\n- Only extracts tokens matching `^[a-z0-9_]+$`\n- Returns unique names in first-occurrence order\n- Gated by `COMMONPLACE_EXTRACT_MENTIONS` env var (default: on)\n\n资料来源：[src/store/mentions.ts]()\n\n### Embedding Flow\n\n```mermaid\ngraph TD\n    A[memory_save or scan] --> B[extractMentions from body]\n    B --> C[MemoryGraph.addMentionsEdge for each]\n    D[Save/write memory] --> E[embedder.embed description + body]\n    E --> F[Write .embedding sidecar]\n    G[Search query] --> H[embedder.embed query]\n    H --> I[Compare vectors with store]\n    I --> J[Return ranked results]\n```\n\n## CLI Architecture\n\n### Command Dispatch\n\nThe CLI entry point (`src/index.ts`) dispatches to subcommands:\n\n| Command | Handler | Purpose |\n|---------|---------|---------|\n| `commonplace migrate` | `migrateMain` | Embed missing/stale sidecars, import from Claude Code |\n| `commonplace graph` | `graphMain` | Graph operations (DAR-933) |\n\n```mermaid\ngraph TD\n    A[commonplace CLI] --> B{First arg}\n    B -->|graph| C[graphMain]\n    B -->|migrate| D[migrateMain]\n    B -->|unknown| E[Error: unknown subcommand]\n    \n    C --> F[embedderFactory]\n    D --> F\n    F --> G[MemoryStore.scan]\n```\n\nThe embedder is constructed via a lazy factory to avoid model loading until needed. 资料来源：[src/index.ts]()\n\n### Migration Modes\n\n**Scan/Embed Pass**:\n1. Load all `.md` files\n2. For each, check if `.embedding` sidecar is fresh\n3. Re-embed stale or missing sidecars\n4. Remove orphan sidecars (`.embedding` with no matching `.md`)\n\n**Import from Claude Code**:\n1. Detect `~/.claude/projects/*/memory/*.md` files\n2. Copy non-colliding files to `COMMONPLACE_USER_DIR`\n3. Run scan/embed pass on imported files\n\n资料来源：[src/cli/migrate.ts]()\n\n## MCP Server Integration\n\nThe MCP handlers expose memory operations as tools:\n\n| Tool | Scope | Description |\n|------|-------|-------------|\n| `memory_save` | user/project | Save memory with auto-embed |\n| `memory_search` | user/project | Semantic search with optional graph expansion |\n| `memory_list` | user/project | List memories by type filter |\n| `memory_read` | user/project | Retrieve single memory |\n| `memory_delete` | user/project | Delete memory and sidecar |\n| `memory_link` | user/project | Create graph edge |\n| `memory_unlink` | user/project | Remove graph edge |\n| `memory_path` | user/project | Get filesystem path for memory |\n\n资料来源：[README.md](), [src/server/handlers.ts]()\n\n### Search Result Structure\n\n```typescript\nexport interface MemorySearchMatch {\n  name: string;\n  type: MemoryType;\n  description: string;\n  body: string;        // Full body, never truncated\n  score: number;       // Cosine similarity, 3 decimals\n  relations: Relation[];\n}\n```\n\nThe body is returned verbatim per DAR-920 ac-3 — no truncation, summarization, or transformation. 资料来源：[src/server/handlers.ts:35-50]()\n\n## Data Flow Summary\n\n```mermaid\ngraph TD\n    subgraph External[\"External Consumers\"]\n        MCP[MCP Tools]\n        CLI[CLI Commands]\n    end\n    \n    subgraph Core[\"MemoryStore Core\"]\n        Index[in-memory index]\n        Graph[MemoryGraph]\n        Embedder[Embedder]\n    end\n    \n    subgraph Persistence[\"Persistence Layer\"]\n        Files[.md files]\n        Sidecars[.embedding sidecars]\n        Locks[.locks/ directory]\n    end\n    \n    MCP --> Core\n    CLI --> Core\n    Core --> Index\n    Core --> Graph\n    Core --> Embedder\n    Index --> Files\n    Index --> Sidecars\n    Core --> Locks\n```\n\n## Key Design Decisions\n\n| Decision | Rationale |\n|----------|------------|\n| Markdown as source of truth | Human-readable, version-control friendly, no lock-in |\n| SHA-256 content hash | Deterministic identity for embedding invalidation |\n| Graph fields excluded from sha | Adding/removing edges doesn't invalidate embeddings |\n| Dual-store architecture | Separates personal context from project-specific knowledge |\n| Atomic writes + advisory locks | Safe concurrent access without database |\n| Lazy embedder factory | Avoid expensive model loading on non-embed subcommands |\n\n资料来源：[src/store/memory.ts:contentSha](), [CLAUDE.md]()\n\n---\n\n<a id='project-structure'></a>\n\n## Project Structure\n\n### 相关页面\n\n相关主题：[System Architecture](#system-architecture), [Memory Store](#memory-store)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\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/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n- [src/store/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [CONTRIBUTING.md](https://github.com/rickbassham/commonplace/blob/main/CONTRIBUTING.md)\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n</details>\n\n# Project Structure\n\n## Overview\n\nCommonplace is a personal knowledge management system designed for AI agents operating via Claude Code. It provides persistent memory storage through markdown files with YAML frontmatter, vector embeddings for semantic search, and a graph structure for tracking relationships between memories.\n\nThe project is structured as a Node.js CLI application with an MCP (Model Context Protocol) server component. 资料来源：[src/index.ts:1-25]()\n\n## Directory Layout\n\n```\ncommonplace/\n├── src/\n│   ├── index.ts              # CLI entry point and dispatcher\n│   ├── bin/\n│   │   ├── boot.ts           # Boot process for MCP server\n│   │   └── commonplace-mcp.ts # MCP server stdio interface\n│   ├── cli/\n│   │   ├── migrate.ts         # Migration command implementation\n│   │   └── graph.ts           # Graph query command\n│   ├── server/\n│   │   └── server.ts          # MCP protocol server\n│   ├── store/\n│   │   ├── memory-store.ts    # Core memory management\n│   │   ├── memory.ts          # Memory I/O and serialization\n│   │   ├── atomic-write.ts    # Atomic file operations\n│   │   └── mentions.ts        # [[name]] mention extraction\n│   └── embedder/\n│       └── index.ts           # Vector embedding generation\n├── package.json\n└── tsconfig.json\n```\n\n## Entry Points\n\nThe project declares two bin entries in `package.json`:\n\n| Bin Name | Target | Purpose |\n|----------|--------|---------|\n| `commonplace` | `dist/index.js` | Human-readable CLI output for migrate and graph commands |\n| `commonplace-mcp` | `dist/bin/commonplace-mcp.js` | Stdio MCP server for AI tool integration |\n\n资料来源：[src/index.ts:25-40]()\n\nThe deliberate separation ensures the MCP server's JSON-RPC framing is never polluted by CLI output. 资料来源：[src/index.ts:42-45]()\n\n## CLI Dispatcher\n\nThe main CLI entry point (`src/index.ts`) acts as a subcommand router. It supports two primary command paths:\n\n1. **`commonplace migrate`** — Detect known external memory sources and import memories\n2. **`commonplace migrate <dir>`** — Rebuild sidecars for an existing memory directory\n3. **`commonplace graph`** — Query memory relationship graph 资料来源：[src/index.ts:54-77]()\n\n```mermaid\ngraph TD\n    A[commonplace CLI] --> B{Subcommand?}\n    B -->|graph| C[graphMain]\n    B -->|migrate| D{Args?}\n    D -->|detect mode| E[detectImportSources]\n    D -->|import mode| F[runImportFromClaudeCode]\n    D -->|rebuild mode| G[migrateMain]\n```\n\nThe dispatcher uses lazy embedder instantiation — the `Embedder` (which triggers model loading) is only constructed when migrateMain decides to run after argument parsing succeeds. 资料来源：[src/index.ts:63-69]()\n\n## Core Modules\n\n### MemoryStore (`src/store/memory-store.ts`)\n\nThe `MemoryStore` class is the central orchestration component for memory management. It maintains:\n\n- An in-memory index of all loaded memories\n- A directory watcher for detecting changes\n- An optional `MemoryGraph` for relationship tracking\n- A lazy embedder factory for generating vector embeddings\n\nKey responsibilities include scanning directories, managing embedding sidecars, handling atomic writes, and processing graph edges. 资料来源：[src/store/memory-store.ts:1-50]()\n\nThe store implements a lazy-scanning pattern where the directory is scanned on first access, and subsequent operations use the cached in-memory index with mtime-based invalidation. 资料来源：[src/store/memory-store.ts:150-180]()\n\n### Memory I/O (`src/store/memory.ts`)\n\nThe `memory.ts` module handles the serialization and deserialization of individual memory files. Each memory consists of:\n\n**YAML Frontmatter:**\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**Content Hashing:**\nThe module exports `contentSha()` which computes a SHA-256 digest of the canonical form: `${type}\\n${name}\\n${description}\\n${body}`. This hash is used to detect content changes without embedding sidecars. 资料来源：[src/store/memory.ts:45-55]()\n\nThe hash deliberately excludes `relations` and `supersedes` fields — graph edges must not invalidate embeddings. 资料来源：[src/store/memory.ts:56-62]()\n\n### Atomic Write (`src/store/atomic-write.ts`)\n\nThe `atomicWrite()` function provides safe file writes using a temp-file-and-rename pattern:\n\n1. Generate a random tmp file name with 16 hex chars of entropy\n2. Verify source and destination are on the same filesystem\n3. Write data to tmp file\n4. Rename tmp file to target path 资料来源：[src/store/atomic-write.ts:1-20]()\n\nThe same-filesystem guard prevents cross-filesystem atomic rename failures which would break the atomicity guarantee. 资料来源：[src/store/atomic-write.ts:21-27]()\n\n### Mention Extraction (`src/store/mentions.ts`)\n\nThe `mentions.ts` module extracts `[[name]]` wiki-style references from memory bodies. It provides a pure tokenizer that:\n\n- Returns unique mention targets in first-occurrence order\n- Validates names against `^[a-z0-9_]+$` (same pattern as memory filenames)\n- Is gated by `COMMONPLACE_EXTRACT_MENTIONS` env var (defaults to on)\n\nThe extracted mentions are forwarded to `MemoryGraph.addMentionsEdge` during `scan()` and `save()` operations. 资料来源：[src/store/mentions.ts:1-30]()\n\n## Memory Scopes\n\nCommonplace supports two memory stores that can be loaded simultaneously:\n\n| Scope | Location | Purpose |\n|-------|----------|---------|\n| User | `~/.commonplace/memory` (default) | Personal rules, preferences, hard feedback |\n| Project | `<project-root>/.commonplace/memory` | Per-project context, architecture notes |\n\nDetection priority:\n1. `COMMONPLACE_PROJECT_DIR` env var (explicit override)\n2. MCP `roots/list` protocol detection\n3. Current working directory scan 资料来源：[README.md:120-145]()\n\nSearch operations merge hits across both stores by descending score, with each match tagged with its originating scope. 资料来源：[README.md:140-145]()\n\n## Embedding Pipeline\n\nEmbeddings are generated using transformers.js and stored as binary sidecar files (`.embedding`). The sidecar format includes:\n\n- Magic bytes and version header\n- Model ID and dimensions\n- Content SHA for staleness detection\n- Binary vector data 资料来源：[src/store/memory-store.ts:200-230]()\n\nSidecar freshness is validated by checking:\n1. File exists and decodes correctly\n2. `modelId` matches current embedder\n3. `dim` matches current embedder dimensions\n4. `contentSha` matches computed hash of current file 资料来源：[src/store/memory-store.ts:200-220]()\n\n## Migration CLI (`src/cli/migrate.ts`)\n\nThe migrate command performs one-shot maintenance on memory directories:\n\n```mermaid\ngraph LR\n    A[Scan .md files] --> B{Embedding check}\n    B -->|Missing| C[Generate embedding]\n    B -->|Stale| D[Re-generate embedding]\n    B -->|Fresh| E[Use cached]\n    C --> F[Write .embedding sidecar]\n    D --> F\n    E --> G[Orphan cleanup]\n    F --> G\n    G --> H[Optional: prune dangling edges]\n```\n\nOperations include:\n- **Embed new files** — Generate `.embedding` for new memories\n- **Re-embed stale files** — Regenerate when content or model changes\n- **Orphan cleanup** — Remove `.embedding` files with no matching `.md`\n- **Dangling edge pruning** — Remove `relations`/`supersedes` pointing to non-existent memories 资料来源：[src/cli/migrate.ts:1-40]()\n\n## MCP Server Architecture\n\nThe MCP server component provides AI tool access to memory operations:\n\n| Tool | Purpose |\n|------|---------|\n| `memory_save` | Create/update memories with YAML frontmatter |\n| `memory_search` | Semantic vector search across stores |\n| `memory_list` | List memories by type/scope |\n| `memory_path` | Find paths between memories via graph traversal |\n\nThe server uses stdio for communication, keeping its output channel separate from the human-readable CLI to prevent JSON-RPC framing pollution. 资料来源：[src/index.ts:42-45]()\n\n## Workflow Summary\n\n```mermaid\ngraph TD\n    subgraph \"CLI Path\"\n        A1[commonplace migrate] --> A2[Argument parsing]\n        A2 --> A3[Lazy embedder creation]\n        A3 --> A4[scan/detect/import]\n    end\n    \n    subgraph \"MCP Path\"\n        B1[commonplace-mcp] --> B2[Stdio server loop]\n        B2 --> B3[Tool request]\n        B3 --> B4[MemoryStore operations]\n        B4 --> B5[JSON-RPC response]\n    end\n    \n    subgraph \"Shared Core\"\n        C1[MemoryStore] --> C2[memory.ts I/O]\n        C1 --> C3[atomic-write.ts]\n        C1 --> C4[MemoryGraph]\n    end\n    \n    A4 --> C1\n    B4 --> C1\n```\n\n## Memory Types\n\nThe system uses a four-element type taxonomy:\n\n| Type | Description |\n|------|-------------|\n| `user` | Personal rules, preferences, identity facts |\n| `feedback` | Corrections and lessons from prior agent behavior |\n| `project` | Per-project context, architecture, conventions |\n| `reference` | Durable neutral knowledge, API shapes, citations |\n\nThese types are enforced in YAML frontmatter and validated by the serialization layer. 资料来源：[README.md:45-65]()\n\n## Build and CI\n\nThe project uses pnpm with the following make targets for CI validation:\n\n| Target | Purpose |\n|--------|---------|\n| `make typecheck` | TypeScript type checking |\n| `make lint` | Code linting |\n| `make build` | Compile TypeScript |\n| `make test` | Run test suite |\n| `make audit` | Security audit (non-blocking for v0.1) |\n\nAll targets must pass on both Node 20 and Node 22 before PR merge. 资料来源：[CONTRIBUTING.md:20-30]()\n\n---\n\n<a id='memory-data-model'></a>\n\n## Memory Data Model\n\n### 相关页面\n\n相关主题：[Memory Types Taxonomy](#memory-types-taxonomy), [Memory Store](#memory-store), [Embedding System](#embedding-system)\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- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/server/tools.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/tools.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</details>\n\n# Memory Data Model\n\nThe Memory Data Model is the core abstraction in Commonplace—a local-first knowledge management system that persists memories as plain Markdown files with typed YAML frontmatter. Each memory represents a discrete unit of knowledge, preference, or context that the agent can recall, search, and link to other memories.\n\n## Overview\n\nMemories are the atomic units of the Commonplace system. They are stored as `.md` files on disk where each file contains:\n\n1. **YAML frontmatter** carrying typed metadata\n2. **Markdown body** containing the actual knowledge content\n\nThe design philosophy treats the markdown file as the source of truth. Derived artifacts (such as `.embedding` sidecars) can be regenerated from the markdown at any time. 资料来源：[CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n\n```mermaid\ngraph LR\n    A[Memory Input] --> B[YAML Frontmatter]\n    A --> C[Markdown Body]\n    B --> D[.md File]\n    C --> D\n    D --> E[.embedding Sidecar]\n    D --> F[Search Index]\n    D --> G[Graph Edges]\n```\n\n## Memory Types\n\nCommonplace defines a four-element taxonomy for categorizing memories. Every memory must declare its type in the frontmatter. 资料来源：[README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n\n| Type | Description | Use Case |\n|------|-------------|----------|\n| `user` | Personal rules, preferences, and identity facts about the human operator | Storing user preferences, communication style, work habits |\n| `feedback` | Corrections and lessons learned from prior agent behavior | Persistent course-corrections, things that didn't work |\n| `project` | Per-project context | Architecture notes, repo conventions, decisions that bind to one codebase |\n| `reference` | Durable, neutral knowledge | API shapes, formulas, citations, lookup-by-meaning content |\n\n### Type Constraints\n\nThe `type` field is mandatory and validated against the allowed set. Attempting to save a memory with an invalid type throws an error:\n\n```typescript\nif (!isMemoryType(memory.type)) {\n  throw new Error(\n    `memory.type must be one of ${MEMORY_TYPES.join(', ')}; got ${JSON.stringify(memory.type)}`,\n  );\n}\n```\n\n资料来源：[src/store/memory.ts:parseMemory](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n## Memory Structure\n\n### TypeScript Interface\n\n```typescript\ninterface Memory {\n  name: string;\n  description: string;\n  type: MemoryType;\n  body: string;\n  relations: Relation[];\n  supersedes: string[];\n}\n```\n\n### Frontmatter Schema\n\nEach memory file follows this YAML frontmatter structure:\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: other_memory_name\n    type: builds-on\nsupersedes:\n  - old_memory_name\n---\n<markdown body content>\n```\n\n资料来源：[src/store/memory.ts:serializeMemory](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n### Field Specifications\n\n| Field | Type | Required | Validation |\n|-------|------|----------|------------|\n| `name` | string | Yes | Must match `^[a-z0-9_]+$`; becomes the filename stem |\n| `description` | string | Yes | Short human-readable summary |\n| `type` | enum | Yes | One of: `user`, `feedback`, `project`, `reference` |\n| `body` | string | Yes | Arbitrary markdown content |\n| `relations` | Relation[] | No | Defaults to `[]`; typed graph edges |\n| `supersedes` | string[] | No | Defaults to `[]`; names of superseded memories |\n\n## Name Validation\n\nMemory names must conform to the pattern `^[a-z0-9_]+$` (lowercase alphanumeric characters and underscores only). This restriction ensures:\n\n- Names are filesystem-safe (no path separators)\n- Names work consistently across storage backends\n- Mention extraction (`[[name]]`) has predictable matching\n\n```typescript\nexport const NAME_PATTERN = /^[a-z0-9_]+$/;\n\nconst validateName = (raw: unknown, ctx: string): string => {\n  if (typeof raw !== 'string') {\n    throw new Error(`${ctx} must be a non-empty string; got ${JSON.stringify(raw)}`);\n  }\n  if (!NAME_PATTERN.test(raw)) {\n    throw new Error(\n      `${ctx} must match ${NAME_PATTERN}; got ${JSON.stringify(raw)}`,\n    );\n  }\n  return raw;\n};\n```\n\n资料来源：[src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n## Relation Model (DAR-925)\n\nThe `relations` field enables explicit typed edges between memories, forming a graph structure. 资料来源：[src/store/memory.ts:parseRelations](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n### Relation Types\n\n| Type | Semantics | Default in Search? |\n|------|-----------|-------------------|\n| `builds-on` | This memory extends or depends on another | Yes |\n| `related-to` | Topic or context overlap with another memory | Yes |\n| `contradicts` | This memory contradicts another | No |\n| `child-of` | Hierarchical parent relationship | No |\n| `mentions` | Body content references another memory | No |\n| `supersedes` | This memory replaces another (via `supersedes` field) | No |\n\nThe default expand types for search results are `['builds-on', 'related-to']`. These are the edge types most likely to surface useful neighbors the agent did not explicitly request. 资料来源：[src/server/handlers.ts:DEFAULT_EXPAND_TYPES](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n\n### Relation Validation\n\nRelations are validated during parse and write operations:\n\n- Each entry must be a mapping with `to` and `type` keys\n- The `to` value must be a valid memory name\n- The `type` value must be one of the allowed relation types\n- Duplicate `(to, type)` pairs are deduplicated preserving first-occurrence order\n- Self-referential relations (`to === memory.name`) are rejected\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:parseRelation](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n## Content SHA (Canonicalization)\n\nThe `contentSha` function computes a SHA-256 hex digest that serves as a canonical identifier for memory content. This digest is used to determine when embeddings need regeneration.\n\n### Canonical Form\n\nThe SHA is computed over the concatenation of:\n\n```\n${type}\\n${name}\\n${description}\\n${body}\n```\n\n### Critical Design Decision\n\n**Graph fields (`relations` and `supersedes`) do NOT participate in the SHA computation.** Adding or removing graph edges does not invalidate the corresponding embedding sidecar. This means:\n\n- Embeddings are based on semantic content only\n- Graph operations are lightweight and don't trigger re-embedding\n- The `contentSha` remains stable across graph modifications\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:contentSha](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n## Serialization and Parsing\n\n### Serialization (`serializeMemory`)\n\nThe `serializeMemory` function converts an in-memory `Memory` object to its canonical UTF-8 markdown representation:\n\n1. Validates the memory type\n2. Parses and deduplicates relations and supersedes\n3. Rejects self-referential relations\n4. Serializes YAML frontmatter followed by the body\n\n```typescript\nexport const serializeMemory = (memory: Memory): string => {\n  if (!isMemoryType(memory.type)) {\n    throw new Error(\n      `memory.type must be one of ${MEMORY_TYPES.join(', ')}; got ${JSON.stringify(memory.type)}`,\n    );\n  }\n  const relations = parseRelations(memory.relations);\n  const supersedes = parseSupersedes(memory.supersedes);\n  // ... validation checks ...\n  const fmObject = {\n    name: memory.name,\n    description: memory.description,\n    type: memory.type,\n    ...(relations.length > 0 ? { relations } : {}),\n    ...(supersedes.length > 0 ? { supersedes } : {}),\n  };\n  const fmYaml = stringifyYaml(fmObject);\n  return `---\\n${fmYaml}---\\n${memory.body}`;\n};\n```\n\n资料来源：[src/store/memory.ts:serializeMemory](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n### Parsing (`parseMemory`)\n\nThe `parseMemory` function reads a markdown file and extracts the typed memory object:\n\n1. Splits on `\\n---\\n` to separate frontmatter from body\n2. Parses YAML frontmatter using `parseYaml`\n3. Validates required fields (`name`, `description`, `type`)\n4. Parses optional `relations` and `supersedes` arrays\n5. Rejects unknown frontmatter fields\n\n```typescript\nexport const parseMemory = (raw: string): Memory => {\n  // Splits on the first `---` boundary\n  const fmEnd = raw.indexOf('\\n---', 4);\n  const fmRaw = raw.slice(4, fmEnd);\n  const body = raw.slice(fmEnd + 4).replace(/^\\n/, '');\n  const fmObject = parseYaml(fmRaw);\n  // ... field extraction and validation ...\n  return { name, description, type: type as MemoryType, body, relations, supersedes };\n};\n```\n\n资料来源：[src/store/memory.ts:parseMemory](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n## Memory Store Architecture\n\nThe `MemoryStore` class manages a directory of memory files and their associated sidecars. 资料来源：[src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n\n```mermaid\ngraph TD\n    subgraph MemoryStore\n        A[Directory] --> B[scan]\n        A --> C[save]\n        A --> D[delete]\n        A --> E[linkEdge]\n        A --> F[unlinkEdge]\n    end\n    B --> G[Memory Entry]\n    C --> H[serializeMemory]\n    C --> I[atomicWrite]\n    E --> J[parseMemory]\n    E --> K[serializeMemory]\n    G --> L[contentSha]\n    G --> M[Embedding Sidecar]\n```\n\n### Key Operations\n\n| Operation | Description |\n|-----------|-------------|\n| `scan()` | Discovers all `.md` files, validates/reuses/regenerates `.embedding` sidecars, removes orphans |\n| `save()` | Creates new memory file with atomic write; refuses to overwrite |\n| `delete()` | Removes memory file and sidecar |\n| `linkEdge()` | Adds a typed relation to a memory |\n| `unlinkEdge()` | Removes a typed relation from a memory |\n\n### Orphan Cleanup (DAR-918)\n\nAfter scanning, `scan()` walks the directory again and removes any `.embedding` sidecar whose matching `<name>.md` is missing. This prevents silent accumulation of dead-weight sidecar files. 资料来源：[src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n\n## Mention Extraction (DAR-927)\n\nThe `mentions` module extracts `[[name]]` style references from memory body content. 资料来源：[src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n\n### Extraction Rules\n\n- Only `<name>` tokens matching `^[a-z0-9_]+$` are recognized\n- Other patterns are silently ignored\n- Mentions are forwarded to `MemoryGraph.addMentionsEdge`\n- Extraction is gated by `COMMONPLACE_EXTRACT_MENTIONS` env var (default: on)\n\n### Out of Scope\n\n- Wiki-style backlink rendering or autocomplete\n- Code-fence or inline-code awareness (mentions in code blocks are extracted like any other)\n- Surfacing mentions through MCP tool responses\n\n## Multi-Store Design\n\nCommonplace supports two memory stores with different scopes: 资料来源：[src/server/tools.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/tools.ts)\n\n| Scope | Location | Purpose |\n|-------|----------|---------|\n| `user` | `COMMONPLACE_USER_DIR` (default: `~/.commonplace`) | Cross-project memories |\n| `project` | Detected project root | Per-project memories |\n\n### Scope Behavior\n\n- **Reads** merge across both stores when `scope` is omitted\n- **Writes** default to `user` when `scope` is omitted\n- **Project store** auto-creates on first `memory_save({ scope: 'project' })`\n- **Deletions** require explicit `scope` when name exists in both stores\n\n## MCP Tool Integration\n\nThe four core memory tools interact with the data model as follows: 资料来源：[src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n\n### memory_save\n\nCreates a new memory file. Validates name, type, and description against the data model constraints.\n\n### memory_list\n\nReturns frontmatter-only entries (name, type, description, scope) without body content.\n\n### memory_search\n\nReturns matches with full body content. Each match includes:\n- `name`, `type`, `description`, `body`\n- `score` (cosine similarity, 3 decimals)\n- `relations` (outgoing authored edges)\n\n### memory_delete\n\nRemoves memory and sidecar. Requires `scope` when name exists in both stores.\n\n### memory_link / memory_unlink\n\nManipulate explicit typed edges without modifying the memory body or triggering re-embedding.\n\n## Write Safety\n\nMemory writes implement several safety guarantees: 资料来源：[src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n\n1. **No Overwrite** - `save()` refuses to overwrite existing entries; callers must `delete()` first\n2. **Atomic Writes** - Uses temp-file + rename pattern (DAR-923)\n3. **Advisory Locking** - Per-name locks prevent racing writers across processes\n4. **Lazy Directory Creation** - Parent directory created recursively on first save to project scope\n\n## Sidecar Format\n\nEach memory may have an associated `.embedding` sidecar file containing:\n\n- Magic number for format detection\n- Version byte\n- Model ID\n- Dimensions\n- `contentSha` for cache validation\n- Binary embedding vector\n\nThe sidecar is derived from the `.md` file and regenerated when:\n- The sidecar is missing or corrupt\n- The `modelId` or `dim` doesn't match the current embedder\n- The `contentSha` doesn't match the current memory content\n\n资料来源：[src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n\n## Summary\n\nThe Memory Data Model provides:\n\n| Aspect | Implementation |\n|--------|---------------|\n| **Storage** | Plain `.md` files with YAML frontmatter |\n| **Metadata** | Name, type, description, relations, supersedes |\n| **Content** | Arbitrary markdown body |\n| **Identification** | SHA-256 over type, name, description, body |\n| **Taxonomy** | Four types: user, feedback, project, reference |\n| **Graph** | Typed relations with six edge types |\n| **Mentions** | `[[name]]` extraction from body content |\n| **Stores** | User-scope and project-scope directories |\n| **Safety** | No-overwrite contract, atomic writes, advisory locks |\n\n---\n\n<a id='memory-types-taxonomy'></a>\n\n## Memory Types Taxonomy\n\n### 相关页面\n\n相关主题：[Memory Data Model](#memory-data-model), [Memory Store](#memory-store), [Semantic Search](#semantic-search)\n\n<details>\n<summary>Source Files Used</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/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- [src/server/tools.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/tools.ts)\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n</details>\n\n# Memory Types Taxonomy\n\n## Overview\n\nThe Memory Types Taxonomy is a four-element classification system that categorizes memories stored in Commonplace. Each memory carries a `type` field that determines its scope, purpose, and how it should be used by the AI agent. This taxonomy enables organized knowledge management across personal rules, learned corrections, project-specific context, and reference materials.\n\nMemory types serve as the primary organizational primitive for the entire system. They appear in YAML frontmatter of markdown files, are validated at write time, and are used to filter search results and graph traversals. Source: [README.md]()\n\n## The Four Memory Types\n\n| Type | Purpose | Scope | Typical Content |\n|------|---------|-------|-----------------|\n| `user` | Personal rules, preferences, and identity facts about the human operator | Cross-project | Operating preferences, name, role, interaction style |\n| `feedback` | Corrections and lessons learned from prior agent behavior | Cross-project | Persistent course-corrections, mistake patterns |\n| `project` | Per-project context specific to one codebase | Single project | Architecture notes, repo conventions, decisions |\n| `reference` | Durable, neutral knowledge | Cross-project | API shapes, formulas, citations, lookup knowledge |\n\nSource: [README.md]()\n\n### User Type\n\nThe `user` type captures information about the human operating the AI agent. This includes personal rules, preferences, identity facts, and operational context that should persist across all projects. Memories of this type represent the agent's understanding of who it is working with and how that person prefers to be addressed or assisted.\n\nExample frontmatter:\n```yaml\n---\nname: user_prefers_typescript\ndescription: Prefers TypeScript over JavaScript for new projects\ntype: user\n---\n```\n\n### Feedback Type\n\nThe `feedback` type stores corrections and lessons learned from prior agent behavior. When an agent makes a mistake or receives guidance, the correction is persisted as a feedback memory to prevent recurrence. These memories represent persistent course-corrections that shape future interactions.\n\n### Project Type\n\nThe `project` type contains information that is specific to a single codebase or repository. Unlike `user` and `feedback` memories which are shared across all projects, `project` memories are isolated to a particular working directory. This type is used for architecture notes, conventions unique to the codebase, and decisions that only apply within that project.\n\n### Reference Type\n\nThe `reference` type holds durable, neutral knowledge that can be looked up by meaning. This includes API documentation, formulas, citations, and any factual information that should persist independently of specific projects or interactions.\n\n## Memory File Structure\n\nEach memory is stored as a markdown file with YAML frontmatter. The frontmatter defines the memory's metadata while the body contains the actual content.\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: project_planning_rules\n    type: builds-on\nsupersedes:\n  - old_scope_rules\n---\n<markdown body content>\n```\n\nSource: [src/store/memory.ts:1-50]()\n\n## Type Validation\n\nThe system enforces strict validation on the `type` field. During save operations, the type is validated against the allowed set. An invalid type results in an error that lists all permitted values:\n\n```\nmemory.type must be one of user, feedback, project, reference; got \"invalid_type\"\n```\n\nSource: [src/store/memory.ts:100-105]()\n\n### Validation Code\n\n```typescript\nexport const isMemoryType = (v: unknown): v is MemoryType =>\n  typeof v === 'string' && (MEMORY_TYPES as readonly string[]).includes(v);\n```\n\nSource: [src/store/memory.ts:60-62]()\n\n## Scope and Store Architecture\n\nThe taxonomy is complemented by a two-tier store architecture that separates memories by scope:\n\n```mermaid\ngraph TD\n    A[Memory Store] --> B[User Store]\n    A --> C[Project Store]\n    B --> D[~/.commonplace/memories/]\n    C --> E[.claude/memories/]\n```\n\nBoth stores accept the same four memory types, but the `project` store is isolated to project-specific memories while the `user` store holds cross-project memories of any type.\n\n### Scope Parameter\n\nWhen saving memories, the `scope` argument determines which store receives the data:\n\n| Scope Value | Target Store | Default |\n|-------------|--------------|---------|\n| `user` | User store (`~/.commonplace/memories/`) | Yes |\n| `project` | Project store (`.claude/memories/`) | No |\n\nSource: [src/server/tools.ts:50-60]()\n\n## Type Usage in API Tools\n\n### memory_save\n\nThe `memory_save` tool requires the `type` parameter:\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `name` | string | Yes | Memory identifier matching `^[a-z0-9_]+$` |\n| `type` | enum | Yes | One of: `user`, `feedback`, `project`, `reference` |\n| `description` | string | Yes | Short human description |\n| `body` | string | Yes | Markdown body content |\n| `scope` | enum | No | `user` (default) or `project` |\n\nSource: [src/server/tools.ts:30-55]()\n\n### memory_list\n\nThe `memory_list` tool returns memories with their type information:\n\n```typescript\ninterface MemoryListResult {\n  memories: Array<{\n    name: string;\n    type: MemoryType;\n    description: string;\n    scope: Scope;\n  }>;\n}\n```\n\nSource: [src/server/handlers.ts:80-90]()\n\n## Type Filtering in Search\n\nWhen searching memories, the system can filter by type. The default search behavior includes all types, but callers can specify a subset:\n\n```typescript\ninterface MemorySearchParams {\n  query: string;\n  types?: MemoryType[];  // Filter by memory types\n  scope?: Scope;         // Filter by user/project store\n}\n```\n\nSource: [src/server/handlers.ts:100-110]()\n\n## Graph Relations by Type\n\nGraph edges between memories are typed, and the default expansion types in graph queries prioritize certain memory types:\n\n```typescript\nexport const DEFAULT_EXPAND_TYPES: readonly EdgeType[] = \n  ['builds-on', 'related-to'] as const;\n```\n\nSource: [src/server/handlers.ts:15-20]()\n\n## Mention Extraction by Type\n\nThe `[[name]]` mention extraction system operates on memory bodies regardless of type. All four memory types support body-mention extraction when the environment variable `COMMONPLACE_EXTRACT_MENTIONS` is set (default: enabled).\n\nSource: [src/store/mentions.ts:20-30]()\n\n## Import and Migration\n\nThe migration system can import memories from Claude Code's auto-memory directories. During import, memories are classified and saved to the appropriate store:\n\n```mermaid\ngraph LR\n    A[Claude Code<br/>auto-memory] --> B[Detect Type]\n    B --> C{Source Type}\n    C -->|project memory| D[Project Store]\n    C -->|other| E[User Store]\n```\n\nSource: [src/cli/migrate.ts:30-60]()\n\n## Best Practices\n\n1. **Use `user` for personal context** - Store facts about the human operator that should persist across all projects.\n\n2. **Use `feedback` for corrections** - Record agent mistakes and guidance to improve future responses.\n\n3. **Use `project` for codebase-specific knowledge** - Keep architecture and convention notes isolated to their relevant repository.\n\n4. **Use `reference` for reusable knowledge** - Store API documentation, formulas, and factual information that can be looked up by meaning.\n\n5. **Validate before saving** - Ensure the type field is valid to avoid runtime errors.\n\n## Related Features\n\n- [Graph Relations](graph-relations) - Edges between memories\n- [Mention Extraction](mentions) - `[[name]]` syntax support\n- [Search API](search) - Querying memories by type\n- [Migration Tools](migration) - Importing from external sources\n\n---\n\n<a id='memory-store'></a>\n\n## Memory Store\n\n### 相关页面\n\n相关主题：[Memory Data Model](#memory-data-model), [Embedding System](#embedding-system), [Semantic Search](#semantic-search)\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/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/store/graph.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/graph.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n- [src/server/tools.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/tools.ts)\n- [CHANGELOG.md](https://github.com/rickbassham/commonplace/blob/main/CHANGELOG.md)\n</details>\n\n# Memory Store\n\nThe Memory Store is the core persistence layer of the Commonplace system. It manages the lifecycle of memory entries—markdown files with YAML frontmatter and binary embedding sidecars—providing atomic writes, concurrent access control, semantic search, and graph-based relationship tracking.\n\n## Overview\n\nThe Memory Store implements a local-first, file-based storage system where each memory is persisted as a `.md` file alongside a derived `.embedding` sidecar. It supports two independent stores (`user` and `project`) and exposes both low-level filesystem operations and high-level search/list functionality through an internal API consumed by the MCP server layer.\n\n**Key characteristics:**\n\n| Characteristic | Description |\n|----------------|-------------|\n| Storage model | Local filesystem with markdown + sidecar files |\n| Concurrency | Per-memory advisory locking via `proper-lockfile` |\n| Atomicity | Write-through-temp-and-rename pattern |\n| Search | Offline semantic search using `transformers.js` + `bge-base-en-v1.5` |\n| Graph | In-memory adjacency list for typed relationships |\n| Mentions | `[[name]]` extraction from body content |\n\n资料来源：[memory-store.ts:1-50]()\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"Memory Store Layer\"\n        MS[MemoryStore]\n        G[MemoryGraph]\n        ATOMIC[atomicWrite]\n        LOCK[acquireNameLock]\n    end\n    \n    subgraph \"Persistence Layer\"\n        FS[FileSystem]\n        MD[*.md Files]\n        EMB[*.embedding Sidecars]\n    end\n    \n    subgraph \"Integration\"\n        HANDLERS[MCP Handlers]\n        SEARCH[Search Handler]\n    end\n    \n    MS --> G\n    MS --> ATOMIC\n    MS --> LOCK\n    ATOMIC --> FS\n    LOCK --> FS\n    MS --> MD\n    MS --> EMB\n    HANDLER_FACTORIES[Handler Factories] --> MS\n    SEARCH --> MS\n```\n\nThe `MemoryStore` class owns the directory-scanning, file I/O, embedding caching, and mtime-based invalidation logic. It delegates locking to `acquireNameLock`, writes to `atomicWrite`, and maintains an optional `MemoryGraph` instance for relationship tracking.\n\n资料来源：[memory-store.ts:50-120]()\n\n## Memory Data Model\n\n### Memory Structure\n\nA memory consists of:\n\n1. **YAML Frontmatter**: Structured metadata\n2. **Markdown Body**: Arbitrary content containing `[[name]]` mention syntax\n\n```typescript\ninterface Memory {\n  name: string;           // Filename stem, matches ^[a-z0-9_]+$\n  description: string;    // Short human description\n  type: MemoryType;       // 'user' | 'feedback' | 'project' | 'reference'\n  body: string;           // Markdown content\n  relations: Relation[];  // Typed graph edges (DAR-925)\n  supersedes: string[];   // Names of superseded memories\n}\n\ninterface Relation {\n  to: string;             // Target memory name\n  type: RelationType;     // 'builds-on' | 'related-to' | 'contradicts' | 'child-of'\n}\n```\n\n资料来源：[memory.ts:1-80]()\n\n### File Format\n\nMemory files use canonical markdown with YAML frontmatter:\n\n```markdown\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: project_context\n    type: builds-on\nsupersedes:\n  - old_feedback\n---\n<body content here>\n```\n\nThe frontmatter is canonicalized by `stringifyYaml` to ensure round-trip idempotence. The file is the source of truth; sidecars are derived.\n\n资料来源：[memory.ts:80-120]()\n\n### Content Hashing\n\nThe `contentSha` function computes a deterministic SHA-256 digest used for sidecar validation:\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**Important**: The sha covers only the v0.1 baseline frontmatter (`type`, `name`, `description`) plus the body. Graph fields (`relations`, `supersedes`) are excluded to prevent embedding invalidation when edges change.\n\n资料来源：[memory.ts:140-155]()\n\n## Core Operations\n\n### Initialization\n\n```typescript\nclass MemoryStore {\n  constructor(\n    dir: string,\n    embedder: Embedder,\n    graph?: MemoryGraph,\n    lockOptions?: LockOptions\n  )\n}\n```\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `dir` | `string` | Path to the memory directory |\n| `embedder` | `Embedder` | Embedding pipeline (model ID, dimension, encode function) |\n| `graph` | `MemoryGraph?` | Optional graph instance for relationship tracking |\n| `lockOptions` | `LockOptions?` | Lock staleness and retry configuration |\n\nThe constructor stores the embedder reference for lazy re-embedding and initializes in-memory state. The directory is created lazily on first save.\n\n资料来源：[memory-store.ts:50-80]()\n\n### Scan Operation\n\nThe `scan()` method rebuilds the in-memory index from disk:\n\n```typescript\nasync scan(opts?: ScanOptions): Promise<ScanResult>\n```\n\n**Behavior:**\n1. Walk the directory for `*.md` files\n2. For each file, check if the matching `*.embedding` sidecar is reusable based on:\n   - Magic + version + length checks\n   - `modelId` match\n   - Dimension match\n   - `contentSha` match\n3. Re-embed and rewrite sidecar when stale\n4. Remove orphan sidecars (files with no matching `.md`)\n\n| Sidecar Check | Fresh If... |\n|---------------|-------------|\n| File exists | Yes |\n| Decodes correctly | Yes |\n| `modelId` matches | Yes |\n| `dim` matches | Yes |\n| `contentSha` matches | Yes |\n\n资料来源：[memory-store.ts:150-250]()\n\n### Save Operation\n\n```typescript\nasync save(name: string, memory: Memory): Promise<void>\n```\n\n**Workflow:**\n\n```mermaid\ngraph TD\n    START[save called] --> CHECK_EXISTS{existsSync<br/>${name}.md?}\n    CHECK_EXISTS -->|No| MKDIR[mkdir -p dir]\n    CHECK_EXISTS -->|Yes| ERROR[Error: exists]\n    MKDIR --> LOCK[acquireNameLock]\n    LOCK --> RE_CHECK{existsSync<br/>${name}.md?}\n    RE_CHECK -->|Yes| RELEASE[Release lock]\n    RE_CHECK -->|No| SERIALIZE[serializeMemory]\n    SERIALIZE --> EMBED[embed body]\n    EMBED --> ATOMIC_WRITE_MD[atomicWrite<br/>${name}.md]\n    ATOMIC_WRITE_MD --> ATOMIC_WRITE_EMB[atomicWrite<br/>${name}.embedding]\n    ATOMIC_WRITE_EMB --> UPDATE_INDEX[Update in-memory index]\n    UPDATE_INDEX --> RELEASE\n    RELEASE --> DONE[Return]\n    ERROR --> ABORT[Throw]\n```\n\n**Key behaviors:**\n- Refuses to overwrite existing entries (delete first, then save)\n- Lazily creates directory on first save\n- Holds per-name advisory lock for entire write operation\n- Uses atomic write for both `.md` and `.embedding`\n\n资料来源：[memory-store.ts:280-380]()\n\n### Search Operation\n\n```typescript\nasync search(query: string, opts?: SearchOptions): Promise<MemorySearchResult>\n```\n\n**Search options:**\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `type` | `MemoryType?` | undefined | Filter by memory type |\n| `limit` | `number` | 20 | Maximum results |\n| `expandTypes` | `EdgeType[]` | `['builds-on', 'related-to']` | Edge types to include |\n| `minScore` | `number` | 0 | Minimum similarity score |\n\nThe search computes query embeddings via the embedder, performs brute-force top-k cosine similarity against all loaded memories, and enriches results with outgoing graph edges. Superseded memories are excluded by default.\n\n资料来源：[memory-store.ts:380-450](), [handlers.ts:80-120]()\n\n### Delete Operation\n\n```typescript\nasync delete(name: string, opts?: DeleteOptions): Promise<void>\n```\n\n```mermaid\ngraph TD\n    START[delete called] --> LOCK[acquireNameLock]\n    LOCK --> UNLINK_MD[unlinkSync<br/>${name}.md]\n    UNLINK_MD --> UNLINK_EMB[unlinkSync<br/>${name}.embedding]\n    UNLINK_EMB --> REMOVE_INDEX[Remove from in-memory index]\n    REMOVE_INDEX --> GRAPH_REMOVE[graph.remove<br/>if exists]\n    GRAPH_REMOVE --> RELEASE[Release lock]\n    RELEASE --> DONE\n```\n\n资料来源：[memory-store.ts:450-500]()\n\n### List Operation\n\n```typescript\nasync list(opts?: ListOptions): Promise<MemoryListResult>\n```\n\nReturns frontmatter-only entries (name, type, description, scope) without body content. Filters can be applied by type.\n\n资料来源：[memory-store.ts:500-550](), [handlers.ts:150-180]()\n\n## Atomic Write Mechanism\n\nThe `atomicWrite` helper implements the write-through-temp-and-rename pattern:\n\n```typescript\nexport const atomicWrite = async (\n  target: string,\n  data: Buffer | Uint8Array\n): Promise<void>\n```\n\n**Algorithm:**\n\n```mermaid\ngraph TD\n    START[atomicWrite] --> TMP[Generate tmp filename]\n    TMP --> STAT_TMP[stat tmp parent]\n    STAT_TMP --> CHECK_FS{same filesystem?}\n    CHECK_FS -->|No| ERROR[Error: cross-fs]\n    CHECK_FS -->|Yes| WRITE[writeFileSync tmp]\n    WRITE --> FSYNC[fsync tmp file]\n    FSYNC --> RENAME[renameSync tmp → target]\n    RENAME --> DONE\n```\n\n**Safety guarantees:**\n- Same-filesystem check via `dev` comparison prevents cross-fs rename\n- Random 16-char hex suffix prevents collision\n- `fsync` before rename ensures durability\n- Failure during write leaves original file untouched\n\n资料来源：[atomic-write.ts:1-60]()\n\n## Concurrency Control\n\n### Per-Memory Locking\n\nThe `acquireNameLock` function uses `proper-lockfile` for advisory locking:\n\n```typescript\nconst acquireNameLock = async (\n  dir: string,\n  name: string\n): Promise<() => Promise<void>>\n```\n\n**Configuration:**\n\n| Option | Value | Purpose |\n|--------|-------|---------|\n| `stale` | 5000ms | Reclaim orphaned locks from crashed holders |\n| `realpath` | `false` | Works before file exists |\n| `retries` | configurable | Retry on transient lock acquisition failure |\n\n**Lock target pattern:** `${dir}/.locks/${name}.lock`\n\nThe lock is held for the entire save operation (both `.md` and `.embedding` writes), serializing concurrent writers on the same memory name across processes.\n\n资料来源：[memory-store.ts:120-170]()\n\n## Graph Integration\n\nThe `MemoryStore` optionally owns a `MemoryGraph` instance for tracking relationships:\n\n```typescript\nclass MemoryGraph {\n  add(memory: GraphMemory): void\n  addEdge(edge: Edge): void\n  remove(name: string): void\n  getOutbound(name: string): Edge[]\n  getInbound(name: string): Edge[]\n  detectDangling(): Edge[]\n  rebuild(memories: GraphMemory[], mentions: Mention[]): void\n}\n```\n\n**Edge types:**\n| Type | Default Included | Description |\n|------|------------------|--------------|\n| `builds-on` | Yes | Forward dependency |\n| `related-to` | Yes | General association |\n| `mentions` | No | Body `[[name]]` extraction |\n| `supersedes` | No | Replacement relationship |\n| `contradicts` | No | Contradictory memory |\n| `child-of` | No | Hierarchical relationship |\n\n资料来源：[graph.ts:1-80](), [handlers.ts:40-60]()\n\n## Mention Extraction\n\nThe `extractMentions` function parses `[[name]]` tokens from body content:\n\n```typescript\nexport const extractMentions(body: string): string[]\n```\n\n**Rules:**\n- Matches `<name>` tokens with pattern `^[a-z0-9_]+$`\n- Returns unique set in first-occurrence order\n- Extraction can be disabled via `COMMONPLACE_EXTRACT_MENTIONS=false`\n\nThe MemoryStore calls `extractMentions` during `scan()` and `save()`, forwarding results to `MemoryGraph.addMentionsEdge`.\n\n资料来源：[mentions.ts:1-50]()\n\n## MCP Tool Integration\n\nThe MemoryStore is consumed by MCP handler factories in `handlers.ts`:\n\n| Handler Factory | MCP Tool | Operation |\n|-----------------|----------|-----------|\n| `createMemorySaveHandler` | `memory_save` | Save new memory |\n| `createMemoryListHandler` | `memory_list` | List memories |\n| `createMemoryDeleteHandler` | `memory_delete` | Delete memory |\n| `createMemorySearchHandler` | `memory_search` | Semantic search |\n| `createMemoryLinkHandler` | `memory_link` | Add graph edge |\n| `createMemoryUnlinkHandler` | `memory_unlink` | Remove graph edge |\n\nAll handlers accept an optional `scope: 'user' | 'project'` argument that selects which store to operate on.\n\n资料来源：[handlers.ts:180-300](), [tools.ts:1-100]()\n\n## Configuration\n\n### Directory Configuration\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `COMMONPLACE_USER_DIR` | `~/.config/commonplace` | User store directory |\n| `COMMONPLACE_PROJECT_DIR` | (auto-detected) | Project store directory |\n\n### Feature Flags\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | Enable `[[name]]` extraction |\n\n资料来源：[memory-store.ts:1-50](), [mentions.ts:1-30]()\n\n## Error Handling\n\n| Error Condition | Message | Recovery |\n|-----------------|---------|----------|\n| Duplicate save | `MemoryStore.save: a memory file already exists at ${path}` | Delete first, then save |\n| Lock busy | `MemoryStore: lock for memory \\`${name}\\` is busy` | Retry after other writer releases |\n| Cross-filesystem atomic | `atomicWrite: refusing to rename across filesystems` | Check filesystem layout |\n| Invalid memory type | `memory.type must be one of ${MEMORY_TYPES}` | Validate before save |\n| Self-reference relation | `memory relation target cannot be self` | Remove invalid relation |\n\n资料来源：[memory-store.ts:280-350](), [memory.ts:180-220](), [atomic-write.ts:30-40]()\n\n## Sidecar Format\n\nEmbedding sidecars are binary files with the following structure:\n\n```\n[magic: 4 bytes][version: 1 byte][dim: 4 bytes LE][vector: dim * 4 bytes]\n```\n\n| Field | Size | Description |\n|-------|------|-------------|\n| magic | 4 bytes | Magic bytes for file identification |\n| version | 1 byte | Format version number |\n| dim | 4 bytes | Vector dimension (little-endian) |\n| vector | dim × 4 bytes | Float32 embedding values |\n\n资料来源：[memory-store.ts:200-250]()\n</details>\n\n---\n\n<a id='embedding-system'></a>\n\n## Embedding System\n\n### 相关页面\n\n相关主题：[Memory Store](#memory-store), [Semantic Search](#semantic-search)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/embedder/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/embedder/index.ts)\n- [src/store/sidecar.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/sidecar.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/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.ts)\n- [src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts)\n</details>\n\n# Embedding System\n\nThe embedding system in Commonplace transforms markdown memory content into vector representations stored as sidecar files, enabling semantic search across the memory store. It is designed to treat the `.md` source as the single source of truth, with embeddings as derived, regenerable artifacts.\n\n## Architecture Overview\n\nThe embedding pipeline consists of three primary layers:\n\n1. **Memory Layer** (`src/store/memory.ts`) — parses and serializes markdown with YAML frontmatter, computes canonical content hashes\n2. **Store Layer** (`src/store/memory-store.ts`) — orchestrates the scan/embed lifecycle, validates sidecar freshness, manages orphan cleanup\n3. **Embedder Layer** (`src/embedder/index.ts`) — generates vector embeddings via transformers.js\n\n```mermaid\ngraph TD\n    A[Markdown File] --> B[readMemory]\n    B --> C[contentSha Computation]\n    C --> D[Load Sidecar]\n    D --> E{Sidecar Fresh?}\n    E -->|Yes| F[Skip Embedding]\n    E -->|No| G[Embedder.embed]\n    G --> H[Serialize Sidecar]\n    H --> I[atomicWrite]\n    I --> J[.embedding Sidecar]\n    C -.-> K[body text + frontmatter]\n    F --> L[Use Existing Sidecar]\n```\n\n## Content Hash (contentSha)\n\nThe canonical content hash is computed over a specific slice of the memory's data structure, deliberately excluding graph-related fields to prevent embedding invalidation when relationships change.\n\n### Canonical Hash Inputs\n\n| Field | Included | Rationale |\n|-------|----------|-----------|\n| `type` | ✅ Yes | Memory type affects semantic context |\n| `name` | ✅ Yes | Name is part of semantic identity |\n| `description` | ✅ Yes | Description is semantically meaningful |\n| `body` | ✅ Yes | Full body content |\n| `relations` | ❌ No | Graph edges are derived, not source |\n| `supersedes` | ❌ No | Graph edges are derived, not source |\n\n资料来源：[src/store/memory.ts:contentSha function]()\n\nThe hash formula is:\n```\nsha256(\"${type}\\n${name}\\n${description}\\n${body}\")\n```\n\nThis produces a 64-character lowercase hex string that uniquely identifies the semantic content of a memory.\n\n### SHA Scope Justification\n\nThe graph fields (`relations`, `supersedes`) are intentionally excluded per DAR-925 design decisions. Adding or removing graph edges must not invalidate existing embeddings because:\n\n- Embeddings are derived from semantic content, not graph topology\n- Forcing re-embedding on graph edits would create unnecessary API calls\n- The sidecar is explicitly marked as derived, not authoritative\n\n## Sidecar Format\n\nEmbeddings are stored in `.embedding` sidecar files alongside their corresponding `.md` files. The sidecar encodes sufficient metadata to validate freshness without re-reading the markdown.\n\n### Sidecar Schema\n\n| Field | Type | Purpose |\n|-------|------|---------|\n| `modelId` | string | Identifies the embedding model used |\n| `dim` | number | Embedding vector dimensionality |\n| `contentSha` | string | Hash of canonical content |\n| `embedding` | number[] | The vector data |\n\n资料来源：[src/store/sidecar.ts]()\n\n### Sidecar File Naming\n\nSidecar files follow the naming convention `<name>.embedding` where `<name>` matches the corresponding memory file `<name>.md`. This 1:1 correspondence enables orphan detection.\n\n## Scan Lifecycle\n\nThe `MemoryStore.scan()` method implements the complete embed lifecycle, checking each memory's sidecar for freshness and triggering regeneration when needed.\n\n### Freshness Criteria\n\nA sidecar is considered **fresh** (reusable) when ALL of the following hold:\n\n1. The `.embedding` file exists\n2. It decodes successfully (magic + version + length checks pass)\n3. `decoded.modelId === embedder.modelId`\n4. `decoded.dim === embedder.dim`\n5. `decoded.contentSha === contentSha(memoryAsRead)`\n\n资料来源：[src/store/memory-store.ts:scan method]()\n\nIf ANY criterion fails, the memory is re-embedded and the sidecar rewritten.\n\n### Scan Process\n\n```mermaid\ngraph TD\n    A[Start Scan] --> B[Read all .md files]\n    B --> C{For each memory}\n    C --> D{No sidecar?}\n    D -->|Yes| E[Trigger embed]\n    D -->|No| F{Decode passes?}\n    F -->|No| E\n    F -->|Yes| G{modelId match?}\n    G -->|No| E\n    G -->|Yes| H{dim match?}\n    H -->|No| E\n    H -->|Yes| I{contentSha match?}\n    I -->|Yes| J[Skip - use existing]\n    I -->|No| E\n    C --> K[Orphan Cleanup]\n    K --> L[Remove orphaned .embedding files]\n    E --> M[Write new sidecar]\n    J --> C\n    M --> C\n```\n\n### Orphan Cleanup\n\nAfter processing all memories, scan performs a second directory walk to detect and remove orphan sidecars — `.embedding` files whose matching `.md` no longer exists. Orphans are reported via the `ScanResult.orphaned` field.\n\n资料来源：[src/store/memory-store.ts:orphan cleanup]()\n\n## Atomic Write Strategy\n\nSidecar writes use an atomic write-temp-rename pattern to prevent corruption from partial writes.\n\n### Write Sequence\n\n1. Generate random tmp filename: `<basename>.<8-hex-chars>.tmp`\n2. Write data to tmp file\n3. Verify source and target are on same filesystem (`dev` match)\n4. Rename tmp file to target (atomic on same filesystem)\n\n资料来源：[src/store/atomic-write.ts]()\n\n### Cross-Filesystem Guard\n\n```typescript\nif (targetDirStat.dev !== tmpDirStat.dev) {\n  throw new Error(\"refusing to rename across filesystems\");\n}\n```\n\nThis guard ensures rename operations remain atomic, as rename(2) is not atomic across filesystem boundaries.\n\n## Integration Points\n\n### CLI Entry Point\n\nThe main CLI (`src/index.ts`) wires the embedder factory into the migrate command:\n\n```typescript\nembedderFactory: () => new Embedder(resolveModelId(process.env)),\n```\n\nThe lazy factory ensures the transformers.js model is only loaded when an actual embed call occurs, not during argument parsing.\n\n### Migrate Command\n\nThe `commonplace migrate <dir>` command exposes scan functionality as a standalone tool:\n\n- Re-embeds any `.md` whose sidecar is missing or stale\n- Cleans up orphaned sidecars\n- Optionally prunes dangling graph edges (--prune-dangling flag)\n\n资料来源：[src/cli/migrate.ts:migrateScan]()\n\n## Configuration\n\n### Environment Variables\n\n| Variable | Default | Purpose |\n|----------|---------|---------|\n| `COMMONPLACE_EMBEDDING_MODEL` | model-specific | Embedding model identifier |\n\nThe `resolveModelId()` function reads the environment to determine which embedding model to instantiate.\n\n### Embedder Initialization\n\nThe `Embedder` class is instantiated with the resolved model ID. Model loading (transformers.js) occurs on first `embed()` call, not on construction, enabling lazy initialization.\n\n## Memory Types and Embedding\n\nAll four memory types are embeddable with identical treatment:\n\n| Type | Description | Embedding Behavior |\n|------|-------------|-------------------|\n| `user` | Personal rules and preferences | Standard |\n| `feedback` | Lessons from prior behavior | Standard |\n| `project` | Per-project context | Standard |\n| `reference` | Durable knowledge | Standard |\n\nMemory type is included in the content hash, so type changes trigger re-embedding.\n\n## Summary\n\nThe embedding system provides:\n\n- **Semantic search** via vector embeddings\n- **Source-of-truth isolation** with SHA-scoped content hashes\n- **Automatic regeneration** when content changes\n- **Orphan cleanup** for stale sidecars\n- **Atomic writes** for corruption prevention\n- **Model portability** validation through metadata checks\n\nAll embedding behavior is derived from markdown content; the `.embedding` files are regenerable artifacts that can be deleted and rebuilt via the migrate command at any time.\n\n---\n\n<a id='semantic-search'></a>\n\n## Semantic Search\n\n### 相关页面\n\n相关主题：[Embedding System](#embedding-system), [Graph Features](#graph-features), [MCP Tool Reference](#mcp-tool-reference)\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/graph.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/graph.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.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# Semantic Search\n\nSemantic search enables finding memories by meaning rather than exact keyword matching. The system embeds memory content into high-dimensional vectors and uses cosine similarity to rank results against a query.\n\n## Overview\n\nThe semantic search system consists of three main layers:\n\n1. **Embedding Pipeline** — Converts text into dense vectors using a local transformer model\n2. **Vector Storage** — Binary `.embedding` sidecar files generated from markdown content\n3. **Search Engine** — Cosine similarity ranking across one or both memory stores\n\nMemories are stored as markdown files with YAML frontmatter. Each memory has a corresponding `.embedding` sidecar containing its pre-computed vector representation. The embedding is derived from the canonical memory content and cached until the content changes (detected via SHA-256 hash).\n\n资料来源：[src/store/memory.ts:1-50]()\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"CLI / MCP Layer\"\n        H[handlers.ts]\n    end\n    \n    subgraph \"Store Layer\"\n        MS[MemoryStore]\n        G[MemoryGraph]\n    end\n    \n    subgraph \"I/O Layer\"\n        FS[File System]\n    end\n    \n    subgraph \"Embedding Layer\"\n        E[Embedder]\n        TFM[transformers.js]\n        BGE[bge-base-en-v1.5]\n    end\n    \n    H --> MS\n    MS --> E\n    E --> TFM\n    TFM --> BGE\n    MS <--> G\n    MS <--> FS\n    G -.-> MS\n    \n    style E fill:#e1f5fe\n    style BGE fill:#fff3e0\n```\n\n### Component Responsibilities\n\n| Component | File | Role |\n|-----------|------|------|\n| `MemoryStore` | memory-store.ts | Manages scanning, embedding, and search operations |\n| `Embedder` | embedder.ts | Wraps transformers.js for local inference |\n| `MemoryGraph` | graph.ts | Tracks relations and enriches search results |\n| `handlers.ts` | handlers.ts | MCP tool handler for memory_search |\n\n资料来源：[src/store/memory-store.ts:1-100]()\n\n## Embedding Pipeline\n\n### Model Configuration\n\nThe system uses `bge-base-en-v1.5` from the BGE (BAAI General Embedding) family. This model produces 768-dimensional dense vectors optimized for semantic similarity tasks.\n\n```typescript\n// Resolved from environment: EMBEDDING_MODEL_ID\nconst DEFAULT_MODEL_ID = 'Xenova/bge-base-en-v1.5';\n```\n\nThe embedder runs entirely offline via `@huggingface/transformers` (transformers.js), requiring no external API calls or internet connectivity after the initial model load.\n\n资料来源：[src/store/memory-store.ts:100-150]()\n\n### Embedding Derivation\n\nEmbeddings are derived from the **canonical memory content**, defined as:\n\n```\n${type}\\n${name}\\n${description}\\n${body}\n```\n\nThe SHA-256 hash of this canonical string is computed and compared against stored hashes to detect content changes. This ensures embeddings are regenerated only when necessary.\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${description}\\n${body}`, 'utf8')\n    .digest('hex');\n```\n\n**Important**: Graph fields (`relations`, `supersedes`) do NOT affect the canonical content or embedding. Adding or removing graph edges does not invalidate the embedding sidecar.\n\n资料来源：[src/store/memory.ts:80-100]()\n\n### Sidecar Format\n\nEach memory generates a binary `.embedding` sidecar file in the same directory as the `.md` file:\n\n```\n~/.commonplace/memory/\n├── feedback_scope.md\n├── feedback_scope.embedding  ← binary float32 vectors\n└── architecture.md\n    └── architecture.embedding\n```\n\nThe sidecar is **derived data** — it can be deleted and regenerated at any time from the markdown source.\n\n资料来源：[CLAUDE.md:1-30]()\n\n## Search Workflow\n\n```mermaid\nsequenceDiagram\n    participant C as MCP Client\n    participant H as memory_search Handler\n    participant MS as MemoryStore\n    participant E as Embedder\n    participant FS as File System\n    \n    C->>H: memory_search({ query, k?, scope? })\n    H->>MS: search(query, k, opts)\n    \n    Note over MS: Load user store<br/>+ project store if present\n    \n    MS->>E: embed(query)\n    E->>E: Load model (lazy)\n    E-->>MS: queryVector[768]\n    \n    MS->>FS: Load all .embedding sidecars\n    FS-->>MS: Float32Array vectors\n    \n    loop Per-memory\n        MS->>MS: cosineSimilarity(queryVector, memoryVector)\n    end\n    \n    MS->>G: Filter supersedes, enrich relations\n    G-->>MS: Augmented matches\n    \n    MS-->>H: MemorySearchResult[]\n    H-->>C: JSON response\n```\n\n### Search Flow Details\n\n1. **Query embedding** — The search query is embedded using the same model as memory content\n2. **Vector loading** — All `.embedding` sidecars are loaded into memory (lazy, cached)\n3. **Similarity computation** — Brute-force cosine similarity between query vector and all memory vectors\n4. **Result filtering** — Superseded memories are excluded by default\n5. **Graph enrichment** — Results include outgoing relations from the frontmatter\n\n资料来源：[src/store/memory-store.ts:200-300]()\n\n## Memory Search API\n\n### MCP Tool: `memory_search`\n\nInput schema:\n\n| Argument | Type | Required | Default | Description |\n|----------|------|----------|---------|-------------|\n| `query` | string | Yes | — | Natural language search query |\n| `k` | integer | No | 5 | Maximum number of results to return |\n| `type` | MemoryType | No | — | Filter by memory type (user/feedback/project/reference) |\n| `includeSuperseded` | boolean | No | false | Include memories superseded by others |\n| `expandTypes` | string[] | No | ['builds-on', 'related-to'] | Edge types to include in results |\n| `scope` | 'user' \\| 'project' | No | merged | Which store to search |\n\n### Response Schema\n\n```typescript\ninterface MemorySearchResult {\n  query: string;\n  matches: MemorySearchMatch[];\n  scope: 'user' | 'project' | 'merged';\n}\n\ninterface MemorySearchMatch {\n  name: string;\n  type: MemoryType;\n  description: string;\n  body: string;       // Full body verbatim (never truncated)\n  score: number;      // Cosine similarity, 3 decimals\n  relations: Relation[];  // Outgoing edges from frontmatter\n  scope: 'user' | 'project';\n}\n```\n\n**Note**: The body is never truncated, summarized, or transformed. The caller receives exactly what was persisted.\n\n资料来源：[src/server/handlers.ts:50-120]()\n\n### Default Expand Types\n\nOnly `builds-on` and `related-to` are included by default. Other edge types require explicit opt-in:\n\n```typescript\nexport const DEFAULT_EXPAND_TYPES: readonly EdgeType[] = \n  ['builds-on', 'related-to'] as const;\n```\n\nThis prevents surprising the agent with `mentions`, `supersedes`, `contradicts`, or `child-of` edges unless requested.\n\n资料来源：[src/server/handlers.ts:15-25]()\n\n## Memory Stores and Scoping\n\n### Dual-Store Architecture\n\nThe system supports two independent memory stores:\n\n| Store | Location | Purpose |\n|-------|----------|---------|\n| User Store | `~/.commonplace/memory` (default) | Personal rules, preferences, feedback |\n| Project Store | `<project-root>/.commonplace/memory` | Per-project context |\n\n### Detection Priority\n\nProject store selection follows this priority:\n\n1. `COMMONPLACE_PROJECT_DIR` env var (explicit override)\n2. MCP `roots/list` response\n3. Current working directory\n\nIf none apply, only the user store is loaded.\n\n### Merged Search\n\nWhen `scope` is omitted, search merges results from both stores by descending score. Each match carries a `scope` tag identifying its source.\n\n资料来源：[src/server/handlers.ts:150-200]()\n\n## Scan and Re-embedding\n\n### Trigger Conditions\n\nThe store performs a lazy rescan when:\n\n1. Directory mtime advances past the baseline (new files detected)\n2. Memory is saved (triggers immediate re-embedding)\n\n```typescript\n// MemoryStore.scan() behavior:\n// - Skips if dir mtime hasn't changed (lastScanMtimeMs baseline)\n// - Regenerates embedding for any memory with changed sha\n// - Stores new dir mtime as baseline after scan\n```\n\n### Lazy Re-embedding\n\nOn save, the system:\n1. Computes `contentSha` for the new content\n2. Compares against stored hash\n3. Regenerates embedding only if hash differs\n\nThis avoids redundant model inference for graph-only changes (relation additions/removals).\n\n资料来源：[src/store/memory-store.ts:250-280]()\n\n## Content-Based Mention Extraction\n\nWhile not part of the vector search pipeline, `[[name]]` mentions in body text create graph edges that enrich search results:\n\n```typescript\n// Mention extraction (DAR-927)\n// Scanned during save/scan, not during search\n// Creates 'mentions' edges in MemoryGraph\n```\n\nMention extraction is controlled by `COMMONPLACE_EXTRACT_MENTIONS` env var (default: enabled). Regex pattern matches `<name>` tokens against `^[a-z0-9_]+$`.\n\n资料来源：[src/store/mentions.ts:1-50]()\n\n## Related Features\n\n| Feature | Description |\n|---------|-------------|\n| [Memory List](memory-list) | List memories without semantic scoring |\n| [Memory Graph](memory-graph) | Graph traversal and path finding |\n| [Memory Link/Unlink](memory-link) | Manual edge creation |\n| [Migrate](cli-migrate) | Import from Claude Code auto-memory |\n\n## Configuration Reference\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `EMBEDDING_MODEL_ID` | `Xenova/bge-base-en-v1.5` | HuggingFace model identifier |\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | User store root |\n| `COMMONPLACE_PROJECT_DIR` | — | Project store override |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `true` | Enable `[[name]]` extraction |\n| `COMMONPLACE_EMBED_BATCH_SIZE` | — | Batch size for embedding |\n\n---\n\n<a id='graph-features'></a>\n\n## Graph Features\n\n### 相关页面\n\n相关主题：[Semantic Search](#semantic-search), [MCP Tool Reference](#mcp-tool-reference)\n\n<details>\n<summary>Relevant Source Files</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/cli/graph.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/graph.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/server/tools.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/tools.ts)\n</details>\n\n# Graph Features\n\n## Overview\n\nThe Graph Features system provides a network-based view of memories, enabling relationships between notes to be tracked, queried, and visualized. Rather than treating each memory as an isolated entity, the graph layer exposes connections through authored `relations` in frontmatter, `supersedes` declarations, and automatic `[[name]]` mention extraction from body content.\n\nThe graph is not a separate data store—it derives from the same markdown files that form the memory corpus. Each `.md` file in a memory store may declare outgoing edges via its YAML frontmatter, and the in-memory `MemoryGraph` maintains an adjacency list for efficient traversal.\n\n资料来源：[src/store/graph.ts:1-30]()\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"Memory Sources\"\n        UserStore[\"User Memory Store<br/>(~/.commonplace)\"]\n        ProjectStore[\"Project Memory Store<br/>(./.commonplace)\"]\n    end\n    \n    subgraph \"Graph Layer\"\n        MemoryGraph[\"MemoryGraph\"]\n        AdjacencyList[\"Adjacency List<br/>(Map&lt;name, Edge[]&gt;)\"]\n    end\n    \n    subgraph \"Edge Sources\"\n        Relations[\"relations[]<br/>frontmatter field\"]\n        Supersedes[\"supersedes[]<br/>frontmatter field\"]\n        Mentions[\"[[name]] mentions<br/>body extraction\"]\n    end\n    \n    UserStore --> MemoryGraph\n    ProjectStore --> MemoryGraph\n    MemoryGraph --> AdjacencyList\n    Relations --> MemoryGraph\n    Supersedes --> MemoryGraph\n    Mentions --> MemoryGraph\n```\n\n### Core Components\n\n| Component | File | Purpose |\n|-----------|------|---------|\n| `MemoryGraph` | `src/store/graph.ts` | In-memory graph with adjacency list, edge management, and traversal |\n| `Edge` / `DanglingEdge` | `src/store/graph.ts` | Data models for directed edges |\n| `MemoryStore` | `src/store/memory-store.ts` | Persists graph edges via frontmatter, maintains in-memory sync |\n| `mentions.ts` | `src/store/mentions.ts` | Extracts `[[name]]` tokens from body content |\n| `handlers.ts` | `src/server/handlers.ts` | MCP tool handlers for graph operations |\n| `graph.ts` CLI | `src/cli/graph.ts` | Command-line graph visualization |\n\n资料来源：[src/store/graph.ts:25-45]()\n\n## Edge Types\n\nThe graph supports a union of edge types drawn from three sources:\n\n| Edge Type | Source | Description |\n|-----------|--------|-------------|\n| `related-to` | `relations[]` frontmatter | General-purpose association between memories |\n| `builds-on` | `relations[]` frontmatter | Memory that extends or depends on another |\n| `contradicts` | `relations[]` frontmatter | Memory that opposes or negates another |\n| `child-of` | `relations[]` frontmatter | Hierarchical parent-child relationship |\n| `supersedes` | `supersedes[]` frontmatter | Memory that replaces or renders another obsolete |\n| `mentions` | Body `[[name]]` extraction | Memory references another by name in its body |\n\n资料来源：[src/store/graph.ts:15-25]()\n\n### Frontmatter Declaration\n\nMemories declare outgoing edges in YAML frontmatter:\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: scope_contract\n    type: builds-on\n  - to: legacy_approach\n    type: supersedes\n---\n<memory body content>\n```\n\n资料来源：[src/store/memory.ts:1-30]()\n\n## MemoryGraph Module\n\nThe `MemoryGraph` class maintains an in-memory adjacency list and exposes methods for adding, removing, and querying edges.\n\n### Data Model\n\n```typescript\n// src/store/graph.ts\nexport interface Edge {\n  from: string;\n  to: string;\n  type: EdgeType;\n}\n\nexport interface DanglingEdge {\n  from: string;\n  to: string;\n  type: string;  // widened to string for extensibility\n}\n```\n\n资料来源：[src/store/graph.ts:30-45]()\n\n### Graph Construction\n\nThe graph is built during store initialization by iterating all memories and emitting edges for each source:\n\n1. For each memory, emit one edge per `relations[]` entry\n2. Emit one `supersedes` edge per `supersedes[]` entry\n3. Emit one `mentions` edge per `[[name]]` token in body (if extraction enabled)\n\n```mermaid\ngraph LR\n    A[\"scan()\"] --> B[\"For each memory\"]\n    B --> C[\"Parse relations[]\"]\n    B --> D[\"Parse supersedes[]\"]\n    B --> E[\"Extract [[name]] mentions\"]\n    C --> F[\"addEdge()\"]\n    D --> F\n    E --> F\n```\n\n资料来源：[src/store/graph.ts:50-80]()\n\n## Mentions Extraction\n\nThe `[[name]]` mention extractor (DAR-927) parses body content for wiki-style name references and surfaces them as graph edges.\n\n### Tokenizer Rules\n\n- Extracts tokens matching the pattern `[[name]]` where `name` conforms to `^[a-z0-9_]+$`\n- Names must match the same validation rule used for memory filenames\n- Tokens not matching this pattern are silently ignored\n- Code fences and inline code are **not** excluded (per contract, the tokenizer operates purely on regex over body content)\n\n### Configuration\n\n| Environment Variable | Default | Description |\n|---------------------|---------|-------------|\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | Set to `'false'` to disable mention extraction |\n\n资料来源：[src/store/mentions.ts:1-45]()\n\n## MCP Tools\n\nThe MCP server exposes graph operations as JSON-RPC tools.\n\n### memory_graph\n\nTraverses the graph starting from a named memory and returns the neighborhood.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `name` | string | required | Root memory name |\n| `depth` | integer | `1` | Maximum edge traversal depth |\n| `types` | string[] | authored + supersedes | Edge types to follow |\n| `direction` | `'in' \\| 'out' \\| 'both'` | `'both'` | Traversal direction |\n| `scope` | `'user' \\| 'project'` | auto | Memory scope filter |\n\n资料来源：[src/server/tools.ts:1-50]()\n\n### memory_link\n\nCreates a directed edge between two memories.\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `from` | string | Source memory name |\n| `to` | string | Target memory name |\n| `type` | RelationType | Edge type (one of the four authored types) |\n\n资料来源：[src/store/memory-store.ts:80-120]()\n\n### memory_unlink\n\nRemoves one or more edges from a memory.\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `from` | string | Source memory name |\n| `to` | string | Target memory name |\n| `type` | RelationType (optional) | Specific edge type to remove; if omitted, removes all edges to target |\n\n资料来源：[src/store/memory-store.ts:120-160]()\n\n## CLI Integration\n\nThe `commonplace graph` command provides command-line graph visualization (DAR-933).\n\n### Usage\n\n```bash\ncommonplace graph <name> [options]\n```\n\n### Options\n\n| Flag | Type | Default | Description |\n|------|------|---------|-------------|\n| `--depth, -d` | integer | `1` | Traversal depth |\n| `--types, -t` | string | all except mentions | Comma-separated edge types |\n| `--direction, -D` | `in\\|out\\|both` | `both` | Traversal direction |\n| `--format, -f` | `mermaid\\|json\\|dot` | `mermaid` | Output format |\n| `--scope, -s` | `user\\|project\\|both` | `both` | Memory scope |\n\n资料来源：[src/cli/graph.ts:1-80]()\n\n### Output Formats\n\n#### Mermaid (default)\n\n```mermaid\nflowchart LR\n  memory_a[\"memory_a (feedback)\"]\n  memory_b[\"memory_b (project)\"]\n  memory_a -- \"builds-on\" --> memory_b\n```\n\n#### JSON\n\nReturns the `MemoryGraphResult` structure verbatim for piping to external tools:\n\n```json\n{\n  \"root\": \"memory_a\",\n  \"nodes\": [...],\n  \"edges\": [...]\n}\n```\n\n#### DOT\n\nGraphviz DOT format for archival or large-graph workflows.\n\n资料来源：[src/cli/graph.ts:80-150]()\n\n## Dangling Edge Detection\n\nThe graph detects edges whose `to` target does not correspond to any existing memory. These \"dangling edges\" are identified during graph construction and can be pruned.\n\n### Detection\n\n| Step | Description |\n|------|-------------|\n| 1 | Build adjacency list from all memories |\n| 2 | Collect all known memory names |\n| 3 | For each edge, verify `to` exists in name set |\n| 4 | Flag edges where `to` is absent |\n\n### Pruning\n\nThe `migrate prune` command removes dangling edges:\n\n```bash\ncommonplace migrate --prune [--dry-run]\n```\n\nResults show per-memory counts and total edges removed.\n\n资料来源：[src/store/graph.ts:80-120]()\n\n## Out of Scope\n\nThe following features are explicitly deferred to future iterations:\n\n| Feature | Issue | Notes |\n|---------|-------|-------|\n| Verifying referenced names exist on disk | DAR-926 | Dangling detection exists; validation does not |\n| In-memory adjacency list builder | DAR-926 | Graph derives from store, not built independently |\n| `[[name]]` backlink rendering | DAR-927 | AC excludes wiki-style rendering |\n| Centrality / PageRank | DAR-931 | Future ranking metrics |\n| Traversal / path queries | DAR-932 | Neighborhood walk only for v0.1 |\n\n资料来源：[src/store/graph.ts:10-20]()\n\n## Summary\n\nThe Graph Features system treats the memory corpus as a navigable network. Edges originate from three sources—authored `relations`, explicit `supersedes` declarations, and automatic `[[name]]` mention extraction—and are consolidated into a unified in-memory adjacency list. The MCP server exposes CRUD operations on edges, the CLI provides visualization, and the architecture intentionally keeps the graph derived rather than authoritative, ensuring it never diverges from the underlying markdown files.\n\n---\n\n<a id='mcp-tool-reference'></a>\n\n## MCP Tool Reference\n\n### 相关页面\n\n相关主题：[Server Handlers](#server-handlers), [Semantic Search](#semantic-search), [Graph Features](#graph-features)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/server/tools.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/tools.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.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- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n</details>\n\n# MCP Tool Reference\n\nThe Model Context Protocol (MCP) server exposes a set of tools that enable external clients—primarily Claude Code—to interact with the commonplace book. These tools provide CRUD operations for memories, semantic search, and graph management. The MCP stdio server acts as the bridge between the local embedding pipeline and any MCP-compatible client.\n\n资料来源：[src/server/handlers.ts:1-25]()\n\n## Architecture Overview\n\nThe MCP server is implemented in `src/server/` and wired to the memory store layer. Tool requests arrive via stdio JSON-RPC, are validated in handler functions, dispatched to the `MemoryStore`, and returned as JSON-serializable responses wrapped in MCP content blocks.\n\n```mermaid\ngraph TD\n    A[MCP Client<br/>Claude Code] --> B[stdio JSON-RPC]\n    B --> C[server.ts<br/>CallToolRequest Dispatcher]\n    C --> D[handlers.ts<br/>Tool Handlers]\n    D --> E[MemoryStore]\n    E --> F[memory.ts<br/>YAML + Embedding I/O]\n    E --> G[graph.ts<br/>In-memory Graph]\n    F --> H[.md Files<br/>+ .embedding Sidecars]\n```\n\n资料来源：[src/server/handlers.ts:17-23]()\n\n## Tool Categories\n\nThe MCP server exposes two categories of tools:\n\n| Category | Purpose | Tools |\n|----------|---------|-------|\n| **Memory CRUD** | Create, read, delete, and search memories | `memory_save`, `memory_list`, `memory_delete`, `memory_search` |\n| **Graph Management** | Manage relationships between memories | `memory_link`, `memory_unlink` |\n\n资料来源：[README.md:1-50]()\n\n## Scope Model\n\nEvery tool accepts an optional `scope` argument that selects which memory store to address:\n\n| Scope | Description |\n|-------|-------------|\n| `user` | Cross-project memories stored in `COMMONPLACE_USER_DIR` |\n| `project` | Project-specific memories stored in `COMMONPLACE_PROJECT_DIR` |\n\nWhen `scope` is omitted, reads merge across both stores and writes default to `user`.\n\n资料来源：[src/server/handlers.ts:30-35]()\n\n## Memory Types\n\nAll memory tools operate on a four-element taxonomy defined in the store layer:\n\n| Type | Purpose |\n|------|---------|\n| `user` | Personal rules, preferences, and identity facts about the human operator |\n| `feedback` | Corrections and lessons learned from prior agent behaviour; persistent course-corrections |\n| `project` | Per-project context like architecture notes, repo conventions, and decisions |\n| `reference` | Durable, neutral knowledge: API shapes, formulas, citations |\n\n资料来源：[src/store/memory.ts:1-30]()\n\n## Memory CRUD Tools\n\n### memory_save\n\nSave a memory as a markdown file with YAML frontmatter and a derived embedding sidecar. Refuses to overwrite an existing entry; the contract is delete + save.\n\n**Input Schema:**\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `name` | string | Yes | Memory name. Must match `^[a-z0-9_]+$`. Becomes the filename stem. |\n| `type` | `user \\| feedback \\| project \\| reference` | Yes | One of the four memory types. |\n| `description` | string | Yes | Short description used in search result summaries. |\n| `body` | string | Yes | Markdown content of the memory. |\n| `scope` | `'user' \\| 'project'` | No | Which store to write to. Defaults to `'user'`. |\n\n资料来源：[README.md:50-80]()\n\n**Validation:** Arguments are validated manually at handler entry. The handler checks `name` against `validateName`, `type` against `MEMORY_TYPES`, and passes store errors through unchanged.\n\n资料来源：[src/server/handlers.ts:40-55]()\n\n### memory_list\n\nList all memories, optionally filtered by type.\n\n**Input Schema:**\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `type` | `user \\| feedback \\| project \\| reference` | No | Filter to memories of this type only. |\n| `scope` | `'user' \\| 'project'` | No | Which store to query. Defaults to merging both stores. |\n\n**Response:** Returns an array of memory entries with `name`, `type`, `description`, and `body` fields.\n\n资料来源：[src/server/handlers.ts:60-75]()\n\n### memory_delete\n\nDelete a memory by name from the specified store.\n\n**Input Schema:**\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `name` | string | Yes | Name of the memory to delete. |\n| `scope` | `'user' \\| 'project'` | No | Which store to delete from. Defaults to `'user'`. |\n\n资料来源：[src/server/handlers.ts:80-95]()\n\n### memory_search\n\nSemantic search across all memories using local embeddings.\n\n**Input Schema:**\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `query` | string | Yes | Natural language search query. |\n| `type` | `user \\| feedback \\| project \\| reference` | No | Filter to memories of this type only. |\n| `limit` | number | No | Maximum results to return. Defaults to `DEFAULT_SEARCH_LIMIT`. |\n| `scope` | `'user' \\| 'project'` | No | Which store to search. Defaults to merging both stores. |\n\n资料来源：[src/server/handlers.ts:100-130]()\n\n**Response Enrichment:** Search results include relations from connected memories and exclude notes marked as superseded. This is handled by `MemoryGraph` integration.\n\n资料来源：[src/store/memory-store.ts:1-50]()\n\n## Graph Management Tools\n\n### memory_link\n\nCreate a directed edge between two memories, establishing a typed relationship.\n\n**Input Schema:**\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `from` | string | Yes | Source memory name. |\n| `to` | string | Yes | Target memory name. |\n| `type` | `RelationType \\| 'supersedes'` | Yes | Relationship type. |\n| `scope` | `'user' \\| 'project'` | No | Which store contains both memories. |\n\n**Relation Types:**\n\n| Type | Description |\n|------|-------------|\n| `builds-on` | The source memory builds upon the target |\n| `implements` | The source memory implements the target |\n| `relates-to` | General relationship between memories |\n| `supersedes` | The source memory supersedes the target |\n\n**Behavior:**\n\n- Throws if the edge already exists (no duplicate edges).\n- Updates the `relations` array in the source memory's YAML frontmatter.\n- Mutates the in-memory entry in place for consistency.\n- Refreshes the directory mtime baseline to avoid wasteful rescans.\n\n资料来源：[src/store/memory-store.ts:200-280]()\n\n```mermaid\ngraph LR\n    A[memory: feedback_scope] -->|builds-on| B[memory: scope_management]\n    A -->|supersedes| C[memory: old_feedback_v1]\n```\n\n### memory_unlink\n\nRemove a directed edge between two memories.\n\n**Input Schema:**\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `from` | string | Yes | Source memory name. |\n| `to` | string | Yes | Target memory name. |\n| `type` | `RelationType \\| 'supersedes'` | No | Specific edge type to remove. If omitted, removes ALL edges from `from` to `to`. |\n\n**Behavior:**\n\n- No-op when the requested edge does not exist (no atomic write, no graph mutation).\n- Returns `{ ..., note: '<reason>' }` for friendly messaging when edges don't exist.\n- When edges are removed, writes the source `.md` through `atomicWrite`, updates the in-memory entry in place, and calls `MemoryGraph.removeEdge`.\n\n资料来源：[src/store/memory-store.ts:300-400]()\n\n## Validation Strategy\n\nTool argument validation is deliberately manual rather than schema-library-based:\n\n- Zero new dependencies for validation logic.\n- Rejection messages are tailored to name the offending field.\n- Store layer errors are passed through unchanged to preserve context.\n\n资料来源：[src/server/handlers.ts:15-20]()\n\n## Response Format\n\nAll tool responses are JSON-serializable shapes wrapped in a single text content block by the MCP server's `CallToolRequest` dispatcher in `server.ts`. The dispatcher handles both the CRUD tools and graph tools uniformly.\n\n资料来源：[src/server/handlers.ts:20-23]()\n\n## Environment Variables\n\nThe MCP server respects the following environment variables:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace` | Directory for user-scoped memories |\n| `COMMONPLACE_PROJECT_DIR` | `<cwd>/.commonplace` | Directory for project-scoped memories |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | Enable `[[name]]` mention extraction from body content |\n\n资料来源：[src/store/mentions.ts:1-30]()\n\n## MCP Server Binary\n\nThe MCP server is exposed as the `commonplace-mcp` binary, separate from the CLI's `commonplace` command. This separation ensures the MCP stdio framing channel is never polluted by CLI output.\n\n资料来源：[src/index.ts:1-30]()\n\n## See Also\n\n- [Memory Store Architecture](./memory-store-architecture.md) — In-depth details on embedding, sidecars, and graph integration\n- [CLI Reference](./cli-reference.md) — The `commonplace` CLI for migration and graph commands\n- [Memory File Format](./memory-file-format.md) — YAML frontmatter schema and content hashing\n\n---\n\n<a id='server-handlers'></a>\n\n## Server Handlers\n\n### 相关页面\n\n相关主题：[MCP Tool Reference](#mcp-tool-reference), [System Architecture](#system-architecture)\n\n<details>\n<summary>Related Source Files</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n- [src/server/server.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/server.ts)\n- [src/server/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/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/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts)\n</details>\n\n# Server Handlers\n\n## Overview\n\nServer Handlers are the core request-processing layer in the Commonplace MCP server. They implement the MCP (Model Context Protocol) tool handlers that bridge the MCP client interface to the underlying `MemoryStore` persistence layer. Each handler is a factory function that produces an MCP-compatible request handler with consistent validation, error handling, and response shaping.\n\nThe handler system is designed around:\n\n- **Factory pattern**: Each handler is created via a factory function (e.g., `createMemorySaveHandler`, `createMemoryListHandler`) that encapsulates store access and validation logic.\n- **Typed interfaces**: All inputs and outputs use TypeScript interfaces exported from `handlers.ts` for compile-time safety.\n- **Scope awareness**: Handlers support both `user` and `project` scopes, allowing memories to be stored in different directories.\n- **Graph integration**: Handlers can optionally work with the `MemoryGraph` to enrich responses with relation data.\n\n## Architecture\n\n### Request Flow\n\n```mermaid\ngraph TD\n    A[MCP Request] --> B[Server dispatch]\n    B --> C{Handler Factory}\n    C --> D[createMemorySaveHandler]\n    C --> E[createMemoryListHandler]\n    C --> F[createMemorySearchHandler]\n    C --> G[createMemoryDeleteHandler]\n    C --> H[createMemoryLinkHandler]\n    C --> I[createMemoryUnlinkHandler]\n    D --> J[MemoryStore]\n    E --> J\n    F --> J\n    G --> J\n    H --> J\n    I --> J\n    J --> K[MemoryGraph]\n    J --> L[File System]\n    K --> M[Relation Enrichment]\n    L --> N[.md + .embedding files]\n    M --> O[MCP Response]\n    N --> O\n```\n\n### Handler Factory Pattern\n\nEach handler follows the factory pattern documented in `handlers.ts`:\n\n```typescript\nexport const createMemorySaveHandler = (opts: CreateHandlerOptions) => {\n  const { userStore, projectStore } = resolveStores(opts);\n  return async (request: MemorySaveRequest): Promise<MemorySaveResult> => {\n    // Validation and processing\n  };\n};\n```\n\n资料来源：[src/server/handlers.ts:1-50]()\n\n## Handler Types\n\n### MemorySaveHandler\n\n**Purpose**: Creates or updates a memory note with YAML frontmatter and markdown body.\n\n**Factory**: `createMemorySaveHandler(options: CreateHandlerOptions)`\n\n**Request Interface**:\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `name` | `string` | Yes | Memory identifier matching `^[a-z0-9_]+$` |\n| `type` | `MemoryType` | Yes | One of: `user`, `feedback`, `project`, `reference` |\n| `description` | `string` | Yes | Brief description for search relevance |\n| `body` | `string` | Yes | Markdown content |\n| `scope` | `Scope` | No | `user` (default) or `project` |\n\n**Response Interface**:\n\n```typescript\nexport interface MemorySaveResult {\n  saved: {\n    name: string;\n    type: MemoryType;\n    description: string;\n  };\n  path: string;\n  /** Which store the memory was written to (DAR-924) */\n  scope: Scope;\n}\n```\n\n资料来源：[src/server/handlers.ts:80-95]()\n\n**Validation**:\n- Name must match `NAME_PATTERN` (`^[a-z0-9_]+$`)\n- Type must be one of `MEMORY_TYPES`\n- Scope is validated via `validateScope()` helper\n- Duplicate relations are deduplicated on write\n\n资料来源：[src/store/memory.ts:1-50]()\n\n### MemoryListHandler\n\n**Purpose**: Returns all memories from a store, optionally filtered by type and scope.\n\n**Factory**: `createMemoryListHandler(options: CreateHandlerOptions)`\n\n**Request Interface**:\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `type` | `MemoryType` | No | Filter by memory type |\n| `scope` | `Scope` | No | Filter by scope (`user`/`project`) |\n\n**Response Interface**:\n\n```typescript\nexport interface MemoryListResult {\n  memories: Array<{\n    name: string;\n    type: MemoryType;\n    description: string;\n    /** Which store this entry came from */\n    scope: Scope;\n  }>;\n}\n```\n\n资料来源：[src/server/handlers.ts:97-108]()\n\n### MemorySearchHandler\n\n**Purpose**: Performs semantic search across memory embeddings using cosine similarity.\n\n**Factory**: `createMemorySearchHandler(options: CreateHandlerOptions)`\n\n**Request Interface**:\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `query` | `string` | Yes | Natural language search query |\n| `limit` | `number` | No | Max results (default: 10) |\n| `type` | `MemoryType` | No | Filter by type |\n| `scope` | `Scope` | No | Filter by scope |\n| `expand` | `boolean` | No | Include related memories (default: true) |\n| `expandTypes` | `EdgeType[]` | No | Which relation types to expand |\n\n**Response Interface**:\n\n```typescript\nexport interface MemorySearchMatch {\n  name: string;\n  type: MemoryType;\n  description: string;\n  body: string;          // Full body, never truncated\n  score: number;         // Cosine similarity, 3 decimals\n  relations: Relation[]; // Outgoing graph edges\n}\n```\n\n资料来源：[src/server/handlers.ts:35-60]()\n\n**Expand Types Configuration**:\n\n| Type | Default | Description |\n|------|---------|-------------|\n| `builds-on` | Yes | Included by default |\n| `related-to` | Yes | Included by default |\n| `mentions` | No | Requires opt-in |\n| `supersedes` | No | Requires opt-in |\n| `contradicts` | No | Requires opt-in |\n| `child-of` | No | Requires 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:20-30]()\n\n**Response Enrichment**:\n\nWhen `expand` is enabled, the handler enriches results by:\n1. Fetching direct matches from `MemoryStore.search()`\n2. For each match, query `MemoryGraph` for outgoing edges matching `expandTypes`\n3. Add expanded memories to response (marked with `expanded: true`)\n4. Exclude superseded memories unless explicitly requested\n\n### MemoryDeleteHandler\n\n**Purpose**: Removes a memory from the store by name.\n\n**Factory**: `createMemoryDeleteHandler(options: CreateHandlerOptions)`\n\n**Request Interface**:\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `name` | `string` | Yes | Memory name to delete |\n| `scope` | `Scope` | No | Scope hint for store resolution |\n\n**Response Interface**:\n\n```typescript\nexport interface MemoryDeleteResult {\n  deleted: string;\n  scope: Scope;\n}\n```\n\n### MemoryLinkHandler\n\n**Purpose**: Creates a directed edge between two memories in the graph.\n\n**Factory**: `createMemoryLinkHandler(options: CreateHandlerOptions)`\n\n**Request Interface**:\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `from` | `string` | Yes | Source memory name |\n| `to` | `string` | Yes | Target memory name |\n| `type` | `RelationType` | Yes | Edge type |\n| `scope` | `Scope` | No | Scope for operation |\n\n**Relation Types**:\n\n| Type | Description |\n|------|-------------|\n| `builds-on` | Memory extends or depends on another |\n| `related-to` | Memory has loose association |\n| `contradicts` | Memory refutes another |\n| `child-of` | Memory is subordinate to another |\n\n**Internal Behavior**:\nThe handler delegates to `MemoryStore.linkEdge()` which:\n1. Validates both memory names exist\n2. Adds the relation to the source memory's frontmatter\n3. If type is `supersedes`, also adds to `supersedes` list\n4. Writes updated markdown via atomic write\n5. Updates the in-memory `MemoryGraph`\n\n资料来源：[src/store/memory-store.ts:1-50]()\n\n### MemoryUnlinkHandler\n\n**Purpose**: Removes a directed edge between two memories.\n\n**Factory**: `createMemoryUnlinkHandler(options: CreateHandlerOptions)`\n\n**Request Interface**:\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `from` | `string` | Yes | Source memory name |\n| `to` | `string` | Yes | Target memory name |\n| `type` | `RelationType \\| 'supersedes'` | No | Specific edge type to remove. Omit to remove all edges to target |\n\n**Behavior**:\n- No-op when the requested edge does not exist\n- When `type` is omitted, removes ALL edges from `from` -> `to`\n- Returns `{ relations, supersedes, note }` describing the new state\n\n资料来源：[src/store/memory-store.ts:100-150]()\n\n## Store Resolution\n\nHandlers use the `resolveStores` helper to map request scopes to actual store instances:\n\n```typescript\nconst resolveStores = (opts: { store?: MemoryStore; userStore?: MemoryStore; projectStore?: MemoryStore }) => {\n  const userStore = opts.userStore ?? opts.store;\n  if (userStore === undefined) {\n    throw new Error(`${toolName}: handler factory requires a userStore`);\n  }\n  return { userStore, projectStore: opts.projectStore };\n};\n```\n\n资料来源：[src/server/handlers.ts:65-75]()\n\n## Scope System\n\nThe scope system allows memories to be stored in different locations:\n\n| Scope | Directory | Use Case |\n|-------|-----------|----------|\n| `user` | `COMMONPLACE_USER_DIR` | Cross-project knowledge |\n| `project` | `COMMONPLACE_PROJECT_DIR` | Project-specific facts |\n\n**Validation**:\n\n```typescript\nconst SCOPES = ['user', 'project'] as const;\ntype Scope = typeof SCOPES[number];\n\nconst isScope = (v: unknown): v is Scope =>\n  typeof v === 'string' && (SCOPES as readonly string[]).includes(v);\n```\n\n资料来源：[src/server/handlers.ts:55-70]()\n\n## Server Initialization\n\nThe handlers are wired into the MCP server in `server.ts`:\n\n```mermaid\ngraph LR\n    A[MCP Server] --> B[registerTools]\n    B --> C[MemorySaveHandler]\n    B --> D[MemoryListHandler]\n    B --> E[MemorySearchHandler]\n    B --> F[MemoryDeleteHandler]\n    B --> G[MemoryLinkHandler]\n    B --> H[MemoryUnlinkHandler]\n```\n\nThe main entry point (`src/index.ts`) dispatches to the server module:\n\n```typescript\nif (argv[0] === 'graph') {\n  const result = await graphMain({ argv, ... });\n  return result.exitCode;\n}\n```\n\n资料来源：[src/index.ts:1-30]()\n\n## Error Handling\n\nAll handlers follow consistent error handling patterns:\n\n| Error Type | Cause | Response |\n|------------|-------|----------|\n| Validation error | Invalid input format | Throws with descriptive message |\n| Not found | Memory doesn't exist | Handled by store methods |\n| Duplicate edge | Edge already exists | Handled by `linkEdge` |\n| Store unavailable | Store not initialized | Factory throws on construction |\n\n## Integration with MemoryStore\n\nHandlers delegate to `MemoryStore` methods for all persistence operations:\n\n| Handler | Store Method |\n|---------|--------------|\n| MemorySaveHandler | `MemoryStore.save()` |\n| MemoryListHandler | `MemoryStore.all()` |\n| MemorySearchHandler | `MemoryStore.search()` |\n| MemoryDeleteHandler | `MemoryStore.delete()` |\n| MemoryLinkHandler | `MemoryStore.linkEdge()` |\n| MemoryUnlinkHandler | `MemoryStore.unlinkEdge()` |\n\n资料来源：[src/store/memory-store.ts:1-200]()\n\n## Mention Extraction\n\nWhen a memory is saved, the body is scanned for `[[name]]` wiki-link syntax:\n\n```mermaid\ngraph TD\n    A[Memory Save] --> B[Extract mentions]\n    B --> C{NAME_PATTERN test}\n    C -->|pass| D[Add to MemoryGraph]\n    C -->|fail| E[Skip]\n    D --> F[edgesPruned count]\n```\n\nThis extraction is controlled by the `COMMONPLACE_EXTRACT_MENTIONS` environment variable (default: enabled).\n\n资料来源：[src/store/mentions.ts:1-60]()\n\n## Configuration\n\nHandlers are configured via environment variables managed in DAR-913:\n\n| Variable | Default | Effect |\n|----------|---------|--------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace` | User memory directory |\n| `COMMONPLACE_PROJECT_DIR` | `./.commonplace` | Project memory directory |\n| `COMMONPLACE_MODEL_ID` | `Xenova/bge-base-en-v1.5` | Embedding model |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `true` | Enable `[[name]]` extraction |\n\n## Related Documentation\n\n- **Memory Store**: `src/store/memory-store.ts` - Persistence layer\n- **Memory Types**: `src/store/memory.ts` - Type definitions\n- **Atomic Write**: `src/store/atomic-write.ts` - Safe file operations\n- **Mention Extraction**: `src/store/mentions.ts` - `[[name]]` parsing\n- **CLI Entry**: `src/index.ts` - Command dispatch\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 项目说明书",
        "目录",
        "Introduction to Commonplace",
        "Overview",
        "Architecture",
        "Memory Model",
        "MCP Tools",
        "CLI Commands",
        "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": "da2dabfd9977cbe2bfba2463ea0da93bf654e839",
    "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/update-check.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- 文件总数：135\n- 重要文件覆盖：40/135\n- 证据索引条目：80\n- 角色 / Skill 条目：7\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- 共索引 7 个角色 / 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 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- **commonplace_app_structure**（project_doc）：Source tree layout and key architectural facts for the commonplace MCP server 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`.commonplace/memory/commonplace_app_structure.md`\n- **macos_apfs_fsync_test_perf**（project_doc）：Why MemoryStore-backed tests are dramatically slower on macOS than 激活提示：当用户需要理解项目结构、安装方式或边界时参考。 证据：`.commonplace/memory/macos_apfs_fsync_test_perf.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.6.0\", \"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 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- **Directory layout**（documentation）：Commonplace is a local-first memory MCP server. Source is split by responsibility under src/ . 证据：`.commonplace/memory/commonplace_app_structure.md`\n- **macOS APFS fsync is the dominant cost in write-heavy tests**（documentation）：macOS APFS fsync is the dominant cost in write-heavy tests 证据：`.commonplace/memory/macos_apfs_fsync_test_perf.md`\n- **.Release Please Manifest**（structured_config）：{ \".\": \"0.6.0\" } 证据：`.release-please-manifest.json`\n- **Release Please Config**（structured_config）：{ \"include-component-in-tag\": false, \"packages\": { \".\": { \"release-type\": \"node\", \"bump-minor-pre-major\": true, \"extra-files\": { \"type\": \"generic\", \"path\": \"src/server/server.ts\" } , \"changelog-sections\": { \"type\": \"feat\", \"section\": \"Added\" }, { \"type\": \"fix\", \"section\": \"Fixed\" }, { \"type\": \"perf\", \"section\": \"Performance\" }, { \"type\": \"refactor\", \"section\": \"Changed\" }, { \"type\": \"revert\", \"section\": \"Reverted\" }, { \"type\": \"chore\", \"section\": \"Miscellaneous\", \"hidden\": true }, { \"type\": \"test\", \"section\": \"Tests\", \"hidden\": true }, { \"type\": \"docs\", \"section\": \"Documentation\", \"hidden\": true }, { \"type\": \"ci\", \"section\": \"CI\", \"hidden\": true }, { \"type\": \"build\", \"section\": \"Build\", \"hi… 证据：`release-please-config.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 证据：`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 graph CLI 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. 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 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 malformed pr… 证据：`scripts/derive-dist-tag.sh`\n- **!/usr/bin/env bash**（source_file）：!/usr/bin/env bash 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 the preco… 证据：`scripts/reproduce-cold-start-race.sh`\n- **!/usr/bin/env bash**（source_file）：!/usr/bin/env bash 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 ci-workflow contract tests. Usage: ./scripts/setup-branch-protection.sh own… 证据：`scripts/setup-branch-protection.sh`\n- **!/usr/bin/env node**（source_file）：!/usr/bin/env node / Bin entry: the commonplace CLI dispatcher. 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 rebuild-sidecars-for-an-existing-dir path and the 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.json declares two bin entries: - commonplace - dist/in… 证据：`src/index.ts`\n- **Atomic Write.Test**（source_file）：/ Contract tests for the atomicWrite helper: - 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 ordering deterministically. / 证据：`tests/atomic-write.test.ts`\n- **Ci Workflow.Test**（source_file）：/ CI-workflow 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）：/ 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 alphabe… 证据：`tests/derive-dist-tag.test.ts`\n- **Embedder.Integration.Test**（source_file）：/ Contract integration tests for the Embedder. 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 lengt… 证据：`tests/embedder.integration.test.ts`\n- **Embedder.Readonly Types**（source_file）：/ 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 the readonly contract required. 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）：/ Unit 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 . / 证据：`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 The spawned-bin integration test was flaky on cold-cache make test runs. Surface symptoms varied: - MCP error -32000: Connection closed , 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 Xenova/bge-base-en-v1.5 via the real @huggingface/transformers pipel… 证据：`tests/global-setup.ts`\n- **Graph Bin.Integration.Test**（source_file）：/ 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）：/ Contract tests for the commonplace graph subcommand. 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）：/ Contract tests for the MemoryGraph class -- an in-memory adjacency structure built from the relations and supersedes frontmatter graph fields layered over the MemoryStore entries. / 证据：`tests/graph.test.ts`\n- **Memory Graph.Test**（source_file）：/ Contract tests for the relations and supersedes frontmatter graph fields layered on top of the memory I/O primitives: - readMemory path - { ..., relations, supersedes } - writeMemory path, memory accepts relations / supersedes - contentSha memory MUST NOT depend on relations / supersedes / 证据：`tests/memory-graph.test.ts`\n- **Memory Pinned.Test**（source_file）：/ Tests for ac-1: memory frontmatter pinned: boolean field. The pinned field is optional, defaults to false when absent, and round-trips through readMemory / writeMemory . The flag is excluded from contentSha so toggling it does not invalidate sidecars. / 证据：`tests/memory-pinned.test.ts`\n- **Memory Store Multiprocess.Test**（source_file）：/ 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 / 证据：`tests/memory-store-multiprocess.test.ts`\n- **Memory Store Search.Test**（source_file）：/ Contract 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, so cosine reduces to a dot product. 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）：/ 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 worker uses… 证据：`tests/memory-store-stress.test.ts`\n- **Memory Store.Test**（source_file）：/ Contract tests for the MemoryStore class -- the in-memory vector index backed by / .md + .embedding sidecar files. 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）：/ Contract 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 / 证据：`tests/memory.test.ts`\n- **Mentions Store.Test**（source_file）：/ Contract tests -- MemoryStore wiring for body-mention extraction. 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 . / 证据：`tests/mentions-store.test.ts`\n- **Mentions.Test**（source_file）：/ Contract tests -- pure tokenizer extractMentions . 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. / 证据：`tests/mentions.test.ts`\n- **Migrate Bin.Integration.Test**（source_file）：/ 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 warms the cac… 证据：`tests/migrate-bin.integration.test.ts`\n- **Migrate Import.Test**（source_file）：/ 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. / 证据：`tests/migrate-import.test.ts`\n- **Migrate Resilience.Test**（source_file）：/ 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 . / 证据：`tests/migrate-resilience.test.ts`\n- **Migrate.Test**（source_file）：/ Contract tests for runMigrate programmatic API and the argv-parsing wrapper. / 证据：`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. Catch link rot: README markdown links to files in the repo must resolve on disk. Everything else about README quality prose, section ordering, specific phrasings, install-command verbatims is a review-time concern. Asserting on prose turns natural documentation rewrites into test rewrites for no meaningful coverage. / 证据：`tests/readme.test.ts`\n- **Release Please.Test**（source_file）：/ Contract tests: release-please pipeline shape. Verifies the static, committed artefacts of the release-please flow workflow YAML, config JSON, manifest JSON , the cleanup of the legacy commit-and-tag-version c-and-t-v stack, the CONTRIBUTING.md rewrite, and the scripts/setup-branch-protection.sh payload edits Phase 3 . Manual-typed contract tests ac-2, ac-7, ac-8, ac-9 live-API, ac-10, ac-11 are post-merge / live-API operations and intentionally not exercised here. / import { describe, expect, it } from 'vitest'; import { execFileSync } from 'node:child process'; import { existsSync, readFileSync } from 'node:fs'; import { join } from 'node:path'; import { parse as parseYaml } from 'yaml'; 证据：`tests/release-please.test.ts`\n- **Release Workflow.Test**（source_file）：/ 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 : 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）：/ Scaffolding 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）：/ Scaffolding 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）：/ 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）：/ Cold-start invariants for the spawned-bin integration harness. Background tests/server-bin.integration.test.ts 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 integration tests each loa… 证据：`tests/server-bin-cold-start.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- **Introduction to Commonplace**：importance `high`\n  - source_paths: README.md, CLAUDE.md, src/index.ts\n- **Quick Start Guide**：importance `high`\n  - source_paths: README.md, package.json\n- **System Architecture**：importance `high`\n  - source_paths: CLAUDE.md, src/embedder/index.ts, src/store/memory-store.ts, src/server/index.ts, src/server/server.ts\n- **Project Structure**：importance `medium`\n  - source_paths: src/index.ts, src/bin/boot.ts, src/bin/commonplace-mcp.ts, src/embedder/index.ts, src/store/memory-store.ts\n- **Memory Data Model**：importance `high`\n  - source_paths: src/store/memory.ts, src/store/sidecar.ts, docs/sidecar-format.md\n- **Memory Types Taxonomy**：importance `high`\n  - source_paths: src/store/memory.ts, src/store/memory-store.ts, README.md\n- **Memory Store**：importance `high`\n  - source_paths: src/store/memory-store.ts, src/store/memory.ts, src/store/atomic-write.ts\n- **Embedding System**：importance `high`\n  - source_paths: src/embedder/index.ts, src/store/sidecar.ts\n\n## Repo Inspection Evidence / 源码检查证据\n\n- repo_clone_verified: true\n- repo_inspection_verified: true\n- repo_commit: `da2dabfd9977cbe2bfba2463ea0da93bf654e839`\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/update-check.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`\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-18 04:25:02 UTC\n\n## 目录\n\n- [Introduction to Commonplace](#introduction)\n- [Quick Start Guide](#quickstart)\n- [System Architecture](#system-architecture)\n- [Project Structure](#project-structure)\n- [Memory Data Model](#memory-data-model)\n- [Memory Types Taxonomy](#memory-types-taxonomy)\n- [Memory Store](#memory-store)\n- [Embedding System](#embedding-system)\n- [Semantic Search](#semantic-search)\n- [Graph Features](#graph-features)\n- [MCP Tool Reference](#mcp-tool-reference)\n- [Server Handlers](#server-handlers)\n\n<a id='introduction'></a>\n\n## Introduction to Commonplace\n\n### 相关页面\n\n相关主题：[Quick Start Guide](#quickstart), [System Architecture](#system-architecture), [Memory Data Model](#memory-data-model)\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- [src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.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/store/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n- [CHANGELOG.md](https://github.com/rickbassham/commonplace/blob/main/CHANGELOG.md)\n- [CONTRIBUTING.md](https://github.com/rickbassham/commonplace/blob/main/CONTRIBUTING.md)\n</details>\n\n# Introduction to Commonplace\n\nCommonplace is a local-first personal knowledge management system that functions as an MCP (Model Context Protocol) server. It enables AI agents to persistently store, retrieve, and reason about notes using semantic search, all without requiring external API calls or cloud services. 资料来源：[README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n\n## Overview\n\nCommonplace operates as a flat directory of Markdown files with YAML frontmatter. Each note is a plain `.md` file, and embeddings are stored in `.embedding` sidecar files generated locally using `transformers.js`. This architecture ensures that:\n\n- **Notes are human-readable and portable** — since memories are plain Markdown files, they can be edited, backed up, or version-controlled using standard tools.\n- **Embeddings are derived, not the source of truth** — `.embedding` files are regenerable from `.md` files at any time and may be deleted or rebuilt without data loss. 资料来源：[CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"MCP Client Layer\"\n        A[\"Claude Code / AI Agent\"]\n    end\n    \n    subgraph \"MCP Server Layer\"\n        B[\"commonplace MCP Server<br/>stdio interface\"]\n    end\n    \n    subgraph \"Store Layer\"\n        C[\"MemoryStore<br/>src/store/memory-store.ts\"]\n        D[\"MemoryGraph<br/>Graph relationships\"]\n        E[\"Embedder<br/>transformers.js + bge-base-en-v1.5\"]\n    end\n    \n    subgraph \"Filesystem Layer\"\n        F[\"COMMONPLACE_USER_DIR<br/>~/.commonplace\"]\n        G[\"COMMONPLACE_PROJECT_DIR<br/>.commonplace\"]\n    end\n    \n    A -->|\"MCP Protocol\"| B\n    B --> C\n    C --> D\n    C --> E\n    C --> F\n    C --> G\n    \n    F -.->|\"user scope\"| C\n    G -.->|\"project scope\"| C\n```\n\n### Key Components\n\n| Component | File | Responsibility |\n|-----------|------|-----------------|\n| MCP Server | `src/server/handlers.ts` | Handles MCP protocol communication, registers tools |\n| MemoryStore | `src/store/memory-store.ts` | Manages CRUD operations, scanning, searching |\n| MemoryGraph | `src/store/memory-store.ts` | In-memory graph for relations and mentions |\n| Embedder | `src/store/embedder.ts` | Local embedding generation via transformers.js |\n| Memory I/O | `src/store/memory.ts` | Parses/serializes `.md` files with YAML frontmatter |\n| Atomic Write | `src/store/atomic-write.ts` | Safe file writes to prevent corruption |\n| Mentions | `src/store/mentions.ts` | Extracts `[[name]]` references from body content |\n\n## Memory Model\n\n### Memory Types\n\nMemories are classified into a four-element taxonomy defined at 资料来源：[README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n\n| Type | Purpose | Example |\n|------|---------|---------|\n| `user` | Personal rules, preferences, identity facts about the human operator | Coding style preferences, work schedule |\n| `feedback` | Corrections and lessons learned from prior agent behavior | \"Don't shrink scope unilaterally\" |\n| `project` | Per-project context like architecture notes, repo conventions | API conventions, decision records |\n| `reference` | Durable, neutral knowledge: API shapes, formulas, citations | Library documentation, formulas |\n\n### Memory File Format\n\nA memory is a Markdown file with YAML frontmatter:\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: scope_management\n    type: builds-on\nsupersedes:\n  - old_scope_note\n---\n<Body content here. Can contain [[other_memory_name]] mentions.>\n```\n\n**Frontmatter Fields:**\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `name` | string | Yes | Memory identifier matching `^[a-z0-9_]+$` |\n| `description` | string | Yes | Brief summary of the memory |\n| `type` | enum | Yes | One of: `user`, `feedback`, `project`, `reference` |\n| `relations` | array | No | List of `{to, type}` edges to other memories |\n| `supersedes` | array | No | List of memory names this memory replaces |\n\nThe `contentSha` is computed from `${type}\\n${name}\\n${description}\\n${body}` — graph fields do not affect the hash, so adding or removing edges does not invalidate embeddings. 资料来源：[src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n### Relation Types\n\nGraph edges support the following relation types 资料来源：[src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts):\n\n| Relation Type | Description |\n|---------------|-------------|\n| `builds-on` | This memory extends or depends on another |\n| `related-to` | Tangentially connected memories |\n| `contradicts` | This memory opposes another |\n| `child-of` | This memory is a sub-component of another |\n| `mentions` | Body contains `[[name]]` reference |\n\n## MCP Tools\n\nCommonplace exposes the following tools via MCP protocol 资料来源：[CHANGELOG.md](https://github.com/rickbassham/commonplace/blob/main/CHANGELOG.md):\n\n### memory_save\n\nSaves a memory as a Markdown file with YAML frontmatter and generates an embedding sidecar. Refuses to overwrite existing entries.\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `name` | string | Yes | Memory name, must match `^[a-z0-9_]+$` |\n| `type` | enum | Yes | One of the four memory types |\n| `description` | string | Yes | Brief description |\n| `body` | string | Yes | Full memory content |\n| `scope` | enum | No | `'user'` (default) or `'project'` |\n\n### memory_list\n\nReturns all memories of a given type.\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `type` | enum | Yes | Filter by memory type |\n| `scope` | enum | No | `'user'`, `'project'`, or both (default) |\n\n### memory_delete\n\nRemoves a memory and its embedding sidecar.\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `name` | string | Yes | Memory name to delete |\n| `scope` | enum | No | `'user'` (default) or `'project'` |\n\n### memory_search\n\nPerforms semantic search across memories using cosine similarity.\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `query` | string | Yes | Natural language query |\n| `type` | enum | No | Filter by memory type |\n| `limit` | number | No | Maximum results (default: 5) |\n| `scope` | enum | No | `'user'`, `'project'`, or both (default) |\n\n### memory_link\n\nCreates a directed edge between two memories.\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `from` | string | Yes | Source memory name |\n| `to` | string | Yes | Target memory name |\n| `type` | enum | Yes | One of: `builds-on`, `related-to`, `contradicts`, `child-of` |\n| `scope` | enum | No | `'user'` (default) or `'project'` |\n\n### memory_unlink\n\nRemoves an edge between two memories.\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `from` | string | Yes | Source memory name |\n| `to` | string | Yes | Target memory name |\n| `type` | enum | No | Specific edge type to remove; omit to remove all |\n\n## CLI Commands\n\nThe `commonplace` CLI provides additional management functions 资料来源：[src/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n\n### migrate\n\nThe `migrate` command handles embedding sidecar management and migration between systems.\n\n```\ncommonplace migrate <dir> [--dry-run] [--prune-dangling]\n```\n\n**Functions:**\n\n1. **Embeds** any `.md` whose `.embedding` sidecar is missing\n2. **Re-embeds** any `.md` whose sidecar is stale (contentSha, modelId, or dim mismatch)\n3. **Removes** orphaned `.embedding` files whose matching `.md` is gone\n4. **Prunes** dangling edges when `--prune-dangling` is specified\n\n### Import from Claude Code\n\n```\ncommonplace migrate --from claude-code        # import memories\ncommonplace migrate --from claude-code --dry-run  # preview import\n```\n\nImport copies compatible `.md` files from Claude Code's auto-memory locations (`~/.claude/projects/*/memory/*.md`) into `COMMONPLACE_USER_DIR`.\n\n**Conflict Policy:** Skip and report — if a memory already exists, the source is skipped without overwrite. Use `--dry-run` to preview conflicts.\n\n## Scopes and Directory Structure\n\nCommonplace supports two independent scopes 资料来源：[src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts):\n\n```mermaid\ngraph LR\n    A[\"~/.commonplace<br/>COMMONPLACE_USER_DIR\"] <--> B[\"Cross-project memories<br/>user scope\"]\n    C[\".commonplace<br/>COMMONPLACE_PROJECT_DIR\"] <--> D[\"Project-specific memories<br/>project scope\"]\n```\n\n| Scope | Directory | Contents |\n|-------|-----------|----------|\n| `user` | `~/.commonplace/` | Cross-project memories (preferences, general feedback) |\n| `project` | `.commonplace/` | Per-project memories (conventions, decisions) |\n\nWhen `scope` is omitted on tool calls, reads merge across both stores while writes default to `user`.\n\n## Search Behavior\n\nSearch results include 资料来源：[src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts):\n\n| Field | Description |\n|-------|-------------|\n| `name` | Memory identifier |\n| `type` | Memory type |\n| `description` | Brief summary |\n| `body` | Full body content (never truncated) |\n| `score` | Cosine similarity, rounded to 3 decimals |\n| `relations` | Outgoing graph edges from this memory |\n\n**Expand Types:** By default, search enriches results with `builds-on` and `related-to` neighbors. Pass `expandTypes: ['supersedes']` to include superseded entries explicitly.\n\n**Supersedes Handling:** Entries listed in another memory's `supersedes` field are excluded by default from search results. Pass `excludeSuperseded: false` to include them.\n\n## [[name]] Mentions\n\nBody mentions are extracted using a regex tokenizer 资料来源：[src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts):\n\n- Only `<name>` tokens matching `^[a-z0-9_]+$` are recognized\n- Mentions are added as directed edges in the MemoryGraph\n- Extraction is controlled by `COMMONPLACE_EXTRACT_MENTIONS` env var (default: on)\n\nMentions are **not**:\n- Rendered as wiki-style links\n- Aware of code fences or inline code blocks (intentional)\n- Surfaced through MCP tool responses (DAR-929/DAR-932)\n\n## Installation and Setup\n\nAfter installing Commonplace:\n\n```bash\nnpm install -g commonplace\n# or\npnpm add -g commonplace\n```\n\nConfigure Claude Code to use the MCP server by adding to your settings. After restarting Claude Code sessions, the four memory tools become available. 资料来源：[README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n\n## Workflow Summary\n\n```mermaid\ngraph TD\n    A[\"Agent starts task\"] --> B[\"memory_search or memory_list\"]\n    B --> C{\"Results found?\"}\n    C -->|Yes| D[\"Use memory content\"]\n    C -->|No| E[\"Gather new information\"]\n    E --> F[\"memory_save<br/>with appropriate type\"]\n    F --> G[\"Embedding generated<br/>and stored\"]\n    D --> H[\"Complete task\"]\n    G --> H\n```\n\n## Contributing\n\nThis project follows a squash-merge workflow with the following requirements 资料来源：[CONTRIBUTING.md](https://github.com/rickbassham/commonplace/blob/main/CONTRIBUTING.md):\n\n1. Branch from `main` with descriptive names\n2. No direct pushes to `main` — all changes via PR\n3. CI must pass: `make typecheck`, `make lint`, `make build`, `make test`\n4. All PR conversations must be resolved before merge\n5. Squash-merge only to keep history linear\n\nThe project dogfoods Commonplace for its own memory — developers are encouraged to use `mcp__commonplace__memory_save` for cross-project and project-specific lessons. 资料来源：[CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n\n---\n\n<a id='quickstart'></a>\n\n## Quick Start Guide\n\n### 相关页面\n\n相关主题：[Introduction to Commonplace](#introduction), [MCP Tool Reference](#mcp-tool-reference)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [CONTRIBUTING.md](https://github.com/rickbassham/commonplace/blob/main/CONTRIBUTING.md)\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/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n- [src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n</details>\n\n# Quick Start Guide\n\nWelcome to **Commonplace** — a persistent, embeddable memory system for AI agents that operates on plain markdown files with YAML frontmatter.\n\n## Prerequisites\n\nBefore getting started, ensure your environment meets the following requirements:\n\n| Requirement | Version | Notes |\n|-------------|---------|-------|\n| Node.js | 20 or 22 | CI runs on both versions |\n| pnpm | latest | Package manager for this project |\n| Claude Code | compatible | For MCP tool integration |\n\n资料来源：[CONTRIBUTING.md:1-20]()\n\n## Installation\n\n### From Source\n\nClone the repository and install dependencies:\n\n```bash\ngit clone https://github.com/rickbassham/commonplace.git\ncd commonplace\npnpm install\n```\n\n### Build the Project\n\n```bash\nmake build\n```\n\nThis compiles the TypeScript source and prepares the CLI binary.\n\n资料来源：[CONTRIBUTING.md:22-30]()\n\n## Core Concepts\n\n### Memory Types\n\nEvery memory in Commonplace has a `type` field that categorizes its content:\n\n| Type | Purpose | Example |\n|------|---------|---------|\n| `user` | Personal rules, preferences, identity facts | `preferred_code_style`, `keyboard_shortcuts` |\n| `feedback` | Corrections and lessons learned | `dont_shrink_scope_unilaterally`, `verify_api_response` |\n| `project` | Per-project context, architecture, conventions | `monorepo_structure`, `db_schema_notes` |\n| `reference` | Durable neutral knowledge, API docs | `openapi_spec_location`, `rate_limit_formulas` |\n\n资料来源：[README.md:1-20]()\n\n### Memory Scopes\n\nCommonplace supports two parallel memory stores:\n\n```mermaid\ngraph TD\n    A[Claude Code Session] --> B{Scope Selection}\n    B -->|user| C[User Store]\n    B -->|project| D[Project Store]\n    C --> E[~/.commonplace/memory]\n    D --> F[COMMONPLACE_PROJECT_DIR<br/>or<br/>.commonplace/memory]\n    \n    style C fill:#e1f5fe\n    style D fill:#fff3e0\n```\n\n| Scope | Location | Use Case |\n|-------|----------|----------|\n| `user` | `~/.commonplace/memory` (default) | Cross-project memories, personal preferences |\n| `project` | Project root `.commonplace/memory` | Repository-specific context |\n\n资料来源：[README.md:45-70]()\n\n### Memory File Structure\n\nEach memory is stored as a markdown file with YAML frontmatter:\n\n```yaml\n---\nname: my_memory_name\ndescription: Brief description of this memory\ntype: feedback\nrelations:\n  - to: other_memory\n    type: builds-on\nsupersedes:\n  - old_memory_name\n---\nBody content goes here. Can contain [[wiki-links]] to other memories.\n```\n\n资料来源：[src/store/memory.ts:35-55]()\n\n## CLI Commands\n\n### Migrate Command\n\nThe `commonplace migrate` command manages your memory directory:\n\n```bash\n# Scan and embed all memories\ncommonplace migrate <dir>\n\n# Preview changes without writing\ncommonplace migrate <dir> --dry-run\n\n# Remove dangling references\ncommonplace migrate <dir> --prune-dangling\n```\n\n#### Migration Workflow\n\n```mermaid\ngraph TD\n    A[commonplace migrate <dir>] --> B{Orphan Detection}\n    B -->|Sidecar exists<br/>no .md file| C[Clean up orphan]\n    B -->|.md exists<br/>no sidecar| D[Embed memory]\n    B -->|Sidecar stale| E[Re-embed memory]\n    B -->|Both fresh| F[Mark unchanged]\n    \n    C --> G[Report: orphaned]\n    D --> H[Report: embedded]\n    E --> I[Report: re-embedded]\n    F --> J[Report: loaded]\n    \n    style G fill:#c8e6c9\n    style H fill:#c8e6c9\n    style I fill:#c8e6c9\n    style J fill:#c8e6c9\n```\n\n资料来源：[src/cli/migrate.ts:50-85]()\n\n### Import from Claude Code\n\nImport memories from Claude Code's auto-memory directories:\n\n```bash\n# Detect candidates\ncommonplace migrate --from claude-code\n\n# Perform import\ncommonplace migrate --from claude-code --auto\n```\n\nThe import:\n1. Scans `~/.claude/projects/*/memory/*.md` for candidates\n2. Copies compatible files to your user store (skips if target exists)\n3. Runs embed pass on newly imported files\n\n资料来源：[src/cli/migrate.ts:120-180]()\n\n## MCP Tool Reference\n\nAfter installation, four tools become available in Claude Code:\n\n### memory_save\n\nSave a new memory:\n\n```json\n{\n  \"name\": \"my_memory\",\n  \"type\": \"project\",\n  \"body\": \"Detailed content here...\"\n}\n```\n\n### memory_search\n\nSearch memories by semantic similarity:\n\n```json\n{\n  \"query\": \"scope handshake\",\n  \"limit\": 3,\n  \"type\": \"feedback\"\n}\n```\n\n### memory_list\n\nList all memories, optionally filtered:\n\n```json\n{\n  \"type\": \"reference\",\n  \"includeSuperseded\": false\n}\n```\n\n### memory_link / memory_unlink\n\nCreate or remove relationships between memories:\n\n```json\n// memory_link\n{\n  \"from\": \"architecture_overview\",\n  \"to\": \"feedback_scope\",\n  \"type\": \"builds-on\"\n}\n```\n\n资料来源：[README.md:100-200]()\n\n## Search and Expansion\n\n### One-Hop Expansion\n\nWhen searching, you can expand results to include connected memories:\n\n```mermaid\ngraph LR\n    A[Query] --> B[Direct Hits]\n    B --> C{expand: 'one-hop'}\n    C -->|Enabled| D[Outbound Edges]\n    D --> E[Neighbors]\n    C -->|Disabled| F[Direct Only]\n    \n    E -.->|via: {source, edge}| B\n```\n\n| Parameter | Values | Default | Description |\n|-----------|--------|---------|-------------|\n| `expand` | `none`, `one-hop` | `none` | Expansion mode |\n| `expandTypes` | edge types array | `['builds-on', 'related-to']` | Which edges to follow |\n| `expandLimit` | integer | `2` | Max neighbors per hit |\n\n资料来源：[README.md:180-220]()\n\n## Development Workflow\n\n### Make Targets\n\n| Target | Purpose |\n|--------|---------|\n| `make typecheck` | Run TypeScript type checking |\n| `make lint` | Run ESLint |\n| `make build` | Compile TypeScript to JavaScript |\n| `make test` | Run test suite |\n| `make audit` | Security audit (non-blocking) |\n\n### Branch Strategy\n\n1. Branch from `main` with a descriptive name\n2. Open a PR against `main`\n3. Ensure CI passes before merge\n4. Squash-merge to keep history linear\n\n资料来源：[CONTRIBUTING.md:5-35]()\n\n## Configuration\n\n### Environment Variables\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | User memory store location |\n| `COMMONPLACE_PROJECT_DIR` | (project root) | Project memory store override |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | Enable `[[name]]` extraction |\n\n资料来源：[src/store/mentions.ts:10-25]()\n\n## Troubleshooting\n\n### Embedding Sidecars\n\nThe `.embedding` sidecar files are derived and regenerable. If embeddings seem stale:\n\n```bash\n# Rebuild all embeddings\ncommonplace migrate <dir>\n```\n\n### Dangling References\n\nIf memories reference names that no longer exist:\n\n```bash\n# Preview dangling removal\ncommonplace migrate <dir> --dry-run --prune-dangling\n\n# Execute cleanup\ncommonplace migrate <dir> --prune-dangling\n```\n\n资料来源：[src/cli/migrate.ts:60-80]()\n\n## See Also\n\n- [Memory Store Architecture](../architecture/memory-store.md) — Detailed internal design\n- [MCP Integration](../integration/mcp-tools.md) — Tool contracts and responses\n- [Contributing Guide](../contributing/CONTRIBUTING.md) — Development standards\n\n---\n\n<a id='system-architecture'></a>\n\n## System Architecture\n\n### 相关页面\n\n相关主题：[Project Structure](#project-structure), [Embedding System](#embedding-system), [Memory Store](#memory-store)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.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/store/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.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- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n\nNote: `src/embedder/index.ts`, `src/server/index.ts`, and `src/server/server.ts` were referenced but not included in the provided context.\n\n</details>\n\n# System Architecture\n\n## Overview\n\nCommonplace is a persistent memory system for AI agents that stores contextual knowledge as markdown files with YAML frontmatter. The system provides semantic search across memories using embeddings, a graph-based relationship model for linking related memories, and a dual-store architecture supporting both user-level and project-level contexts.\n\nThe architecture is designed around the principle that **markdown files are the source of truth** — `.embedding` sidecar files are derived and regenerable at any time. 资料来源：[CLAUDE.md]()\n\n## Core Components\n\n| Component | File | Purpose |\n|-----------|------|---------|\n| MemoryStore | `src/store/memory-store.ts` | Central store managing in-memory index, file I/O, search, and graph edges |\n| Memory I/O | `src/store/memory.ts` | YAML frontmatter parsing, serialization, content hashing |\n| Atomic Write | `src/store/atomic-write.ts` | Safe file writes via temp-file + rename pattern |\n| Mentions Extractor | `src/store/mentions.ts` | Extracts `[[name]]` references from memory bodies |\n| MCP Server | `src/server/handlers.ts` | Tool handlers exposing memory operations via Model Context Protocol |\n| CLI Entry | `src/index.ts` | Command-line interface dispatcher |\n\n## Memory Model\n\n### Data Structure\n\nEach memory is a markdown file with the following structure:\n\n```yaml\n---\nname: memory_name\ndescription: Brief description\ntype: user | feedback | project | reference\nrelations:           # DAR-925, optional\n  - to: other_name\n    type: builds-on\nsupersedes:          # DAR-925, optional\n  - old_name\n---\n<body content>\n```\n\nThe `contentSha` is computed from the canonical form `${type}\\n${name}\\n${description}\\n${body}` — intentionally excluding graph fields (`relations`, `supersedes`) so adding or removing edges does not invalidate embeddings. 资料来源：[src/store/memory.ts:30-35]()\n\n### Memory Types\n\n| Type | Purpose |\n|------|---------|\n| `user` | Personal rules, preferences, identity facts about the human operator |\n| `feedback` | Corrections and lessons learned from prior agent behaviour |\n| `project` | Per-project context (architecture notes, repo conventions) |\n| `reference` | Durable, neutral knowledge (API shapes, formulas, citations) |\n\n资料来源：[README.md]()\n\n## Dual-Store Architecture\n\nCommonplace loads up to two memory stores side by side:\n\n```mermaid\ngraph TD\n    subgraph User_Store[\"User Store (always loaded)\"]\n        U[~/.commonplace/memory]\n    end\n    \n    subgraph Project_Store[\"Project Store (conditional)\"]\n        P[.commonplace/memory in project root]\n    end\n    \n    MS[MemoryStore instances]\n    Search[Search merges across both stores]\n    \n    U --> MS\n    P --> MS\n    MS --> Search\n```\n\n### Store Detection Priority\n\n1. `COMMONPLACE_PROJECT_DIR` env var (explicit override, always wins)\n2. MCP `roots/list` response for project root detection\n3. Current working directory traversal\n\n资料来源：[README.md]()\n\n### Scope Behavior\n\n- **Reads** merge hits across both stores by descending score\n- **Writes** default to `user` scope when `scope` argument is omitted\n- Search results carry a `scope: 'user' | 'project'` tag identifying the source store\n\n## MemoryStore Architecture\n\n### Core Responsibilities\n\nThe `MemoryStore` class is the central orchestrator responsible for:\n\n1. **Indexing** — maintaining an in-memory array of memory entries\n2. **File I/O** — reading/writing `.md` files with YAML frontmatter\n3. **Embedding** — coordinating with the embedder for semantic search\n4. **Graph edges** — managing `relations[]` and `supersedes[]` arrays\n5. **Caching** — detecting directory changes to avoid redundant rescans\n\n资料来源：[src/store/memory-store.ts]()\n\n### Scan and Cache Invalidation\n\nThe `scan()` method rebuilds the in-memory index by walking the directory. Sidecar freshness is determined by:\n\n```mermaid\ngraph TD\n    A[Check .embedding exists] --> B{Decode success?}\n    B -->|No| C[Re-embed]\n    B -->|Yes| D{modelId matches?}\n    D -->|No| C\n    D -->|Yes| E{dim matches?}\n    E -->|No| C\n    E -->|Yes| F{contentSha matches?}\n    F -->|No| C\n    F -->|Yes| G[Sidecar is fresh, reuse]\n    \n    C --> H[Write new .embedding sidecar]\n    G --> I[Use existing sidecar]\n```\n\nReuse criteria per memory:\n- `.embedding` file exists and decodes (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:60-75]()\n\n### Orphan Cleanup (DAR-918)\n\nAfter the per-`.md` pass, `scan()` walks the directory again and removes any `.embedding` file whose matching `<name>.md` is missing. This prevents dead weight accumulation from deleted memories.\n\n```mermaid\ngraph LR\n    A[Scan directory] --> B[Find all .md files]\n    A --> C[Find all .embedding files]\n    B --> D[Build .md set]\n    C --> E[For each .embedding]\n    E --> F{basename.md exists?}\n    F -->|No| G[Delete orphan sidecar]\n    F -->|Yes| H[Keep sidecar]\n```\n\n## Graph System (DAR-925)\n\n### Edge Types\n\n| Type | Storage Location | Behavior |\n|------|------------------|----------|\n| `related-to` | `relations[]` | Deduped by `(to, type)` |\n| `builds-on` | `relations[]` | Deduped by `(to, type)` |\n| `contradicts` | `relations[]` | Deduped by `(to, type)` |\n| `child-of` | `relations[]` | Deduped by `(to, type)` |\n| `supersedes` | `supersedes[]` | Deduped by name |\n| `mentions` | Auto-extracted | From `[[name]]` body tokens |\n\n资料来源：[src/server/handlers.ts:20-30]()\n\n### Edge Operations\n\nThe `MemoryStore` provides two primary graph mutation methods:\n\n**`linkEdge(from, to, type)`**\n- Validates: no self-edges, both memories loaded, no duplicate edges\n- Writes source `.md` through `atomicWrite`\n- Updates in-memory entry in place\n- Calls `MemoryGraph.addEdge()` incrementally\n\n资料来源：[src/store/memory-store.ts:linkEdge-method]()\n\n**`unlinkEdge(from, to, type?)`**\n- Removes matching entry from `relations[]` or `supersedes[]`\n- When `type` omitted, removes ALL edges from → to\n- No-op if edge doesn't exist\n\n### Default Expand Types\n\nWhen searching with graph expansion, the default edge types are `['builds-on', 'related-to']`. Other types require explicit 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:15-20]()\n\n## Atomic Write System (DAR-923)\n\n### Pattern\n\nThe atomic write uses a tmpfile + rename sequence:\n\n1. Generate tmp name: `<basename>.<8-hex-chars>.tmp`\n2. Write data to tmp file in same directory\n3. Rename tmp → target (atomic on same filesystem)\n\n### Safety Guards\n\n```mermaid\ngraph TD\n    A[atomicWrite called] --> B{Same filesystem?}\n    B -->|No| C[Throw: cross-fs rename not atomic]\n    B -->|Yes| D[Write to tmp file]\n    D --> E[Rename tmp → target]\n    E --> F[Release tmp file handle]\n    G[On error] --> H[Cleanup tmp file]\n```\n\n**Cross-filesystem guard**: The implementation stats both the target directory and tmpfile directory, requiring matching `dev` (device number). 资料来源：[src/store/atomic-write.ts]()\n\n### Advisory Locking\n\nMemory operations acquire a proper-lockfile lock before writing:\n\n- Lock target: `<dir>/.locks/<name>.lock`\n- `stale: 5000` — orphaned locks from crashed processes are reclaimed after 5 seconds\n- `realpath: false` — works even when target file doesn't exist yet\n- `ELOCKED` error translated to: `MemoryStore: lock for memory '<name>' is busy`\n\n资料来源：[src/store/memory-store.ts:acquireNameLock]()\n\n## Embedding Pipeline\n\n### Mentions Extraction (DAR-927)\n\nThe `[[name]]` tokenizer extracts unique mention targets from memory bodies:\n\n```typescript\nexport const extractMentions = (body: string): string[]\n```\n\n- Only extracts tokens matching `^[a-z0-9_]+$`\n- Returns unique names in first-occurrence order\n- Gated by `COMMONPLACE_EXTRACT_MENTIONS` env var (default: on)\n\n资料来源：[src/store/mentions.ts]()\n\n### Embedding Flow\n\n```mermaid\ngraph TD\n    A[memory_save or scan] --> B[extractMentions from body]\n    B --> C[MemoryGraph.addMentionsEdge for each]\n    D[Save/write memory] --> E[embedder.embed description + body]\n    E --> F[Write .embedding sidecar]\n    G[Search query] --> H[embedder.embed query]\n    H --> I[Compare vectors with store]\n    I --> J[Return ranked results]\n```\n\n## CLI Architecture\n\n### Command Dispatch\n\nThe CLI entry point (`src/index.ts`) dispatches to subcommands:\n\n| Command | Handler | Purpose |\n|---------|---------|---------|\n| `commonplace migrate` | `migrateMain` | Embed missing/stale sidecars, import from Claude Code |\n| `commonplace graph` | `graphMain` | Graph operations (DAR-933) |\n\n```mermaid\ngraph TD\n    A[commonplace CLI] --> B{First arg}\n    B -->|graph| C[graphMain]\n    B -->|migrate| D[migrateMain]\n    B -->|unknown| E[Error: unknown subcommand]\n    \n    C --> F[embedderFactory]\n    D --> F\n    F --> G[MemoryStore.scan]\n```\n\nThe embedder is constructed via a lazy factory to avoid model loading until needed. 资料来源：[src/index.ts]()\n\n### Migration Modes\n\n**Scan/Embed Pass**:\n1. Load all `.md` files\n2. For each, check if `.embedding` sidecar is fresh\n3. Re-embed stale or missing sidecars\n4. Remove orphan sidecars (`.embedding` with no matching `.md`)\n\n**Import from Claude Code**:\n1. Detect `~/.claude/projects/*/memory/*.md` files\n2. Copy non-colliding files to `COMMONPLACE_USER_DIR`\n3. Run scan/embed pass on imported files\n\n资料来源：[src/cli/migrate.ts]()\n\n## MCP Server Integration\n\nThe MCP handlers expose memory operations as tools:\n\n| Tool | Scope | Description |\n|------|-------|-------------|\n| `memory_save` | user/project | Save memory with auto-embed |\n| `memory_search` | user/project | Semantic search with optional graph expansion |\n| `memory_list` | user/project | List memories by type filter |\n| `memory_read` | user/project | Retrieve single memory |\n| `memory_delete` | user/project | Delete memory and sidecar |\n| `memory_link` | user/project | Create graph edge |\n| `memory_unlink` | user/project | Remove graph edge |\n| `memory_path` | user/project | Get filesystem path for memory |\n\n资料来源：[README.md](), [src/server/handlers.ts]()\n\n### Search Result Structure\n\n```typescript\nexport interface MemorySearchMatch {\n  name: string;\n  type: MemoryType;\n  description: string;\n  body: string;        // Full body, never truncated\n  score: number;       // Cosine similarity, 3 decimals\n  relations: Relation[];\n}\n```\n\nThe body is returned verbatim per DAR-920 ac-3 — no truncation, summarization, or transformation. 资料来源：[src/server/handlers.ts:35-50]()\n\n## Data Flow Summary\n\n```mermaid\ngraph TD\n    subgraph External[\"External Consumers\"]\n        MCP[MCP Tools]\n        CLI[CLI Commands]\n    end\n    \n    subgraph Core[\"MemoryStore Core\"]\n        Index[in-memory index]\n        Graph[MemoryGraph]\n        Embedder[Embedder]\n    end\n    \n    subgraph Persistence[\"Persistence Layer\"]\n        Files[.md files]\n        Sidecars[.embedding sidecars]\n        Locks[.locks/ directory]\n    end\n    \n    MCP --> Core\n    CLI --> Core\n    Core --> Index\n    Core --> Graph\n    Core --> Embedder\n    Index --> Files\n    Index --> Sidecars\n    Core --> Locks\n```\n\n## Key Design Decisions\n\n| Decision | Rationale |\n|----------|------------|\n| Markdown as source of truth | Human-readable, version-control friendly, no lock-in |\n| SHA-256 content hash | Deterministic identity for embedding invalidation |\n| Graph fields excluded from sha | Adding/removing edges doesn't invalidate embeddings |\n| Dual-store architecture | Separates personal context from project-specific knowledge |\n| Atomic writes + advisory locks | Safe concurrent access without database |\n| Lazy embedder factory | Avoid expensive model loading on non-embed subcommands |\n\n资料来源：[src/store/memory.ts:contentSha](), [CLAUDE.md]()\n\n---\n\n<a id='project-structure'></a>\n\n## Project Structure\n\n### 相关页面\n\n相关主题：[System Architecture](#system-architecture), [Memory Store](#memory-store)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\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/cli/migrate.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/migrate.ts)\n- [src/store/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [CONTRIBUTING.md](https://github.com/rickbassham/commonplace/blob/main/CONTRIBUTING.md)\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n</details>\n\n# Project Structure\n\n## Overview\n\nCommonplace is a personal knowledge management system designed for AI agents operating via Claude Code. It provides persistent memory storage through markdown files with YAML frontmatter, vector embeddings for semantic search, and a graph structure for tracking relationships between memories.\n\nThe project is structured as a Node.js CLI application with an MCP (Model Context Protocol) server component. 资料来源：[src/index.ts:1-25]()\n\n## Directory Layout\n\n```\ncommonplace/\n├── src/\n│   ├── index.ts              # CLI entry point and dispatcher\n│   ├── bin/\n│   │   ├── boot.ts           # Boot process for MCP server\n│   │   └── commonplace-mcp.ts # MCP server stdio interface\n│   ├── cli/\n│   │   ├── migrate.ts         # Migration command implementation\n│   │   └── graph.ts           # Graph query command\n│   ├── server/\n│   │   └── server.ts          # MCP protocol server\n│   ├── store/\n│   │   ├── memory-store.ts    # Core memory management\n│   │   ├── memory.ts          # Memory I/O and serialization\n│   │   ├── atomic-write.ts    # Atomic file operations\n│   │   └── mentions.ts        # [[name]] mention extraction\n│   └── embedder/\n│       └── index.ts           # Vector embedding generation\n├── package.json\n└── tsconfig.json\n```\n\n## Entry Points\n\nThe project declares two bin entries in `package.json`:\n\n| Bin Name | Target | Purpose |\n|----------|--------|---------|\n| `commonplace` | `dist/index.js` | Human-readable CLI output for migrate and graph commands |\n| `commonplace-mcp` | `dist/bin/commonplace-mcp.js` | Stdio MCP server for AI tool integration |\n\n资料来源：[src/index.ts:25-40]()\n\nThe deliberate separation ensures the MCP server's JSON-RPC framing is never polluted by CLI output. 资料来源：[src/index.ts:42-45]()\n\n## CLI Dispatcher\n\nThe main CLI entry point (`src/index.ts`) acts as a subcommand router. It supports two primary command paths:\n\n1. **`commonplace migrate`** — Detect known external memory sources and import memories\n2. **`commonplace migrate <dir>`** — Rebuild sidecars for an existing memory directory\n3. **`commonplace graph`** — Query memory relationship graph 资料来源：[src/index.ts:54-77]()\n\n```mermaid\ngraph TD\n    A[commonplace CLI] --> B{Subcommand?}\n    B -->|graph| C[graphMain]\n    B -->|migrate| D{Args?}\n    D -->|detect mode| E[detectImportSources]\n    D -->|import mode| F[runImportFromClaudeCode]\n    D -->|rebuild mode| G[migrateMain]\n```\n\nThe dispatcher uses lazy embedder instantiation — the `Embedder` (which triggers model loading) is only constructed when migrateMain decides to run after argument parsing succeeds. 资料来源：[src/index.ts:63-69]()\n\n## Core Modules\n\n### MemoryStore (`src/store/memory-store.ts`)\n\nThe `MemoryStore` class is the central orchestration component for memory management. It maintains:\n\n- An in-memory index of all loaded memories\n- A directory watcher for detecting changes\n- An optional `MemoryGraph` for relationship tracking\n- A lazy embedder factory for generating vector embeddings\n\nKey responsibilities include scanning directories, managing embedding sidecars, handling atomic writes, and processing graph edges. 资料来源：[src/store/memory-store.ts:1-50]()\n\nThe store implements a lazy-scanning pattern where the directory is scanned on first access, and subsequent operations use the cached in-memory index with mtime-based invalidation. 资料来源：[src/store/memory-store.ts:150-180]()\n\n### Memory I/O (`src/store/memory.ts`)\n\nThe `memory.ts` module handles the serialization and deserialization of individual memory files. Each memory consists of:\n\n**YAML Frontmatter:**\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**Content Hashing:**\nThe module exports `contentSha()` which computes a SHA-256 digest of the canonical form: `${type}\\n${name}\\n${description}\\n${body}`. This hash is used to detect content changes without embedding sidecars. 资料来源：[src/store/memory.ts:45-55]()\n\nThe hash deliberately excludes `relations` and `supersedes` fields — graph edges must not invalidate embeddings. 资料来源：[src/store/memory.ts:56-62]()\n\n### Atomic Write (`src/store/atomic-write.ts`)\n\nThe `atomicWrite()` function provides safe file writes using a temp-file-and-rename pattern:\n\n1. Generate a random tmp file name with 16 hex chars of entropy\n2. Verify source and destination are on the same filesystem\n3. Write data to tmp file\n4. Rename tmp file to target path 资料来源：[src/store/atomic-write.ts:1-20]()\n\nThe same-filesystem guard prevents cross-filesystem atomic rename failures which would break the atomicity guarantee. 资料来源：[src/store/atomic-write.ts:21-27]()\n\n### Mention Extraction (`src/store/mentions.ts`)\n\nThe `mentions.ts` module extracts `[[name]]` wiki-style references from memory bodies. It provides a pure tokenizer that:\n\n- Returns unique mention targets in first-occurrence order\n- Validates names against `^[a-z0-9_]+$` (same pattern as memory filenames)\n- Is gated by `COMMONPLACE_EXTRACT_MENTIONS` env var (defaults to on)\n\nThe extracted mentions are forwarded to `MemoryGraph.addMentionsEdge` during `scan()` and `save()` operations. 资料来源：[src/store/mentions.ts:1-30]()\n\n## Memory Scopes\n\nCommonplace supports two memory stores that can be loaded simultaneously:\n\n| Scope | Location | Purpose |\n|-------|----------|---------|\n| User | `~/.commonplace/memory` (default) | Personal rules, preferences, hard feedback |\n| Project | `<project-root>/.commonplace/memory` | Per-project context, architecture notes |\n\nDetection priority:\n1. `COMMONPLACE_PROJECT_DIR` env var (explicit override)\n2. MCP `roots/list` protocol detection\n3. Current working directory scan 资料来源：[README.md:120-145]()\n\nSearch operations merge hits across both stores by descending score, with each match tagged with its originating scope. 资料来源：[README.md:140-145]()\n\n## Embedding Pipeline\n\nEmbeddings are generated using transformers.js and stored as binary sidecar files (`.embedding`). The sidecar format includes:\n\n- Magic bytes and version header\n- Model ID and dimensions\n- Content SHA for staleness detection\n- Binary vector data 资料来源：[src/store/memory-store.ts:200-230]()\n\nSidecar freshness is validated by checking:\n1. File exists and decodes correctly\n2. `modelId` matches current embedder\n3. `dim` matches current embedder dimensions\n4. `contentSha` matches computed hash of current file 资料来源：[src/store/memory-store.ts:200-220]()\n\n## Migration CLI (`src/cli/migrate.ts`)\n\nThe migrate command performs one-shot maintenance on memory directories:\n\n```mermaid\ngraph LR\n    A[Scan .md files] --> B{Embedding check}\n    B -->|Missing| C[Generate embedding]\n    B -->|Stale| D[Re-generate embedding]\n    B -->|Fresh| E[Use cached]\n    C --> F[Write .embedding sidecar]\n    D --> F\n    E --> G[Orphan cleanup]\n    F --> G\n    G --> H[Optional: prune dangling edges]\n```\n\nOperations include:\n- **Embed new files** — Generate `.embedding` for new memories\n- **Re-embed stale files** — Regenerate when content or model changes\n- **Orphan cleanup** — Remove `.embedding` files with no matching `.md`\n- **Dangling edge pruning** — Remove `relations`/`supersedes` pointing to non-existent memories 资料来源：[src/cli/migrate.ts:1-40]()\n\n## MCP Server Architecture\n\nThe MCP server component provides AI tool access to memory operations:\n\n| Tool | Purpose |\n|------|---------|\n| `memory_save` | Create/update memories with YAML frontmatter |\n| `memory_search` | Semantic vector search across stores |\n| `memory_list` | List memories by type/scope |\n| `memory_path` | Find paths between memories via graph traversal |\n\nThe server uses stdio for communication, keeping its output channel separate from the human-readable CLI to prevent JSON-RPC framing pollution. 资料来源：[src/index.ts:42-45]()\n\n## Workflow Summary\n\n```mermaid\ngraph TD\n    subgraph \"CLI Path\"\n        A1[commonplace migrate] --> A2[Argument parsing]\n        A2 --> A3[Lazy embedder creation]\n        A3 --> A4[scan/detect/import]\n    end\n    \n    subgraph \"MCP Path\"\n        B1[commonplace-mcp] --> B2[Stdio server loop]\n        B2 --> B3[Tool request]\n        B3 --> B4[MemoryStore operations]\n        B4 --> B5[JSON-RPC response]\n    end\n    \n    subgraph \"Shared Core\"\n        C1[MemoryStore] --> C2[memory.ts I/O]\n        C1 --> C3[atomic-write.ts]\n        C1 --> C4[MemoryGraph]\n    end\n    \n    A4 --> C1\n    B4 --> C1\n```\n\n## Memory Types\n\nThe system uses a four-element type taxonomy:\n\n| Type | Description |\n|------|-------------|\n| `user` | Personal rules, preferences, identity facts |\n| `feedback` | Corrections and lessons from prior agent behavior |\n| `project` | Per-project context, architecture, conventions |\n| `reference` | Durable neutral knowledge, API shapes, citations |\n\nThese types are enforced in YAML frontmatter and validated by the serialization layer. 资料来源：[README.md:45-65]()\n\n## Build and CI\n\nThe project uses pnpm with the following make targets for CI validation:\n\n| Target | Purpose |\n|--------|---------|\n| `make typecheck` | TypeScript type checking |\n| `make lint` | Code linting |\n| `make build` | Compile TypeScript |\n| `make test` | Run test suite |\n| `make audit` | Security audit (non-blocking for v0.1) |\n\nAll targets must pass on both Node 20 and Node 22 before PR merge. 资料来源：[CONTRIBUTING.md:20-30]()\n\n---\n\n<a id='memory-data-model'></a>\n\n## Memory Data Model\n\n### 相关页面\n\n相关主题：[Memory Types Taxonomy](#memory-types-taxonomy), [Memory Store](#memory-store), [Embedding System](#embedding-system)\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- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/server/tools.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/tools.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</details>\n\n# Memory Data Model\n\nThe Memory Data Model is the core abstraction in Commonplace—a local-first knowledge management system that persists memories as plain Markdown files with typed YAML frontmatter. Each memory represents a discrete unit of knowledge, preference, or context that the agent can recall, search, and link to other memories.\n\n## Overview\n\nMemories are the atomic units of the Commonplace system. They are stored as `.md` files on disk where each file contains:\n\n1. **YAML frontmatter** carrying typed metadata\n2. **Markdown body** containing the actual knowledge content\n\nThe design philosophy treats the markdown file as the source of truth. Derived artifacts (such as `.embedding` sidecars) can be regenerated from the markdown at any time. 资料来源：[CLAUDE.md](https://github.com/rickbassham/commonplace/blob/main/CLAUDE.md)\n\n```mermaid\ngraph LR\n    A[Memory Input] --> B[YAML Frontmatter]\n    A --> C[Markdown Body]\n    B --> D[.md File]\n    C --> D\n    D --> E[.embedding Sidecar]\n    D --> F[Search Index]\n    D --> G[Graph Edges]\n```\n\n## Memory Types\n\nCommonplace defines a four-element taxonomy for categorizing memories. Every memory must declare its type in the frontmatter. 资料来源：[README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n\n| Type | Description | Use Case |\n|------|-------------|----------|\n| `user` | Personal rules, preferences, and identity facts about the human operator | Storing user preferences, communication style, work habits |\n| `feedback` | Corrections and lessons learned from prior agent behavior | Persistent course-corrections, things that didn't work |\n| `project` | Per-project context | Architecture notes, repo conventions, decisions that bind to one codebase |\n| `reference` | Durable, neutral knowledge | API shapes, formulas, citations, lookup-by-meaning content |\n\n### Type Constraints\n\nThe `type` field is mandatory and validated against the allowed set. Attempting to save a memory with an invalid type throws an error:\n\n```typescript\nif (!isMemoryType(memory.type)) {\n  throw new Error(\n    `memory.type must be one of ${MEMORY_TYPES.join(', ')}; got ${JSON.stringify(memory.type)}`,\n  );\n}\n```\n\n资料来源：[src/store/memory.ts:parseMemory](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n## Memory Structure\n\n### TypeScript Interface\n\n```typescript\ninterface Memory {\n  name: string;\n  description: string;\n  type: MemoryType;\n  body: string;\n  relations: Relation[];\n  supersedes: string[];\n}\n```\n\n### Frontmatter Schema\n\nEach memory file follows this YAML frontmatter structure:\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: other_memory_name\n    type: builds-on\nsupersedes:\n  - old_memory_name\n---\n<markdown body content>\n```\n\n资料来源：[src/store/memory.ts:serializeMemory](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n### Field Specifications\n\n| Field | Type | Required | Validation |\n|-------|------|----------|------------|\n| `name` | string | Yes | Must match `^[a-z0-9_]+$`; becomes the filename stem |\n| `description` | string | Yes | Short human-readable summary |\n| `type` | enum | Yes | One of: `user`, `feedback`, `project`, `reference` |\n| `body` | string | Yes | Arbitrary markdown content |\n| `relations` | Relation[] | No | Defaults to `[]`; typed graph edges |\n| `supersedes` | string[] | No | Defaults to `[]`; names of superseded memories |\n\n## Name Validation\n\nMemory names must conform to the pattern `^[a-z0-9_]+$` (lowercase alphanumeric characters and underscores only). This restriction ensures:\n\n- Names are filesystem-safe (no path separators)\n- Names work consistently across storage backends\n- Mention extraction (`[[name]]`) has predictable matching\n\n```typescript\nexport const NAME_PATTERN = /^[a-z0-9_]+$/;\n\nconst validateName = (raw: unknown, ctx: string): string => {\n  if (typeof raw !== 'string') {\n    throw new Error(`${ctx} must be a non-empty string; got ${JSON.stringify(raw)}`);\n  }\n  if (!NAME_PATTERN.test(raw)) {\n    throw new Error(\n      `${ctx} must match ${NAME_PATTERN}; got ${JSON.stringify(raw)}`,\n    );\n  }\n  return raw;\n};\n```\n\n资料来源：[src/store/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n## Relation Model (DAR-925)\n\nThe `relations` field enables explicit typed edges between memories, forming a graph structure. 资料来源：[src/store/memory.ts:parseRelations](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n### Relation Types\n\n| Type | Semantics | Default in Search? |\n|------|-----------|-------------------|\n| `builds-on` | This memory extends or depends on another | Yes |\n| `related-to` | Topic or context overlap with another memory | Yes |\n| `contradicts` | This memory contradicts another | No |\n| `child-of` | Hierarchical parent relationship | No |\n| `mentions` | Body content references another memory | No |\n| `supersedes` | This memory replaces another (via `supersedes` field) | No |\n\nThe default expand types for search results are `['builds-on', 'related-to']`. These are the edge types most likely to surface useful neighbors the agent did not explicitly request. 资料来源：[src/server/handlers.ts:DEFAULT_EXPAND_TYPES](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n\n### Relation Validation\n\nRelations are validated during parse and write operations:\n\n- Each entry must be a mapping with `to` and `type` keys\n- The `to` value must be a valid memory name\n- The `type` value must be one of the allowed relation types\n- Duplicate `(to, type)` pairs are deduplicated preserving first-occurrence order\n- Self-referential relations (`to === memory.name`) are rejected\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:parseRelation](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n## Content SHA (Canonicalization)\n\nThe `contentSha` function computes a SHA-256 hex digest that serves as a canonical identifier for memory content. This digest is used to determine when embeddings need regeneration.\n\n### Canonical Form\n\nThe SHA is computed over the concatenation of:\n\n```\n${type}\\n${name}\\n${description}\\n${body}\n```\n\n### Critical Design Decision\n\n**Graph fields (`relations` and `supersedes`) do NOT participate in the SHA computation.** Adding or removing graph edges does not invalidate the corresponding embedding sidecar. This means:\n\n- Embeddings are based on semantic content only\n- Graph operations are lightweight and don't trigger re-embedding\n- The `contentSha` remains stable across graph modifications\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:contentSha](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n## Serialization and Parsing\n\n### Serialization (`serializeMemory`)\n\nThe `serializeMemory` function converts an in-memory `Memory` object to its canonical UTF-8 markdown representation:\n\n1. Validates the memory type\n2. Parses and deduplicates relations and supersedes\n3. Rejects self-referential relations\n4. Serializes YAML frontmatter followed by the body\n\n```typescript\nexport const serializeMemory = (memory: Memory): string => {\n  if (!isMemoryType(memory.type)) {\n    throw new Error(\n      `memory.type must be one of ${MEMORY_TYPES.join(', ')}; got ${JSON.stringify(memory.type)}`,\n    );\n  }\n  const relations = parseRelations(memory.relations);\n  const supersedes = parseSupersedes(memory.supersedes);\n  // ... validation checks ...\n  const fmObject = {\n    name: memory.name,\n    description: memory.description,\n    type: memory.type,\n    ...(relations.length > 0 ? { relations } : {}),\n    ...(supersedes.length > 0 ? { supersedes } : {}),\n  };\n  const fmYaml = stringifyYaml(fmObject);\n  return `---\\n${fmYaml}---\\n${memory.body}`;\n};\n```\n\n资料来源：[src/store/memory.ts:serializeMemory](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n### Parsing (`parseMemory`)\n\nThe `parseMemory` function reads a markdown file and extracts the typed memory object:\n\n1. Splits on `\\n---\\n` to separate frontmatter from body\n2. Parses YAML frontmatter using `parseYaml`\n3. Validates required fields (`name`, `description`, `type`)\n4. Parses optional `relations` and `supersedes` arrays\n5. Rejects unknown frontmatter fields\n\n```typescript\nexport const parseMemory = (raw: string): Memory => {\n  // Splits on the first `---` boundary\n  const fmEnd = raw.indexOf('\\n---', 4);\n  const fmRaw = raw.slice(4, fmEnd);\n  const body = raw.slice(fmEnd + 4).replace(/^\\n/, '');\n  const fmObject = parseYaml(fmRaw);\n  // ... field extraction and validation ...\n  return { name, description, type: type as MemoryType, body, relations, supersedes };\n};\n```\n\n资料来源：[src/store/memory.ts:parseMemory](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n\n## Memory Store Architecture\n\nThe `MemoryStore` class manages a directory of memory files and their associated sidecars. 资料来源：[src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n\n```mermaid\ngraph TD\n    subgraph MemoryStore\n        A[Directory] --> B[scan]\n        A --> C[save]\n        A --> D[delete]\n        A --> E[linkEdge]\n        A --> F[unlinkEdge]\n    end\n    B --> G[Memory Entry]\n    C --> H[serializeMemory]\n    C --> I[atomicWrite]\n    E --> J[parseMemory]\n    E --> K[serializeMemory]\n    G --> L[contentSha]\n    G --> M[Embedding Sidecar]\n```\n\n### Key Operations\n\n| Operation | Description |\n|-----------|-------------|\n| `scan()` | Discovers all `.md` files, validates/reuses/regenerates `.embedding` sidecars, removes orphans |\n| `save()` | Creates new memory file with atomic write; refuses to overwrite |\n| `delete()` | Removes memory file and sidecar |\n| `linkEdge()` | Adds a typed relation to a memory |\n| `unlinkEdge()` | Removes a typed relation from a memory |\n\n### Orphan Cleanup (DAR-918)\n\nAfter scanning, `scan()` walks the directory again and removes any `.embedding` sidecar whose matching `<name>.md` is missing. This prevents silent accumulation of dead-weight sidecar files. 资料来源：[src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n\n## Mention Extraction (DAR-927)\n\nThe `mentions` module extracts `[[name]]` style references from memory body content. 资料来源：[src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n\n### Extraction Rules\n\n- Only `<name>` tokens matching `^[a-z0-9_]+$` are recognized\n- Other patterns are silently ignored\n- Mentions are forwarded to `MemoryGraph.addMentionsEdge`\n- Extraction is gated by `COMMONPLACE_EXTRACT_MENTIONS` env var (default: on)\n\n### Out of Scope\n\n- Wiki-style backlink rendering or autocomplete\n- Code-fence or inline-code awareness (mentions in code blocks are extracted like any other)\n- Surfacing mentions through MCP tool responses\n\n## Multi-Store Design\n\nCommonplace supports two memory stores with different scopes: 资料来源：[src/server/tools.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/tools.ts)\n\n| Scope | Location | Purpose |\n|-------|----------|---------|\n| `user` | `COMMONPLACE_USER_DIR` (default: `~/.commonplace`) | Cross-project memories |\n| `project` | Detected project root | Per-project memories |\n\n### Scope Behavior\n\n- **Reads** merge across both stores when `scope` is omitted\n- **Writes** default to `user` when `scope` is omitted\n- **Project store** auto-creates on first `memory_save({ scope: 'project' })`\n- **Deletions** require explicit `scope` when name exists in both stores\n\n## MCP Tool Integration\n\nThe four core memory tools interact with the data model as follows: 资料来源：[src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n\n### memory_save\n\nCreates a new memory file. Validates name, type, and description against the data model constraints.\n\n### memory_list\n\nReturns frontmatter-only entries (name, type, description, scope) without body content.\n\n### memory_search\n\nReturns matches with full body content. Each match includes:\n- `name`, `type`, `description`, `body`\n- `score` (cosine similarity, 3 decimals)\n- `relations` (outgoing authored edges)\n\n### memory_delete\n\nRemoves memory and sidecar. Requires `scope` when name exists in both stores.\n\n### memory_link / memory_unlink\n\nManipulate explicit typed edges without modifying the memory body or triggering re-embedding.\n\n## Write Safety\n\nMemory writes implement several safety guarantees: 资料来源：[src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n\n1. **No Overwrite** - `save()` refuses to overwrite existing entries; callers must `delete()` first\n2. **Atomic Writes** - Uses temp-file + rename pattern (DAR-923)\n3. **Advisory Locking** - Per-name locks prevent racing writers across processes\n4. **Lazy Directory Creation** - Parent directory created recursively on first save to project scope\n\n## Sidecar Format\n\nEach memory may have an associated `.embedding` sidecar file containing:\n\n- Magic number for format detection\n- Version byte\n- Model ID\n- Dimensions\n- `contentSha` for cache validation\n- Binary embedding vector\n\nThe sidecar is derived from the `.md` file and regenerated when:\n- The sidecar is missing or corrupt\n- The `modelId` or `dim` doesn't match the current embedder\n- The `contentSha` doesn't match the current memory content\n\n资料来源：[src/store/memory-store.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory-store.ts)\n\n## Summary\n\nThe Memory Data Model provides:\n\n| Aspect | Implementation |\n|--------|---------------|\n| **Storage** | Plain `.md` files with YAML frontmatter |\n| **Metadata** | Name, type, description, relations, supersedes |\n| **Content** | Arbitrary markdown body |\n| **Identification** | SHA-256 over type, name, description, body |\n| **Taxonomy** | Four types: user, feedback, project, reference |\n| **Graph** | Typed relations with six edge types |\n| **Mentions** | `[[name]]` extraction from body content |\n| **Stores** | User-scope and project-scope directories |\n| **Safety** | No-overwrite contract, atomic writes, advisory locks |\n\n---\n\n<a id='memory-types-taxonomy'></a>\n\n## Memory Types Taxonomy\n\n### 相关页面\n\n相关主题：[Memory Data Model](#memory-data-model), [Memory Store](#memory-store), [Semantic Search](#semantic-search)\n\n<details>\n<summary>Source Files Used</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/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- [src/server/tools.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/tools.ts)\n- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n</details>\n\n# Memory Types Taxonomy\n\n## Overview\n\nThe Memory Types Taxonomy is a four-element classification system that categorizes memories stored in Commonplace. Each memory carries a `type` field that determines its scope, purpose, and how it should be used by the AI agent. This taxonomy enables organized knowledge management across personal rules, learned corrections, project-specific context, and reference materials.\n\nMemory types serve as the primary organizational primitive for the entire system. They appear in YAML frontmatter of markdown files, are validated at write time, and are used to filter search results and graph traversals. Source: [README.md]()\n\n## The Four Memory Types\n\n| Type | Purpose | Scope | Typical Content |\n|------|---------|-------|-----------------|\n| `user` | Personal rules, preferences, and identity facts about the human operator | Cross-project | Operating preferences, name, role, interaction style |\n| `feedback` | Corrections and lessons learned from prior agent behavior | Cross-project | Persistent course-corrections, mistake patterns |\n| `project` | Per-project context specific to one codebase | Single project | Architecture notes, repo conventions, decisions |\n| `reference` | Durable, neutral knowledge | Cross-project | API shapes, formulas, citations, lookup knowledge |\n\nSource: [README.md]()\n\n### User Type\n\nThe `user` type captures information about the human operating the AI agent. This includes personal rules, preferences, identity facts, and operational context that should persist across all projects. Memories of this type represent the agent's understanding of who it is working with and how that person prefers to be addressed or assisted.\n\nExample frontmatter:\n```yaml\n---\nname: user_prefers_typescript\ndescription: Prefers TypeScript over JavaScript for new projects\ntype: user\n---\n```\n\n### Feedback Type\n\nThe `feedback` type stores corrections and lessons learned from prior agent behavior. When an agent makes a mistake or receives guidance, the correction is persisted as a feedback memory to prevent recurrence. These memories represent persistent course-corrections that shape future interactions.\n\n### Project Type\n\nThe `project` type contains information that is specific to a single codebase or repository. Unlike `user` and `feedback` memories which are shared across all projects, `project` memories are isolated to a particular working directory. This type is used for architecture notes, conventions unique to the codebase, and decisions that only apply within that project.\n\n### Reference Type\n\nThe `reference` type holds durable, neutral knowledge that can be looked up by meaning. This includes API documentation, formulas, citations, and any factual information that should persist independently of specific projects or interactions.\n\n## Memory File Structure\n\nEach memory is stored as a markdown file with YAML frontmatter. The frontmatter defines the memory's metadata while the body contains the actual content.\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: project_planning_rules\n    type: builds-on\nsupersedes:\n  - old_scope_rules\n---\n<markdown body content>\n```\n\nSource: [src/store/memory.ts:1-50]()\n\n## Type Validation\n\nThe system enforces strict validation on the `type` field. During save operations, the type is validated against the allowed set. An invalid type results in an error that lists all permitted values:\n\n```\nmemory.type must be one of user, feedback, project, reference; got \"invalid_type\"\n```\n\nSource: [src/store/memory.ts:100-105]()\n\n### Validation Code\n\n```typescript\nexport const isMemoryType = (v: unknown): v is MemoryType =>\n  typeof v === 'string' && (MEMORY_TYPES as readonly string[]).includes(v);\n```\n\nSource: [src/store/memory.ts:60-62]()\n\n## Scope and Store Architecture\n\nThe taxonomy is complemented by a two-tier store architecture that separates memories by scope:\n\n```mermaid\ngraph TD\n    A[Memory Store] --> B[User Store]\n    A --> C[Project Store]\n    B --> D[~/.commonplace/memories/]\n    C --> E[.claude/memories/]\n```\n\nBoth stores accept the same four memory types, but the `project` store is isolated to project-specific memories while the `user` store holds cross-project memories of any type.\n\n### Scope Parameter\n\nWhen saving memories, the `scope` argument determines which store receives the data:\n\n| Scope Value | Target Store | Default |\n|-------------|--------------|---------|\n| `user` | User store (`~/.commonplace/memories/`) | Yes |\n| `project` | Project store (`.claude/memories/`) | No |\n\nSource: [src/server/tools.ts:50-60]()\n\n## Type Usage in API Tools\n\n### memory_save\n\nThe `memory_save` tool requires the `type` parameter:\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `name` | string | Yes | Memory identifier matching `^[a-z0-9_]+$` |\n| `type` | enum | Yes | One of: `user`, `feedback`, `project`, `reference` |\n| `description` | string | Yes | Short human description |\n| `body` | string | Yes | Markdown body content |\n| `scope` | enum | No | `user` (default) or `project` |\n\nSource: [src/server/tools.ts:30-55]()\n\n### memory_list\n\nThe `memory_list` tool returns memories with their type information:\n\n```typescript\ninterface MemoryListResult {\n  memories: Array<{\n    name: string;\n    type: MemoryType;\n    description: string;\n    scope: Scope;\n  }>;\n}\n```\n\nSource: [src/server/handlers.ts:80-90]()\n\n## Type Filtering in Search\n\nWhen searching memories, the system can filter by type. The default search behavior includes all types, but callers can specify a subset:\n\n```typescript\ninterface MemorySearchParams {\n  query: string;\n  types?: MemoryType[];  // Filter by memory types\n  scope?: Scope;         // Filter by user/project store\n}\n```\n\nSource: [src/server/handlers.ts:100-110]()\n\n## Graph Relations by Type\n\nGraph edges between memories are typed, and the default expansion types in graph queries prioritize certain memory types:\n\n```typescript\nexport const DEFAULT_EXPAND_TYPES: readonly EdgeType[] = \n  ['builds-on', 'related-to'] as const;\n```\n\nSource: [src/server/handlers.ts:15-20]()\n\n## Mention Extraction by Type\n\nThe `[[name]]` mention extraction system operates on memory bodies regardless of type. All four memory types support body-mention extraction when the environment variable `COMMONPLACE_EXTRACT_MENTIONS` is set (default: enabled).\n\nSource: [src/store/mentions.ts:20-30]()\n\n## Import and Migration\n\nThe migration system can import memories from Claude Code's auto-memory directories. During import, memories are classified and saved to the appropriate store:\n\n```mermaid\ngraph LR\n    A[Claude Code<br/>auto-memory] --> B[Detect Type]\n    B --> C{Source Type}\n    C -->|project memory| D[Project Store]\n    C -->|other| E[User Store]\n```\n\nSource: [src/cli/migrate.ts:30-60]()\n\n## Best Practices\n\n1. **Use `user` for personal context** - Store facts about the human operator that should persist across all projects.\n\n2. **Use `feedback` for corrections** - Record agent mistakes and guidance to improve future responses.\n\n3. **Use `project` for codebase-specific knowledge** - Keep architecture and convention notes isolated to their relevant repository.\n\n4. **Use `reference` for reusable knowledge** - Store API documentation, formulas, and factual information that can be looked up by meaning.\n\n5. **Validate before saving** - Ensure the type field is valid to avoid runtime errors.\n\n## Related Features\n\n- [Graph Relations](graph-relations) - Edges between memories\n- [Mention Extraction](mentions) - `[[name]]` syntax support\n- [Search API](search) - Querying memories by type\n- [Migration Tools](migration) - Importing from external sources\n\n---\n\n<a id='memory-store'></a>\n\n## Memory Store\n\n### 相关页面\n\n相关主题：[Memory Data Model](#memory-data-model), [Embedding System](#embedding-system), [Semantic Search](#semantic-search)\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/memory.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/memory.ts)\n- [src/store/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.ts)\n- [src/store/mentions.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/mentions.ts)\n- [src/store/graph.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/graph.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n- [src/server/tools.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/tools.ts)\n- [CHANGELOG.md](https://github.com/rickbassham/commonplace/blob/main/CHANGELOG.md)\n</details>\n\n# Memory Store\n\nThe Memory Store is the core persistence layer of the Commonplace system. It manages the lifecycle of memory entries—markdown files with YAML frontmatter and binary embedding sidecars—providing atomic writes, concurrent access control, semantic search, and graph-based relationship tracking.\n\n## Overview\n\nThe Memory Store implements a local-first, file-based storage system where each memory is persisted as a `.md` file alongside a derived `.embedding` sidecar. It supports two independent stores (`user` and `project`) and exposes both low-level filesystem operations and high-level search/list functionality through an internal API consumed by the MCP server layer.\n\n**Key characteristics:**\n\n| Characteristic | Description |\n|----------------|-------------|\n| Storage model | Local filesystem with markdown + sidecar files |\n| Concurrency | Per-memory advisory locking via `proper-lockfile` |\n| Atomicity | Write-through-temp-and-rename pattern |\n| Search | Offline semantic search using `transformers.js` + `bge-base-en-v1.5` |\n| Graph | In-memory adjacency list for typed relationships |\n| Mentions | `[[name]]` extraction from body content |\n\n资料来源：[memory-store.ts:1-50]()\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"Memory Store Layer\"\n        MS[MemoryStore]\n        G[MemoryGraph]\n        ATOMIC[atomicWrite]\n        LOCK[acquireNameLock]\n    end\n    \n    subgraph \"Persistence Layer\"\n        FS[FileSystem]\n        MD[*.md Files]\n        EMB[*.embedding Sidecars]\n    end\n    \n    subgraph \"Integration\"\n        HANDLERS[MCP Handlers]\n        SEARCH[Search Handler]\n    end\n    \n    MS --> G\n    MS --> ATOMIC\n    MS --> LOCK\n    ATOMIC --> FS\n    LOCK --> FS\n    MS --> MD\n    MS --> EMB\n    HANDLER_FACTORIES[Handler Factories] --> MS\n    SEARCH --> MS\n```\n\nThe `MemoryStore` class owns the directory-scanning, file I/O, embedding caching, and mtime-based invalidation logic. It delegates locking to `acquireNameLock`, writes to `atomicWrite`, and maintains an optional `MemoryGraph` instance for relationship tracking.\n\n资料来源：[memory-store.ts:50-120]()\n\n## Memory Data Model\n\n### Memory Structure\n\nA memory consists of:\n\n1. **YAML Frontmatter**: Structured metadata\n2. **Markdown Body**: Arbitrary content containing `[[name]]` mention syntax\n\n```typescript\ninterface Memory {\n  name: string;           // Filename stem, matches ^[a-z0-9_]+$\n  description: string;    // Short human description\n  type: MemoryType;       // 'user' | 'feedback' | 'project' | 'reference'\n  body: string;           // Markdown content\n  relations: Relation[];  // Typed graph edges (DAR-925)\n  supersedes: string[];   // Names of superseded memories\n}\n\ninterface Relation {\n  to: string;             // Target memory name\n  type: RelationType;     // 'builds-on' | 'related-to' | 'contradicts' | 'child-of'\n}\n```\n\n资料来源：[memory.ts:1-80]()\n\n### File Format\n\nMemory files use canonical markdown with YAML frontmatter:\n\n```markdown\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: project_context\n    type: builds-on\nsupersedes:\n  - old_feedback\n---\n<body content here>\n```\n\nThe frontmatter is canonicalized by `stringifyYaml` to ensure round-trip idempotence. The file is the source of truth; sidecars are derived.\n\n资料来源：[memory.ts:80-120]()\n\n### Content Hashing\n\nThe `contentSha` function computes a deterministic SHA-256 digest used for sidecar validation:\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**Important**: The sha covers only the v0.1 baseline frontmatter (`type`, `name`, `description`) plus the body. Graph fields (`relations`, `supersedes`) are excluded to prevent embedding invalidation when edges change.\n\n资料来源：[memory.ts:140-155]()\n\n## Core Operations\n\n### Initialization\n\n```typescript\nclass MemoryStore {\n  constructor(\n    dir: string,\n    embedder: Embedder,\n    graph?: MemoryGraph,\n    lockOptions?: LockOptions\n  )\n}\n```\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `dir` | `string` | Path to the memory directory |\n| `embedder` | `Embedder` | Embedding pipeline (model ID, dimension, encode function) |\n| `graph` | `MemoryGraph?` | Optional graph instance for relationship tracking |\n| `lockOptions` | `LockOptions?` | Lock staleness and retry configuration |\n\nThe constructor stores the embedder reference for lazy re-embedding and initializes in-memory state. The directory is created lazily on first save.\n\n资料来源：[memory-store.ts:50-80]()\n\n### Scan Operation\n\nThe `scan()` method rebuilds the in-memory index from disk:\n\n```typescript\nasync scan(opts?: ScanOptions): Promise<ScanResult>\n```\n\n**Behavior:**\n1. Walk the directory for `*.md` files\n2. For each file, check if the matching `*.embedding` sidecar is reusable based on:\n   - Magic + version + length checks\n   - `modelId` match\n   - Dimension match\n   - `contentSha` match\n3. Re-embed and rewrite sidecar when stale\n4. Remove orphan sidecars (files with no matching `.md`)\n\n| Sidecar Check | Fresh If... |\n|---------------|-------------|\n| File exists | Yes |\n| Decodes correctly | Yes |\n| `modelId` matches | Yes |\n| `dim` matches | Yes |\n| `contentSha` matches | Yes |\n\n资料来源：[memory-store.ts:150-250]()\n\n### Save Operation\n\n```typescript\nasync save(name: string, memory: Memory): Promise<void>\n```\n\n**Workflow:**\n\n```mermaid\ngraph TD\n    START[save called] --> CHECK_EXISTS{existsSync<br/>${name}.md?}\n    CHECK_EXISTS -->|No| MKDIR[mkdir -p dir]\n    CHECK_EXISTS -->|Yes| ERROR[Error: exists]\n    MKDIR --> LOCK[acquireNameLock]\n    LOCK --> RE_CHECK{existsSync<br/>${name}.md?}\n    RE_CHECK -->|Yes| RELEASE[Release lock]\n    RE_CHECK -->|No| SERIALIZE[serializeMemory]\n    SERIALIZE --> EMBED[embed body]\n    EMBED --> ATOMIC_WRITE_MD[atomicWrite<br/>${name}.md]\n    ATOMIC_WRITE_MD --> ATOMIC_WRITE_EMB[atomicWrite<br/>${name}.embedding]\n    ATOMIC_WRITE_EMB --> UPDATE_INDEX[Update in-memory index]\n    UPDATE_INDEX --> RELEASE\n    RELEASE --> DONE[Return]\n    ERROR --> ABORT[Throw]\n```\n\n**Key behaviors:**\n- Refuses to overwrite existing entries (delete first, then save)\n- Lazily creates directory on first save\n- Holds per-name advisory lock for entire write operation\n- Uses atomic write for both `.md` and `.embedding`\n\n资料来源：[memory-store.ts:280-380]()\n\n### Search Operation\n\n```typescript\nasync search(query: string, opts?: SearchOptions): Promise<MemorySearchResult>\n```\n\n**Search options:**\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `type` | `MemoryType?` | undefined | Filter by memory type |\n| `limit` | `number` | 20 | Maximum results |\n| `expandTypes` | `EdgeType[]` | `['builds-on', 'related-to']` | Edge types to include |\n| `minScore` | `number` | 0 | Minimum similarity score |\n\nThe search computes query embeddings via the embedder, performs brute-force top-k cosine similarity against all loaded memories, and enriches results with outgoing graph edges. Superseded memories are excluded by default.\n\n资料来源：[memory-store.ts:380-450](), [handlers.ts:80-120]()\n\n### Delete Operation\n\n```typescript\nasync delete(name: string, opts?: DeleteOptions): Promise<void>\n```\n\n```mermaid\ngraph TD\n    START[delete called] --> LOCK[acquireNameLock]\n    LOCK --> UNLINK_MD[unlinkSync<br/>${name}.md]\n    UNLINK_MD --> UNLINK_EMB[unlinkSync<br/>${name}.embedding]\n    UNLINK_EMB --> REMOVE_INDEX[Remove from in-memory index]\n    REMOVE_INDEX --> GRAPH_REMOVE[graph.remove<br/>if exists]\n    GRAPH_REMOVE --> RELEASE[Release lock]\n    RELEASE --> DONE\n```\n\n资料来源：[memory-store.ts:450-500]()\n\n### List Operation\n\n```typescript\nasync list(opts?: ListOptions): Promise<MemoryListResult>\n```\n\nReturns frontmatter-only entries (name, type, description, scope) without body content. Filters can be applied by type.\n\n资料来源：[memory-store.ts:500-550](), [handlers.ts:150-180]()\n\n## Atomic Write Mechanism\n\nThe `atomicWrite` helper implements the write-through-temp-and-rename pattern:\n\n```typescript\nexport const atomicWrite = async (\n  target: string,\n  data: Buffer | Uint8Array\n): Promise<void>\n```\n\n**Algorithm:**\n\n```mermaid\ngraph TD\n    START[atomicWrite] --> TMP[Generate tmp filename]\n    TMP --> STAT_TMP[stat tmp parent]\n    STAT_TMP --> CHECK_FS{same filesystem?}\n    CHECK_FS -->|No| ERROR[Error: cross-fs]\n    CHECK_FS -->|Yes| WRITE[writeFileSync tmp]\n    WRITE --> FSYNC[fsync tmp file]\n    FSYNC --> RENAME[renameSync tmp → target]\n    RENAME --> DONE\n```\n\n**Safety guarantees:**\n- Same-filesystem check via `dev` comparison prevents cross-fs rename\n- Random 16-char hex suffix prevents collision\n- `fsync` before rename ensures durability\n- Failure during write leaves original file untouched\n\n资料来源：[atomic-write.ts:1-60]()\n\n## Concurrency Control\n\n### Per-Memory Locking\n\nThe `acquireNameLock` function uses `proper-lockfile` for advisory locking:\n\n```typescript\nconst acquireNameLock = async (\n  dir: string,\n  name: string\n): Promise<() => Promise<void>>\n```\n\n**Configuration:**\n\n| Option | Value | Purpose |\n|--------|-------|---------|\n| `stale` | 5000ms | Reclaim orphaned locks from crashed holders |\n| `realpath` | `false` | Works before file exists |\n| `retries` | configurable | Retry on transient lock acquisition failure |\n\n**Lock target pattern:** `${dir}/.locks/${name}.lock`\n\nThe lock is held for the entire save operation (both `.md` and `.embedding` writes), serializing concurrent writers on the same memory name across processes.\n\n资料来源：[memory-store.ts:120-170]()\n\n## Graph Integration\n\nThe `MemoryStore` optionally owns a `MemoryGraph` instance for tracking relationships:\n\n```typescript\nclass MemoryGraph {\n  add(memory: GraphMemory): void\n  addEdge(edge: Edge): void\n  remove(name: string): void\n  getOutbound(name: string): Edge[]\n  getInbound(name: string): Edge[]\n  detectDangling(): Edge[]\n  rebuild(memories: GraphMemory[], mentions: Mention[]): void\n}\n```\n\n**Edge types:**\n| Type | Default Included | Description |\n|------|------------------|--------------|\n| `builds-on` | Yes | Forward dependency |\n| `related-to` | Yes | General association |\n| `mentions` | No | Body `[[name]]` extraction |\n| `supersedes` | No | Replacement relationship |\n| `contradicts` | No | Contradictory memory |\n| `child-of` | No | Hierarchical relationship |\n\n资料来源：[graph.ts:1-80](), [handlers.ts:40-60]()\n\n## Mention Extraction\n\nThe `extractMentions` function parses `[[name]]` tokens from body content:\n\n```typescript\nexport const extractMentions(body: string): string[]\n```\n\n**Rules:**\n- Matches `<name>` tokens with pattern `^[a-z0-9_]+$`\n- Returns unique set in first-occurrence order\n- Extraction can be disabled via `COMMONPLACE_EXTRACT_MENTIONS=false`\n\nThe MemoryStore calls `extractMentions` during `scan()` and `save()`, forwarding results to `MemoryGraph.addMentionsEdge`.\n\n资料来源：[mentions.ts:1-50]()\n\n## MCP Tool Integration\n\nThe MemoryStore is consumed by MCP handler factories in `handlers.ts`:\n\n| Handler Factory | MCP Tool | Operation |\n|-----------------|----------|-----------|\n| `createMemorySaveHandler` | `memory_save` | Save new memory |\n| `createMemoryListHandler` | `memory_list` | List memories |\n| `createMemoryDeleteHandler` | `memory_delete` | Delete memory |\n| `createMemorySearchHandler` | `memory_search` | Semantic search |\n| `createMemoryLinkHandler` | `memory_link` | Add graph edge |\n| `createMemoryUnlinkHandler` | `memory_unlink` | Remove graph edge |\n\nAll handlers accept an optional `scope: 'user' | 'project'` argument that selects which store to operate on.\n\n资料来源：[handlers.ts:180-300](), [tools.ts:1-100]()\n\n## Configuration\n\n### Directory Configuration\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `COMMONPLACE_USER_DIR` | `~/.config/commonplace` | User store directory |\n| `COMMONPLACE_PROJECT_DIR` | (auto-detected) | Project store directory |\n\n### Feature Flags\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | Enable `[[name]]` extraction |\n\n资料来源：[memory-store.ts:1-50](), [mentions.ts:1-30]()\n\n## Error Handling\n\n| Error Condition | Message | Recovery |\n|-----------------|---------|----------|\n| Duplicate save | `MemoryStore.save: a memory file already exists at ${path}` | Delete first, then save |\n| Lock busy | `MemoryStore: lock for memory \\`${name}\\` is busy` | Retry after other writer releases |\n| Cross-filesystem atomic | `atomicWrite: refusing to rename across filesystems` | Check filesystem layout |\n| Invalid memory type | `memory.type must be one of ${MEMORY_TYPES}` | Validate before save |\n| Self-reference relation | `memory relation target cannot be self` | Remove invalid relation |\n\n资料来源：[memory-store.ts:280-350](), [memory.ts:180-220](), [atomic-write.ts:30-40]()\n\n## Sidecar Format\n\nEmbedding sidecars are binary files with the following structure:\n\n```\n[magic: 4 bytes][version: 1 byte][dim: 4 bytes LE][vector: dim * 4 bytes]\n```\n\n| Field | Size | Description |\n|-------|------|-------------|\n| magic | 4 bytes | Magic bytes for file identification |\n| version | 1 byte | Format version number |\n| dim | 4 bytes | Vector dimension (little-endian) |\n| vector | dim × 4 bytes | Float32 embedding values |\n\n资料来源：[memory-store.ts:200-250]()\n</details>\n\n---\n\n<a id='embedding-system'></a>\n\n## Embedding System\n\n### 相关页面\n\n相关主题：[Memory Store](#memory-store), [Semantic Search](#semantic-search)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/embedder/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/embedder/index.ts)\n- [src/store/sidecar.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/sidecar.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/atomic-write.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/atomic-write.ts)\n- [src/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts)\n</details>\n\n# Embedding System\n\nThe embedding system in Commonplace transforms markdown memory content into vector representations stored as sidecar files, enabling semantic search across the memory store. It is designed to treat the `.md` source as the single source of truth, with embeddings as derived, regenerable artifacts.\n\n## Architecture Overview\n\nThe embedding pipeline consists of three primary layers:\n\n1. **Memory Layer** (`src/store/memory.ts`) — parses and serializes markdown with YAML frontmatter, computes canonical content hashes\n2. **Store Layer** (`src/store/memory-store.ts`) — orchestrates the scan/embed lifecycle, validates sidecar freshness, manages orphan cleanup\n3. **Embedder Layer** (`src/embedder/index.ts`) — generates vector embeddings via transformers.js\n\n```mermaid\ngraph TD\n    A[Markdown File] --> B[readMemory]\n    B --> C[contentSha Computation]\n    C --> D[Load Sidecar]\n    D --> E{Sidecar Fresh?}\n    E -->|Yes| F[Skip Embedding]\n    E -->|No| G[Embedder.embed]\n    G --> H[Serialize Sidecar]\n    H --> I[atomicWrite]\n    I --> J[.embedding Sidecar]\n    C -.-> K[body text + frontmatter]\n    F --> L[Use Existing Sidecar]\n```\n\n## Content Hash (contentSha)\n\nThe canonical content hash is computed over a specific slice of the memory's data structure, deliberately excluding graph-related fields to prevent embedding invalidation when relationships change.\n\n### Canonical Hash Inputs\n\n| Field | Included | Rationale |\n|-------|----------|-----------|\n| `type` | ✅ Yes | Memory type affects semantic context |\n| `name` | ✅ Yes | Name is part of semantic identity |\n| `description` | ✅ Yes | Description is semantically meaningful |\n| `body` | ✅ Yes | Full body content |\n| `relations` | ❌ No | Graph edges are derived, not source |\n| `supersedes` | ❌ No | Graph edges are derived, not source |\n\n资料来源：[src/store/memory.ts:contentSha function]()\n\nThe hash formula is:\n```\nsha256(\"${type}\\n${name}\\n${description}\\n${body}\")\n```\n\nThis produces a 64-character lowercase hex string that uniquely identifies the semantic content of a memory.\n\n### SHA Scope Justification\n\nThe graph fields (`relations`, `supersedes`) are intentionally excluded per DAR-925 design decisions. Adding or removing graph edges must not invalidate existing embeddings because:\n\n- Embeddings are derived from semantic content, not graph topology\n- Forcing re-embedding on graph edits would create unnecessary API calls\n- The sidecar is explicitly marked as derived, not authoritative\n\n## Sidecar Format\n\nEmbeddings are stored in `.embedding` sidecar files alongside their corresponding `.md` files. The sidecar encodes sufficient metadata to validate freshness without re-reading the markdown.\n\n### Sidecar Schema\n\n| Field | Type | Purpose |\n|-------|------|---------|\n| `modelId` | string | Identifies the embedding model used |\n| `dim` | number | Embedding vector dimensionality |\n| `contentSha` | string | Hash of canonical content |\n| `embedding` | number[] | The vector data |\n\n资料来源：[src/store/sidecar.ts]()\n\n### Sidecar File Naming\n\nSidecar files follow the naming convention `<name>.embedding` where `<name>` matches the corresponding memory file `<name>.md`. This 1:1 correspondence enables orphan detection.\n\n## Scan Lifecycle\n\nThe `MemoryStore.scan()` method implements the complete embed lifecycle, checking each memory's sidecar for freshness and triggering regeneration when needed.\n\n### Freshness Criteria\n\nA sidecar is considered **fresh** (reusable) when ALL of the following hold:\n\n1. The `.embedding` file exists\n2. It decodes successfully (magic + version + length checks pass)\n3. `decoded.modelId === embedder.modelId`\n4. `decoded.dim === embedder.dim`\n5. `decoded.contentSha === contentSha(memoryAsRead)`\n\n资料来源：[src/store/memory-store.ts:scan method]()\n\nIf ANY criterion fails, the memory is re-embedded and the sidecar rewritten.\n\n### Scan Process\n\n```mermaid\ngraph TD\n    A[Start Scan] --> B[Read all .md files]\n    B --> C{For each memory}\n    C --> D{No sidecar?}\n    D -->|Yes| E[Trigger embed]\n    D -->|No| F{Decode passes?}\n    F -->|No| E\n    F -->|Yes| G{modelId match?}\n    G -->|No| E\n    G -->|Yes| H{dim match?}\n    H -->|No| E\n    H -->|Yes| I{contentSha match?}\n    I -->|Yes| J[Skip - use existing]\n    I -->|No| E\n    C --> K[Orphan Cleanup]\n    K --> L[Remove orphaned .embedding files]\n    E --> M[Write new sidecar]\n    J --> C\n    M --> C\n```\n\n### Orphan Cleanup\n\nAfter processing all memories, scan performs a second directory walk to detect and remove orphan sidecars — `.embedding` files whose matching `.md` no longer exists. Orphans are reported via the `ScanResult.orphaned` field.\n\n资料来源：[src/store/memory-store.ts:orphan cleanup]()\n\n## Atomic Write Strategy\n\nSidecar writes use an atomic write-temp-rename pattern to prevent corruption from partial writes.\n\n### Write Sequence\n\n1. Generate random tmp filename: `<basename>.<8-hex-chars>.tmp`\n2. Write data to tmp file\n3. Verify source and target are on same filesystem (`dev` match)\n4. Rename tmp file to target (atomic on same filesystem)\n\n资料来源：[src/store/atomic-write.ts]()\n\n### Cross-Filesystem Guard\n\n```typescript\nif (targetDirStat.dev !== tmpDirStat.dev) {\n  throw new Error(\"refusing to rename across filesystems\");\n}\n```\n\nThis guard ensures rename operations remain atomic, as rename(2) is not atomic across filesystem boundaries.\n\n## Integration Points\n\n### CLI Entry Point\n\nThe main CLI (`src/index.ts`) wires the embedder factory into the migrate command:\n\n```typescript\nembedderFactory: () => new Embedder(resolveModelId(process.env)),\n```\n\nThe lazy factory ensures the transformers.js model is only loaded when an actual embed call occurs, not during argument parsing.\n\n### Migrate Command\n\nThe `commonplace migrate <dir>` command exposes scan functionality as a standalone tool:\n\n- Re-embeds any `.md` whose sidecar is missing or stale\n- Cleans up orphaned sidecars\n- Optionally prunes dangling graph edges (--prune-dangling flag)\n\n资料来源：[src/cli/migrate.ts:migrateScan]()\n\n## Configuration\n\n### Environment Variables\n\n| Variable | Default | Purpose |\n|----------|---------|---------|\n| `COMMONPLACE_EMBEDDING_MODEL` | model-specific | Embedding model identifier |\n\nThe `resolveModelId()` function reads the environment to determine which embedding model to instantiate.\n\n### Embedder Initialization\n\nThe `Embedder` class is instantiated with the resolved model ID. Model loading (transformers.js) occurs on first `embed()` call, not on construction, enabling lazy initialization.\n\n## Memory Types and Embedding\n\nAll four memory types are embeddable with identical treatment:\n\n| Type | Description | Embedding Behavior |\n|------|-------------|-------------------|\n| `user` | Personal rules and preferences | Standard |\n| `feedback` | Lessons from prior behavior | Standard |\n| `project` | Per-project context | Standard |\n| `reference` | Durable knowledge | Standard |\n\nMemory type is included in the content hash, so type changes trigger re-embedding.\n\n## Summary\n\nThe embedding system provides:\n\n- **Semantic search** via vector embeddings\n- **Source-of-truth isolation** with SHA-scoped content hashes\n- **Automatic regeneration** when content changes\n- **Orphan cleanup** for stale sidecars\n- **Atomic writes** for corruption prevention\n- **Model portability** validation through metadata checks\n\nAll embedding behavior is derived from markdown content; the `.embedding` files are regenerable artifacts that can be deleted and rebuilt via the migrate command at any time.\n\n---\n\n<a id='semantic-search'></a>\n\n## Semantic Search\n\n### 相关页面\n\n相关主题：[Embedding System](#embedding-system), [Graph Features](#graph-features), [MCP Tool Reference](#mcp-tool-reference)\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/graph.ts](https://github.com/rickbassham/commonplace/blob/main/src/store/graph.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.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# Semantic Search\n\nSemantic search enables finding memories by meaning rather than exact keyword matching. The system embeds memory content into high-dimensional vectors and uses cosine similarity to rank results against a query.\n\n## Overview\n\nThe semantic search system consists of three main layers:\n\n1. **Embedding Pipeline** — Converts text into dense vectors using a local transformer model\n2. **Vector Storage** — Binary `.embedding` sidecar files generated from markdown content\n3. **Search Engine** — Cosine similarity ranking across one or both memory stores\n\nMemories are stored as markdown files with YAML frontmatter. Each memory has a corresponding `.embedding` sidecar containing its pre-computed vector representation. The embedding is derived from the canonical memory content and cached until the content changes (detected via SHA-256 hash).\n\n资料来源：[src/store/memory.ts:1-50]()\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"CLI / MCP Layer\"\n        H[handlers.ts]\n    end\n    \n    subgraph \"Store Layer\"\n        MS[MemoryStore]\n        G[MemoryGraph]\n    end\n    \n    subgraph \"I/O Layer\"\n        FS[File System]\n    end\n    \n    subgraph \"Embedding Layer\"\n        E[Embedder]\n        TFM[transformers.js]\n        BGE[bge-base-en-v1.5]\n    end\n    \n    H --> MS\n    MS --> E\n    E --> TFM\n    TFM --> BGE\n    MS <--> G\n    MS <--> FS\n    G -.-> MS\n    \n    style E fill:#e1f5fe\n    style BGE fill:#fff3e0\n```\n\n### Component Responsibilities\n\n| Component | File | Role |\n|-----------|------|------|\n| `MemoryStore` | memory-store.ts | Manages scanning, embedding, and search operations |\n| `Embedder` | embedder.ts | Wraps transformers.js for local inference |\n| `MemoryGraph` | graph.ts | Tracks relations and enriches search results |\n| `handlers.ts` | handlers.ts | MCP tool handler for memory_search |\n\n资料来源：[src/store/memory-store.ts:1-100]()\n\n## Embedding Pipeline\n\n### Model Configuration\n\nThe system uses `bge-base-en-v1.5` from the BGE (BAAI General Embedding) family. This model produces 768-dimensional dense vectors optimized for semantic similarity tasks.\n\n```typescript\n// Resolved from environment: EMBEDDING_MODEL_ID\nconst DEFAULT_MODEL_ID = 'Xenova/bge-base-en-v1.5';\n```\n\nThe embedder runs entirely offline via `@huggingface/transformers` (transformers.js), requiring no external API calls or internet connectivity after the initial model load.\n\n资料来源：[src/store/memory-store.ts:100-150]()\n\n### Embedding Derivation\n\nEmbeddings are derived from the **canonical memory content**, defined as:\n\n```\n${type}\\n${name}\\n${description}\\n${body}\n```\n\nThe SHA-256 hash of this canonical string is computed and compared against stored hashes to detect content changes. This ensures embeddings are regenerated only when necessary.\n\n```typescript\nexport const contentSha = (memory: Memory): string =>\n  createHash('sha256')\n    .update(`${memory.type}\\n${memory.name}\\n${description}\\n${body}`, 'utf8')\n    .digest('hex');\n```\n\n**Important**: Graph fields (`relations`, `supersedes`) do NOT affect the canonical content or embedding. Adding or removing graph edges does not invalidate the embedding sidecar.\n\n资料来源：[src/store/memory.ts:80-100]()\n\n### Sidecar Format\n\nEach memory generates a binary `.embedding` sidecar file in the same directory as the `.md` file:\n\n```\n~/.commonplace/memory/\n├── feedback_scope.md\n├── feedback_scope.embedding  ← binary float32 vectors\n└── architecture.md\n    └── architecture.embedding\n```\n\nThe sidecar is **derived data** — it can be deleted and regenerated at any time from the markdown source.\n\n资料来源：[CLAUDE.md:1-30]()\n\n## Search Workflow\n\n```mermaid\nsequenceDiagram\n    participant C as MCP Client\n    participant H as memory_search Handler\n    participant MS as MemoryStore\n    participant E as Embedder\n    participant FS as File System\n    \n    C->>H: memory_search({ query, k?, scope? })\n    H->>MS: search(query, k, opts)\n    \n    Note over MS: Load user store<br/>+ project store if present\n    \n    MS->>E: embed(query)\n    E->>E: Load model (lazy)\n    E-->>MS: queryVector[768]\n    \n    MS->>FS: Load all .embedding sidecars\n    FS-->>MS: Float32Array vectors\n    \n    loop Per-memory\n        MS->>MS: cosineSimilarity(queryVector, memoryVector)\n    end\n    \n    MS->>G: Filter supersedes, enrich relations\n    G-->>MS: Augmented matches\n    \n    MS-->>H: MemorySearchResult[]\n    H-->>C: JSON response\n```\n\n### Search Flow Details\n\n1. **Query embedding** — The search query is embedded using the same model as memory content\n2. **Vector loading** — All `.embedding` sidecars are loaded into memory (lazy, cached)\n3. **Similarity computation** — Brute-force cosine similarity between query vector and all memory vectors\n4. **Result filtering** — Superseded memories are excluded by default\n5. **Graph enrichment** — Results include outgoing relations from the frontmatter\n\n资料来源：[src/store/memory-store.ts:200-300]()\n\n## Memory Search API\n\n### MCP Tool: `memory_search`\n\nInput schema:\n\n| Argument | Type | Required | Default | Description |\n|----------|------|----------|---------|-------------|\n| `query` | string | Yes | — | Natural language search query |\n| `k` | integer | No | 5 | Maximum number of results to return |\n| `type` | MemoryType | No | — | Filter by memory type (user/feedback/project/reference) |\n| `includeSuperseded` | boolean | No | false | Include memories superseded by others |\n| `expandTypes` | string[] | No | ['builds-on', 'related-to'] | Edge types to include in results |\n| `scope` | 'user' \\| 'project' | No | merged | Which store to search |\n\n### Response Schema\n\n```typescript\ninterface MemorySearchResult {\n  query: string;\n  matches: MemorySearchMatch[];\n  scope: 'user' | 'project' | 'merged';\n}\n\ninterface MemorySearchMatch {\n  name: string;\n  type: MemoryType;\n  description: string;\n  body: string;       // Full body verbatim (never truncated)\n  score: number;      // Cosine similarity, 3 decimals\n  relations: Relation[];  // Outgoing edges from frontmatter\n  scope: 'user' | 'project';\n}\n```\n\n**Note**: The body is never truncated, summarized, or transformed. The caller receives exactly what was persisted.\n\n资料来源：[src/server/handlers.ts:50-120]()\n\n### Default Expand Types\n\nOnly `builds-on` and `related-to` are included by default. Other edge types require explicit opt-in:\n\n```typescript\nexport const DEFAULT_EXPAND_TYPES: readonly EdgeType[] = \n  ['builds-on', 'related-to'] as const;\n```\n\nThis prevents surprising the agent with `mentions`, `supersedes`, `contradicts`, or `child-of` edges unless requested.\n\n资料来源：[src/server/handlers.ts:15-25]()\n\n## Memory Stores and Scoping\n\n### Dual-Store Architecture\n\nThe system supports two independent memory stores:\n\n| Store | Location | Purpose |\n|-------|----------|---------|\n| User Store | `~/.commonplace/memory` (default) | Personal rules, preferences, feedback |\n| Project Store | `<project-root>/.commonplace/memory` | Per-project context |\n\n### Detection Priority\n\nProject store selection follows this priority:\n\n1. `COMMONPLACE_PROJECT_DIR` env var (explicit override)\n2. MCP `roots/list` response\n3. Current working directory\n\nIf none apply, only the user store is loaded.\n\n### Merged Search\n\nWhen `scope` is omitted, search merges results from both stores by descending score. Each match carries a `scope` tag identifying its source.\n\n资料来源：[src/server/handlers.ts:150-200]()\n\n## Scan and Re-embedding\n\n### Trigger Conditions\n\nThe store performs a lazy rescan when:\n\n1. Directory mtime advances past the baseline (new files detected)\n2. Memory is saved (triggers immediate re-embedding)\n\n```typescript\n// MemoryStore.scan() behavior:\n// - Skips if dir mtime hasn't changed (lastScanMtimeMs baseline)\n// - Regenerates embedding for any memory with changed sha\n// - Stores new dir mtime as baseline after scan\n```\n\n### Lazy Re-embedding\n\nOn save, the system:\n1. Computes `contentSha` for the new content\n2. Compares against stored hash\n3. Regenerates embedding only if hash differs\n\nThis avoids redundant model inference for graph-only changes (relation additions/removals).\n\n资料来源：[src/store/memory-store.ts:250-280]()\n\n## Content-Based Mention Extraction\n\nWhile not part of the vector search pipeline, `[[name]]` mentions in body text create graph edges that enrich search results:\n\n```typescript\n// Mention extraction (DAR-927)\n// Scanned during save/scan, not during search\n// Creates 'mentions' edges in MemoryGraph\n```\n\nMention extraction is controlled by `COMMONPLACE_EXTRACT_MENTIONS` env var (default: enabled). Regex pattern matches `<name>` tokens against `^[a-z0-9_]+$`.\n\n资料来源：[src/store/mentions.ts:1-50]()\n\n## Related Features\n\n| Feature | Description |\n|---------|-------------|\n| [Memory List](memory-list) | List memories without semantic scoring |\n| [Memory Graph](memory-graph) | Graph traversal and path finding |\n| [Memory Link/Unlink](memory-link) | Manual edge creation |\n| [Migrate](cli-migrate) | Import from Claude Code auto-memory |\n\n## Configuration Reference\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `EMBEDDING_MODEL_ID` | `Xenova/bge-base-en-v1.5` | HuggingFace model identifier |\n| `COMMONPLACE_USER_DIR` | `~/.commonplace/memory` | User store root |\n| `COMMONPLACE_PROJECT_DIR` | — | Project store override |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `true` | Enable `[[name]]` extraction |\n| `COMMONPLACE_EMBED_BATCH_SIZE` | — | Batch size for embedding |\n\n---\n\n<a id='graph-features'></a>\n\n## Graph Features\n\n### 相关页面\n\n相关主题：[Semantic Search](#semantic-search), [MCP Tool Reference](#mcp-tool-reference)\n\n<details>\n<summary>Relevant Source Files</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/cli/graph.ts](https://github.com/rickbassham/commonplace/blob/main/src/cli/graph.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/server/tools.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/tools.ts)\n</details>\n\n# Graph Features\n\n## Overview\n\nThe Graph Features system provides a network-based view of memories, enabling relationships between notes to be tracked, queried, and visualized. Rather than treating each memory as an isolated entity, the graph layer exposes connections through authored `relations` in frontmatter, `supersedes` declarations, and automatic `[[name]]` mention extraction from body content.\n\nThe graph is not a separate data store—it derives from the same markdown files that form the memory corpus. Each `.md` file in a memory store may declare outgoing edges via its YAML frontmatter, and the in-memory `MemoryGraph` maintains an adjacency list for efficient traversal.\n\n资料来源：[src/store/graph.ts:1-30]()\n\n## Architecture\n\n```mermaid\ngraph TD\n    subgraph \"Memory Sources\"\n        UserStore[\"User Memory Store<br/>(~/.commonplace)\"]\n        ProjectStore[\"Project Memory Store<br/>(./.commonplace)\"]\n    end\n    \n    subgraph \"Graph Layer\"\n        MemoryGraph[\"MemoryGraph\"]\n        AdjacencyList[\"Adjacency List<br/>(Map&lt;name, Edge[]&gt;)\"]\n    end\n    \n    subgraph \"Edge Sources\"\n        Relations[\"relations[]<br/>frontmatter field\"]\n        Supersedes[\"supersedes[]<br/>frontmatter field\"]\n        Mentions[\"[[name]] mentions<br/>body extraction\"]\n    end\n    \n    UserStore --> MemoryGraph\n    ProjectStore --> MemoryGraph\n    MemoryGraph --> AdjacencyList\n    Relations --> MemoryGraph\n    Supersedes --> MemoryGraph\n    Mentions --> MemoryGraph\n```\n\n### Core Components\n\n| Component | File | Purpose |\n|-----------|------|---------|\n| `MemoryGraph` | `src/store/graph.ts` | In-memory graph with adjacency list, edge management, and traversal |\n| `Edge` / `DanglingEdge` | `src/store/graph.ts` | Data models for directed edges |\n| `MemoryStore` | `src/store/memory-store.ts` | Persists graph edges via frontmatter, maintains in-memory sync |\n| `mentions.ts` | `src/store/mentions.ts` | Extracts `[[name]]` tokens from body content |\n| `handlers.ts` | `src/server/handlers.ts` | MCP tool handlers for graph operations |\n| `graph.ts` CLI | `src/cli/graph.ts` | Command-line graph visualization |\n\n资料来源：[src/store/graph.ts:25-45]()\n\n## Edge Types\n\nThe graph supports a union of edge types drawn from three sources:\n\n| Edge Type | Source | Description |\n|-----------|--------|-------------|\n| `related-to` | `relations[]` frontmatter | General-purpose association between memories |\n| `builds-on` | `relations[]` frontmatter | Memory that extends or depends on another |\n| `contradicts` | `relations[]` frontmatter | Memory that opposes or negates another |\n| `child-of` | `relations[]` frontmatter | Hierarchical parent-child relationship |\n| `supersedes` | `supersedes[]` frontmatter | Memory that replaces or renders another obsolete |\n| `mentions` | Body `[[name]]` extraction | Memory references another by name in its body |\n\n资料来源：[src/store/graph.ts:15-25]()\n\n### Frontmatter Declaration\n\nMemories declare outgoing edges in YAML frontmatter:\n\n```yaml\n---\nname: feedback_scope\ndescription: Don't shrink scope unilaterally\ntype: feedback\nrelations:\n  - to: scope_contract\n    type: builds-on\n  - to: legacy_approach\n    type: supersedes\n---\n<memory body content>\n```\n\n资料来源：[src/store/memory.ts:1-30]()\n\n## MemoryGraph Module\n\nThe `MemoryGraph` class maintains an in-memory adjacency list and exposes methods for adding, removing, and querying edges.\n\n### Data Model\n\n```typescript\n// src/store/graph.ts\nexport interface Edge {\n  from: string;\n  to: string;\n  type: EdgeType;\n}\n\nexport interface DanglingEdge {\n  from: string;\n  to: string;\n  type: string;  // widened to string for extensibility\n}\n```\n\n资料来源：[src/store/graph.ts:30-45]()\n\n### Graph Construction\n\nThe graph is built during store initialization by iterating all memories and emitting edges for each source:\n\n1. For each memory, emit one edge per `relations[]` entry\n2. Emit one `supersedes` edge per `supersedes[]` entry\n3. Emit one `mentions` edge per `[[name]]` token in body (if extraction enabled)\n\n```mermaid\ngraph LR\n    A[\"scan()\"] --> B[\"For each memory\"]\n    B --> C[\"Parse relations[]\"]\n    B --> D[\"Parse supersedes[]\"]\n    B --> E[\"Extract [[name]] mentions\"]\n    C --> F[\"addEdge()\"]\n    D --> F\n    E --> F\n```\n\n资料来源：[src/store/graph.ts:50-80]()\n\n## Mentions Extraction\n\nThe `[[name]]` mention extractor (DAR-927) parses body content for wiki-style name references and surfaces them as graph edges.\n\n### Tokenizer Rules\n\n- Extracts tokens matching the pattern `[[name]]` where `name` conforms to `^[a-z0-9_]+$`\n- Names must match the same validation rule used for memory filenames\n- Tokens not matching this pattern are silently ignored\n- Code fences and inline code are **not** excluded (per contract, the tokenizer operates purely on regex over body content)\n\n### Configuration\n\n| Environment Variable | Default | Description |\n|---------------------|---------|-------------|\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | Set to `'false'` to disable mention extraction |\n\n资料来源：[src/store/mentions.ts:1-45]()\n\n## MCP Tools\n\nThe MCP server exposes graph operations as JSON-RPC tools.\n\n### memory_graph\n\nTraverses the graph starting from a named memory and returns the neighborhood.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `name` | string | required | Root memory name |\n| `depth` | integer | `1` | Maximum edge traversal depth |\n| `types` | string[] | authored + supersedes | Edge types to follow |\n| `direction` | `'in' \\| 'out' \\| 'both'` | `'both'` | Traversal direction |\n| `scope` | `'user' \\| 'project'` | auto | Memory scope filter |\n\n资料来源：[src/server/tools.ts:1-50]()\n\n### memory_link\n\nCreates a directed edge between two memories.\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `from` | string | Source memory name |\n| `to` | string | Target memory name |\n| `type` | RelationType | Edge type (one of the four authored types) |\n\n资料来源：[src/store/memory-store.ts:80-120]()\n\n### memory_unlink\n\nRemoves one or more edges from a memory.\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `from` | string | Source memory name |\n| `to` | string | Target memory name |\n| `type` | RelationType (optional) | Specific edge type to remove; if omitted, removes all edges to target |\n\n资料来源：[src/store/memory-store.ts:120-160]()\n\n## CLI Integration\n\nThe `commonplace graph` command provides command-line graph visualization (DAR-933).\n\n### Usage\n\n```bash\ncommonplace graph <name> [options]\n```\n\n### Options\n\n| Flag | Type | Default | Description |\n|------|------|---------|-------------|\n| `--depth, -d` | integer | `1` | Traversal depth |\n| `--types, -t` | string | all except mentions | Comma-separated edge types |\n| `--direction, -D` | `in\\|out\\|both` | `both` | Traversal direction |\n| `--format, -f` | `mermaid\\|json\\|dot` | `mermaid` | Output format |\n| `--scope, -s` | `user\\|project\\|both` | `both` | Memory scope |\n\n资料来源：[src/cli/graph.ts:1-80]()\n\n### Output Formats\n\n#### Mermaid (default)\n\n```mermaid\nflowchart LR\n  memory_a[\"memory_a (feedback)\"]\n  memory_b[\"memory_b (project)\"]\n  memory_a -- \"builds-on\" --> memory_b\n```\n\n#### JSON\n\nReturns the `MemoryGraphResult` structure verbatim for piping to external tools:\n\n```json\n{\n  \"root\": \"memory_a\",\n  \"nodes\": [...],\n  \"edges\": [...]\n}\n```\n\n#### DOT\n\nGraphviz DOT format for archival or large-graph workflows.\n\n资料来源：[src/cli/graph.ts:80-150]()\n\n## Dangling Edge Detection\n\nThe graph detects edges whose `to` target does not correspond to any existing memory. These \"dangling edges\" are identified during graph construction and can be pruned.\n\n### Detection\n\n| Step | Description |\n|------|-------------|\n| 1 | Build adjacency list from all memories |\n| 2 | Collect all known memory names |\n| 3 | For each edge, verify `to` exists in name set |\n| 4 | Flag edges where `to` is absent |\n\n### Pruning\n\nThe `migrate prune` command removes dangling edges:\n\n```bash\ncommonplace migrate --prune [--dry-run]\n```\n\nResults show per-memory counts and total edges removed.\n\n资料来源：[src/store/graph.ts:80-120]()\n\n## Out of Scope\n\nThe following features are explicitly deferred to future iterations:\n\n| Feature | Issue | Notes |\n|---------|-------|-------|\n| Verifying referenced names exist on disk | DAR-926 | Dangling detection exists; validation does not |\n| In-memory adjacency list builder | DAR-926 | Graph derives from store, not built independently |\n| `[[name]]` backlink rendering | DAR-927 | AC excludes wiki-style rendering |\n| Centrality / PageRank | DAR-931 | Future ranking metrics |\n| Traversal / path queries | DAR-932 | Neighborhood walk only for v0.1 |\n\n资料来源：[src/store/graph.ts:10-20]()\n\n## Summary\n\nThe Graph Features system treats the memory corpus as a navigable network. Edges originate from three sources—authored `relations`, explicit `supersedes` declarations, and automatic `[[name]]` mention extraction—and are consolidated into a unified in-memory adjacency list. The MCP server exposes CRUD operations on edges, the CLI provides visualization, and the architecture intentionally keeps the graph derived rather than authoritative, ensuring it never diverges from the underlying markdown files.\n\n---\n\n<a id='mcp-tool-reference'></a>\n\n## MCP Tool Reference\n\n### 相关页面\n\n相关主题：[Server Handlers](#server-handlers), [Semantic Search](#semantic-search), [Graph Features](#graph-features)\n\n<details>\n<summary>相关源码文件</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/server/tools.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/tools.ts)\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.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- [README.md](https://github.com/rickbassham/commonplace/blob/main/README.md)\n</details>\n\n# MCP Tool Reference\n\nThe Model Context Protocol (MCP) server exposes a set of tools that enable external clients—primarily Claude Code—to interact with the commonplace book. These tools provide CRUD operations for memories, semantic search, and graph management. The MCP stdio server acts as the bridge between the local embedding pipeline and any MCP-compatible client.\n\n资料来源：[src/server/handlers.ts:1-25]()\n\n## Architecture Overview\n\nThe MCP server is implemented in `src/server/` and wired to the memory store layer. Tool requests arrive via stdio JSON-RPC, are validated in handler functions, dispatched to the `MemoryStore`, and returned as JSON-serializable responses wrapped in MCP content blocks.\n\n```mermaid\ngraph TD\n    A[MCP Client<br/>Claude Code] --> B[stdio JSON-RPC]\n    B --> C[server.ts<br/>CallToolRequest Dispatcher]\n    C --> D[handlers.ts<br/>Tool Handlers]\n    D --> E[MemoryStore]\n    E --> F[memory.ts<br/>YAML + Embedding I/O]\n    E --> G[graph.ts<br/>In-memory Graph]\n    F --> H[.md Files<br/>+ .embedding Sidecars]\n```\n\n资料来源：[src/server/handlers.ts:17-23]()\n\n## Tool Categories\n\nThe MCP server exposes two categories of tools:\n\n| Category | Purpose | Tools |\n|----------|---------|-------|\n| **Memory CRUD** | Create, read, delete, and search memories | `memory_save`, `memory_list`, `memory_delete`, `memory_search` |\n| **Graph Management** | Manage relationships between memories | `memory_link`, `memory_unlink` |\n\n资料来源：[README.md:1-50]()\n\n## Scope Model\n\nEvery tool accepts an optional `scope` argument that selects which memory store to address:\n\n| Scope | Description |\n|-------|-------------|\n| `user` | Cross-project memories stored in `COMMONPLACE_USER_DIR` |\n| `project` | Project-specific memories stored in `COMMONPLACE_PROJECT_DIR` |\n\nWhen `scope` is omitted, reads merge across both stores and writes default to `user`.\n\n资料来源：[src/server/handlers.ts:30-35]()\n\n## Memory Types\n\nAll memory tools operate on a four-element taxonomy defined in the store layer:\n\n| Type | Purpose |\n|------|---------|\n| `user` | Personal rules, preferences, and identity facts about the human operator |\n| `feedback` | Corrections and lessons learned from prior agent behaviour; persistent course-corrections |\n| `project` | Per-project context like architecture notes, repo conventions, and decisions |\n| `reference` | Durable, neutral knowledge: API shapes, formulas, citations |\n\n资料来源：[src/store/memory.ts:1-30]()\n\n## Memory CRUD Tools\n\n### memory_save\n\nSave a memory as a markdown file with YAML frontmatter and a derived embedding sidecar. Refuses to overwrite an existing entry; the contract is delete + save.\n\n**Input Schema:**\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `name` | string | Yes | Memory name. Must match `^[a-z0-9_]+$`. Becomes the filename stem. |\n| `type` | `user \\| feedback \\| project \\| reference` | Yes | One of the four memory types. |\n| `description` | string | Yes | Short description used in search result summaries. |\n| `body` | string | Yes | Markdown content of the memory. |\n| `scope` | `'user' \\| 'project'` | No | Which store to write to. Defaults to `'user'`. |\n\n资料来源：[README.md:50-80]()\n\n**Validation:** Arguments are validated manually at handler entry. The handler checks `name` against `validateName`, `type` against `MEMORY_TYPES`, and passes store errors through unchanged.\n\n资料来源：[src/server/handlers.ts:40-55]()\n\n### memory_list\n\nList all memories, optionally filtered by type.\n\n**Input Schema:**\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `type` | `user \\| feedback \\| project \\| reference` | No | Filter to memories of this type only. |\n| `scope` | `'user' \\| 'project'` | No | Which store to query. Defaults to merging both stores. |\n\n**Response:** Returns an array of memory entries with `name`, `type`, `description`, and `body` fields.\n\n资料来源：[src/server/handlers.ts:60-75]()\n\n### memory_delete\n\nDelete a memory by name from the specified store.\n\n**Input Schema:**\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `name` | string | Yes | Name of the memory to delete. |\n| `scope` | `'user' \\| 'project'` | No | Which store to delete from. Defaults to `'user'`. |\n\n资料来源：[src/server/handlers.ts:80-95]()\n\n### memory_search\n\nSemantic search across all memories using local embeddings.\n\n**Input Schema:**\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `query` | string | Yes | Natural language search query. |\n| `type` | `user \\| feedback \\| project \\| reference` | No | Filter to memories of this type only. |\n| `limit` | number | No | Maximum results to return. Defaults to `DEFAULT_SEARCH_LIMIT`. |\n| `scope` | `'user' \\| 'project'` | No | Which store to search. Defaults to merging both stores. |\n\n资料来源：[src/server/handlers.ts:100-130]()\n\n**Response Enrichment:** Search results include relations from connected memories and exclude notes marked as superseded. This is handled by `MemoryGraph` integration.\n\n资料来源：[src/store/memory-store.ts:1-50]()\n\n## Graph Management Tools\n\n### memory_link\n\nCreate a directed edge between two memories, establishing a typed relationship.\n\n**Input Schema:**\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `from` | string | Yes | Source memory name. |\n| `to` | string | Yes | Target memory name. |\n| `type` | `RelationType \\| 'supersedes'` | Yes | Relationship type. |\n| `scope` | `'user' \\| 'project'` | No | Which store contains both memories. |\n\n**Relation Types:**\n\n| Type | Description |\n|------|-------------|\n| `builds-on` | The source memory builds upon the target |\n| `implements` | The source memory implements the target |\n| `relates-to` | General relationship between memories |\n| `supersedes` | The source memory supersedes the target |\n\n**Behavior:**\n\n- Throws if the edge already exists (no duplicate edges).\n- Updates the `relations` array in the source memory's YAML frontmatter.\n- Mutates the in-memory entry in place for consistency.\n- Refreshes the directory mtime baseline to avoid wasteful rescans.\n\n资料来源：[src/store/memory-store.ts:200-280]()\n\n```mermaid\ngraph LR\n    A[memory: feedback_scope] -->|builds-on| B[memory: scope_management]\n    A -->|supersedes| C[memory: old_feedback_v1]\n```\n\n### memory_unlink\n\nRemove a directed edge between two memories.\n\n**Input Schema:**\n\n| Argument | Type | Required | Description |\n|----------|------|----------|-------------|\n| `from` | string | Yes | Source memory name. |\n| `to` | string | Yes | Target memory name. |\n| `type` | `RelationType \\| 'supersedes'` | No | Specific edge type to remove. If omitted, removes ALL edges from `from` to `to`. |\n\n**Behavior:**\n\n- No-op when the requested edge does not exist (no atomic write, no graph mutation).\n- Returns `{ ..., note: '<reason>' }` for friendly messaging when edges don't exist.\n- When edges are removed, writes the source `.md` through `atomicWrite`, updates the in-memory entry in place, and calls `MemoryGraph.removeEdge`.\n\n资料来源：[src/store/memory-store.ts:300-400]()\n\n## Validation Strategy\n\nTool argument validation is deliberately manual rather than schema-library-based:\n\n- Zero new dependencies for validation logic.\n- Rejection messages are tailored to name the offending field.\n- Store layer errors are passed through unchanged to preserve context.\n\n资料来源：[src/server/handlers.ts:15-20]()\n\n## Response Format\n\nAll tool responses are JSON-serializable shapes wrapped in a single text content block by the MCP server's `CallToolRequest` dispatcher in `server.ts`. The dispatcher handles both the CRUD tools and graph tools uniformly.\n\n资料来源：[src/server/handlers.ts:20-23]()\n\n## Environment Variables\n\nThe MCP server respects the following environment variables:\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace` | Directory for user-scoped memories |\n| `COMMONPLACE_PROJECT_DIR` | `<cwd>/.commonplace` | Directory for project-scoped memories |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `'true'` | Enable `[[name]]` mention extraction from body content |\n\n资料来源：[src/store/mentions.ts:1-30]()\n\n## MCP Server Binary\n\nThe MCP server is exposed as the `commonplace-mcp` binary, separate from the CLI's `commonplace` command. This separation ensures the MCP stdio framing channel is never polluted by CLI output.\n\n资料来源：[src/index.ts:1-30]()\n\n## See Also\n\n- [Memory Store Architecture](./memory-store-architecture.md) — In-depth details on embedding, sidecars, and graph integration\n- [CLI Reference](./cli-reference.md) — The `commonplace` CLI for migration and graph commands\n- [Memory File Format](./memory-file-format.md) — YAML frontmatter schema and content hashing\n\n---\n\n<a id='server-handlers'></a>\n\n## Server Handlers\n\n### 相关页面\n\n相关主题：[MCP Tool Reference](#mcp-tool-reference), [System Architecture](#system-architecture)\n\n<details>\n<summary>Related Source Files</summary>\n\n以下源码文件用于生成本页说明：\n\n- [src/server/handlers.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/handlers.ts)\n- [src/server/server.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/server.ts)\n- [src/server/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/server/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/index.ts](https://github.com/rickbassham/commonplace/blob/main/src/index.ts)\n</details>\n\n# Server Handlers\n\n## Overview\n\nServer Handlers are the core request-processing layer in the Commonplace MCP server. They implement the MCP (Model Context Protocol) tool handlers that bridge the MCP client interface to the underlying `MemoryStore` persistence layer. Each handler is a factory function that produces an MCP-compatible request handler with consistent validation, error handling, and response shaping.\n\nThe handler system is designed around:\n\n- **Factory pattern**: Each handler is created via a factory function (e.g., `createMemorySaveHandler`, `createMemoryListHandler`) that encapsulates store access and validation logic.\n- **Typed interfaces**: All inputs and outputs use TypeScript interfaces exported from `handlers.ts` for compile-time safety.\n- **Scope awareness**: Handlers support both `user` and `project` scopes, allowing memories to be stored in different directories.\n- **Graph integration**: Handlers can optionally work with the `MemoryGraph` to enrich responses with relation data.\n\n## Architecture\n\n### Request Flow\n\n```mermaid\ngraph TD\n    A[MCP Request] --> B[Server dispatch]\n    B --> C{Handler Factory}\n    C --> D[createMemorySaveHandler]\n    C --> E[createMemoryListHandler]\n    C --> F[createMemorySearchHandler]\n    C --> G[createMemoryDeleteHandler]\n    C --> H[createMemoryLinkHandler]\n    C --> I[createMemoryUnlinkHandler]\n    D --> J[MemoryStore]\n    E --> J\n    F --> J\n    G --> J\n    H --> J\n    I --> J\n    J --> K[MemoryGraph]\n    J --> L[File System]\n    K --> M[Relation Enrichment]\n    L --> N[.md + .embedding files]\n    M --> O[MCP Response]\n    N --> O\n```\n\n### Handler Factory Pattern\n\nEach handler follows the factory pattern documented in `handlers.ts`:\n\n```typescript\nexport const createMemorySaveHandler = (opts: CreateHandlerOptions) => {\n  const { userStore, projectStore } = resolveStores(opts);\n  return async (request: MemorySaveRequest): Promise<MemorySaveResult> => {\n    // Validation and processing\n  };\n};\n```\n\n资料来源：[src/server/handlers.ts:1-50]()\n\n## Handler Types\n\n### MemorySaveHandler\n\n**Purpose**: Creates or updates a memory note with YAML frontmatter and markdown body.\n\n**Factory**: `createMemorySaveHandler(options: CreateHandlerOptions)`\n\n**Request Interface**:\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `name` | `string` | Yes | Memory identifier matching `^[a-z0-9_]+$` |\n| `type` | `MemoryType` | Yes | One of: `user`, `feedback`, `project`, `reference` |\n| `description` | `string` | Yes | Brief description for search relevance |\n| `body` | `string` | Yes | Markdown content |\n| `scope` | `Scope` | No | `user` (default) or `project` |\n\n**Response Interface**:\n\n```typescript\nexport interface MemorySaveResult {\n  saved: {\n    name: string;\n    type: MemoryType;\n    description: string;\n  };\n  path: string;\n  /** Which store the memory was written to (DAR-924) */\n  scope: Scope;\n}\n```\n\n资料来源：[src/server/handlers.ts:80-95]()\n\n**Validation**:\n- Name must match `NAME_PATTERN` (`^[a-z0-9_]+$`)\n- Type must be one of `MEMORY_TYPES`\n- Scope is validated via `validateScope()` helper\n- Duplicate relations are deduplicated on write\n\n资料来源：[src/store/memory.ts:1-50]()\n\n### MemoryListHandler\n\n**Purpose**: Returns all memories from a store, optionally filtered by type and scope.\n\n**Factory**: `createMemoryListHandler(options: CreateHandlerOptions)`\n\n**Request Interface**:\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `type` | `MemoryType` | No | Filter by memory type |\n| `scope` | `Scope` | No | Filter by scope (`user`/`project`) |\n\n**Response Interface**:\n\n```typescript\nexport interface MemoryListResult {\n  memories: Array<{\n    name: string;\n    type: MemoryType;\n    description: string;\n    /** Which store this entry came from */\n    scope: Scope;\n  }>;\n}\n```\n\n资料来源：[src/server/handlers.ts:97-108]()\n\n### MemorySearchHandler\n\n**Purpose**: Performs semantic search across memory embeddings using cosine similarity.\n\n**Factory**: `createMemorySearchHandler(options: CreateHandlerOptions)`\n\n**Request Interface**:\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `query` | `string` | Yes | Natural language search query |\n| `limit` | `number` | No | Max results (default: 10) |\n| `type` | `MemoryType` | No | Filter by type |\n| `scope` | `Scope` | No | Filter by scope |\n| `expand` | `boolean` | No | Include related memories (default: true) |\n| `expandTypes` | `EdgeType[]` | No | Which relation types to expand |\n\n**Response Interface**:\n\n```typescript\nexport interface MemorySearchMatch {\n  name: string;\n  type: MemoryType;\n  description: string;\n  body: string;          // Full body, never truncated\n  score: number;         // Cosine similarity, 3 decimals\n  relations: Relation[]; // Outgoing graph edges\n}\n```\n\n资料来源：[src/server/handlers.ts:35-60]()\n\n**Expand Types Configuration**:\n\n| Type | Default | Description |\n|------|---------|-------------|\n| `builds-on` | Yes | Included by default |\n| `related-to` | Yes | Included by default |\n| `mentions` | No | Requires opt-in |\n| `supersedes` | No | Requires opt-in |\n| `contradicts` | No | Requires opt-in |\n| `child-of` | No | Requires 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:20-30]()\n\n**Response Enrichment**:\n\nWhen `expand` is enabled, the handler enriches results by:\n1. Fetching direct matches from `MemoryStore.search()`\n2. For each match, query `MemoryGraph` for outgoing edges matching `expandTypes`\n3. Add expanded memories to response (marked with `expanded: true`)\n4. Exclude superseded memories unless explicitly requested\n\n### MemoryDeleteHandler\n\n**Purpose**: Removes a memory from the store by name.\n\n**Factory**: `createMemoryDeleteHandler(options: CreateHandlerOptions)`\n\n**Request Interface**:\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `name` | `string` | Yes | Memory name to delete |\n| `scope` | `Scope` | No | Scope hint for store resolution |\n\n**Response Interface**:\n\n```typescript\nexport interface MemoryDeleteResult {\n  deleted: string;\n  scope: Scope;\n}\n```\n\n### MemoryLinkHandler\n\n**Purpose**: Creates a directed edge between two memories in the graph.\n\n**Factory**: `createMemoryLinkHandler(options: CreateHandlerOptions)`\n\n**Request Interface**:\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `from` | `string` | Yes | Source memory name |\n| `to` | `string` | Yes | Target memory name |\n| `type` | `RelationType` | Yes | Edge type |\n| `scope` | `Scope` | No | Scope for operation |\n\n**Relation Types**:\n\n| Type | Description |\n|------|-------------|\n| `builds-on` | Memory extends or depends on another |\n| `related-to` | Memory has loose association |\n| `contradicts` | Memory refutes another |\n| `child-of` | Memory is subordinate to another |\n\n**Internal Behavior**:\nThe handler delegates to `MemoryStore.linkEdge()` which:\n1. Validates both memory names exist\n2. Adds the relation to the source memory's frontmatter\n3. If type is `supersedes`, also adds to `supersedes` list\n4. Writes updated markdown via atomic write\n5. Updates the in-memory `MemoryGraph`\n\n资料来源：[src/store/memory-store.ts:1-50]()\n\n### MemoryUnlinkHandler\n\n**Purpose**: Removes a directed edge between two memories.\n\n**Factory**: `createMemoryUnlinkHandler(options: CreateHandlerOptions)`\n\n**Request Interface**:\n\n| Field | Type | Required | Description |\n|-------|------|----------|-------------|\n| `from` | `string` | Yes | Source memory name |\n| `to` | `string` | Yes | Target memory name |\n| `type` | `RelationType \\| 'supersedes'` | No | Specific edge type to remove. Omit to remove all edges to target |\n\n**Behavior**:\n- No-op when the requested edge does not exist\n- When `type` is omitted, removes ALL edges from `from` -> `to`\n- Returns `{ relations, supersedes, note }` describing the new state\n\n资料来源：[src/store/memory-store.ts:100-150]()\n\n## Store Resolution\n\nHandlers use the `resolveStores` helper to map request scopes to actual store instances:\n\n```typescript\nconst resolveStores = (opts: { store?: MemoryStore; userStore?: MemoryStore; projectStore?: MemoryStore }) => {\n  const userStore = opts.userStore ?? opts.store;\n  if (userStore === undefined) {\n    throw new Error(`${toolName}: handler factory requires a userStore`);\n  }\n  return { userStore, projectStore: opts.projectStore };\n};\n```\n\n资料来源：[src/server/handlers.ts:65-75]()\n\n## Scope System\n\nThe scope system allows memories to be stored in different locations:\n\n| Scope | Directory | Use Case |\n|-------|-----------|----------|\n| `user` | `COMMONPLACE_USER_DIR` | Cross-project knowledge |\n| `project` | `COMMONPLACE_PROJECT_DIR` | Project-specific facts |\n\n**Validation**:\n\n```typescript\nconst SCOPES = ['user', 'project'] as const;\ntype Scope = typeof SCOPES[number];\n\nconst isScope = (v: unknown): v is Scope =>\n  typeof v === 'string' && (SCOPES as readonly string[]).includes(v);\n```\n\n资料来源：[src/server/handlers.ts:55-70]()\n\n## Server Initialization\n\nThe handlers are wired into the MCP server in `server.ts`:\n\n```mermaid\ngraph LR\n    A[MCP Server] --> B[registerTools]\n    B --> C[MemorySaveHandler]\n    B --> D[MemoryListHandler]\n    B --> E[MemorySearchHandler]\n    B --> F[MemoryDeleteHandler]\n    B --> G[MemoryLinkHandler]\n    B --> H[MemoryUnlinkHandler]\n```\n\nThe main entry point (`src/index.ts`) dispatches to the server module:\n\n```typescript\nif (argv[0] === 'graph') {\n  const result = await graphMain({ argv, ... });\n  return result.exitCode;\n}\n```\n\n资料来源：[src/index.ts:1-30]()\n\n## Error Handling\n\nAll handlers follow consistent error handling patterns:\n\n| Error Type | Cause | Response |\n|------------|-------|----------|\n| Validation error | Invalid input format | Throws with descriptive message |\n| Not found | Memory doesn't exist | Handled by store methods |\n| Duplicate edge | Edge already exists | Handled by `linkEdge` |\n| Store unavailable | Store not initialized | Factory throws on construction |\n\n## Integration with MemoryStore\n\nHandlers delegate to `MemoryStore` methods for all persistence operations:\n\n| Handler | Store Method |\n|---------|--------------|\n| MemorySaveHandler | `MemoryStore.save()` |\n| MemoryListHandler | `MemoryStore.all()` |\n| MemorySearchHandler | `MemoryStore.search()` |\n| MemoryDeleteHandler | `MemoryStore.delete()` |\n| MemoryLinkHandler | `MemoryStore.linkEdge()` |\n| MemoryUnlinkHandler | `MemoryStore.unlinkEdge()` |\n\n资料来源：[src/store/memory-store.ts:1-200]()\n\n## Mention Extraction\n\nWhen a memory is saved, the body is scanned for `[[name]]` wiki-link syntax:\n\n```mermaid\ngraph TD\n    A[Memory Save] --> B[Extract mentions]\n    B --> C{NAME_PATTERN test}\n    C -->|pass| D[Add to MemoryGraph]\n    C -->|fail| E[Skip]\n    D --> F[edgesPruned count]\n```\n\nThis extraction is controlled by the `COMMONPLACE_EXTRACT_MENTIONS` environment variable (default: enabled).\n\n资料来源：[src/store/mentions.ts:1-60]()\n\n## Configuration\n\nHandlers are configured via environment variables managed in DAR-913:\n\n| Variable | Default | Effect |\n|----------|---------|--------|\n| `COMMONPLACE_USER_DIR` | `~/.commonplace` | User memory directory |\n| `COMMONPLACE_PROJECT_DIR` | `./.commonplace` | Project memory directory |\n| `COMMONPLACE_MODEL_ID` | `Xenova/bge-base-en-v1.5` | Embedding model |\n| `COMMONPLACE_EXTRACT_MENTIONS` | `true` | Enable `[[name]]` extraction |\n\n## Related Documentation\n\n- **Memory Store**: `src/store/memory-store.ts` - Persistence layer\n- **Memory Types**: `src/store/memory.ts` - Type definitions\n- **Atomic Write**: `src/store/atomic-write.ts` - Safe file operations\n- **Mention Extraction**: `src/store/mentions.ts` - `[[name]]` parsing\n- **CLI Entry**: `src/index.ts` - Command dispatch\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> Copy the prompt below into your AI host before installing anything.\n> Its purpose is to let you safely feel the project's workflow, not to claim the project has already run.\n\n## Copy this prompt\n\n```text\nYou are using an independent Doramagic capability pack for rickbassham/commonplace.\n\nProject:\n- Name: commonplace\n- Repository: https://github.com/rickbassham/commonplace\n- Summary: Local-first semantic memory MCP server. A commonplace book for your agent — markdown source-of-truth, sidecar embeddings, no database.\n- Host target: mcp_host\n\nGoal:\nHelp me evaluate this project for the following task without installing it yet: Local-first semantic memory MCP server. A commonplace book for your agent — markdown source-of-truth, sidecar embeddings, no database.\n\nBefore taking action:\n1. Restate my task, success standard, and boundary.\n2. Identify whether the next step requires tools, browser access, network access, filesystem access, credentials, package installation, or host configuration.\n3. Use only the Doramagic Project Pack, the upstream repository, and the source-linked evidence listed below.\n4. If a real command, install step, API call, file write, or host integration is required, mark it as \"requires post-install verification\" and ask for approval first.\n5. If evidence is missing, say \"evidence is missing\" instead of filling the gap.\n\nPreviewable capabilities:\n- Capability 1: Local-first semantic memory MCP server. A commonplace book for your agent — markdown source-of-truth, sidecar embeddings, no database.\n\nCapabilities that require post-install verification:\n- Capability 1: Use the source-backed project context to guide one small, checkable workflow step.\n\nCore service flow:\n1. introduction: Introduction to Commonplace. Produce one small intermediate artifact and wait for confirmation.\n2. quickstart: Quick Start Guide. Produce one small intermediate artifact and wait for confirmation.\n3. system-architecture: System Architecture. Produce one small intermediate artifact and wait for confirmation.\n4. memory-data-model: Memory Data Model. Produce one small intermediate artifact and wait for confirmation.\n5. memory-types-taxonomy: Memory Types Taxonomy. Produce one small intermediate artifact and wait for confirmation.\n\nSource-backed evidence to keep in mind:\n- https://github.com/rickbassham/commonplace\n- https://github.com/rickbassham/commonplace#readme\n- README.md\n- CLAUDE.md\n- src/index.ts\n- package.json\n- src/embedder/index.ts\n- src/store/memory-store.ts\n- src/server/index.ts\n- src/server/server.ts\n\nFirst response rules:\n1. Start Step 1 only.\n2. Explain the one service action you will perform first.\n3. Ask exactly three questions about my target workflow, success standard, and sandbox boundary.\n4. Stop and wait for my answers.\n\nStep 1 follow-up protocol:\n- After I answer the first three questions, stay in Step 1.\n- Produce six parts only: clarified task, success standard, boundary conditions, two or three options, tradeoffs for each option, and one recommendation.\n- End by asking whether I confirm the recommendation.\n- Do not move to Step 2 until I explicitly confirm.\n\nConversation rules:\n- Advance one step at a time and wait for confirmation after each small artifact.\n- Write outputs as recommendations or planned checks, not as completed execution.\n- Do not claim tests passed, files changed, commands ran, APIs were called, or the project was installed.\n- If the user asks for execution, first provide the sandbox setup, expected output, rollback, and approval checkpoint.\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"
}
