Docs / guides / semantic-search · Edit on GitHub

Semantic Search

Introduction

The semantic command provides natural-language search over function symbols in your codebase. Instead of matching exact names or patterns, you describe what you are looking for in plain English (e.g., "shopping cart checkout") and rgctl returns the most semantically similar functions.

Semantic search is built on a separate opt-in index (semantic_index.bin) that embeds every function symbol into a vector space. Queries are then answered via Hamming nearest-neighbor search, returning results ranked by a fusion score that combines vector similarity with keyword matching.

Use Cases

  • Exploring an unfamiliar codebase. Ask "where is the payment processing logic?" without knowing function names.
  • Finding related functionality. Search for "authentication" to discover all auth-related functions across the codebase.
  • Agent-assisted development. LLM agents use semantic search to locate relevant code without reading every file.
  • Migration discovery. Find all functions related to a concept (e.g., "database connection") when planning to extract a module.
  • Documentation cross-referencing. Search across code and documentation sections with --scope docs.

Example Project

This guide uses the CoolStore (example/coolstore). Make sure you have run discover first:

rgctl -r example/coolstore discover

Step-by-Step

1. Build the Semantic Index

Semantic search requires a separate indexing step. Run semantic index after discover:

rgctl -r example/coolstore semantic index

Output:

Indexed 7526 functions (vocab-accumulate-v2, 256 dims) → example/coolstore/.rgctl/semantic_index.bin
  incremental: 0 reused, 7526 embedded, 0 removed

What happened:

  • rgctl embedded all 7,526 function symbols into 256-dimensional vectors using the vocab-accumulate-v2 model (a compiled token-table embedder that requires no external model or ONNX runtime).
  • The index was written to .rgctl/semantic_index.bin.
  • On subsequent runs, unchanged functions are reused (incremental indexing).

2. Query with Natural Language

Search for functions related to "shopping cart checkout":

rgctl -r example/coolstore -f json semantic query "shopping cart checkout" --limit 5

Output:

{
  "dimensions": 256,
  "hits": [
    {
      "distance": 63,
      "file_path": "example/coolstore/./src/main/webapp/bower_components/angular-animate/angular-animate.js",
      "fused_score": 0.4749,
      "name": "close",
      "node_id": "5bda7d09-ac18-40c7-a90a-3a8876894947",
      "ranking": "fusion",
      "score": 0.4749
    }
  ],
  "index_schema_version": 2,
  "model_id": "vocab-accumulate-v2",
  "query": "shopping cart checkout",
  "schema_version": 3
}

What this tells you:

  • hits -- the top 5 most semantically similar functions, ranked by fused_score.
  • distance -- the Hamming distance in the vector space (lower is more similar).
  • fused_score -- a combined score from vector similarity and keyword matching (fusion ranking).
  • ranking: "fusion" -- indicates the result was ranked using both semantic and keyword signals.

3. Keyword-Only Search

Disable fusion to use pure keyword matching:

rgctl -r example/coolstore -f json semantic query "checkout" \
  --limit 5 --no-fusion

4. Increase Candidate Pool

For more thorough searches, increase the candidate pool that the fusion step considers:

rgctl -r example/coolstore -f json semantic query "order processing" \
  --limit 10 --candidate-pool 200

5. Community-Scoped Search

Search within a specific scope. Community-scoped search finds entire communities relevant to your query:

rgctl -r example/coolstore -f json semantic query "checkout" \
  --scope community --limit 10

6. Document-Scoped Search

To search documentation sections instead of code functions, first index with the docs scope:

rgctl -r example/coolstore semantic index --scope docs --embedder hash

Then query:

rgctl -r example/coolstore -f json semantic query "deployment instructions" \
  --scope docs --limit 5

Note: the --scope flag on the index command determines what gets embedded. The --scope on query does not filter -- it is the index scope that matters.

7. Choosing an Embedder

rgctl supports three embedding backends:

EmbedderCommandRequirementsBest For
vocab (default)semantic indexNoneGeneral use, no external dependencies
hashsemantic index --embedder hashNoneFast indexing, CI environments
code-daemonsemantic index --embedder code-daemonONNX weights (Git LFS)Highest quality embeddings

For most users, the default vocab embedder provides a good balance of quality and speed.

Understanding Results

FieldMeaning
fused_scoreCombined semantic + keyword similarity (0.0 = no match, 1.0 = perfect match)
distanceRaw Hamming distance in vector space (lower = more similar)
rankingRanking method used: fusion (default) or vector
nameFunction name
file_pathSource file containing the function
node_idUnique graph node ID for cross-referencing with other commands

Benefits

  • No exact name required. Find functions by describing what they do, not what they are called.
  • Zero external dependencies. The default vocab embedder is compiled into the binary -- no model downloads, no ONNX runtime.
  • Incremental indexing. Only re-embeds changed functions on subsequent runs.
  • Fusion ranking. Combines vector similarity with keyword matching for more relevant results.
  • Multi-scope. Search code functions, documentation sections, or communities.

Related Guides