Metadata-Version: 2.4
Name: nova-rag
Version: 0.1.0
Summary: Local code intelligence MCP server — semantic search + code graph + impact analysis. Ask code in plain language.
Author: Vladimir Pronevic
License-Expression: MIT
License-File: LICENSE
Keywords: claude-code,code-graph,code-search,mcp,nova-rag,rag,semantic-search
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.11
Requires-Dist: faiss-cpu>=1.7.0
Requires-Dist: mcp>=1.0.0
Requires-Dist: numpy>=1.26.0
Requires-Dist: pathspec>=0.12.0
Requires-Dist: sentence-transformers>=3.0.0
Requires-Dist: tree-sitter-c-sharp>=0.23.0
Requires-Dist: tree-sitter-go>=0.23.0
Requires-Dist: tree-sitter-java>=0.23.0
Requires-Dist: tree-sitter-javascript>=0.23.0
Requires-Dist: tree-sitter-python>=0.23.0
Requires-Dist: tree-sitter-rust>=0.23.0
Requires-Dist: tree-sitter-typescript>=0.23.0
Requires-Dist: tree-sitter>=0.23.0
Requires-Dist: watchdog>=4.0.0
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Description-Content-Type: text/markdown

# nova-rag

[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
[![MCP](https://img.shields.io/badge/MCP-compatible-green.svg)](https://modelcontextprotocol.io)
[![Tests](https://img.shields.io/badge/tests-99%20passed-brightgreen.svg)]()
[![Free](https://img.shields.io/badge/price-free%20forever-brightgreen.svg)]()

> **This project is completely free and open source (MIT).** No paid tiers, no premium features, no "contact sales" — everything is included.
> If nova-rag saves you time, the best way to say thanks is to **give it a star** on GitHub. It helps others discover the project and keeps development going.

**Ask questions about code in plain language. Get answers with full context.**

Don't know the function name? Don't need to. Ask *"where is payment processing?"* and get the function, who calls it, what it calls, and where it lives — in one request.

The only MCP server that combines **semantic code search** with **code graph intelligence**. Other code graph servers (CodeGraph, Code Pathfinder, CodeGraphContext) require exact symbol names. nova-rag understands natural language.

```
You:    "how is authentication handled?"

nova-rag: handleAuth() in src/auth/middleware.py:42
         Callers: login_endpoint, process_request, verify_session
         Callees: verify_token, get_user, logger.error

         AuthService class in src/auth/service.py:8
         Extends: BaseService
         Callers: register_endpoint, oauth_callback
```

100% local. No API keys. No data leaves your machine.

---

## The Problem

```
┌─────────────────────────────────────────────────────────────────────────┐
│                    You're new on a 3000-file project                    │
│                    You need to fix a payment bug                        │
│                    You don't know ANY function names                    │
└────────────────────────────────┬────────────────────────────────────────┘
                                 │
                 ┌───────────────┴───────────────┐
                 ▼                               ▼
    ┌────────────────────────┐      ┌────────────────────────┐
    │  Other code servers    │      │      nova-rag           │
    ├────────────────────────┤      ├────────────────────────┤
    │                        │      │                        │
    │ You: "where is         │      │ You: "where is         │
    │  payment processing?"  │      │  payment processing?"  │
    │                        │      │                        │
    │ Server: ❌ needs exact  │      │ Server: ✅              │
    │ function name          │      │ processStripeWebhook() │
    │                        │      │   in payments/hook.py  │
    │ You: grep "payment"    │      │   Callers: checkout,   │
    │ → 200 results...       │      │     subscription       │
    │ You: grep "pay"        │      │   Callees: update,     │
    │ → 500 results...       │      │     send_receipt       │
    │                        │      │                        │
    │ ⏱ 20 minutes later...  │      │ ⏱ 10 seconds           │
    │ Found it!              │      │ Full picture. Done.    │
    └────────────────────────┘      └────────────────────────┘
```

---

## Quick Start

```
┌──────────────────────────────────────────────┐
│  Step 1: Install                             │
│  $ pip install nova-rag                       │
│                                              │
│  Step 2: Connect to Claude Code              │
│  $ claude mcp add rag -- nova-rag             │
│                                              │
│  Step 3: Ask anything                        │
│  > "how is authentication handled?"          │
│  > "who calls the validate function?"        │
│  > "find dead code in src/auth"              │
│  > "class hierarchy of UserService"          │
└──────────────────────────────────────────────┘
```

### Connect to Claude Desktop

Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):

```json
{
  "mcpServers": {
    "rag": {
      "command": "nova-rag",
      "args": []
    }
  }
}
```

### Connect to VS Code / Cursor

VS Code — `.vscode/mcp.json`:
```json
{ "servers": { "rag": { "command": "nova-rag" } } }
```

Cursor — `~/.cursor/mcp.json`:
```json
{ "mcpServers": { "rag": { "command": "nova-rag" } } }
```

---

## Usage Guide — Just Ask in Plain Language

Once connected, you don't need to call tools manually. Just ask Claude Code in natural language — nova-rag handles the rest.

### Find code (semantic search)

```
> where is payment processing?
> how is authentication handled?
> show me the database connection code
```

nova-rag finds relevant functions even if you don't know their names. Results include callers/callees for full context.

### Who calls a function

```
> who calls handleAuth?
> who uses validate?
```

Shows every place in the codebase that calls this function, with file paths and line numbers.

### What a function calls

```
> what does processData call?
> what functions does login call inside?
```

Shows all functions called inside a given function.

### Who imports a module

```
> who imports psycopg2?
> who imports the auth module?
```

### Find dead code

```
> find unused functions
> find unused code in src/
```

Lists functions and methods that are never called anywhere.

### Impact analysis — what breaks if I change this?

```
> what is the impact of changing validate?
> what breaks if I change handleAuth?
```

Shows direct callers, transitive callers, affected files, affected tests, and risk level.

### Class hierarchy

```
> class hierarchy of UserService
> inheritance of DataProcessor
```

Shows parents (extends/implements) and children.

### Recent git changes

```
> what changed this week?
> what changed in auth last week?
```

Shows modified files, new/changed symbols, insertions/deletions.

### First run

On your first query to a new project:
1. Embedding model downloads (~80MB) — once, then cached
2. Project indexes (30-120s) — once, then incremental
3. File watcher starts — auto-updates index on file changes

All subsequent queries are instant.

---

## What It Does — Visual Guide

### The Smart Router

One tool handles everything. It reads your query and routes automatically:

```
                         ┌──────────────────┐
                         │   code_search()  │
                         │   "your query"   │
                         └────────┬─────────┘
                                  │
                    ┌─────────────┼─────────────┐
                    │ Intent      │ Detection   │
                    ▼             ▼             ▼
          ┌─────────────┐ ┌────────────┐ ┌──────────────┐
          │  "where is  │ │ "who calls │ │ "dead code"  │
          │  error      │ │ handleAuth"│ │              │
          │  handling?" │ │            │ │              │
          └──────┬──────┘ └─────┬──────┘ └──────┬───────┘
                 │              │               │
                 ▼              ▼               ▼
          ┌────────────┐ ┌───────────┐ ┌──────────────┐
          │  Semantic  │ │  Graph    │ │  Dead Code   │
          │  Search    │ │  Query    │ │  Detection   │
          │ (hybrid)   │ │ (callers) │ │              │
          └────────────┘ └───────────┘ └──────────────┘

  Also detects: callees, importers, class hierarchy
  Works in English and Russian
```

### Hybrid Search — How Two Engines Beat One

```
  Query: "error handling"
      │
      ├───────────────────────────────────────────┐
      │                                           │
      ▼                                           ▼
  ┌──────────────────────┐          ┌──────────────────────┐
  │   🧠 Vector Search    │          │   📝 Keyword Search   │
  │   (Neural Network)   │          │   (SQLite FTS5)      │
  │                      │          │                      │
  │ Understands MEANING  │          │ Matches exact WORDS  │
  │                      │          │                      │
  │ "error handling" →   │          │ "error handling" →   │
  │  finds try/catch,    │          │  finds code with     │
  │  exception handlers, │          │  literal "error" or  │
  │  error responses     │          │  "handling" in text  │
  │  even without those  │          │                      │
  │  exact words         │          │                      │
  └──────────┬───────────┘          └──────────┬───────────┘
             │ rank 1, 2, 3...                 │ rank 1, 2, 3...
             │                                 │
             └────────────┬────────────────────┘
                          │
                          ▼
              ┌───────────────────────┐
              │  Reciprocal Rank      │
              │  Fusion (RRF)         │
              │                       │
              │  score = 1/(k+rank₁)  │
              │       + 1/(k+rank₂)   │
              │                       │
              │  Best of both worlds  │
              └───────────┬───────────┘
                          │
                          ▼
              ┌───────────────────────┐
              │  Results + Graph      │
              │                       │
              │  handle_error()       │
              │    Callers: login,    │
              │      register         │
              │    Callees: log,      │
              │      format_response  │
              └───────────────────────┘
```

**What each engine catches:**

```
  ┌──────────────────────────┬──────────────┬──────────────┬──────────────┐
  │ Query                    │ Vector only  │ Keyword only │ Hybrid (RRF) │
  ├──────────────────────────┼──────────────┼──────────────┼──────────────┤
  │ "error handling"         │ ✅ finds     │ ✅ finds     │ ✅ best of   │
  │                          │ related code │ exact words  │ both         │
  ├──────────────────────────┼──────────────┼──────────────┼──────────────┤
  │ "getUserById"            │ ⚠️ returns   │ ✅ exact     │ ✅ exact     │
  │                          │ fetchUser    │ match        │ match #1     │
  ├──────────────────────────┼──────────────┼──────────────┼──────────────┤
  │ "database connection"    │ ✅ finds     │ ❌ no match  │ ✅ found     │
  │                          │ get_pool()   │ (wrong words)│ via vector   │
  ├──────────────────────────┼──────────────┼──────────────┼──────────────┤
  │ "auth middleware setup"  │ ✅ semantic  │ ⚠️ partial   │ ✅ combined  │
  │                          │ match        │ match        │ score        │
  └──────────────────────────┴──────────────┴──────────────┴──────────────┘
```

### Code Graph — What Gets Extracted

```
  Source file: src/auth/middleware.py
  ┌─────────────────────────────────────────────────┐
  │ from auth.tokens import verify_token             │──── Import
  │ from db import get_user                          │──── Import
  │                                                  │
  │ class AuthMiddleware(BaseMiddleware):             │──── Symbol (class)
  │     │                                            │     + Inheritance
  │     │   def handleAuth(self, request):           │──── Symbol (method)
  │     │       token = verify_token(request.token)  │──── Call
  │     │       user = get_user(token.user_id)       │──── Call
  │     │       if not user:                         │
  │     │           logger.error("No user")          │──── Call
  │     │       return user                          │
  │     │                                            │
  └─────┴────────────────────────────────────────────┘

  Extracted graph for this file:

  ┌─────────────┐     ┌──────────────────────────────────────┐
  │  Symbols    │     │  AuthMiddleware (class, line 4)      │
  │             │     │  handleAuth (method, line 6)          │
  └─────────────┘     └──────────────────────────────────────┘

  ┌─────────────┐     ┌──────────────────────────────────────┐
  │  Calls      │     │  handleAuth → verify_token (line 7)  │
  │             │     │  handleAuth → get_user (line 8)       │
  │             │     │  handleAuth → logger.error (line 10)  │
  └─────────────┘     └──────────────────────────────────────┘

  ┌─────────────┐     ┌──────────────────────────────────────┐
  │  Imports    │     │  auth.tokens → verify_token          │
  │             │     │  db → get_user                        │
  └─────────────┘     └──────────────────────────────────────┘

  ┌─────────────┐     ┌──────────────────────────────────────┐
  │ Inheritance │     │  AuthMiddleware extends BaseMiddleware│
  └─────────────┘     └──────────────────────────────────────┘
```

### Graph Queries — What You Can Ask

```
  ┌──────────────────────────────────────────────────────────────┐
  │                     handleAuth()                             │
  │                                                              │
  │  ◀── CALLERS ──────────────── CALLEES ──▶                    │
  │                                                              │
  │  login_endpoint()          verify_token()                    │
  │  process_request()         get_user()                        │
  │  test_auth_flow()          logger.error()                    │
  │                                                              │
  │  ◀── IMPORTERS ──────────── HIERARCHY ──▶                    │
  │                                                              │
  │  routes/auth.py            BaseMiddleware                    │
  │  middleware/main.py           ▲                               │
  │  tests/test_auth.py          │ extends                       │
  │                            AuthMiddleware                    │
  │                               ▲                               │
  │                               │ extends                       │
  │                            AdminMiddleware                   │
  └──────────────────────────────────────────────────────────────┘

  direction="callers"  → left side (who calls this?)
  direction="callees"  → right side (what does this call?)
  direction="importers"→ bottom-left (who imports this?)
  direction="hierarchy"→ bottom-right (inheritance tree)
  direction="both"     → callers + callees
  depth=2              → callers of callers (transitive)
```

### Transitive Callers (depth=2)

```
  rag_graph("verify_token", direction="callers", depth=2)

  verify_token()
     │
     ◀── handleAuth()                      ← depth 1 (direct callers)
     │      │
     │      ◀── login_endpoint()           ← depth 2 (callers of callers)
     │      ◀── process_request()
     │      ◀── test_auth_flow()
     │
     ◀── refresh_session()                 ← depth 1
            │
            ◀── session_middleware()        ← depth 2
            ◀── test_refresh()
```

### Dead Code Detection

```
  rag_deadcode()

  All symbols:          Symbols with callers:     Dead code:
  ┌───────────────┐     ┌───────────────┐         ┌───────────────┐
  │ handleAuth    │     │ handleAuth ✅  │         │               │
  │ verify_token  │     │ verify_token ✅│         │               │
  │ get_user      │  →  │ get_user ✅    │    →    │ old_validate  │
  │ old_validate  │     │               │         │ format_v1     │
  │ format_v1     │     │               │         │ LegacyParser  │
  │ LegacyParser  │     │               │         │               │
  │ main          │     │ main (skip)   │         │ 3 functions   │
  │ test_auth     │     │ test_ (skip)  │         │ 0 callers     │
  └───────────────┘     └───────────────┘         └───────────────┘

  Filters out: main, __init__, setUp, tearDown, test_*
```

### Class Hierarchy

```
  rag_graph("DataProcessor", direction="hierarchy")

                    ┌─────────────────┐
                    │  BaseProcessor   │
                    │  (base.py:5)     │
                    └────────┬────────┘
                             │ extends
                    ┌────────┴────────┐
                    │ DataProcessor    │  ◀── you asked about this
                    │ (processor.py:12)│
                    └────────┬────────┘
                             │ extends
               ┌─────────────┼─────────────┐
      ┌────────┴────────┐         ┌────────┴────────┐
      │AdvancedProcessor│         │ StreamProcessor  │
      │ (advanced.py:8) │         │ (stream.py:15)   │
      └─────────────────┘         └──────────────────┘
```

### Indexing Pipeline — What Happens Inside

```
  Your project (3000 files)
       │
       ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │  Phase 1: File Discovery                                        │
  │  ├── Walk all files recursively                                 │
  │  ├── Skip: .git, node_modules, __pycache__, binaries            │
  │  ├── Respect .gitignore                                         │
  │  └── Skip files > 1MB                                           │
  │  Result: 1200 indexable files                                   │
  └──────────────────────────────┬──────────────────────────────────┘
                                 │
                                 ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │  Phase 2: Parallel Processing  (8 threads)            ⚡ FAST  │
  │                                                                 │
  │  Thread 1: auth.py ──┐                                          │
  │  Thread 2: db.py ────┤  Each thread:                            │
  │  Thread 3: api.py ───┤  ├── Read file                           │
  │  Thread 4: utils.py ─┤  ├── Tree-sitter parse                   │
  │  Thread 5: models.py ┤  ├── Extract chunks (functions, classes)  │
  │  Thread 6: tests.py ─┤  ├── Extract graph (calls, imports)      │
  │  Thread 7: views.py ─┤  └── Extract inheritance                  │
  │  Thread 8: forms.py ─┘                                          │
  │                                                                 │
  │  Result: chunks + graph data for all files                      │
  └──────────────────────────────┬──────────────────────────────────┘
                                 │
                                 ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │  Phase 3: Embedding  (sequential — model not thread-safe)       │
  │                                                                 │
  │  all-MiniLM-L6-v2 model (384-dim vectors)                      │
  │  Batch size: 64 chunks at a time                                │
  │  ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐                           │
  │  │Batch1│→│Batch2│→│Batch3│→│Batch4│→ ...                       │
  │  └──────┘ └──────┘ └──────┘ └──────┘                           │
  └──────────────────────────────┬──────────────────────────────────┘
                                 │
                                 ▼
  ┌─────────────────────────────────────────────────────────────────┐
  │  Phase 4: Storage  (sequential — SQLite not thread-safe)        │
  │                                                                 │
  │  ┌─────────────┐    ┌──────────────────────────────────┐        │
  │  │    FAISS     │    │           SQLite                  │        │
  │  │              │    │                                   │        │
  │  │  384-dim     │    │  chunks ──── FTS5 keyword index  │        │
  │  │  vectors     │    │  symbols ─── function/class defs │        │
  │  │  for cosine  │    │  calls ───── caller→callee edges │        │
  │  │  similarity  │    │  imports ─── file→module edges   │        │
  │  │              │    │  inheritance─ parent→child edges  │        │
  │  └─────────────┘    └──────────────────────────────────┘        │
  └─────────────────────────────────────────────────────────────────┘
```

### After Indexing — File Watcher Keeps It Fresh

```
  ┌──────────────┐
  │ You edit     │
  │ auth.py      │
  └──────┬───────┘
         │ filesystem event
         ▼
  ┌──────────────┐    5 sec     ┌───────────────────────┐
  │  Watchdog    │──debounce──▶ │  Incremental reindex  │
  │  Observer    │              │  Only changed files   │
  └──────────────┘              └───────────────────────┘

  No manual rag_index needed. Always fresh.
```

---

## All Tools Reference

### `code_search` — Smart Router (recommended)

One tool for everything. Auto-detects intent from your query.

```
  code_search("where is error handling?")        → intent: search
  code_search("who calls handleAuth?")           → intent: callers
  code_search("what does processData call?")     → intent: callees
  code_search("who imports psycopg2?")           → intent: importers
  code_search("dead code in src/auth")           → intent: deadcode
  code_search("class hierarchy of UserService")  → intent: hierarchy
```

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `query` | string | yes | — | Natural language query |
| `path` | string | no | cwd | Project directory |
| `top_k` | integer | no | 10 | Max results (for search) |
| `path_filter` | string | no | null | Filter file paths |
| `language` | string | no | null | Filter by language |

### `rag_search` — Direct Hybrid Search

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `query` | string | yes | — | Search query |
| `path` | string | no | cwd | Project directory |
| `top_k` | integer | no | 10 | Max results |
| `path_filter` | string | no | null | Filter file paths |
| `language` | string | no | null | Filter by language |

### `rag_graph` — Direct Graph Navigation

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `name` | string | yes | — | Symbol name |
| `path` | string | no | cwd | Project directory |
| `direction` | string | no | `"both"` | `"callers"`, `"callees"`, `"both"`, `"importers"`, `"hierarchy"` |
| `depth` | integer | no | 1 | Traversal depth (1-2) |

### `rag_deadcode` — Dead Code Detection

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `path` | string | no | cwd | Project directory |
| `path_filter` | string | no | null | Scope to specific path |

### `rag_index` — Index / Reindex

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `path` | string | no | cwd | Directory to index |
| `force` | boolean | no | false | Full rebuild |

### `rag_status` — Index Status

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `path` | string | no | cwd | Project directory |

Returns: `indexed_files`, `total_chunks`, `symbols`, `calls`, `imports`, `inheritances`, `index_size_mb`.

### `rag_watch` — File Watcher

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `path` | string | no | cwd | Directory to watch |

---

## Supported Languages

```
  ┌──────────────────┬────────────────────────────┬──────────────────────────┐
  │ Language         │ Chunks                     │ Graph                    │
  ├──────────────────┼────────────────────────────┼──────────────────────────┤
  │ Python           │ functions, classes, defs    │ calls, imports, inherit  │
  │ TypeScript / TSX │ functions, classes, ifaces  │ calls, imports, inherit  │
  │ JavaScript / JSX │ functions, classes, arrows  │ calls, imports           │
  │ C#               │ methods, classes, structs   │ calls, imports, inherit  │
  │ Go               │ functions, methods, types   │ calls, imports           │
  │ Rust             │ functions, impls, traits    │ calls, imports, inherit  │
  │ Java             │ methods, classes, ifaces    │ calls, imports, inherit  │
  ├──────────────────┼────────────────────────────┼──────────────────────────┤
  │ Other text files │ 60-line sliding window     │ —                        │
  └──────────────────┴────────────────────────────┴──────────────────────────┘

  All languages also get: file header chunks (imports, docstrings)
                          + symbol name extraction from AST
```

---

## Use with CLAUDE.md

Add to your project's `CLAUDE.md`:

```markdown
## Code Search (nova-rag)

This project has a local code intelligence index. Prefer `code_search` over Grep for questions about the codebase:

- "where is payment processing?" → finds relevant functions with full context
- "who calls handleAuth?" → shows all call sites
- "dead code in src/" → finds unused functions
- "class hierarchy of UserService" → shows inheritance tree

Search results include callers/callees — use them to understand the full picture.
For exact string matches (TODOs, error messages), use Grep as usual.
```

---

## Comparison

### nova-rag vs Code Graph Servers

```
  ┌────────────────────────────┬──────────────────┬──────────────────────┐
  │                            │     nova-rag      │  Code Graph Servers  │
  │                            │                  │  (CodeGraph, Code    │
  │                            │                  │   Pathfinder, etc.)  │
  ├────────────────────────────┼──────────────────┼──────────────────────┤
  │ "where is error handling?" │ ✅ Understands   │ ❌ Needs exact name  │
  │ "who calls handleAuth?"   │ ✅ Yes           │ ✅ Yes (strength)    │
  │ Semantic search            │ ✅ Hybrid V+K    │ ❌ No               │
  │ Dataflow analysis          │ ❌ No            │ ✅ Code Pathfinder   │
  │ Impact analysis            │ ⚠️  Basic depth=2 │ ✅ Full blast radius │
  │ Languages                  │ 7                │ Up to 64             │
  │ Dependencies               │ ~2-3GB (PyTorch) │ 20MB-200MB           │
  │ Setup                      │ pip install      │ Varies               │
  └────────────────────────────┴──────────────────┴──────────────────────┘

  They complement each other:
  nova-rag = explore & discover    →    Code Pathfinder = deep analysis
  "find the right symbols"             "analyze those symbols deeply"
```

### nova-rag vs RAG Document Servers

```
  ┌────────────────────────────┬──────────────────┬──────────────────────┐
  │                            │     nova-rag      │  Document RAG        │
  │                            │                  │  (mcp-local-rag,     │
  │                            │                  │   ChromaDB-MCP)      │
  ├────────────────────────────┼──────────────────┼──────────────────────┤
  │ Code graph                 │ ✅ Full          │ ❌ No               │
  │ Dead code detection        │ ✅ Yes           │ ❌ No               │
  │ Tree-sitter chunking       │ ✅ 7 languages   │ ❌ Text splitting    │
  │ Smart router               │ ✅ Auto-detects  │ ❌ No               │
  │ Class hierarchy            │ ✅ Yes           │ ❌ No               │
  │ Designed for               │ Code             │ Documents (PDF, MD)  │
  └────────────────────────────┴──────────────────┴──────────────────────┘
```

---

## Configuration

| Variable | Default | Description |
|---|---|---|
| `NOVA_RAG_MODEL` | `all-MiniLM-L6-v2` | Sentence-transformers model |
| `NOVA_RAG_CHUNK_SIZE` | `60` | Max lines per sliding window chunk |
| `NOVA_RAG_CHUNK_OVERLAP` | `10` | Overlap between chunks |
| `NOVA_RAG_BATCH_SIZE` | `64` | Embedding batch size |
| `NOVA_RAG_DATA_DIR` | `~/.nova-rag` | Index storage directory |

```
  Storage layout:

  ~/.nova-rag/
  ├── a1b2c3d4e5f6/          ← project hash
  │   ├── faiss.index         ← vector embeddings
  │   └── meta.db             ← SQLite (chunks, graph, FTS5)
  └── f6e5d4c3b2a1/          ← another project
      ├── faiss.index
      └── meta.db

  One index per project. Persisted between sessions.
```

---

## Troubleshooting

**First search is slow:** Model (~80MB) downloads on first use. Pre-loaded in background on subsequent starts.

**High memory (~400MB):** That's the embedding model. Use `NOVA_RAG_MODEL=all-MiniLM-L12-v2` for smaller footprint.

**Index stale:** File watcher auto-updates. Force full rebuild: `rag_index(force=true)`.

**Server won't start:** Check `which nova-rag` or run `python -m nova_rag` for error output.

---

## Development

```bash
git clone https://github.com/yourusername/nova-rag.git
cd nova-rag
pip install -e ".[dev]"
pytest tests/ -v   # 99 tests
```

### Project Structure

```
  src/nova_rag/
  ├── server.py      MCP server, 11 tools including smart router
  ├── searcher.py    Smart router, hybrid search, graph queries, dead code
  ├── indexer.py     Multithreaded file processing + embedding
  ├── chunker.py     Tree-sitter AST parsing (7 languages) + fallback
  ├── graph.py       Code graph: symbols, calls, imports, inheritance
  ├── store.py       FAISS + SQLite (FTS5 + graph + inheritance)
  ├── watcher.py     File watcher for auto re-indexing
  └── config.py      Environment-based configuration
```

## Contributing

1. Fork the repo
2. Create a feature branch
3. Write tests for new functionality
4. Ensure all 99 tests pass (`pytest tests/ -v`)
5. Submit a PR

## License

MIT — see [LICENSE](LICENSE) for details.
