bobjia/dsh-context-milvus

dsh-context-milvus

claude-context-milvus like plugin for Deepseek Harness (DSH)

待分类deepseekdeepseek-harnessdsh-context-milvus

dsh-context-milvus

English | 简体中文

A DSH plugin that provides semantic code search over a Milvus vector database, with a complete index ↔ search pipeline.

dsh-context-milvus = equips your DSH Agent with a dedicated codebase semantic search engine. Milvus handles high-speed vector retrieval, transforming "needle-in-a-haystack grep" into precise recall of relevant code snippets — reducing tokens, minimizing tool calls, and improving coding agent quality on large repositories.


Why dsh-context-milvus?

dsh-context-milvus is an open-source code semantic search plugin for DeepSeek Harness (DSH) coding agents, built on Milvus as the vector database and registered as a Cordis Plugin. Its core purpose: solve the high token consumption, excessive tool calls, context pollution, and poor large-codebase comprehension that plague native DSH Agent grep workflows.

Native DSH Agent workflow: encounter a problem → repeatedly search_code (grep) → read files → search again, flooding the prompt with irrelevant text, exploding tool calls, increasing token costs, and making it easy to miss dependencies in large repositories.

Native grep workflow pain pointdsh-context-milvus solution
Literal string matching only — semantically related but differently named code is missedVector semantic search — matches by code meaning, not just keywords
Multiple tool call rounds, reading many irrelevant files, token explosionReturns only truly relevant code snippets, split by AST at function/class boundaries for precision
Flooding context with grep output and irrelevant source code, causing context pollution and degraded model reasoningMilvus pre-built index, Agent gets concise effective context in one tool call without search noise in the prompt
Thousands of files in large repos, Agent traversal is extremely inefficientMilvus vector DB enables fast retrieval over millions of code blocks, supports incremental index updates without full repo rescanning
Can only search already-open or known-path filesAfter full-repo indexing, can semantically search any code location regardless of file path knowledge

Features

  • search_code — Semantic code search: natural language query, returns matching code snippets
  • index_code — Index codebase: AST parsing + chunking → Embedding → Milvus storage
  • index_status — View index status: file count, last index time, hash statistics
  • find_callers — Code relationship analysis (impact analysis): find all references to a symbol, with cross-file import resolution
  • trace_call_chain — Call chain tracing: BFS expansion from entry symbol (impact/dependency analysis), with cross-file resolution disambiguation
  • Hybrid search — BM25 keyword + vector semantic dual-path retrieval, RRF fusion, hybridMode toggle
  • Chunk overlap — AST chunks include surrounding context lines (chunkContextLines, default 2) for better recall
  • Query expansion — expands natural-language queries with code synonyms before embedding (queryExpansion, default on)
  • Two-stage reranking — retrieves a topK×3 pool then applies proportional term-overlap & name-match boosts, keeping the Milvus score primary (rerankEnabled, default on)
  • Ignore pattern system — Three-layer gitignore-style ignore rules (default + codebase + global)
  • Incremental indexing — Merkle SHA-256 hash tracking, processes only changed files
  • Workspace isolation — Independent Merkle state files per workspace, no interference
  • ADR decision memory system — Records design rationale behind code changes (Architecture Decision Records), supports semantic search, CRUD, constraint injection, and consistency checking
  • Code relationship analysis — Extracts symbol references from AST during indexing (references, language-specific syntax nodes), supports cross-file exact matching
  • Cross-file import resolution (V2) — Scans import/export statements using tree-sitter AST during indexing, builds a persistent bidirectional Import Map, enabling find_callers/trace_call_chain to perform precise cross-file symbol matching (same-name disambiguation, cross-module tracing)
  • Native telemetry (enabled by default) — search_code / index_code / index_status write one JSONL line per execution (enabled by default, metadata only, no source code captured), with an analysis script for descriptive stats + Bootstrap CI + correlation

Codex CLI support

The retrieval engine behind this plugin is published separately as dsh-context-milvus-core, so the same code also runs as a stdio MCP server for OpenAI Codex CLI (and any other MCP client) from the codex-context-milvus package. It exposes the five retrieval tools — search_code, index_code, index_status, find_callers, trace_call_chain — and shares the same Milvus collection and per-workspace index state as the DSH plugin. Start it with ADR_ENABLED=true and the 8 ADR decision-memory tools are registered as well; the four that write to disk stay gated behind CONTEXT_MILVUS_ADR_WRITE.

Shortest setup:

codex mcp add context-milvus -- npx -y codex-context-milvus mcp

See packages/codex/README.md for the init wizard, the environment variable reference, the error-code table, and current limitations (ADR tools are off by default, no runtime config hot-reload).

Offline / air-gapped install

An offline machine cannot resolve the ~230-package production closure, so the payload has to be built on a connected one. Seed a scratch install with the package as its only production dependency, then carry either the npm cache or the whole node_modules:

mkdir ctxmilvus-offline && cd ctxmilvus-offline
npm init -y
npm pkg set dependencies.codex-context-milvus=0.7.1
npm install --omit=dev --cache ./npm-cache

tar czf ctxmilvus-offline.tgz npm-cache package.json package-lock.json   # method A
tar czf ctxmilvus-tree.tgz node_modules                                  # method B

On the target, method A installs with npm ci --omit=dev --offline --cache ./npm-cache (--offline makes npm fail on a missing tarball instead of reaching for a network that is not there), while method B only needs the tree extracted and the binary invoked directly. Two traps: the generated config.toml starts the server with npx -y, which is a registry call on every Codex launch, so point command/args at the local bin/mcp.js; and the tree-sitter* prebuilds for linux/darwin/win32 × x64/arm64 come inside the tarballs, so one bundle is cross-platform — any other triple needs a compiler. The full recipe, including the prebuild-pruning trick and the exact TOML, is in packages/codex/README.md → Offline install.


Effectiveness Evaluation

A reproducible statistical evaluation suite (see scripts/eval/) quantifies how dsh-context-milvus improves retrieval quality and end-to-end agent efficiency. It covers offline retrieval quality, end-to-end agent evaluation, and native telemetry — using nonparametric statistics (Wilcoxon, Bootstrap CI, Cliff's Δ) with a unified file-level relevance standard. Run instructions and full reports live in scripts/eval/*/output/report.md.

Offline retrieval quality — 21 annotated queries × 19-file multi-language corpus

Three retrieval strategies compared: G (grep keyword), R (naive RAG: sliding-window + pure vector), P (plugin: AST chunking + BM25 hybrid + RRF + chunk overlap + query expansion + two-stage reranking).

MetricG (grep)R (naive RAG)P (plugin)
recall@100.95241.00000.9524
MRR0.67540.95240.8452
nDCG@100.74460.96100.8725
hit@10.47620.90480.7619
precision@10 (file-level)0.42030.10950.2730
precision@10 (chunk-level)——0.3619

Note on precision@10: Two metrics are reported. File-level precision@10 de-duplicates results by file path (each file counted once), measuring how many unique relevant files appear in the top-K. Chunk-level precision@10 counts each result independently, matching the classic IR definition: "of the 10 entries the Agent sees, how many are from relevant files?" The chunk-level metric is higher because the Agent benefits from multiple chunks of the same relevant file clustering in the top results.

Key findings:

  • Two-stage reranking lifts hit@1 by 6.7% (from 0.714 to 0.762 vs P0 baseline): proportional term-overlap (+30%) and name-matching (+15%) boosts improve first-hit accuracy. The gap to naive RAG (0.905) narrowed from 0.14 to 0.14.
  • Chunk-level precision@10 = 0.362: the Agent sees ~3.6 relevant entries per 10 results. This is bounded by the corpus (each query has only 1-2 relevant files, each producing few chunks) — the ceiling is determined by the number of chunks per relevant file, not search quality.
  • AST chunking + query expansion + chunk overlap drive precision: P vs R precision@10 +0.1635 (p=0.00013, Cliff's Δ=0.868 — large effect). Function/class-boundary chunks with surrounding context lines are far more focused than fixed sliding windows.
  • Semantic search beats keyword grep on ranking: P vs G MRR +0.1698 (p=0.108), nDCG@10 +0.1280 (p=0.100) — relevant files rank higher, with near-significant p-values.
  • grep precision is high but recall is brittle: G has the best precision@10 (0.4203) but the worst hit@1 (0.4762) — keyword-only search misses semantically-related code (e.g. "retry with exponential backoff" never matches withRetry).

End-to-end agent evaluation — 8 tasks × 3 runs × 3 strategies

GroupAverage pass rateToken consumption
G (grep)37.5%baseline
R (naive RAG)50.0%−928 vs G
P (plugin)62.5%−2109 vs G

Key findings:

  • Highest task pass rate: P 62.5% vs G 37.5% vs R 50.0%.
  • Significant token reduction: P vs G Δmean −2109 tokens/task (95% CI [−2325, −1864]), Wilcoxon p=0.014, significant after Holm correction, Cliff's Δ=−1.0. P also beats R by −928 tokens/task (p=0.014).

Native telemetry (enabled by default)

search_code / index_code / index_status record execution metrics (query, result count, top score, duration, files/chunks indexed, etc.) as one JSONL line per call — enabled by default (telemetryEnabled: true), no source code content captured. Run node scripts/eval/telemetry/run.mjs to generate a descriptive statistics + Bootstrap CI + correlation report from ~/.milvus-index/telemetry.jsonl (mode 0600).

To turn it off: set telemetryEnabled to false in Settings → Plugins → dsh-context-milvus (or set telemetryEnabled: false in cordis.patch.yml).


What role does Milvus play, and why Milvus?

  1. Stores AST-chunked code vectors: dsh-context-milvus uses tree-sitter AST to split code at function/class/method boundaries, generates embeddings, and stores them in Milvus — avoiding cutting a function in half.
  2. High-performance vector search: Encodes the query and performs vector similarity search with low latency, suitable for real-time Agent tool calls.

    Note: BM25 keyword fusion is already implemented — Milvus native BM25 full-text search + vector semantic dual-path retrieval, RRF fusion (hybridMode enabled by default).

  3. Supports self-hosted Milvus / Zilliz Cloud, two deployment options; teams can control data; supports incremental indexing after code changes without full rebuild.
  4. Specifically adapted for code RAG: Supports path-scoped filtering (search_code path parameter), allowing directory-limited searches — ideal for codebase scenarios.

DSH plugin architecture advantages

It is not a standalone MCP service, but a DSH plugin (Cordis Plugin) embedded directly into the DSH Agent process:

  • Zero network overhead: Plugin and Agent share the same process, tool calls don't go through HTTP, latency far below MCP
  • Naturally shares DSH resource configuration: Reuses DSH's config management, environment variable injection, and logging system — no additional configuration needed
  • DSH Web GUI integration: Visual configuration through Settings → Plugins interface, no YAML hand-editing
  • DSH ecosystem compatibility: Shares the tool registry with other DSH plugins (bash, agent-loop, web-search, etc.), Agents can freely combine them

Core Workflow

Registered DSH tools

ToolFunctionKey Parameters
search_codeSemantic code searchquery (natural language), topK (result count), path (search scope)
index_codeIndex codebasemode (full/incremental), path (target path)
index_statusView index statuspath (view per-workspace status)
search_adrSemantic ADR searchquery (natural language), status, topK
search_adr_by_fileFind ADRs by file pathfile_path (code file path), status
create_adrCreate new ADRtitle (required), requirement, change_type
update_adrUpdate existing ADRadr_id (required), content, status
list_adrsList ADR recordsstatus, change_type, limit
load_constraintsLoad active ADR constraintsadr_ids, format
check_adr_consistencyCheck ADR-code consistencyfile_path, fix
find_callersFind all references to a symbol for impact analysis, supports cross-file import resolutionsymbol (required), direction, maxResults, sourceFile, resolve
trace_call_chainBFS call chain tracing from entry symbol (impact/dependency analysis), supports import resolution disambiguationentry (required), direction, maxDepth, maxResults, resolve

Workflow

  1. Run index_code: Parse the project, split code blocks via tree-sitter AST → call Embedding API to generate vectors → store in Milvus collection.
  2. Agent encounters a coding problem, calls search_code for hybrid search (vector semantic + BM25 keyword, RRF fusion).
  3. Milvus returns the most relevant code snippets, injected into the Agent's context.
  4. Agent debugs, refactors, or develops based on precise context — no more frantic grep file reading.
  5. After code changes, run index_code mode=incremental to incrementally re-index only changed files.
  6. Check index status anytime with index_status (indexed files, total code blocks, last index time).
  7. Before modifying code, use find_callers for impact analysis: see which places reference the symbol to avoid missing cascading effects. For same-name symbols across files, use the sourceFile parameter to disambiguate by definition file.
  8. Understand call chains with trace_call_chain: BFS expansion from entry function, direction=backward traces callers, direction=forward traces downstream dependencies. resolve: false falls back to V1 name-matching mode.
  9. Cross-file reference analysis: find_callers and trace_call_chain enable import resolution by default (resolve: true). The Import Map built during indexing automatically maps import { X } from './foo' to foo.ts's exports, eliminating same-name ambiguity and supporting cross-module call chain tracing. Falls back to V1 name matching when the import map is not built.

ADR decision memory workflow

The ADR decision memory system records the "why" behind code changes (design decisions, trade-offs, constraints), enabling the Agent to not only read code but understand its evolution:

Note: ADR functionality is disabled by default. To enable it, set adrEnabled: true in the DSH config panel (Settings → Plugins → dsh-context-milvus).

  1. Before modifying code with ADR coverage, use search_adr_by_file to check if the file has decision records, avoiding violation of existing decisions.
  2. When making design decisions, use create_adr to record the context, alternatives, and rationale, and use update_adr to maintain code_anchors linking to code locations.
  3. When needing to understand constraints, use load_constraints to load active ADR constraints into the context.
  4. After creating or updating ADRs, use check_adr_consistency to verify ADR-code consistency, with fix for auto-repair.
  5. Use search_adr for semantic search of historical decisions, understanding "why this was done this way."

Spec Document Fusion

When the brainstorming skill produces specification documents, they can be linked to the codebase through the following steps:

  1. Write spec documents: brainstorming output saved to docs/superpowers/specs/YYYY-MM-DD-<topic>-design.md
  2. Generate anchors: Call index_specs to automatically detect code references in the document and generate frontmatter + code_anchors
  3. Index: index_code automatically scans docs/superpowers/specs/ and docs/superpowers/plans/ directories
  4. Discover: search_adr returns both ADR and spec document results (with docType annotation)

Configuration

FieldDefaultDescription
specRootdocs/superpowers/specsSpec document directory (relative to indexRoot)
planRootdocs/superpowers/plansImplementation plan directory (relative to indexRoot)

Spec document fusion follows the adrEnabled toggle — no additional configuration needed.


Prerequisites

1. Install Ollama (Embedding service)

# macOS
brew install ollama

# Linux
curl -fsSL https://ollama.com/install.sh | sh

# Start Ollama service
ollama serve

Or use any OpenAI-compatible Embedding API service (OpenAI, Alibaba Cloud Bailian, etc.) by configuring embeddingEndpoint and embeddingApiKey.

2. Install Embedding model

# Pull nomic-embed-text model (default)
ollama pull nomic-embed-text

# Or other supported Embedding models:
ollama pull bge-m3
ollama pull mxbai-embed-large

3. Install Milvus (vector database)

Docker (recommended):

# Pull and start Milvus standalone
docker run -d --name milvus \
  -p 19530:19530 \
  -p 9091:9091 \
  milvusdb/milvus:latest

# Verify connection
docker ps | grep milvus

Milvus cluster mode (Docker Compose):

# Download docker-compose file
wget https://github.com/milvus-io/milvus/releases/latest/download/milvus-standalone-docker-compose.yml -O docker-compose.yml

# Start
docker compose up -d

Or use Zilliz Cloud managed service — no self-hosting required.

Verify installation

# Verify Ollama
curl http://localhost:11434/api/tags

# Verify Milvus
docker run -it --rm \
  -e MILVUS_URL=localhost:19530 \
  milvusdb/milvus-sdk-node:latest \
  node -e "const {MilvusClient} = require('@zilliz/milvus2-sdk-node'); \
  new MilvusClient({address:'localhost:19530'}).listCollections().then(r=>console.log(r))"

Install to DSH

Requires DSH ≥ 0.2.0-rc.1. The 0.2.0 release train keeps the settings plugin contract established in 0.1.7 — the host's installSection() and the client's settingsScope service are gone, and the config schema now relies on schemastery's .volatile(), which older harnesses do not ship. There is no compatibility mode: on an older harness the plugin cannot load.

The plugin is published to the npm registry. Install directly via DSH CLI:

dsh plugin --profile web add dsh-context-milvus

The npm package includes pre-built dist/ output — no build step required during installation, avoiding the ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED error.

Method 2: From local tarball (offline / local development)

Build and package as a tarball, then install directly:

# 1. Build
npm run build

# 2. Package as tarball
pnpm pack

# 3. Install to profile
dsh plugin --profile web add ./dsh-context-milvus-0.1.3.tgz

pnpm pack produces a tarball containing the compiled dist/ output — no build step required during installation, so pnpm won't raise ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED.

Method 3: From Git (requires additional configuration)

dsh plugin --profile web add git+https://github.com/bobjia/dsh-context-milvus.git

dist/ output is not committed to git. The plugin uses the prepare script to automatically run tsc during installation.

pnpm 10 limitation: pnpm 10 blocks execution of build scripts by default. If you see:

ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED
The git-hosted package "dsh-context-milvus@0.1.2" needs to execute build scripts
but is not in the "onlyBuiltDependencies" allowlist.

Add to your profile's pnpm-workspace.yaml:

# ~/.dsh/profiles/<profile-name>/pnpm-workspace.yaml
onlyBuiltDependencies:
- dsh-context-milvus

Then re-run the install command. Or run pnpm approve-builds and select dsh-context-milvus.

To avoid this authorization, use Method 1 (npm) or Method 2 (tarball).

Configure the plugin

After installation, edit cordis.patch.yml under your profile:

# ~/.dsh/profiles/<profile-name>/cordis.patch.yml
- id: dsh-context-milvus
  config:
    milvusAddress: localhost:19530
    milvusCollection: code_embeddings
    milvusDim: 768
    embeddingEndpoint: http://localhost:11434/api/embed
    embeddingModel: nomic-embed-text
    indexRoot: /path/to/your/code
    indexExtensions: .ts,.tsx,.js,.py,.java,.go,.rs,.c,.inc,.cpp,.cs,.scala,.php,.kt,.kts
    hybridMode: true
    bm25RrfK: 60

Restart DSH after configuration.

Build from source (local development)

If using a local development version:

1. Install dependencies

cd /mnt/home/bobjia/workspace/dsh-context-milvus
npm install --legacy-peer-deps
# Link DSH runtime packages (npm install may break these links)
ln -sf /mnt/home/bobjia/.npm-global/lib/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai/cordis \
  node_modules/@deepseek-ai/cordis
ln -sf /mnt/home/bobjia/.npm-global/lib/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai/dsh-tools \
  node_modules/@deepseek-ai/dsh-tools
ln -sf /mnt/home/bobjia/.npm-global/lib/node_modules/@deepseek-ai/dsh/node_modules/@deepseek-ai/schemastery \
  node_modules/@deepseek-ai/schemastery

3. Register with DSH

# Install as local dependency
dsh plugin --profile web add file:/mnt/home/bobjia/workspace/dsh-context-milvus

dsh plugin add automatically adds the plugin to dsh.profile.bundles — no need to manually edit package.json.

4. Configure plugin

Edit ~/.dsh/profiles/<profile-name>/cordis.patch.yml (same as above) and restart DSH.


Configuration System

Priority (highest → lowest)

  1. Cordis Config (set via cordis.patch.yml or DSH Web GUI)
  2. Environment variables (fallback)
  3. Defaults (e.g., localhost:19530)

Configuration fields

FieldEnvironment VariableTypeDefaultDescription
milvusAddressMILVUS_ADDRESSstringlocalhost:19530Milvus server address
milvusTokenMILVUS_TOKENstring (secret)emptyMilvus auth token
milvusCollectionMILVUS_COLLECTIONstringcode_embeddingsCollection name
milvusDimMILVUS_EMBEDDING_DIMnumber768Vector dimension
`embeddingE