# cqs ("seeks")

Code intelligence MCP server that saves AI agents tokens. Semantic search, call graph tracing, impact analysis — in single tool calls instead of dozens of file reads. Local ML, GPU-accelerated.

**TL;DR:** Semantic code search for Claude Code. Instead of grep, it understands what code *does* — so Claude finds relevant functions without knowing exact names. Tools like `trace`, `impact`, `gather`, and `batch` collapse 5-10 sequential tool calls into one, cutting context window usage by 50-80% on common code navigation tasks.

[![Crates.io](https://img.shields.io/crates/v/cqs.svg)](https://crates.io/crates/cqs)
[![CI](https://github.com/jamie8johnson/cqs/actions/workflows/ci.yml/badge.svg)](https://github.com/jamie8johnson/cqs/actions/workflows/ci.yml)
[![CodeQL](https://github.com/jamie8johnson/cqs/actions/workflows/codeql.yml/badge.svg)](https://github.com/jamie8johnson/cqs/actions/workflows/codeql.yml)

---

> **`<claude>`**
>
> You're an AI assistant reading this. cqs gives you semantic code search + code intelligence via MCP.
>
> **Why you want this:** Find functions by what they do, not their names. Tools like `cqs_trace`, `cqs_impact`, and `cqs_gather` collapse 5-10 file reads into one call, saving context window for actual work.
>
> **Setup:** `claude mcp add cqs -- cqs serve --project /path/to/project`
>
> **`</claude>`**

---

## Install

**Requires Rust 1.88+** (due to `ort` ONNX runtime dependency)

```bash
cargo install cqs
```

**Upgrading?** Schema changes require rebuilding the index:
```bash
cqs index --force  # Run after upgrading from older versions (current schema: v10)
```

## Quick Start

```bash
# Download model and initialize
cqs init

# Index your project
cd /path/to/project
cqs index

# Search
cqs "retry with exponential backoff"
cqs "validate email with regex"
cqs "database connection pool"
```

## Filters

```bash
# By language
cqs --lang rust "error handling"
cqs --lang python "parse json"

# By path pattern
cqs --path "src/*" "config"
cqs --path "tests/**" "mock"
cqs --path "**/*.go" "interface"

# By chunk type
cqs --chunk-type function "retry logic"
cqs --chunk-type struct "config"
cqs --chunk-type enum "error types"

# By structural pattern
cqs --pattern async "request handling"
cqs --pattern unsafe "memory operations"
cqs --pattern recursion "tree traversal"
# Patterns: builder, error_swallow, async, mutex, unsafe, recursion

# Combined
cqs --lang typescript --path "src/api/*" "authentication"
cqs --lang rust --chunk-type function --pattern async "database query"

# Hybrid search tuning
cqs --name-boost 0.2 "retry logic"   # Semantic-heavy (default)
cqs --name-boost 0.8 "serve_http"    # Name-heavy for known identifiers

# Show surrounding context
cqs -C 3 "error handling"       # 3 lines before/after each result

# Output options
cqs --json "query"           # JSON output
cqs --no-content "query"     # File:line only, no code
cqs -n 10 "query"            # Limit results
cqs -t 0.5 "query"           # Min similarity threshold
```

## Configuration

Set default options via config files. CLI flags override config file values.

**Config locations (later overrides earlier):**
1. `~/.config/cqs/config.toml` - user defaults
2. `.cqs.toml` in project root - project overrides

**Example `.cqs.toml`:**

```toml
# Default result limit
limit = 10

# Minimum similarity threshold (0.0 - 1.0)
threshold = 0.4

# Name boost for hybrid search (0.0 = pure semantic, 1.0 = pure name)
name_boost = 0.2

# Note weight in search results (0.0-1.0, lower = notes rank below code)
note_weight = 1.0

# Output modes
quiet = false
verbose = false
```

## Watch Mode

Keep your index up to date automatically:

```bash
cqs watch              # Watch for changes and reindex
cqs watch --debounce 1000  # Custom debounce (ms)
```

Watch mode respects `.gitignore` by default. Use `--no-ignore` to index ignored files.

## Call Graph

Find function call relationships:

```bash
cqs callers <name>   # Functions that call <name>
cqs callees <name>   # Functions called by <name>
cqs notes list       # List all project notes with sentiment
```

Use cases:
- **Impact analysis**: What calls this function I'm about to change?
- **Context expansion**: Show related functions
- **Entry point discovery**: Find functions with no callers

Call graph is indexed across all files - callers are found regardless of which file they're in.

## Discovery Tools

```bash
# Find functions similar to a given function (search by example)
cqs similar search_filtered                    # by name
cqs similar src/search.rs:search_filtered      # by file:name

# Function card: signature, callers, callees, similar functions
cqs explain search_filtered
cqs explain src/search.rs:search_filtered --json

# Semantic diff between indexed snapshots
cqs diff old-version                           # project vs reference
cqs diff old-version new-ref                   # two references
cqs diff old-version --threshold 0.90          # stricter "modified" cutoff
```

## Code Intelligence

```bash
# Follow a call chain between two functions (BFS shortest path)
cqs trace cmd_query search_filtered
cqs trace cmd_query search_filtered --max-depth 5

# Impact analysis: what breaks if I change this function?
cqs impact search_filtered                # direct callers + affected tests
cqs impact search_filtered --depth 3      # transitive callers

# Map functions to their tests
cqs test-map search_filtered
cqs test-map search_filtered --depth 3 --json

# Module overview: chunks, callers, callees, notes for a file
cqs context src/search.rs
cqs context src/search.rs --json
```

## Maintenance

```bash
# Find dead code (functions never called by indexed code)
cqs dead                    # Conservative: excludes main, tests, trait impls
cqs dead --include-pub      # Include public API functions
cqs dead --json             # JSON output

# Garbage collection (remove stale index entries)
cqs gc                      # Prune deleted files, rebuild HNSW

# Cross-project search
cqs project register mylib /path/to/lib   # Register a project
cqs project list                          # Show registered projects
cqs project search "retry logic"          # Search across all projects
cqs project remove mylib                  # Unregister

# Smart context assembly (gather related code)
cqs gather "error handling"               # Seed search + call graph expansion
cqs gather "auth flow" --expand 2         # Deeper expansion
cqs gather "config" --direction callers   # Only callers, not callees
```

## Reference Indexes (Multi-Index Search)

Search across your project and external codebases simultaneously:

```bash
cqs ref add tokio /path/to/tokio          # Index an external codebase
cqs ref add stdlib /path/to/rust/library --weight 0.6  # Custom weight
cqs ref list                               # Show configured references
cqs ref update tokio                       # Re-index from source
cqs ref remove tokio                       # Remove reference and index files
```

Once added, all searches automatically include reference results:

```bash
cqs "spawn async task"    # Finds results in project AND tokio reference
```

Reference results are ranked with a weight multiplier (default 0.8) so project results naturally appear first at equal similarity.

**MCP integration**: The `cqs_search` tool gains a `sources` parameter to filter which indexes to search:
- Omit `sources` to search all indexes
- `sources: ["project"]` — search only the primary project
- `sources: ["tokio"]` — search only the tokio reference

References are configured in `.cqs.toml`:

```toml
[[reference]]
name = "tokio"
path = "/home/user/.local/share/cqs/refs/tokio"
source = "/home/user/code/tokio"
weight = 0.8
```

## Claude Code Integration

### Why use cqs?

Without cqs, Claude uses grep/glob to find code and reads entire files for context. With cqs:

- **Fewer tool calls**: `trace`, `impact`, `gather`, `context` each replace 5-10 sequential file reads with a single call
- **Less context burn**: Focused `cqs_read` returns a function + its type dependencies — not the whole file. `batch` runs 10 queries in one round-trip
- **Find code by behavior**: "function that retries with backoff" finds retry logic even if it's named `doWithAttempts`
- **Navigate unfamiliar codebases**: Semantic search finds relevant code without knowing project structure

### Setup

**Step 1:** Add cqs as an MCP server:

```bash
claude mcp add cqs -- cqs serve --project /path/to/project
```

Or manually in `~/.claude.json`:

```json
{
  "projects": {
    "/path/to/project": {
      "mcpServers": {
        "cqs": {
          "command": "cqs",
          "args": ["serve", "--project", "/path/to/project"]
        }
      }
    }
  }
}
```

**Note:** The `--project` argument is required because MCP servers run from an unpredictable working directory.

**GPU acceleration:** Add `--gpu` for faster query embedding after warmup:
```bash
cqs serve --gpu --project /path/to/project
```
GPU: ~12ms warm queries. CPU (default): ~22ms. Server starts instantly with HNSW, upgrades to GPU in background.

**Step 2:** Add to your project's `CLAUDE.md` so Claude uses it automatically:

```markdown
## Code Search

Use `cqs_search` for semantic code search instead of grep/glob when looking for:
- Functions by behavior ("retry with backoff", "parse config")
- Implementation patterns ("error handling", "database connection")
- Code where you don't know the exact name

Available tools:
- `cqs_search` - semantic search with `language`, `path_pattern`, `threshold`, `limit`, `name_boost`, `note_weight`, `semantic_only`, `name_only`
  - Use `name_only=true` for "where is X defined?" queries (skips embedding, searches function names directly)
- `cqs_stats` - index stats, chunk counts, HNSW index status
- `cqs_callers` - find functions that call a given function
- `cqs_callees` - find functions called by a given function
- `cqs_read` - read file with context notes injected as comments (use `focus` param for function + type deps only)
- `cqs_add_note` - add observation to project memory (indexed for future searches)
- `cqs_update_note` - update an existing note's text, sentiment, or mentions
- `cqs_remove_note` - remove a note from project memory
- `cqs_audit_mode` - toggle audit mode to exclude notes from search/read results
- `cqs_similar` - find functions similar to a given function (search by example)
- `cqs_explain` - function card: signature, callers, callees, similar functions
- `cqs_diff` - semantic diff between indexed snapshots
- `cqs_trace` - follow call chain between two functions (BFS shortest path). `format: "mermaid"` for diagrams
- `cqs_impact` - what breaks if you change X? Callers with snippets + affected tests
- `cqs_test_map` - map functions to tests that exercise them
- `cqs_batch` - execute multiple queries in one call (up to 10)
- `cqs_context` - module-level understanding: chunks, callers, callees, notes for a file
- `cqs_gather` - smart context assembly: seed search + call graph BFS expansion
- `cqs_dead` - find functions/methods never called by indexed code
- `cqs_gc` - report index staleness (stale/missing file counts)

Keep index fresh: run `cqs watch` in a background terminal, or `cqs index` after significant changes.
```

### HTTP Transport

For web integrations, use the HTTP transport:

```bash
cqs serve --transport http --port 3000 --project /path/to/project
```

Endpoints:
- `POST /mcp` - JSON-RPC requests (MCP protocol messages)
- `GET /mcp` - SSE stream for server-to-client notifications
- `GET /health` - Health check (returns 200 OK when server is ready)

**Authentication:** For network-exposed servers, API key authentication is required:

```bash
# Via flag
cqs serve --transport http --api-key SECRET --project /path/to/project

# Via environment variable
export CQS_API_KEY=SECRET
cqs serve --transport http --project /path/to/project

# Via file (recommended - keeps secret out of process list)
echo "SECRET" > /path/to/keyfile
cqs serve --transport http --api-key-file /path/to/keyfile --project /path/to/project
```

Clients must include `Authorization: Bearer SECRET` header.

**Network binding:** By default, cqs binds to localhost only. To expose on a network:

```bash
# Requires both flags for safety
cqs serve --transport http --bind 0.0.0.0 --dangerously-allow-network-bind --api-key SECRET
```

Implements MCP Streamable HTTP spec 2025-11-25 with Origin validation and protocol version headers.

## Supported Languages

- Rust
- Python
- TypeScript
- JavaScript (JSDoc `@param`/`@returns` tags improve search quality)
- Go
- C
- Java

## Indexing

By default, `cqs index` respects `.gitignore` rules:

```bash
cqs index              # Respects .gitignore
cqs index --no-ignore  # Index everything
cqs index --force      # Re-index all files
cqs index --dry-run    # Show what would be indexed
```

## How It Works

1. Parses code with tree-sitter to extract:
   - Functions and methods
   - Classes and structs
   - Enums, traits, interfaces
   - Constants
2. Generates embeddings with E5-base-v2 (runs locally)
   - Includes doc comments for better semantic matching
3. Stores in SQLite with vector search + FTS5 keyword index
4. **Hybrid search (RRF)**: Combines semantic similarity with keyword matching
   - Semantic search finds conceptually related code
   - Keyword search catches exact identifier matches (e.g., `parseConfig`)
   - Reciprocal Rank Fusion merges both rankings for best results
5. Uses GPU if available, falls back to CPU

## HNSW Index Tuning

The HNSW (Hierarchical Navigable Small World) index provides fast approximate nearest neighbor search. Current parameters:

| Parameter | Value | Description |
|-----------|-------|-------------|
| M (connections) | 24 | Max edges per node. Higher = better recall, more memory |
| ef_construction | 200 | Search width during build. Higher = better index, slower build |
| max_layers | 16 | Graph layers. ~log(N) is typical |
| ef_search | 100 | Search width at query time. Higher = better recall, slower search |

**Trade-offs:**
- **Recall vs speed**: Higher ef_search improves recall but slows queries
- **Index size**: ~4KB per vector with current settings
- **Build time**: O(N * M * ef_construction) complexity

For most codebases (<100k chunks), defaults work well. Large repos may benefit from tuning ef_search higher (200+) if recall matters more than latency.

## Search Quality

Hybrid search (RRF) combines semantic understanding with keyword matching:

| Query | Top Match | Score |
|-------|-----------|-------|
| "cosine similarity" | `cosine_similarity` | 0.85 |
| "validate email regex" | `validateEmail` | 0.73 |
| "check if adult age 18" | `isAdult` | 0.71 |
| "pop from stack" | `Stack.Pop` | 0.70 |
| "generate random id" | `generateId` | 0.70 |

## GPU Acceleration (Optional)

cqs works on CPU (~20ms per embedding). GPU provides 3x+ speedup:

| Mode | Single Query | Batch (50 docs) |
|------|--------------|-----------------|
| CPU  | ~20ms        | ~15ms/doc       |
| CUDA | ~6ms         | ~0.3ms/doc      |

For GPU acceleration:

### Linux

```bash
# Add NVIDIA CUDA repo
wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt update

# Install CUDA runtime and cuDNN 9
sudo apt install cuda-cudart-12-6 libcublas-12-6 libcudnn9-cuda-12
```

Set library path:
```bash
export LD_LIBRARY_PATH=/usr/local/cuda-12.6/lib64:/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH
```

### WSL2

Same as Linux, plus:
- Requires NVIDIA GPU driver on Windows host
- Add `/usr/lib/wsl/lib` to `LD_LIBRARY_PATH`
- Tested working with RTX A6000, CUDA 13.0 driver, cuDNN 9.18

### Verify

```bash
cqs doctor  # Shows execution provider (CUDA or CPU)
```

## Contributing

Issues and PRs welcome at [GitHub](https://github.com/jamie8johnson/cqs).

## License

MIT
