Doramagic 项目包 · 项目说明书
contextplus 项目
Context+ 是一款面向开发者的 MCP 服务器,专为追求 99% 准确率而打造。它融合 RAG、Tree-sitter AST、谱聚类与 Obsidian 式链接,将庞大代码库转化为可搜索的层级化功能图谱,为大规模工程提供语义智能。
Architecture & Overview
Context+ 是一个面向 AI 代理的 MCP (Model Context Protocol) 服务器,定位于"大规模工程的语义智能"——通过融合 RAG (Retrieval-Augmented Generation)、Tree-sitter AST、光谱聚类 (Spectral Clustering) 与 Obsidian 风格的双向链接,将庞大的代码库转化为可搜...
继续阅读本节完整说明和来源证据。
项目目的与范围
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-58memory-graph.ts维护带 JSON 持久化、衰减评分 (e^(-λt)) 与自动相似边的属性图谱。资料来源:INSTRUCTIONS.md:42-44embedding-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
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 — 完整的工具清单与环境变量参考
- agent-instructions.md — 面向 AI 代理的工具调用最佳实践
- README.md — 项目定位与工具概述
资料来源:README.md:11-71,INSTRUCTIONS.md:50-70,agent-instructions.md:14-37
Discovery & Analysis Tools
Discovery & Analysis Tools(发现与分析工具集)是 Context+ MCP 服务器向 Agent 暴露的两大类核心工具的统称,共包含 7 个 通过 Model Context Protocol(std
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
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
| search_memory_graph | Semantic search with graph traversal — finds direct matches then walks
| 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). |
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
| run_static_analysis | Run native linters and compilers to find unused variables, dead code, and type errors. Supports TypeScript, Python,
| Tool | Description |
|---|---|
get_blast_radius | Trace every file and line where a symbol is imported or used. Prevents orphaned references. |
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 server (npx pmll-memory-mcp), which adds short-term KV memory and a solution engine — see 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
| `CONTEXTPLUS_EMBED
| 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) |
every task. Map files + symbols with line ranges. |
| `retrieve_with_tr
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). |
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
| \CONTEXTPLUS_EMBED_TRACKER_DEBOUNCE_MS\ | \700\ | Debounce before applying tracker refresh
| 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) |
File Path: landing/src/app/page.tsx
“Context engineering is the delicate art and science of filling the context window with just the right information for the next next step.” </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", }}
</a> </section>
- Andrej Karpathy
<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. |
| \retrieve_with_traversal\ | Start from a node, walk outward, return
\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). |
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。
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 与 issue #27)。当前semantic-navigate已通过CONTEXTPLUS_EMBED_PROVIDER=openai路径提供一种绕行方案,但其他工具是否生效需逐个核对。 - OpenAI 兼容后端未全部生效:issue #34 指出
CONTEXTPLUS_EMBED_PROVIDER=openai在部分嵌入路径中仍被硬编码为 Ollama,因此建议在依赖 OpenAI 后端时优先验证目标工具。 - 嵌套子仓库索引:当父级
.gitignore排除了子仓库 / submodule 所在目录时,文件遍历会跳过这些子树,导致 Discovery 工具返回不完整结果(参考 issue #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 · INSTRUCTIONS.md · agent-instructions.md
资料来源:INSTRUCTIONS.md:1-40、src/tools/semantic-navigate.ts:40-50()。
Embedding Providers & Configuration
Context+ 是一个面向大规模代码库的 MCP 服务器,其语义检索(RAG)、谱聚类(spectral clustering)以及记忆图谱(memory graph)功能都依赖 向量嵌入。系统通过抽象"嵌入提供方"(embedding provider)让用户能够切换底层推理后端,从而在本地 GPU、远程 Ollama 服务或 OpenAI 兼容 API 之间灵活选择。...
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
继续阅读本节完整说明和来源证据。
概述
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)。这些问题都直接关联到本页所述的提供方配置机制。
提供方架构
核心抽象
在 src/tools/semantic-navigate.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] 都依赖这套后端。
数据流
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、Issue #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)。在当前仓库的入口 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]。这一机制对所有提供方一视同仁,避免编辑期间频繁打满显存。
常见故障模式
- OpenAI 提供方未生效:若
CONTEXTPLUS_EMBED_PROVIDER=openai无效,请确认所调用的具体工具内部是否读取该变量,并检查CONTEXTPLUS_OPENAI_*是否在 MCP 客户端的 env 段中被传递(Issue #34)。 - 远程 Ollama 连不上:必须在
.mcp.json的env中显式设置OLLAMA_HOST,否则 SDK 默认连接localhost:11434(Issue #3)。 - 追踪器压力过大:在大型 monorepo 中可调低
CONTEXTPLUS_EMBED_TRACKER_MAX_FILES与CONTEXTPLUS_EMBED_BATCH_SIZE,并设置较长的CONTEXTPLUS_EMBED_TRACKER_DEBOUNCE_MS。 - 缓存陈旧:向量缓存在
.mcp_data/;切换提供方后建议清理该目录,否则旧维度向量与新模型不兼容。
参见
来源:https://github.com/forloopcodes/contextplus / 项目说明书
Memory Graph & Code Operations
Context+ 的"记忆图谱与代码操作"子系统由两层互补的机制组成:长期记忆图谱(一种 RAG 系统)以及带影子恢复点的代码提交流程。INSTRUCTIONS.md 将记忆图谱定位为代理(agent)跨会话累积知识的"粘合层",并要求在每个任务开始时调用 searchmemorygraph 检索历史上下文,任务结束后用 upsertmemorynode 与 creater...
继续阅读本节完整说明和来源证据。
概述
Context+ 的"记忆图谱与代码操作"子系统由两层互补的机制组成:长期记忆图谱(一种 RAG 系统)以及带影子恢复点的代码提交流程。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 的 Zod schema 严格约束:节点为 concept / file / symbol / note 四类,边为 relates_to / depends_on / implements / references / similar_to / contains 六类。资料来源:src/index.ts:1-40
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 中被封装:
| 工具 | 作用 |
|---|---|
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 明确指定了工具的调用时机:任务开始 → search_memory_graph;任务结束 → upsert_memory_node + create_relation,从而避免重复探索并实现跨会话的知识累积。资料来源:agent-instructions.md:1-20
代码操作:propose_commit 与影子恢复
代码操作层强制"先验证后写入"。propose_commit 在 src/tools/propose-commit.ts 中实现,被 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)提供三种工作模式:列出所有 hub、定位单个 hub 并返回其链接文件的骨架(get_file_skeleton 的批量版)、以及 show_orphans 模式列出未链接到任何 hub 的孤立文件。资料来源:src/index.ts:1-50
底层解析由 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):
CONTEXTPLUS_EMBED_PROVIDER=openai、CONTEXTPLUS_OPENAI_BASE_URL等环境变量在当前实现中不生效,Ollama 客户端是硬编码的,无法切换至 OpenAI 兼容服务。 - 远程 Ollama 主机不生效(issue #3):在
.mcp.json的env块中设置OLLAMA_HOST无效——Ollama JS 客户端在构造时未传入 host 参数,因此始终连接localhost:11434。
这两个限制直接影响记忆图谱的嵌入后端选型,部署在远程或自托管环境时需关注。
参见
- 项目主页与工具总览:README.md
- 代理调用顺序与最佳实践:agent-instructions.md
- 架构分层与目录约定:INSTRUCTIONS.md
- 未来路线图(含 CLI 可视化、ACP 集成):TODO.md
来源:https://github.com/forloopcodes/contextplus / 项目说明书
失败模式与踩坑日记
保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。
可能增加新用户试用和生产接入成本。
可能影响授权、密钥配置或安全边界。
假设不成立时,用户拿不到承诺的能力。
新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
Pitfall Log / 踩坑日志
项目: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
来源:Doramagic 发现、验证与编译记录