Markdown source

mdvdb search

Search across indexed markdown files using semantic (vector), lexical (BM25), hybrid (RRF fusion), or edge-based search. Returns ranked results with chunk content, file metadata, and optional graph context.

Usage

mdvdb search [OPTIONS] <QUERY>

Arguments

ArgumentRequiredDescription
<QUERY>YesNatural-language search query string

Options

FlagShortValueDefaultDescription
--limit-l<N>10Maximum number of results to return
--min-score<F>0.0Minimum similarity score threshold (0.0 to 1.0)
--filter-f<KEY=VALUE>Metadata filter expression (repeatable)
--boost-linksfalseEnable link boosting (favor results linked to/from top matches)
--no-boost-linksDisable link boosting (even if enabled in config)
--mode<MODE>hybridSearch mode: hybrid, semantic, lexical, or edge
--semanticShorthand for --mode=semantic
--lexicalShorthand for --mode=lexical
--edge-searchShorthand for --mode=edge (search edge embeddings)
--path<PREFIX>Restrict search to files under this path prefix
--shard<ID>Restrict search to a configured named Shard (conflicts with --path)
--decayfalseEnable time decay (favor recently modified files)
--no-decayDisable time decay (even if enabled in config)
--decay-half-life<DAYS>90.0Half-life in days for time decay (how many days until score is halved)
--decay-exclude<PATTERNS>Comma-separated path prefixes excluded from time decay
--decay-include<PATTERNS>Comma-separated path prefixes where time decay applies (whitelist)
--hops<N>1Number of link hops for graph-aware boosting (1-3)
--expand<N>0Graph expansion depth for context (0-3, 0 disables)
--populatefalseResolve result-file frontmatter relations one level deep

Option Details

--limit, -l

Sets the maximum number of results returned. The default is controlled by MDVDB_SEARCH_DEFAULT_LIMIT (default: 10). See Configuration.

--min-score

Filters out results below this similarity threshold. Score interpretation varies by mode:

  • Semantic: cosine similarity (absolute, 0.0-1.0)
  • Lexical: BM25 score normalized via saturation score / (score + k)
  • Hybrid: RRF score normalized by theoretical maximum

The default is controlled by MDVDB_SEARCH_MIN_SCORE (default: 0.0). See Configuration.

--filter, -f

Metadata filter expressions in KEY=VALUE format. The CLI exposes exact equality on top-level frontmatter fields; it does not parse range, existence, OR, or arbitrary SQL predicates. Repeat the flag to apply multiple filters with AND logic.

Auto-type detection: The value is automatically parsed as:

InputDetected TypeExample
A valid JSON numberNumber--filter year=2024
Exact lowercase true or falseBoolean--filter draft=false
Anything elseString--filter status=published

If the frontmatter field is an array, the filter checks whether the array contains the value. For example, --filter tags=rust matches a document with tags: [rust, cli, tools].

Filters use effective frontmatter, so successfully materialized Formula, Lookup, and Rollup fields are queryable. Link-shaped relation values are syntax-normalized: for example, client=clients/acme, client=clients/acme.md, and client=[[clients/acme]] can all match client: "[[clients/acme|Acme]]". This normalization is syntactic and does not resolve the target file.

# Single filter
mdvdb search "query" --filter status=published

# Multiple filters (AND logic)
mdvdb search "query" -f status=published -f draft=false -f year=2024

--path

Restricts results to files whose path starts with the given prefix. Useful for scoping searches to a subdirectory.

# Only search within the docs/ directory
mdvdb search "authentication" --path docs/

# Only search within a specific project area
mdvdb search "error handling" --path src/api/

--hops

Sets the link-hop depth for graph-aware boosting. When enabled, results that are linked to or from other top results receive a score boost.

  • Range: 1 to 3
  • Requires: --boost-links must also be set
  • Default: 1 (controlled by MDVDB_SEARCH_BOOST_HOPS)
# Boost results linked within 2 hops of top matches
mdvdb search "API design" --boost-links --hops 2

--expand

Controls graph context expansion depth. When set to a value greater than 0, the response includes additional chunks from files linked to the search results, providing supplementary context.

  • Range: 0 to 3 (0 disables expansion)
  • Default: 0 (controlled by MDVDB_SEARCH_EXPAND_GRAPH)
# Include chunks from directly linked files
mdvdb search "authentication" --expand 1

# Include chunks up to 3 hops away
mdvdb search "authentication" --expand 3

--populate

Resolves whole-value frontmatter relations on ranked result files. Each relation includes its raw value, resolved path, existence, title, and target frontmatter. Population is depth one: target frontmatter is returned as stored and is not recursively populated.

mdvdb search "paid invoices" --filter status=paid --populate --json

Only ranked results are populated. Supplementary graph_context entries are unchanged.

Conflicting Options

Certain options are mutually exclusive and cannot be used together:

Option AConflicts WithReason
--semantic--lexical, --mode, --edge-searchOnly one search mode can be active
--lexical--semantic, --mode, --edge-searchOnly one search mode can be active
--edge-search--semantic, --lexical, --modeOnly one search mode can be active
--mode--semantic, --lexical, --edge-search--mode sets the mode explicitly
--boost-links--no-boost-linksCannot enable and disable simultaneously
--decay--no-decayCannot enable and disable simultaneously
--path--shardA query has one folder scope

Dependency Requirements

OptionRequiresReason
--hops--boost-linksHop depth is only meaningful when link boosting is active

Search Modes

The search mode determines which retrieval signals are used. The default mode is hybrid (controlled by MDVDB_SEARCH_MODE).

ModeFlagDescription
hybrid--mode=hybridCombines semantic (HNSW) and lexical (BM25) search using Reciprocal Rank Fusion (RRF). Best for general-purpose queries.
semantic--semantic or --mode=semanticEmbedding-based vector search only (cosine similarity via HNSW). Best for meaning-based queries. Requires an embedding API call.
lexical--lexical or --mode=lexicalBM25 keyword search only (via Tantivy). Best for exact term matching. No embedding API call needed.
edge--edge-search or --mode=edgeSearches semantic edge embeddings between linked documents. Returns edge results instead of chunk results.

For detailed explanations and diagrams, see Search Modes.

Time Decay

When enabled, time decay applies an exponential penalty to older files, favoring recently modified content. The formula is:

adjusted_score = score * 2^(-age_in_days / half_life_days)
  • --decay / --no-decay: Override the config default (MDVDB_SEARCH_DECAY, default: false)
  • --decay-half-life: Override the half-life (MDVDB_SEARCH_DECAY_HALF_LIFE, default: 90.0 days)
  • --decay-exclude: Comma-separated path prefixes excluded from decay (e.g., docs/reference,docs/api)
  • --decay-include: Comma-separated path prefixes where decay applies (whitelist mode)

Exclude takes precedence over include. For detailed explanations, see Time Decay.

Global Options

These options apply to all commands. See Commands Index for details.

FlagShortDescription
--verbose-vIncrease log verbosity (-v info, -vv debug, -vvv trace)
--rootProject root directory (defaults to current directory)
--no-colorDisable colored output
--jsonOutput results as JSON

Examples

# Simple semantic search (uses default hybrid mode)
mdvdb search "how to authenticate users"

# Limit to 5 results with minimum score
mdvdb search "error handling" --limit 5 --min-score 0.3

Search with filters

# Filter by frontmatter field
mdvdb search "deployment" --filter status=published

# Multiple filters (AND logic)
mdvdb search "API endpoints" -f category=backend -f draft=false

# Filter with numeric value
mdvdb search "release notes" --filter year=2024

# Filter a computed field and populate relation context
mdvdb search "large paid invoices" -f status=paid -f total=240 --populate --json

Search modes

# Semantic only (meaning-based, no keyword matching)
mdvdb search "things that are similar to authentication" --semantic

# Lexical only (exact keyword matching, no API call)
mdvdb search "AuthenticationError" --lexical

# Explicit mode flag
mdvdb search "user management" --mode=hybrid

# Edge search (find relationships between documents)
mdvdb search "references to auth module" --edge-search
# Only search within docs/
mdvdb search "configuration" --path docs/

# Search within a specific directory
mdvdb search "error types" --path src/
# Boost results that are linked to/from top matches
mdvdb search "architecture" --boost-links

# Multi-hop link boosting (2 hops)
mdvdb search "architecture" --boost-links --hops 2

# Include context from linked files
mdvdb search "authentication" --expand 1

# Combine boosting and expansion
mdvdb search "API design" --boost-links --hops 2 --expand 2

Time decay

# Favor recently modified files
mdvdb search "release notes" --decay

# Custom half-life (30 days)
mdvdb search "release notes" --decay --decay-half-life 30

# Exclude reference docs from decay
mdvdb search "best practices" --decay --decay-exclude docs/reference,docs/api

# Apply decay only to blog posts
mdvdb search "updates" --decay --decay-include blog/

JSON output

# JSON output for programmatic consumption
mdvdb search "authentication" --json

# JSON with timing information (requires -v)
mdvdb search "authentication" --json -v

# Pipe to jq for processing
mdvdb search "error handling" --json | jq '.results[].file.path'

JSON Output

When --json is used, the output is a SearchOutput object. This example includes fields emitted by --populate:

{
  "results": [
    {
      "score": 0.87,
      "chunk": {
        "chunk_id": "docs/auth.md#2",
        "heading_hierarchy": ["Authentication", "OAuth2 Flow"],
        "content": "The OAuth2 flow begins with...",
        "start_line": 15,
        "end_line": 42
      },
      "file": {
        "path": "docs/auth.md",
        "frontmatter": {
          "title": "Authentication Guide",
          "tags": ["auth", "security"],
          "owner": "[[people/alex]]",
          "priority": 3
        },
        "computed_fields": {"priority": 3},
        "computed_field_errors": {},
        "file_size": 4096,
        "path_components": ["docs", "auth.md"],
        "modified_at": 1710000000,
        "relations": {
          "owner": [
            {
              "raw": "[[people/alex]]",
              "path": "people/alex.md",
              "exists": true,
              "title": "Alex",
              "frontmatter": {"title": "Alex"}
            }
          ]
        }
      }
    }
  ],
  "query": "authentication",
  "total_results": 1,
  "mode": "hybrid"
}

SearchOutput Fields

FieldTypeDescription
resultsSearchResult[]Ranked search results ordered by relevance score
querystringThe original query string
total_resultsnumberNumber of results returned
modestringThe search mode used (hybrid, semantic, lexical, or edge)
timingsSearchTimings?Timing breakdown (only included when -v is used)
graph_contextGraphContextItem[]Chunks from linked files (only included when non-empty, requires --expand)
edge_resultsEdgeSearchResult[]Edge search results (only included when non-empty, --edge-search mode)

SearchResult Fields

FieldTypeDescription
scorenumberRelevance score (0.0-1.0)
chunk.chunk_idstringChunk identifier (e.g., "path.md#0")
chunk.heading_hierarchystring[]Heading hierarchy leading to this chunk
chunk.contentstringThe text content of the matched chunk
chunk.start_linenumber1-based start line in the source file
chunk.end_linenumber1-based end line in the source file (inclusive)
file.pathstringRelative path to the source markdown file
file.frontmatterobject?Parsed YAML frontmatter (null if absent)
file.file_sizenumberFile size in bytes
file.path_componentsstring[]Path split into components
file.modified_atnumber?Filesystem modification time as Unix timestamp
file.computed_fieldsobjectSuccessful computed values mirrored for provenance; frontmatter is authoritative
file.computed_field_errorsobjectComputed-field diagnostics keyed by field name
file.relationsobject?Depth-one resolved relations; present only with --populate

SearchTimings Fields

Included when -v (verbose) flag is used:

FieldTypeDescription
embed_secsnumberTime spent embedding the query
vector_search_secsnumberTime spent in HNSW vector search (0 if lexical-only)
lexical_search_secsnumberTime spent in BM25 lexical search (0 if semantic-only)
fusion_secsnumberTime spent in RRF fusion (0 if not hybrid)
assemble_secsnumberTime spent assembling results (filtering, decay, link boosting)
total_secsnumberTotal wall-clock time

GraphContextItem Fields

Included when --expand is set to a value greater than 0:

FieldTypeDescription
chunkSearchResultChunkThe matched chunk from the linked file
fileSearchResultFileFile-level metadata for the linked file
linked_fromstringPath of the result file this item is linked from
hop_distancenumberNumber of link hops from the result file (1 = direct link)
edge_contextstring?Contextual information about the connecting edge
edge_relationshipstring?Relationship type of the connecting edge

EdgeSearchResult Fields

Included when using --edge-search or --mode=edge:

FieldTypeDescription
scorenumberRelevance score for this edge match
edge_idstringUnique identifier for this edge
source_pathstringSource document path
target_pathstringTarget document path
link_textstringLink text connecting source to target
contextstringContextual text surrounding the link
relationship_typestring?Relationship type label (e.g., “references”, “extends”)
cluster_idnumber?Cluster ID this edge belongs to
strengthnumber?Edge strength/weight

Configuration

The following shell overrides affect search behavior. Equivalent values can be set in project .markdownvdb/config.yaml or user ~/.mdvdb/config.yaml. See Configuration for the complete YAML keys and resolution order.

VariableDefaultDescription
MDVDB_SEARCH_DEFAULT_LIMIT10Default result limit
MDVDB_SEARCH_MIN_SCORE0.0Default minimum score
MDVDB_SEARCH_MODEhybridDefault search mode
MDVDB_SEARCH_RRF_K60.0RRF fusion constant
MDVDB_BM25_NORM_K1.5BM25 score normalization constant
MDVDB_SEARCH_DECAYfalseEnable time decay by default
MDVDB_SEARCH_DECAY_HALF_LIFE90.0Default decay half-life in days
MDVDB_SEARCH_DECAY_EXCLUDEPaths excluded from decay
MDVDB_SEARCH_DECAY_INCLUDEPaths where decay applies
MDVDB_SEARCH_BOOST_LINKSfalseEnable link boosting by default
MDVDB_SEARCH_BOOST_HOPS1Default link boost hops
MDVDB_SEARCH_EXPAND_GRAPH0Default graph expansion depth
MDVDB_SEARCH_EXPAND_LIMIT3Maximum expanded context results
MDVDB_EDGE_BOOST_WEIGHT0.15Edge boost weight

See Also