# https://github.com/forloopcodes/contextplus 项目说明书

生成时间：2026-06-28 12:58:05 UTC

## 目录

- [Architecture & Overview](#page-1)
- [Discovery & Analysis Tools](#page-2)
- [Embedding Providers & Configuration](#page-3)
- [Memory Graph & Code Operations](#page-4)

<a id='page-1'></a>

## Architecture & Overview

### 相关页面

相关主题：[Discovery & Analysis Tools](#page-2), [Embedding Providers & Configuration](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/index.ts](https://github.com/forloopcodes/contextplus/blob/main/src/index.ts)
- [src/core/hub.ts](https://github.com/forloopcodes/contextplus/blob/main/src/core/hub.ts)
- [src/tools/semantic-identifiers.ts](https://github.com/forloopcodes/contextplus/blob/main/src/tools/semantic-identifiers.ts)
- [src/tools/propose-commit.ts](https://github.com/forloopcodes/contextplus/blob/main/src/tools/propose-commit.ts)
- [README.md](https://github.com/forloopcodes/contextplus/blob/main/README.md)
- [INSTRUCTIONS.md](https://github.com/forloopcodes/contextplus/blob/main/INSTRUCTIONS.md)
- [agent-instructions.md](https://github.com/forloopcodes/contextplus/blob/main/agent-instructions.md)
</details>

# Architecture & Overview

## 项目目的与范围

Context+ 是一个面向 AI 代理的 MCP (Model Context Protocol) 服务器,定位于"大规模工程的语义智能"——通过融合 RAG (Retrieval-Augmented Generation)、Tree-sitter AST、光谱聚类 (Spectral Clustering) 与 Obsidian 风格的双向链接,将庞大的代码库转化为可搜索、可分层的特性图谱,以追求 99% 的检索准确率。资料来源:[README.md:1-7]()

系统通过 stdio 传输方式启动,并通过一个 CLI 参数接收目标工程根目录 (默认为 `process.cwd()`),随后注册 17 个 MCP 工具供宿主代理调用。资料来源:[src/index.ts:43-44]()

## 系统架构

Context+ 整体上分为四层:**入口层 (Entry Point)**、**核心层 (Core Layer)**、**工具层 (Tools Layer)** 与 **Git 层 (Git Layer)**,并以本地持久化的内存图谱作为长期记忆,辅以 Ollama 驱动的嵌入与聚类模型。入口 `src/index.ts` 负责装配 `McpServer`、注册工具、加载内嵌的 `agent-instructions.md` 资源,并通过 `contextplus://instructions` URI 暴露给宿主。资料来源:[src/index.ts:25-45](),[INSTRUCTIONS.md:30-44]()

核心层承担跨工具的共享能力:

- `hub.ts` 解析 Obsidian 风格的 `[[wikilink]]` 链接与 `@linked-to` 跨链标签,用于构建特性中心 (Feature Hub) 与孤立文件检测。资料来源:[src/core/hub.ts:6-58]()
- `memory-graph.ts` 维护带 JSON 持久化、衰减评分 (`e^(-λt)`) 与自动相似边的属性图谱。资料来源:[INSTRUCTIONS.md:42-44]()
- `embedding-tracker.ts` 与 `process-lifecycle.ts` 协同管理实时嵌入刷新、批处理上限 (硬性封顶 5-10) 与进程空闲关机。资料来源:[src/index.ts:27-31]()

工具层由 17 个 MCP 端点组成,横跨**发现 (Discovery)**、**分析 (Analysis)**、**代码操作 (Code Ops)**、**版本控制 (Version Control)** 与**记忆/RAG (Memory & RAG)** 五大职能。资料来源:[README.md:11-71]()

Git 层 (`src/git/shadow.ts`) 实现与 git 历史解耦的"影子还原点"机制,使得 `undo_change` 不会污染版本控制。资料来源:[INSTRUCTIONS.md:46-48]()

```mermaid
flowchart TB
    Agent[AI Agent / Claude / Cursor / OpenCode] -->|stdio MCP| Server[src/index.ts<br/>McpServer]
    Server --> Tools[17 MCP Tools]
    Server --> Resources[contextplus://instructions]

    subgraph Core[Core Layer]
      Hub[hub.ts<br/>Wikilink Parser]
      MemGraph[memory-graph.ts<br/>Property Graph]
      Embed[embeddings.ts<br/>Ollama Embeddings]
    end

    subgraph Git[Git Layer]
      Shadow[shadow.ts<br/>Restore Points]
    end

    Tools --> Core
    Tools --> Git
    Embed --> Ollama[(Ollama<br/>nomic-embed-text / llama3.2)]
```

## 工具层职责划分

工具层在功能上划分为五个域,各域工具协同完成"探索 → 理解 → 修改 → 回滚 → 沉淀知识"的工作流。下表概述各域代表工具与职责。

| 工具域 | 代表工具 | 关键职责 |
|--------|----------|----------|
| Discovery | `get_context_tree`、`semantic_identifier_search` | 构建 AST 骨架与按标识符语义检索,需在每次任务开始时调用 |
| Analysis | `get_blast_radius`、`run_static_analysis` | 追踪符号影响范围并执行原生 linter (`tsc`、`eslint`、`py_compile` 等) |
| Code Ops | `propose_commit`、`get_feature_hub` | 强制 2 行文件头、禁止行内注释、最大嵌套深度等规则后再写入 |
| Version Control | `list_restore_points`、`undo_change` | 影子还原点管理,与 git 解耦 |
| Memory & RAG | `search_memory_graph`、`upsert_memory_node`、`create_relation` | 语义搜索 + 1/2 跳邻居遍历 + 跨会话知识沉淀 |

资料来源:[README.md:11-71](),[INSTRUCTIONS.md:50-70](),[agent-instructions.md:14-37]()

以 `semantic_identifier_search` 为例,该工具从 `walker.ts` 遍历得到受支持的文件,经 `parser.ts` 抽取出扁平化的符号列表后,为每个标识符构建包含签名、父符号、行号范围的文档,再调用 `embeddings.ts` 中的 `fetchEmbedding` 生成向量,并维护 `identifier-embeddings-cache.json` (60 秒 TTL) 与 `callsite:` 前缀的调用点缓存。资料来源:[src/tools/semantic-identifiers.ts:1-60]()

`propose_commit` 作为"唯一允许写文件"的入口,在写入前调用 `validateHeader` 校验前两行必须为对应语言的注释 (`//` / `#` / `--`),并通过 `createRestorePoint` 先生成可回滚快照。资料来源:[src/tools/propose-commit.ts:5-32]()

## 环境配置与已知限制

默认嵌入与对话模型依赖 Ollama 本地实例,关键环境变量见下表。社区已记录两项与 Ollama 假设相关的限制:

| 变量 | 默认值 | 说明 |
|------|--------|------|
| `OLLAMA_EMBED_MODEL` | `nomic-embed-text` | 嵌入模型名称 |
| `OLLAMA_CHAT_MODEL` | `llama3.2` | 用于聚类标签的对话模型 |
| `CONTEXTPLUS_EMBED_BATCH_SIZE` | `8` | 单次 GPU 调用的批大小 (硬性封顶 5-10) |
| `CONTEXTPLUS_EMBED_TRACKER` | `true` | 启用变更文件的实时嵌入刷新 |
| `CONTEXTPLUS_EMBED_TRACKER_MAX_FILES` | `8` | 单次刷新最大文件数 |
| `CONTEXTPLUS_EMBED_TRACKER_DEBOUNCE_MS` | `700` | 刷新去抖延迟 |

资料来源:[INSTRUCTIONS.md:52-60]()

社区反馈指出:将 `OLLAMA_HOST` 写入 `.mcp.json` 的 `env` 块对 Ollama JS 客户端并不生效,因为客户端构造时未读取该变量(参见 issue #3 与 #27)。此外,`CONTEXTPLUS_EMBED_PROVIDER=openai` 等文档承诺的 OpenAI 兼容后端目前并未真正接入(issue #34)。在 monorepo 场景下,若子仓库被根目录 `.gitignore` 排除,`walker.ts` 将无法枚举到嵌套子仓库中的源码(issue #38)。Context+ 同时声明 OpenCode 通过标准 MCP 即插即用,并以 `opencode.json` 作为配置目标文件(issue #8,`src/index.ts:14-21`())。

## See Also

- [INSTRUCTIONS.md](https://github.com/forloopcodes/contextplus/blob/main/INSTRUCTIONS.md) — 完整的工具清单与环境变量参考
- [agent-instructions.md](https://github.com/forloopcodes/contextplus/blob/main/agent-instructions.md) — 面向 AI 代理的工具调用最佳实践
- [README.md](https://github.com/forloopcodes/contextplus/blob/main/README.md) — 项目定位与工具概述

---

<a id='page-2'></a>

## Discovery & Analysis Tools

### 相关页面

相关主题：[Architecture & Overview](#page-1), [Embedding Providers & Configuration](#page-3)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/index.ts](https://github.com/forloopcodes/contextplus/blob/main/src/index.ts)
- [src/tools/semantic-identifiers.ts](https://github.com/forloopcodes/contextplus/blob/main/src/tools/semantic-identifiers.ts)
- [src/tools/semantic-navigate.ts](https://github.com/forloopcodes/contextplus/blob/main/src/tools/semantic-navigate.ts)
- [README.md](https://github.com/forloopcodes/contextplus/blob/main/README.md)
- [INSTRUCTIONS.md](https://github.com/forloopcodes/contextplus/blob/main/INSTRUCTIONS.md)
- [agent-instructions.md](https://github.com/forloopcodes/contextplus/blob/main/agent-instructions.md)
- [src/core/hub.ts](https://github.com/forloopcodes/contextplus/blob/main/src/core/hub.ts)
</details>

# Discovery & Analysis Tools

## 概述

Discovery & Analysis Tools（发现与分析工具集）是 Context+ MCP 服务器向 Agent 暴露的两大类核心工具的统称，共包含 **7 个** 通过 Model Context Protocol（std

## File Path: src/core/hub.ts

// Obsidian-style hub parser extracting wikilinks and cross-link tags
// FEATURE: Hierarchical context management via feature hub graph

import { readFile, readdir, stat } from "fs/promises";
import { resolve, relative, join, extname, basename } from "path";

export interface HubLink {
  target: string;
  description?: string;
}

export interface CrossLink {
  hubName: string;
  sourceFile: string;
}

export interface HubInfo {
  hubPath: string;
  title: string;
  links: HubLink[];
  crossLinks: CrossLink[];
  raw: string;
}

const WIKILINK_RE = /\[\[([^\]|]+)(?:\|([^\]]*))?\]\]/g;
const CROSS_LINK_RE = /@linked-to\s+\[\[([^\]]+)\]\]/g;
const HEADER_FEATURE_RE = /^(?:\/\/|#|--)\s*FEATURE:\s*(.+)$/m;

export function parseWikiLinks(content: string): HubLink[] {
  const links: HubLink[] = [];
  const seen = new Set<string>();
  const cleaned = content.replace(CROSS_LINK_RE, "");

  for (const match of cleaned.matchAll(WIKILINK_RE)) {
    const target = match[1].trim();
    if (!seen.has(target)) {
      seen.add(target);
      links.push({ target, description: match[2]?.trim() });
    }
  }
  return links;
}

export function parseCrossLinks(content: string, sourceFile: string): CrossLink[] {
  const crossLinks: CrossLink[] = [];
  for (const match of content.matchAll(CROSS_LINK_RE)) {
    crossLinks.push({ hub

## File Path: README.md

                                                   |

### Analysis

| Tool                  | Description                                                                                                                   |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `get_blast_radius`    | Trace every file and line where a symbol is imported or used. Prevents orphaned references.                                   |
| `run_static_analysis` | Run native linters and compilers to find unused variables, dead code, and type errors. Supports TypeScript, Python, Rust, Go. |

### Code Ops

| Tool              | Description                                                                                                              |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `propose_commit`  | The only way to write code. Validates against strict rules before saving. Creates a shadow restore point before writing. |
| `get_feature_hub` | Obsidian-style feature hub navigator. Hubs are `.md` files with `[[wikilinks]]` that map features to code files.         |

### Version Control

| Tool                  | Description                                                                                                |
| --------------------- | ---------------------------------------------------------------------------------------------------------- |
| `list_restore_points` | List all shadow restore points created by `propose_commit`. Each captures file state before AI changes.    |
| `undo_change`         | Restore files to their state before a specific AI change. Uses shadow restore points. Does not affect git. |

### Memory & RAG

| Tool                      | Description                                                                                              |
| ------------------------- | -------------------------------------------------------------------------------------------------------- |
| `upsert_memory_node`      | Create or update a memory node (concept, file, symbol, note) with auto-generated embeddings.             |
| `create_relation`         | Create typed edges between nodes (relates_to, depends_on, implements, references, similar_to, contains). |
| `search_memory_graph`     | Semantic search with graph traversal — finds direct matches then walks

# Context+

Semantic Intelligence for Large-Scale Engineering.

Context+ is an MCP server designed for developers who demand 99% accuracy. By combining RAG, Tree-sitter AST, Spectral Clustering, and Obsidian-style linking, Context+ turns a massive codebase into a searchable, hierarchical feature graph.

https://github.com/user-attachments/assets/a97a451f-c9b4-468d-b036-15b65fc13e79

## Tools

### Discovery

| Tool                         | Description                                                                                                                                                      |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `get_context_tree`           | Structural AST tree of a project with file headers and symbol ranges (line numbers for functions/classes/methods). Dynamic pruning shrinks output automatically. |
| `get_file_skeleton`          | Function signatures, class methods, and type definitions with line ranges, without reading full bodies. Shows the API surface.                                   |
| `semantic_code_search`       | Search by meaning, not exact text. Uses embeddings over file headers/symbols and returns matched symbol definition lines.                                        |
| `semantic_identifier_search` | Identifier-level semantic retrieval for functions/classes/variables with ranked call sites and line numbers.                                                     |
| `semantic_navigate`          | Browse codebase by meaning using spectral clustering. Groups semantically related files into labeled clusters.                                                   |

### Analysis

| Tool                  | Description                                                                                                                   |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `get_blast_radius`    | Trace every file and line where a symbol is imported or used. Prevents orphaned references.                                   |
| `run_static_analysis` | Run native linters and compilers to find unused variables, dead code, and type errors. Supports TypeScript, Python,

## File Path: INSTRUCTIONS.md

 - Identifier-level semantic search returning ranked definitions + call chains with line numbers.
- `semantic-navigate.ts` - Browse-by-meaning navigator using spectral clustering and Ollama labeling.
- `blast-radius.ts` - Symbol usage tracer across the entire codebase.
- `static-analysis.ts` - Native linter runner (tsc, eslint, py_compile, cargo check, go vet).
- `propose-commit.ts` - Code gatekeeper validating headers, FEATURE tag, no inline comments, nesting, file length.
- `feature-hub.ts` - Obsidian-style feature hub navigator with bundled skeleton views.
- `memory-tools.ts` - Memory graph MCP wrappers (upsert, relate, search, prune, interlink, traverse). The long-term memory graph architecture is also adapted by the complementary [pmll-memory-mcp](https://www.npmjs.com/package/pmll-memory-mcp) server (`npx pmll-memory-mcp`), which adds short-term KV memory and a solution engine — see [drQedwards/PPM](https://github.com/drQedwards/PPM).

The memory graph is a **Retrieval-Augmented Generation (RAG)** system. Agents MUST use `search_memory_graph` at the start of every task to retrieve prior context, and persist learnings with `upsert_memory_node` and `create_relation` after completing work. This prevents redundant exploration and builds cumulative knowledge across sessions.

**Core Layer** (continued):

- `hub.ts` - Wikilink parser for `[[path]]` links, cross-link tags, hub discovery, orphan detection.
- `memory-graph.ts` - In-memory property graph with JSON persistence, decay scoring, and auto-sim

_memory_node` and `create_relation` after completing work. This prevents redundant exploration and builds cumulative knowledge across sessions.

**Core Layer** (continued):

- `hub.ts` - Wikilink parser for `[[path]]` links, cross-link tags, hub discovery, orphan detection.
- `memory-graph.ts` - In-memory property graph with JSON persistence, decay scoring, and auto-similarity edges.

**Git Layer** (`src/git/`):

- `shadow.ts` - Shadow restore point system for undo without touching git history.

**Entry Point**: `src/index.ts` registers 17 MCP tools and starts the stdio transport. Accepts an optional CLI argument for the target project root directory (defaults to `process.cwd()`).

## Environment Variables

| Variable                                | Default            | Description                                                   |
| --------------------------------------- | ------------------ | ------------------------------------------------------------- |
| `OLLAMA_EMBED_MODEL`                    | `nomic-embed-text` | Embedding model name                                          |
| `OLLAMA_API_KEY`                        | (empty)            | Cloud auth (auto-detected by SDK)                             |
| `OLLAMA_CHAT_MODEL`                     | `llama3.2`         | Chat model for cluster labeling                               |
| `CONTEXTPLUS_EMBED_BATCH_SIZE`          | `8`                | Embedding batch per GPU call (hard-capped to 5-10)            |
| `CONTEXTPLUS_EMBED_TRACKER`             | `true`             | Enable realtime embedding updates for changed files/functions |
| `CONTEXTPLUS_EMBED_TRACKER_MAX_FILES`   | `8`                | Max changed files per tracker tick (hard-capped to 5-10)      |
| `CONTEXTPLUS_EMBED

 every task. Map files + symbols with line ranges.                         |
| `semantic_navigate`          | Browse codebase by meaning, not directory structure.                               |
| `get_file_skeleton`          | MUST run before full reads. Get signatures + line ranges first.                    |
| `semantic_code_search`       | Find relevant files by concept with symbol definition lines.                       |
| `semantic_identifier_search` | Find closest functions/classes/variables and ranked call chains with line numbers. |
| `get_blast_radius`           | Before deleting or modifying any symbol.                                           |
| `run_static_analysis`        | After writing code. Catch dead code deterministically.                             |
| `propose_commit`             | The ONLY way to save files. Validates before writing.                              |
| `list_restore_points`        | See undo history.                                                                  |
| `undo_change`                | Revert a bad AI change without touching git.                                       |
| `get_feature_hub`            | Browse feature graph hubs. Find orphaned files.                                    |
| `upsert_memory_node`         | Create/update memory nodes (concept, file, symbol, note) with auto-embedding.      |
| `create_relation`            | Create typed edges between memory nodes (depends_on, implements, etc).             |
| `search_memory_graph`        | Semantic search + graph traversal across 1st/2nd-degree neighbors.                 |
| `prune_stale_links`          | Remove decayed edges (e^(-λt)) and orphan nodes periodically.                      |
| `add_interlinked_context`    | Bulk-add nodes with auto-similarity linking (cosine ≥ 0.72).                       |
| `retrieve_with_tr

## File Path: landing/src/app/api/instructions/route.ts

ama-powered semantic file search with symbol definition lines and 60s cache TTL.
- \`semantic-identifiers.ts\` - Identifier-level semantic search returning ranked definitions + call chains with line numbers.
- \`semantic-navigate.ts\` - Browse-by-meaning navigator using spectral clustering and Ollama labeling.
- \`blast-radius.ts\` - Symbol usage tracer across the entire codebase.
- \`static-analysis.ts\` - Native linter runner (tsc, eslint, py_compile, cargo check, go vet).
- \`propose-commit.ts\` - Code gatekeeper validating headers, FEATURE tag, no inline comments, nesting, file length.
- \`feature-hub.ts\` - Obsidian-style feature hub navigator with bundled skeleton views.
- \`memory-tools.ts\` - Memory graph MCP wrappers (upsert, relate, search, prune, interlink, traverse).

The memory graph is a **Retrieval-Augmented Generation (RAG)** system. Agents MUST use \`search_memory_graph\` at the start of every task to retrieve prior context, and persist learnings with \`upsert_memory_node\` and \`create_relation\` after completing work. This prevents redundant exploration and builds cumulative knowledge across sessions.

**Core Layer** (continued):

- \`hub.ts\` - Wikilink parser for \`[[path]]\` links, cross-link tags, hub discovery, orphan detection.
- \`memory-graph.ts\` - In-memory property graph with JSON persistence, decay scoring, and auto-similarity edges.

**Git Layer** (\`src/git/\`):

- \`shadow.ts\` - Shadow restore point system for undo without touching git history.

**Entry Point**: \`src

 for \`[[path]]\` links, cross-link tags, hub discovery, orphan detection.
- \`memory-graph.ts\` - In-memory property graph with JSON persistence, decay scoring, and auto-similarity edges.

**Git Layer** (\`src/git/\`):

- \`shadow.ts\` - Shadow restore point system for undo without touching git history.

**Entry Point**: \`src/index.ts\` registers 17 MCP tools and starts the stdio transport. Accepts an optional CLI argument for the target project root directory (defaults to \`process.cwd()\`).

## Environment Variables

| Variable                                | Default            | Description                                                   |
| --------------------------------------- | ------------------ | ------------------------------------------------------------- |
| \`OLLAMA_EMBED_MODEL\`                    | \`nomic-embed-text\` | Embedding model name                                          |
| \`OLLAMA_API_KEY\`                        | (empty)            | Cloud auth (auto-detected by SDK)                             |
| \`OLLAMA_CHAT_MODEL\`                     | \`llama3.2\`         | Chat model for cluster labeling                               |
| \`CONTEXTPLUS_EMBED_BATCH_SIZE\`          | \`8\`                | Embedding batch per GPU call (hard-capped to 5-10)            |
| \`CONTEXTPLUS_EMBED_TRACKER\`             | \`true\`             | Enable realtime embedding updates for changed files/functions |
| \`CONTEXTPLUS_EMBED_TRACKER_MAX_FILES\`   | \`8\`                | Max changed files per tracker tick (hard-capped to 5-10)      |
| \`CONTEXTPLUS_EMBED_TRACKER_DEBOUNCE_MS\` | \`700\`              | Debounce before applying tracker refresh                     

## File Path: landing/src/app/page.tsx

 >
          &ldquo;Context engineering is the delicate art and science of filling
          the context window with just the right information for the next
          next step.&rdquo;
        </p>
        <a
          href="https://x.com/karpathy/status/1937902205765607626"
          target="_blank"
          rel="noopener noreferrer"
          style={{
            marginTop: 24,
            fontSize: 16,
            fontWeight: 300,
            color: "var(--text-secondary)",
            textDecoration: "none",
            fontFamily: "var(--font-geist-pixel-square)",
            letterSpacing: "-0.02em",
          }}
        >
          - Andrej Karpathy
        </a>
      </section>

      <footer
        className="site-footer"
        style={{
          position: "relative",
          zIndex: 1,
          padding: "80px 100px",
          display: "flex",
          justifyContent: "space-between",
          alignItems: "center",
          borderTop: "1.5px solid var(--footer-border)",
          background: "var(--nav-bg)",
          backdropFilter: "blur(12px)",
          WebkitBackdropFilter: "blur(12px)",
        }}
      >
        <span
          className="font-light"
          style={{
            fontSize: 22,
            lineHeight: "28px",
            color: "var(--text-primary)",
          }}
        >
          Context+
        </span>
        <div style={{ display: "flex", gap: 16, alignItems: "center" }}>
          <a
            href="https://www.npmjs.com/package/contextplus"
            target="_blank"
            rel="noopener noreferrer"
            style={{

 | 2025-06-26\n  src/tools/search.ts | refactor search\n\nrp-1719383000-b7c1 | 2025-06-26\n  src/index.ts | add new tool"',
  },
  {
    name: "undo_change",
    desc: "Restore files to their state before a specific AI change. Uses shadow restore points. Does not affect git.",
    input: "{ point_id: string }",
    output: '"Restored 1 file(s):\n  src/tools/search.ts"',
  },
  {
    name: "semantic_navigate",
    desc: "Browse codebase by meaning using spectral clustering. Groups semantically related files into labeled clusters.",
    input: "{\n  max_depth?: number,\n  max_clusters?: number\n}",
    output:
      '"Authentication (4 files)\n  src/auth/jwt.ts\n  src/auth/session.ts\n  src/middleware/guard.ts\n  src/models/user.ts\n\nParsing (3 files)\n  src/core/parser.ts\n  src/core/tree-sitter.ts\n  src/core/walker.ts"',
  },
  {
    name: "get_feature_hub",
    desc: "Obsidian-style feature hub navigator. Hubs are .md files with [[wikilinks]] that map features to code files.",
    input:
      "{\n  hub_path?: string,\n  feature_name?: string,\n  show_orphans?: boolean\n}",
    output:
      '"## auth.md\n[[src/auth/jwt.ts]]\n  → verifyToken(token: string)\n  → signToken(payload: object)\n\n[[src/auth/session.ts]]\n  → create

  {
    name: "run_static_analysis",
    desc: "Run the native linter or compiler to find unused variables, dead code, and type errors. Supports TypeScript, Python, Rust, Go.",
    input: "{ target_path?: string }",
    output:
      '"src/utils.ts:14:5\n  error TS2345: Argument of type string\n  is not assignable to parameter\n\nsrc/old.ts:1:1\n  warning: file has no exports"',
  },
  {
    name: "propose_commit",
    desc: "The only way to write code. Validates against strict rules before saving. Creates a shadow restore point before writing.",
    input: "{\n  file_path: string,\n  new_content: string\n}",
    output:
      '"✓ Header comment present\n✓ No inline comments\n✓ Max nesting depth: 3\n✓ File length: 142 lines\n\nSaved src/tools/search.ts\nRestore point: rp-1719384000-a3f2"',
  },
  {
    name: "list_restore_points",
    desc: "List all shadow restore points created by propose_commit. Each captures file state before AI changes.",
    input: "{ }",
    output:
      '"rp-1719384000-a3f2 | 2025-06-26\n  src/tools/search.ts | refactor search\n\nrp-1719383000-b7c1 | 2025-06-26\n  src/index.ts | add new tool"',
  },
  {
    name: "undo_change",
    desc: "Restore files to their state before a specific AI change. Uses shadow

## File Path: src/tools/semantic-identifiers.ts

// Identifier-level semantic retrieval with call-site ranking and line metadata
// FEATURE: Symbol intelligence via semantic search over definitions and usages

import { readFile } from "fs/promises";
import { walkDirectory } from "../core/walker.js";
import { analyzeFile, flattenSymbols, isSupportedFile } from "../core/parser.js";
import {
  fetchEmbedding,
  getEmbeddingBatchSize,
  loadEmbeddingCache,
  saveEmbeddingCache,
  type EmbeddingCache,
} from "../core/embeddings.js";
import { resolve } from "path";

export interface SemanticIdentifierSearchOptions {
  rootDir: string;
  query: string;
  topK?: number;
  topCallsPerIdentifier?: number;
  includeKinds?: string[];
  semanticWeight?: number;
  keywordWeight?: number;
}

interface IdentifierDoc {
  id: string;
  path: string;
  header: string;
  name: string;
  kind: string;
  line: number;
  endLine: number;
  signature: string;
  parentName?: string;
  text: string;
}

interface RankedIdentifier {
  doc: IdentifierDoc;
  semanticScore: number;
  keywordScore: number;
  score: number;
}

interface CallSite {
  file: string;
  line: number;
  context: string;
  semanticScore: number;
  keywordScore: number;
  score: number;
}

interface IdentifierIndex {
  docs: IdentifierDoc[];
  vectors: number[][];
  fileLines: Map<string, string[]>;
}

const IDENTIFIER_CACHE_FILE = "identifier-embeddings-cache.json";
const CALLSITE_CACHE_PREFIX = "callsite:";
const INDEX_TTL_MS = 60_000

## File Path: landing/src/components/IsometricDiagram.tsx

",
    color: "#3a3a3a",
  },
  {
    id: "semantic-navigate",
    label: "Semantic Navigate",
    desc: "Jump to related code by meaning",
    color: "#444444",
  },
  {
    id: "blast-radius",
    label: "Blast Radius",
    desc: "Impact analysis for code changes",
    color: "#555555",
  },
  {
    id: "static-analysis",
    label: "Static Analysis",
    desc: "AST-powered code inspection",
    color: "#666666",
  },
  {
    id: "feature-hub",
    label: "Feature Hub",
    desc: "Cluster features by semantic similarity",
    color: "#777777",
  },
  {
    id: "propose-commit",
    label: "Propose Commit",
    desc: "AI-generated commit messages",
    color: "#888888",
  },
  {
    id: "git-shadow",
    label: "Git Shadow",
    desc: "Lightweight git worktree operations",
    color: "#999999",
  },
  {
    id: "memory-search",
    label: "Memory Search",
    desc: "RAG-powered search with graph traversal",
    color: "#2a4a6a",
  },
  {
    id: "memory-upsert",
    label: "Memory Upsert",
    desc: "Persist learned context as graph nodes",
    color: "#3a5a7a",
  },
  {
    id: "memory-traverse",
    label: "Graph Traverse",
    desc: "Walk linked nodes by relation and decay",
    color: "#4a6a8

## File Path: src/index.ts

";
import { runStaticAnalysis } from "./tools/static-analysis.js";
import { proposeCommit } from "./tools/propose-commit.js";
import { listRestorePoints, restorePoint } from "./git/shadow.js";
import { semanticNavigate } from "./tools/semantic-navigate.js";
import { getFeatureHub } from "./tools/feature-hub.js";
import { toolUpsertMemoryNode, toolCreateRelation, toolSearchMemoryGraph, toolPruneStaleLinks, toolAddInterlinkedContext, toolRetrieveWithTraversal } from "./tools/memory-tools.js";

type AgentTarget = "claude" | "cursor" | "vscode" | "windsurf" | "opencode";

const AGENT_CONFIG_PATH: Record<AgentTarget, string> = {
  claude: ".mcp.json",
  cursor: ".cursor/mcp.json",
  vscode: ".vscode/mcp.json",
  windsurf: ".windsurf/mcp.json",
  opencode: "opencode.json",
};

const SUB_COMMANDS = ["init", "skeleton", "tree"];
const passthroughArgs = process.argv.slice(2);
const ROOT_DIR = passthroughArgs[0] && !SUB_COMMANDS.includes(passthroughArgs[0])
  ? resolve(passthroughArgs[0])
  : process.cwd();
const INSTRUCTIONS_SOURCE_URL = "https://contextplus.vercel.app/api/instructions";
const INSTRUCTIONS_RESOURCE_URI = "contextplus://instructions";
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
let agentInstructions: string | undefined;
try {
  agentInstructions = readFileSync(resolve(PACKAGE_ROOT, "agent-instructions.md"), "utf8");

inks that act as a Map of Content. " +
  "Modes: (1) No args = list all hubs, (2) hub_path or feature_name = show hub with bundled skeletons of all linked files, " +
  "(3) show_orphans = find files not linked to any hub. Prevents orphaned code and enables graph-based codebase navigation.",
  {
    hub_path: z.string().optional().describe("Path to a specific hub .md file (relative to root)."),
    feature_name: z.string().optional().describe("Feature name to search for. Finds matching hub file automatically."),
    show_orphans: z.boolean().optional().describe("If true, lists all source files not linked to any feature hub."),
  },
  withRequestActivity(async ({ hub_path, feature_name, show_orphans }) => ({
    content: [{
      type: "text" as const,
      text: await getFeatureHub({
        rootDir: ROOT_DIR,
        hubPath: hub_path,
        featureName: feature_name,
        showOrphans: show_orphans,
      }),
    }],
  })),
);

server.tool(
  "upsert_memory_node",
  "Create or update a memory node in the linking graph. Nodes represent concepts, files, symbols, or notes with auto-generated embeddings. " +
  "If a node with the same label and type exists, it updates content and increments access count. Returns the node ID for use in create_relation.",
  {
    type: z.enum(["concept", "file", "symbol", "note"]).describe("Node type: concept (abstract ideas), file (source files), symbol (functions/classes), note (free-form)."),
    label: z.string

## File Path: landing/src/components/InstructionsSection.tsx

llama-powered semantic file search with symbol definition lines and 60s cache TTL.
- \`semantic-identifiers.ts\` - Identifier-level semantic search returning ranked definitions + call chains with line numbers.
- \`semantic-navigate.ts\` - Browse-by-meaning navigator using spectral clustering and Ollama labeling.
- \`blast-radius.ts\` - Symbol usage tracer across the entire codebase.
- \`static-analysis.ts\` - Native linter runner (tsc, eslint, py_compile, cargo check, go vet).
- \`propose-commit.ts\` - Code gatekeeper validating headers, FEATURE tag, no inline comments, nesting, file length.
- \`feature-hub.ts\` - Obsidian-style feature hub navigator with bundled skeleton views.
- \`memory-tools.ts\` - Memory graph MCP wrappers (upsert, relate, search, prune, interlink, traverse).

The memory graph is a **Retrieval-Augmented Generation (RAG)** system. Agents MUST use \`search_memory_graph\` at the start of every task to retrieve prior context, and persist learnings with \`upsert_memory_node\` and \`create_relation\` after completing work. This prevents redundant exploration and builds cumulative knowledge across sessions.

**Core Layer** (continued):

- \`hub.ts\` - Wikilink parser for \`[[path]]\` links, cross-link tags, hub discovery, orphan detection.
- \`memory-graph.ts\` - In-memory property graph with JSON persistence, decay scoring, and auto-similarity edges.

**Git Layer** (\`src/git/\`):

- \`shadow.ts\` - Shadow restore point system for undo without touching git history.

**Entry Point**: \`

 parser for \`[[path]]\` links, cross-link tags, hub discovery, orphan detection.
- \`memory-graph.ts\` - In-memory property graph with JSON persistence, decay scoring, and auto-similarity edges.

**Git Layer** (\`src/git/\`):

- \`shadow.ts\` - Shadow restore point system for undo without touching git history.

**Entry Point**: \`src/index.ts\` registers 17 MCP tools and starts the stdio transport. Accepts an optional CLI argument for the target project root directory (defaults to \`process.cwd()\`).

## Environment Variables

| Variable             | Default            | Description                       |
| -------------------- | ------------------ | --------------------------------- |
| \`OLLAMA_EMBED_MODEL\` | \`nomic-embed-text\` | Embedding model name              |
| \`OLLAMA_API_KEY\`     | (empty)            | Cloud auth (auto-detected by SDK) |
| \`OLLAMA_CHAT_MODEL\`  | \`llama3.2\`         | Chat model for cluster labeling   |
| \`CONTEXTPLUS_EMBED_BATCH_SIZE\` | \`8\` | Embedding batch per GPU call (hard-capped to 5-10) |
| \`CONTEXTPLUS_EMBED_TRACKER\` | \`true\` | Enable realtime embedding updates for changed files/functions |
| \`CONTEXTPLUS_EMBED_TRACKER_MAX_FILES\` | \`8\` | Max changed files per tracker tick (hard-capped to 5-10) |
| \`CONTEXTPLUS_EMBED_TRACKER_DEBOUNCE_MS\` | \`700\` | Debounce before applying tracker refresh |

Runtime cache: \`.mcp_data/\` is

`    | Browse codebase by meaning, not directory structure.    |
| \`get_file_skeleton\`    | MUST run before full reads. Get signatures + line ranges first. |
| \`semantic_code_search\` | Find relevant files by concept with symbol definition lines. |
| \`semantic_identifier_search\` | Find closest functions/classes/variables and ranked call chains with line numbers. |
| \`get_blast_radius\`     | Before deleting or modifying any symbol.                |
| \`run_static_analysis\`  | After writing code. Catch dead code deterministically.  |
| \`propose_commit\`       | The ONLY way to save files. Validates before writing.   |
| \`list_restore_points\`  | See undo history.                                       |
| \`undo_change\`          | Revert a bad AI change without touching git.            |
| \`get_feature_hub\`      | Browse feature graph hubs. Find orphaned files.         |
| \`upsert_memory_node\`   | Create/update memory nodes (concept, file, symbol, note) with auto-embedding. |
| \`create_relation\`      | Create typed edges between memory nodes (depends_on, implements, etc). |
| \`search_memory_graph\`  | Semantic search + graph traversal across 1st/2nd-degree neighbors. |
| \`prune_stale_links\`    | Remove decayed edges (e^(-λt)) and orphan nodes periodically. |
| \`add_interlinked_context\` | Bulk-add nodes with auto-similarity linking (cosine ≥ 0.72). |
| \`retrieve_with_traversal\` | Start from a node, walk outward, return

## File Path: src/tools/semantic-navigate.ts

// Semantic project navigator using spectral clustering and provider-agnostic labeling
// Browse codebase by meaning: embeds files, clusters vectors, generates labels

import { walkDirectory } from "../core/walker.js";
import { analyzeFile, flattenSymbols, isSupportedFile } from "../core/parser.js";
import { fetchEmbedding } from "../core/embeddings.js";
import { readFile } from "fs/promises";
import { spectralCluster, findPathPattern } from "../core/clustering.js";
import { extname } from "path";

export interface SemanticNavigateOptions {
  rootDir: string;
  maxDepth?: number;
  maxClusters?: number;
}

interface FileInfo {
  relativePath: string;
  header: string;
  content: string;
  symbolPreview: string[];
}

interface ClusterNode {
  label: string;
  pathPattern: string | null;
  files: FileInfo[];
  children: ClusterNode[];
}

const EMBED_PROVIDER = (process.env.CONTEXTPLUS_EMBED_PROVIDER ?? "ollama").toLowerCase();
const EMBED_MODEL = process.env.OLLAMA_EMBED_MODEL ?? "nomic-embed-text";
const CHAT_MODEL = process.env.OLLAMA_CHAT_MODEL ?? "llama3.2";
const OPENAI_CHAT_MODEL = process.env.CONTEXTPLUS_OPENAI_CHAT_MODEL ?? process.env.OPENAI_CHAT_MODEL ?? "gpt-4o-mini";
const OPENAI_API_KEY = process.env.CONTEXTPLUS_OPENAI_API_KEY ?? process.env.OPENAI_API_KEY ?? "";
const OPENAI_BASE_URL = process.env.CONTEXTPLUS_OPENAI_BASE_URL ?? process.env.OPENAI_BASE_URL ?? "https://api.openai.com/v1";
const MAX_FILES_PER_LEAF = 20;
const NON

## File Path: agent-instructions.md

--------------------------------------------------------------|
| `get_context_tree`          | Start of every task. Map files + symbols with line ranges.   |
| `get_file_skeleton`         | Before full reads. Get signatures + line ranges first.       |
| `semantic_code_search`      | Find relevant files by concept.                              |
| `semantic_identifier_search`| Find functions/classes/variables and their call chains.      |
| `semantic_navigate`         | Browse codebase by meaning, not directory structure.         |
| `get_blast_radius`          | Before deleting or modifying any symbol.                     |
| `get_feature_hub`           | Browse feature graph hubs. Find orphaned files.              |
| `run_static_analysis`       | After writing code. Catch errors deterministically.          |
| `propose_commit`            | Validate and save file changes.                              |
| `list_restore_points`       | See undo history.                                            |
| `undo_change`               | Revert a change without touching git.                        |

### Long-Term Memory Graph

| Tool                        | When to Use                                                  |
|-----------------------------|--------------------------------------------------------------|
| `upsert_memory_node`        | Create/update memory nodes (concept, file, symbol, note).    |
| `create_relation`           | Create typed edges between memory nodes.                     |
| `search_memory_graph`       | Semantic search + graph traversal across neighbors.          |
| `prune_stale_links`         | Remove decayed edges and orphan nodes.                       |
| `add_interlinked_context`   | Bulk-add nodes with auto-similarity linking.                 |
| `retrieve_with_traversal`   | Walk outward from a node, return scored neighbors.           |

io transport）注册的只读工具。它们协同将一个大规模代码库压缩为可被 LLM 高效消费的"结构化视图 + 影响分析"。具体来说：

- **Discovery（发现）** 类共 5 个工具，负责把项目从"目录树"投影为"语义结构树"：项目结构（`get_context_tree`）、文件骨架（`get_file_skeleton`）、文件语义检索（`semantic_code_search`）、标识符语义检索（`semantic_identifier_search`）、按语义聚类浏览（`semantic_navigate`）。
- **Analysis（分析）** 类共 2 个工具，负责评估"如果改动会发生什么"：符号影响域（`get_blast_radius`）与原生静态分析（`run_static_analysis`）。

Context+ 在入口处一次性注册全部 17 个 MCP 工具，Discovery & Analysis Tools 是它们中最贴近"读路径"的部分。资料来源：[src/index.ts:1-50]()。

## Discovery 工具集

### `get_context_tree`

返回项目的结构化 AST 视图，包含每个文件的文件头注释、符号清单及其行号区间（函数 / 类 / 方法），并通过"动态剪枝"机制自动收缩输出规模，避免在巨型仓库中产生上下文溢出。它是 Agent 在每个任务开始时调用的入口工具，用于先建立"地图"再深入。

### `get_file_skeleton`

仅返回函数签名、类方法、类型定义及对应行号，不读取函数体。其设计目的是在 Agent 决定完整读取某个文件之前，先拿到 API 表面（"文件长什么样"）。Agent 指南明确要求"任何完整读取文件之前必须先调用 `get_file_skeleton`"。资料来源：[agent-instructions.md:1-30]()。

### `semantic_code_search` / `semantic_identifier_search`

二者构成两层粒度的语义检索：

- `semantic_code_search` 在文件级进行语义匹配，基于文件头与符号的向量相似度返回带符号定义行的命中结果，并附带 60 秒缓存 TTL；
- `semantic_identifier_search` 进一步下沉到标识符级（函数 / 类 / 变量），对每个标识符附带排序后的调用点（call site）与行号。资料来源：[src/tools/semantic-identifiers.ts:1-60]()。

两者均通过 Ollama Embedding 模型（默认 `nomic-embed-text`）生成向量，并可与关键词打分线性融合（由 `semanticWeight` / `keywordWeight` 参数控制）。

### `semantic_navigate`

与上述"向量最近邻"思路不同，`semantic_navigate` 走的是"按意义浏览"路线：先把仓库内文件全部嵌入为向量，再做**谱聚类（spectral clustering）**将语义相近的文件合并为带标签的簇，最后用 Ollama Chat 模型为每个簇生成可读标签（例如 "Authentication"、"Parsing"）。其可调参数为 `max_depth` 与 `max_clusters`，并通过 `CONTEXTPLUS_EMBED_PROVIDER` 环境变量支持 OpenAI 兼容后端作为兜底。资料来源：[src/tools/semantic-navigate.ts:1-60]()。

```mermaid
flowchart LR
    A[Agent 发起任务] --> B[get_context_tree<br/>建立结构地图]
    B --> C[get_file_skeleton<br/>获取 API 表面]
    C --> D{语义检索}
    D -->|按概念| E[semantic_code_search]
    D -->|按符号| F[semantic_identifier_search]
    D -->|按聚类| G[semantic_navigate]
    E --> H[分析阶段]
    F --> H
    G --> H
    H --> I[get_blast_radius<br/>影响域]
    H --> J[run_static_analysis<br/>静态检查]
```

## Analysis 工具集

### `get_blast_radius`

定位为"删除 / 修改任何符号之前必须调用"的安全网工具。它会追踪一个符号在仓库范围内被 import 或被使用的所有文件与行号，输出"blast radius"清单，从而避免出现孤儿引用。资料来源：[README.md:1-30]()。

### `run_static_analysis`

调用原生编译器与 Linter 来发现未使用变量、dead code、类型错误等确定性问题。当前在源码中明确支持的工具链包括：

- **TypeScript**：`tsc`、`eslint`
- **Python**：`py_compile`
- **Rust**：`cargo check`
- **Go**：`go vet`

输入参数为可选的 `target_path`，输出按文件:行号定位错误。资料来源：[INSTRUCTIONS.md:1-30]()。

## 环境变量与配置

Discovery 路径强烈依赖嵌入服务，关键环境变量如下：

| 变量 | 默认值 | 用途 |
| --- | --- | --- |
| `OLLAMA_EMBED_MODEL` | `nomic-embed-text` | 嵌入模型名 |
| `OLLAMA_CHAT_MODEL` | `llama3.2` | 用于聚类簇标签生成 |
| `CONTEXTPLUS_EMBED_PROVIDER` | `ollama` | 在 `semantic-navigate` 中切换 OpenAI 兼容后端 |
| `CONTEXTPLUS_EMBED_BATCH_SIZE` | `8` | 每次 GPU 调用的嵌入批大小 |
| `CONTEXTPLUS_EMBED_TRACKER` | `true` | 实时刷新已改动文件的嵌入 |

资料来源：[INSTRUCTIONS.md:1-40]()、`src/tools/semantic-navigate.ts:40-50()`。

## 已知问题与社区反馈

- **远程 Ollama 主机**：社区多次反馈 `OLLAMA_HOST` 在 `.mcp.json` 中设置无效——Ollama JS 客户端未读取该变量，默认仍连 `localhost:11434`（参考 [issue #3](https://github.com/forloopcodes/contextplus/issues/3) 与 [issue #27](https://github.com/forloopcodes/contextplus/issues/27)）。当前 `semantic-navigate` 已通过 `CONTEXTPLUS_EMBED_PROVIDER=openai` 路径提供一种绕行方案，但其他工具是否生效需逐个核对。
- **OpenAI 兼容后端未全部生效**：issue #34 指出 `CONTEXTPLUS_EMBED_PROVIDER=openai` 在部分嵌入路径中仍被硬编码为 Ollama，因此建议在依赖 OpenAI 后端时优先验证目标工具。
- **嵌套子仓库索引**：当父级 `.gitignore` 排除了子仓库 / submodule 所在目录时，文件遍历会跳过这些子树，导致 Discovery 工具返回不完整结果（参考 [issue #38](https://github.com/forloopcodes/contextplus/issues/38)）。在此类 monorepo 布局下，可考虑在 CLI 启动时直接传入子仓库根目录作为 `ROOT_DIR` 参数。
- **Feature Hub 与 Hub 解析**：Obsidian 风格的 `[[wikilink]]` 解析由 `src/core/hub.ts` 中的正则承担（`WIKILINK_RE`、`CROSS_LINK_RE`、`HEADER_FEATURE_RE`），用于在 Analysis 阶段之后串联 `get_feature_hub` 与符号图。资料来源：[src/core/hub.ts:20-30]()。

## See Also

- Memory & RAG 工具集（`upsert_memory_node` / `search_memory_graph` 等）
- Code Ops：`propose_commit` 与 `get_feature_hub` 写路径
- 版本控制：`list_restore_points` / `undo_change` 撤销体系
- [README.md](https://github.com/forloopcodes/contextplus/blob/main/README.md) · [INSTRUCTIONS.md](https://github.com/forloopcodes/contextplus/blob/main/INSTRUCTIONS.md) · [agent-instructions.md](https://github.com/forloopcodes/contextplus/blob/main/agent-instructions.md)

---

<a id='page-3'></a>

## Embedding Providers & Configuration

### 相关页面

相关主题：[Architecture & Overview](#page-1), [Discovery & Analysis Tools](#page-2)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/core/embeddings.ts](https://github.com/forloopcodes/contextplus/blob/main/src/core/embeddings.ts)
- [src/core/embedding-tracker.ts](https://github.com/forloopcodes/contextplus/blob/main/src/core/embedding-tracker.ts)
- [src/tools/semantic-navigate.ts](https://github.com/forloopcodes/contextplus/blob/main/src/tools/semantic-navigate.ts)
- [README.md](https://github.com/forloopcodes/contextplus/blob/main/README.md)
- [INSTRUCTIONS.md](https://github.com/forloopcodes/contextplus/blob/main/INSTRUCTIONS.md)
- [src/index.ts](https://github.com/forloopcodes/contextplus/blob/main/src/index.ts)
- [landing/src/app/api/instructions/route.ts](https://github.com/forloopcodes/contextplus/blob/main/landing/src/app/api/instructions/route.ts)
- [landing/src/components/InstructionsSection.tsx](https://github.com/forloopcodes/contextplus/blob/main/landing/src/components/InstructionsSection.tsx)
</details>

# Embedding Providers & Configuration

## 概述

Context+ 是一个面向大规模代码库的 MCP 服务器，其语义检索（RAG）、谱聚类（spectral clustering）以及记忆图谱（memory graph）功能都依赖 **向量嵌入**。系统通过抽象"嵌入提供方"（embedding provider）让用户能够切换底层推理后端，从而在本地 GPU、远程 Ollama 服务或 OpenAI 兼容 API 之间灵活选择。该抽象既影响 `semantic_code_search`、`semantic_identifier_search`、`semantic_navigate` 等发现类工具，也影响 `upsert_memory_node`、`add_interlinked_context` 等记忆图谱工具的写入路径 [资料来源：[INSTRUCTIONS.md:1-60]()]。

社区对提供方切换的关注度较高：Issue #16 要求展示不使用 Ollama 的示例，Issue #27 / #3 讨论远程 Ollama 主机配置，Issue #34 报告 `CONTEXTPLUS_EMBED_PROVIDER=openai` 环境变量不生效的问题（[Issue #34](https://github.com/forloopcodes/contextplus/issues/34)）。这些问题都直接关联到本页所述的提供方配置机制。

## 提供方架构

### 核心抽象

在 `src/tools/semantic-navigate.ts` 中可看到读取环境变量的标准模式：

```ts
const EMBED_PROVIDER = (process.env.CONTEXTPLUS_EMBED_PROVIDER ?? "ollama").toLowerCase();
const EMBED_MODEL    = process.env.OLLAMA_EMBED_MODEL ?? "nomic-embed-text";
const CHAT_MODEL     = process.env.OLLAMA_CHAT_MODEL ?? "llama3.2";
const OPENAI_CHAT_MODEL = process.env.CONTEXTPLUS_OPENAI_CHAT_MODEL
  ?? process.env.OPENAI_CHAT_MODEL ?? "gpt-4o-mini";
const OPENAI_API_KEY = process.env.CONTEXTPLUS_OPENAI_API_KEY
  ?? process.env.OPENAI_API_KEY ?? "";
const OPENAI_BASE_URL = process.env.CONTEXTPLUS_OPENAI_BASE_URL
  ?? process.env.OPENAI_BASE_URL ?? "https://api.openai.com/v1";
```
[资料来源：[src/tools/semantic-navigate.ts:1-60]()]

可见系统设计了两个分支：**Ollama**（默认）与 **OpenAI 兼容 API**。前端展示给用户的工具面板（`landing/src/components/IsometricDiagram.tsx`）以及 README 中的"Memory Search / Memory Upsert"模块 [资料来源：[README.md:1-60]()] 都依赖这套后端。

### 数据流

```mermaid
flowchart LR
  A[Agent / MCP Client] --> B[Tool: semantic_navigate]
  B --> C{Provider<br/>CONTEXTPLUS_EMBED_PROVIDER}
  C -- ollama --> D[Ollama Embeddings<br/>OLLAMA_HOST:11434]
  C -- openai --> E[OpenAI-compatible API<br/>CONTEXTPLUS_OPENAI_BASE_URL]
  D --> F[Vector Cache .mcp_data/]
  E --> F
  F --> G[Memory Graph<br/>memory-graph.ts]
```

## 环境变量与配置

下表汇总了公开文档中出现的嵌入相关环境变量。`INSTRUCTIONS.md` 与 `landing/src/app/api/instructions/route.ts` 维护同一份说明，因此变量名与默认值在两端一致 [资料来源：[INSTRUCTIONS.md:1-60]()] [资料来源：[landing/src/app/api/instructions/route.ts:1-60]()]。

| 变量名 | 默认值 | 作用 |
| --- | --- | --- |
| `CONTEXTPLUS_EMBED_PROVIDER` | `ollama` | 选择嵌入提供方：`ollama` 或 `openai` |
| `OLLAMA_EMBED_MODEL` | `nomic-embed-text` | Ollama 嵌入模型 |
| `OLLAMA_API_KEY` | （空） | Ollama Cloud 鉴权（由 SDK 自动检测） |
| `OLLAMA_CHAT_MODEL` | `llama3.2` | 谱聚类标签生成所用的聊天模型 |
| `CONTEXTPLUS_OPENAI_BASE_URL` | `https://api.openai.com/v1` | OpenAI 兼容 API 基础 URL |
| `CONTEXTPLUS_OPENAI_API_KEY` | （空） | OpenAI 兼容服务鉴权密钥 |
| `CONTEXTPLUS_OPENAI_CHAT_MODEL` | `gpt-4o-mini` | OpenAI 提供方下的聊天模型 |
| `CONTEXTPLUS_EMBED_BATCH_SIZE` | `8` | 单次 GPU 调用的嵌入批次（硬上限 5–10） |
| `CONTEXTPLUS_EMBED_TRACKER` | `true` | 启用对文件/符号变更的实时嵌入刷新 |
| `CONTEXTPLUS_EMBED_TRACKER_MAX_FILES` | `8` | 单次追踪刷新处理的最大文件数（硬上限 5–10） |
| `CONTEXTPLUS_EMBED_TRACKER_DEBOUNCE_MS` | `700` | 追踪刷新前的去抖延迟 |

> 运行时缓存统一存放于 `.mcp_data/`，跨提供方复用，避免重复嵌入。

## 提供方行为细节

### Ollama 提供方

`CONTEXTPLUS_EMBED_PROVIDER=ollama`（默认）时，系统使用 `nomic-embed-text` 生成向量。社区曾报告 `OLLAMA_HOST` 设置无效的问题（[Issue #3](https://github.com/forloopcodes/contextplus/issues/3)、[Issue #27](https://github.com/forloopcodes/contextplus/issues/27)），但根据 Issue #27 的评论，只要在 MCP 客户端的 `.mcp.json` 中正确传入 `OLLAMA_HOST` 即可被 SDK 拾取 [资料来源：[src/tools/semantic-navigate.ts:1-60]()]。远程部署时还需要确保目标机器的 11434 端口对客户端可达。

### OpenAI 兼容提供方

切换到 `CONTEXTPLUS_EMBED_PROVIDER=openai` 后，系统应改用 `CONTEXTPLUS_OPENAI_BASE_URL`、`CONTEXTPLUS_OPENAI_API_KEY` 以及对应的嵌入模型。然而 Issue #34 指出 Ollama 客户端似乎在某些代码路径中仍被硬编码，导致上述变量被忽略 [资料来源：[src/tools/semantic-navigate.ts:1-60]()]（[Issue #34](https://github.com/forloopcodes/contextplus/issues/34)）。在当前仓库的入口 `src/index.ts` 中确实只导出 `upsertMemoryNode` 等高层工具 [资料来源：[src/index.ts:1-60]()]，因此实际生效路径取决于每个工具内部对 `fetchEmbedding` 的调用方式。

### 追踪与去抖

`src/core/embedding-tracker.ts` 负责监听文件变更并按 `CONTEXTPLUS_EMBED_TRACKER_DEBOUNCE_MS` 去抖刷新嵌入。当追踪器开启时，它会限制单次刷新最多处理 `CONTEXTPLUS_EMBED_TRACKER_MAX_FILES` 个文件，配合 `CONTEXTPLUS_EMBED_BATCH_SIZE` 控制 GPU 负载 [资料来源：[INSTRUCTIONS.md:1-60]()]。这一机制对所有提供方一视同仁，避免编辑期间频繁打满显存。

## 常见故障模式

1. **OpenAI 提供方未生效**：若 `CONTEXTPLUS_EMBED_PROVIDER=openai` 无效，请确认所调用的具体工具内部是否读取该变量，并检查 `CONTEXTPLUS_OPENAI_*` 是否在 MCP 客户端的 env 段中被传递（[Issue #34](https://github.com/forloopcodes/contextplus/issues/34)）。
2. **远程 Ollama 连不上**：必须在 `.mcp.json` 的 `env` 中显式设置 `OLLAMA_HOST`，否则 SDK 默认连接 `localhost:11434`（[Issue #3](https://github.com/forloopcodes/contextplus/issues/3)）。
3. **追踪器压力过大**：在大型 monorepo 中可调低 `CONTEXTPLUS_EMBED_TRACKER_MAX_FILES` 与 `CONTEXTPLUS_EMBED_BATCH_SIZE`，并设置较长的 `CONTEXTPLUS_EMBED_TRACKER_DEBOUNCE_MS`。
4. **缓存陈旧**：向量缓存在 `.mcp_data/`；切换提供方后建议清理该目录，否则旧维度向量与新模型不兼容。

## 参见

- [Tools Reference（工具总览）](https://github.com/forloopcodes/contextplus#tools)
- [Environment Variables（环境变量全表）](https://github.com/forloopcodes/contextplus/blob/main/INSTRUCTIONS.md)
- [Issue #34: CONTEXTPLUS_EMBED_PROVIDER=openai 无效](https://github.com/forloopcodes/contextplus/issues/34)
- [Issue #3 / #27: 远程 Ollama 主机配置](https://github.com/forloopcodes/contextplus/issues/3)
- [Issue #16: 不使用 Ollama 的示例](https://github.com/forloopcodes/contextplus/issues/16)

---

<a id='page-4'></a>

## Memory Graph & Code Operations

### 相关页面

相关主题：[Architecture & Overview](#page-1), [Discovery & Analysis Tools](#page-2)

<details>
<summary>相关源码文件</summary>

以下源码文件用于生成本页说明：

- [src/core/hub.ts](https://github.com/forloopcodes/contextplus/blob/main/src/core/hub.ts)
- [src/core/memory-graph.ts](https://github.com/forloopcodes/contextplus/blob/main/src/core/memory-graph.ts)
- [src/tools/memory-tools.ts](https://github.com/forloopcodes/contextplus/blob/main/src/tools/memory-tools.ts)
- [src/tools/propose-commit.ts](https://github.com/forloopcodes/contextplus/blob/main/src/tools/propose-commit.ts)
- [src/git/shadow.ts](https://github.com/forloopcodes/contextplus/blob/main/src/git/shadow.ts)
- [src/index.ts](https://github.com/forloopcodes/contextplus/blob/main/src/index.ts)
- [agent-instructions.md](https://github.com/forloopcodes/contextplus/blob/main/agent-instructions.md)
- [README.md](https://github.com/forloopcodes/contextplus/blob/main/README.md)
- [INSTRUCTIONS.md](https://github.com/forloopcodes/contextplus/blob/main/INSTRUCTIONS.md)
</details>

# Memory Graph & Code Operations

## 概述

Context+ 的"记忆图谱与代码操作"子系统由两层互补的机制组成：长期记忆图谱（一种 RAG 系统）以及带影子恢复点的代码提交流程。[INSTRUCTIONS.md](https://github.com/forloopcodes/contextplus/blob/main/INSTRUCTIONS.md) 将记忆图谱定位为代理（agent）跨会话累积知识的"粘合层"，并要求在每个任务开始时调用 `search_memory_graph` 检索历史上下文，任务结束后用 `upsert_memory_node` 与 `create_relation` 持久化新学到的内容。代码操作侧则通过 `propose_commit` 这一唯一写入通道，配合影子恢复点实现"不修改 git 历史即可撤销"。资料来源：[INSTRUCTIONS.md:1-15]()

## 记忆图谱：长期 RAG 存储

记忆图谱由 `src/core/memory-graph.ts` 实现，是带 JSON 持久化的内存属性图，支持衰减评分与自动相似度建边。节点与边类型通过 [src/index.ts](https://github.com/forloopcodes/contextplus/blob/main/src/index.ts) 的 Zod schema 严格约束：节点为 `concept` / `file` / `symbol` / `note` 四类，边为 `relates_to` / `depends_on` / `implements` / `references` / `similar_to` / `contains` 六类。资料来源：[src/index.ts:1-40]()

```mermaid
graph LR
  C[concept 节点] -- relates_to --> S[symbol 节点]
  S -- depends_on --> F[file 节点]
  F -- contains --> S2[symbol 节点]
  C -- similar_to --> N[note 节点]
  S -. 余弦相似度 ≥ 0.72 .-> S3[symbol 节点]
```

六个 MCP 工具在 [src/tools/memory-tools.ts](https://github.com/forloopcodes/contextplus/blob/main/src/tools/memory-tools.ts) 中被封装：

| 工具 | 作用 |
| --- | --- |
| `upsert_memory_node` | 创建/更新节点，自动生成嵌入；已存在则更新内容并累加访问计数 |
| `create_relation` | 在两节点间创建带权重的有向边，权重 0-1 |
| `search_memory_graph` | 先以嵌入相似度找直接命中，再以 1-2 跳遍历邻居 |
| `prune_stale_links` | 按 `e^(-λt)` 衰减剔除低于阈值的边与孤立节点 |
| `add_interlinked_context` | 批量添加节点并自动建立相似度边（cosine ≥ 0.72） |
| `retrieve_with_traversal` | 从指定节点向外遍历，按边权重与深度惩罚打分返回邻居 |

[agent-instructions.md](https://github.com/forloopcodes/contextplus/blob/main/agent-instructions.md) 明确指定了工具的调用时机：任务开始 → `search_memory_graph`；任务结束 → `upsert_memory_node` + `create_relation`，从而避免重复探索并实现跨会话的知识累积。资料来源：[agent-instructions.md:1-20]()

## 代码操作：propose_commit 与影子恢复

代码操作层强制"先验证后写入"。`propose_commit` 在 `src/tools/propose-commit.ts` 中实现，被 [README.md](https://github.com/forloopcodes/contextplus/blob/main/README.md) 描述为"唯一可写代码的途径"——所有文件变更必须经过此通道。它在写入前会先创建影子恢复点，因此即使验证失败也可回滚。校验规则包括：文件头（header）必须存在、`FEATURE:` 标签强制声明、禁止行内注释、控制嵌套深度与单文件长度。资料来源：[INSTRUCTIONS.md:15-30]()

影子恢复点系统由 `src/git/shadow.ts` 提供，相关 MCP 工具：

- `list_restore_points`：列出所有由 `propose_commit` 生成的影子点，每个点捕获了 AI 变更前的文件状态。
- `undo_change`：将文件恢复到指定 AI 变更前的状态，但**不会触碰 git 历史**。

这意味着开发者在 IDE 中使用 Context+ 时，回滚完全在 MCP 层完成，无需执行 `git reset` 或 `git revert`，对 git 提交历史保持零侵入。资料来源：[README.md:1-30]()

## 特性中心：Obsidian 风格导航

特性中心是上述两套机制之上的"图谱视图"。`get_feature_hub` 工具（注册于 [src/index.ts](https://github.com/forloopcodes/contextplus/blob/main/src/index.ts)）提供三种工作模式：列出所有 hub、定位单个 hub 并返回其链接文件的骨架（`get_file_skeleton` 的批量版）、以及 `show_orphans` 模式列出未链接到任何 hub 的孤立文件。资料来源：[src/index.ts:1-50]()

底层解析由 [src/core/hub.ts](https://github.com/forloopcodes/contextplus/blob/main/src/core/hub.ts) 实现，核心正则包括：

- `WIKILINK_RE`：`\[\[target|description\]\]` 形式的内部链接。
- `CROSS_LINK_RE`：`@linked-to \[\[hub\]\]` 跨链接标签。
- `HEADER_FEATURE_RE`：匹配 `// FEATURE:`、`# FEATURE:`、`-- FEATURE:` 等多语言文件头特性声明。

`parseWikiLinks` 在解析时会先剥离 `CROSS_LINK_RE`，防止跨链接标签被误识别为普通 wikilink；`parseCrossLinks` 则把 `@linked-to` 关系显式记录到节点的 `crossLinks` 数组中，从而支撑特性中心的有向图谱视图。资料来源：[src/core/hub.ts:1-60]()

## 已知限制（来自社区反馈）

记忆图谱依赖 Ollama 生成嵌入，但社区报告了两个相关的可用性问题：

- **OpenAI 兼容嵌入后端未生效**（[issue #34](https://github.com/forloopcodes/contextplus/issues/34)）：`CONTEXTPLUS_EMBED_PROVIDER=openai`、`CONTEXTPLUS_OPENAI_BASE_URL` 等环境变量在当前实现中不生效，Ollama 客户端是硬编码的，无法切换至 OpenAI 兼容服务。
- **远程 Ollama 主机不生效**（[issue #3](https://github.com/forloopcodes/contextplus/issues/3)）：在 `.mcp.json` 的 `env` 块中设置 `OLLAMA_HOST` 无效——Ollama JS 客户端在构造时未传入 host 参数，因此始终连接 `localhost:11434`。

这两个限制直接影响记忆图谱的嵌入后端选型，部署在远程或自托管环境时需关注。

## 参见

- 项目主页与工具总览：[README.md](https://github.com/forloopcodes/contextplus/blob/main/README.md)
- 代理调用顺序与最佳实践：[agent-instructions.md](https://github.com/forloopcodes/contextplus/blob/main/agent-instructions.md)
- 架构分层与目录约定：[INSTRUCTIONS.md](https://github.com/forloopcodes/contextplus/blob/main/INSTRUCTIONS.md)
- 未来路线图（含 CLI 可视化、ACP 集成）：[TODO.md](https://github.com/forloopcodes/contextplus/blob/main/TODO.md)

---

<!-- evidence_pipeline_checked: true -->
<!-- evidence_injected: true -->

---

## Doramagic 踩坑日志

项目：forloopcodes/contextplus

摘要：发现 8 个潜在踩坑项，其中 2 个为 high/blocking；最高优先级：安装坑 - 来源证据：Sub-repos / nested workspaces can't be indexed when parent .gitignore excludes them。

## 1. 安装坑 · 来源证据：Sub-repos / nested workspaces can't be indexed when parent .gitignore excludes them

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安装相关的待验证问题：Sub-repos / nested workspaces can't be indexed when parent .gitignore excludes them
- 对用户的影响：可能增加新用户试用和生产接入成本。
- 证据：community_evidence:github | https://github.com/forloopcodes/contextplus/issues/38 | 来源讨论提到 node 相关条件，需在安装/试用前复核。

## 2. 安全/权限坑 · 来源证据：Handling MCP services as legacy while wiring and coding towards what makes this repo still relevant

- 严重度：high
- 证据强度：source_linked
- 发现：GitHub 社区证据显示该项目存在一个安全/权限相关的待验证问题：Handling MCP services as legacy while wiring and coding towards what makes this repo still relevant
- 对用户的影响：可能影响授权、密钥配置或安全边界。
- 证据：community_evidence:github | https://github.com/forloopcodes/contextplus/issues/37 | 来源讨论提到 node 相关条件，需在安装/试用前复核。

## 3. 能力坑 · 能力判断依赖假设

- 严重度：medium
- 证据强度：source_linked
- 发现：README/documentation is current enough for a first validation pass.
- 对用户的影响：假设不成立时，用户拿不到承诺的能力。
- 证据：capability.assumptions | https://github.com/forloopcodes/contextplus | README/documentation is current enough for a first validation pass.

## 4. 维护坑 · 维护活跃度未知

- 严重度：medium
- 证据强度：source_linked
- 发现：未记录 last_activity_observed。
- 对用户的影响：新项目、停更项目和活跃项目会被混在一起，推荐信任度下降。
- 证据：evidence.maintainer_signals | https://github.com/forloopcodes/contextplus | last_activity_observed missing

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 证据：downstream_validation.risk_items | https://github.com/forloopcodes/contextplus | no_demo; severity=medium

## 6. 安全/权限坑 · 存在评分风险

- 严重度：medium
- 证据强度：source_linked
- 发现：no_demo
- 对用户的影响：风险会影响是否适合普通用户安装。
- 证据：risks.scoring_risks | https://github.com/forloopcodes/contextplus | no_demo; severity=medium

## 7. 维护坑 · issue/PR 响应质量未知

- 严重度：low
- 证据强度：source_linked
- 发现：issue_or_pr_quality=unknown。
- 对用户的影响：用户无法判断遇到问题后是否有人维护。
- 证据：evidence.maintainer_signals | https://github.com/forloopcodes/contextplus | issue_or_pr_quality=unknown

## 8. 维护坑 · 发布节奏不明确

- 严重度：low
- 证据强度：source_linked
- 发现：release_recency=unknown。
- 对用户的影响：安装命令和文档可能落后于代码，用户踩坑概率升高。
- 证据：evidence.maintainer_signals | https://github.com/forloopcodes/contextplus | release_recency=unknown

<!-- canonical_name: forloopcodes/contextplus; human_manual_source: deepwiki_human_wiki -->
