Skip to content

Tools ​

Search the index with BM25. Filters run before limit. The top-level route is the string rust-tfidf.

Arguments ​

FieldRequiredDefaultRule
queryyesNon-empty string
rootnolaunch --root, then LOCUS_ROOT, then CODERAG_ROOTNo working-directory default
limitno10Integer from 1 to 100
include_contentnotrueBoolean
file_extensionsnoevery indexed fileNon-empty array of strings
path_filternononeNon-empty string
exclude_pathsnononeNon-empty array of strings

Parser failures are MCP invalid params and happen before the index refresh.

InputMessage
query absentMissing required field: query
query blank or whitespacequery must not be empty
query not a stringquery must be a string
limit missing type, 0, 101, or nulllimit must be an integer from 1 to 100
include_content not a booleaninclude_content must be a boolean
file_extensions or exclude_paths missing, empty, or not an array of stringsINVALID_FILTER naming the field
path_filter blank or not a stringINVALID_FILTER
Extension token empty, or containing ., /, \, or whitespacefile_extensions contains an invalid extension

ts and .ts both mean the final extension ts. They do not match .tsx. Matching is case-sensitive: TS does not match .ts. Backslashes in paths become slashes. path_filter and exclude_paths are case-sensitive substrings of the repo-relative path.

A query that parses but produces no token (for example ... or a) returns status ok and an empty results array.

Result ​

Wire fields are camelCase.

json
{
  "envelope_version": "1",
  "status": "ok",
  "tool": "codebase_search",
  "product": "locus",
  "product_version": "0.6.4",
  "engine": "coderag-core",
  "route": "rust-tfidf",
  "warnings": [],
  "gaps": [],
  "confidence": { "kind": "deterministic", "notes": [] },
  "query": "authenticate request",
  "results": [
    {
      "path": "src/auth/session.ts",
      "startLine": 40,
      "endLine": 88,
      "symbolName": "authenticate",
      "chunkType": "function",
      "score": 3.4,
      "matchedTerms": ["authenticate", "request"],
      "scoreComponents": [
        {
          "term": "authenticate",
          "termFrequency": 2,
          "documentFrequency": 4,
          "idf": 1.6,
          "bm25": 2.1
        }
      ],
      "snippet": "export function authenticate(request) { ... }"
    }
  ],
  "search": { "elapsedMs": 4, "route": "rust-tfidf" },
  "index": {
    "filesScanned": 120,
    "chunksIndexed": 640,
    "elapsedMs": 12,
    "refreshMode": "cache_hit",
    "filesChanged": 0,
    "filesRemoved": 0
  }
}

The numbers above are the shape, not a recorded trace. product_version is whatever server you are running.

include_content: false sets snippet to null and leaves the other hit fields. warnings and gaps are always empty. payload, when present, copies results.

index.refreshMode is cache_hit, incremental, or full.

Ranking ​

Tokens are ASCII letters, digits, and _, longer than one character, lowercased. BM25 uses k1 = 1.2, b = 0.75, and Lucene-style idf:

text
ln( (N - df + 0.5) / (df + 0.5) + 1 )

N and df are the full index. Filters do not recompute them. Hits sort by score descending. There is no promised tie-break.

Find chunks that share tokens with the chunk containing a known line. The top-level route is the string rust-related.

Arguments ​

FieldRequiredDefaultRule
pathyesRepo-relative, forward slashes, exactly the indexed path
lineyesPositive integer inside a chunk's line range
rootnosame order as searchRequired by the time the call runs
limitno100 becomes 1. No 1–100 cap

Missing path, line, or root are invalid params before refresh. line less than 1 becomes the engine error line must be a positive integer.

An empty result is not an ok payload. The MCP error message is No related chunks found for that location. That includes a path that does not match, a line that falls in the preamble before the first symbol, and a file that is not indexed.

Score ​

Take the seed chunk's unique tokens. Count how many tokens in the candidate occur in that set, including repeated candidate tokens. Divide by the size of the union of the two unique-token sets. A candidate that repeats a shared token can score above 1. This is not Jaccard.

Sort is score descending, then path ascending. snippet is the first 360 characters of the chunk text. scoreComponents is empty. The nested search.route stays rust-tfidf because both tools share that success envelope. Branch on the top-level route.

Index rules that affect both tools ​

Indexed final extensions: ts, tsx, js, jsx, mjs, cjs, rs, md, py, go.

Skipped path segments: node_modules, dist, target, .git. Files larger than 1,048,576 bytes are skipped. Symbol patterns are documented under symbol chunks.

Released under the MIT License.