codebase-indexer
by ygtdgn
README.md
# codebase-indexer
```
/\_/\ codebase-indexer
( •.•) ─────────────────
⊂/ 🌰 \⊃ Semantic code search
/| |\ powered by AI
```
A semantic codebase indexer that chunks your source code, generates embeddings via [Ollama](https://ollama.com), and stores them in [Qdrant](https://qdrant.tech) for natural-language code search. Ships as an [MCP](https://modelcontextprotocol.io) server for [Claude Code](https://docs.anthropic.com/en/docs/claude-code) and [Codex](https://openai.com/index/introducing-codex/) integration, and also works as a standalone CLI.
## Features
- **Semantic search** — find code by meaning, not just keywords (`"retry logic with exponential backoff"`)
- **18 languages** with symbol-aware chunking (functions, classes, interfaces, etc.)
- **70+ file extensions** recognized
- **Incremental indexing** — only re-indexes changed files (MD5 content hashing)
- **MCP server** — plug directly into Claude Code or Codex as a tool provider
- **File watcher** — auto-reindex on save (500ms debounce)
- **Interactive CLI** — squirrel mascot, spinners, colored output
- **Zero config** — sensible defaults, works out of the box with `npx`
## Quick Start
### One-Line Install
The fastest way to get started — checks prerequisites, sets up infrastructure, indexes your project, and configures integrations interactively:
```bash
bash <(curl -fsSL https://raw.githubusercontent.com/ygtdgn/codebase-indexer/main/install.sh)
```
Or equivalently:
```bash
curl -fsSL https://raw.githubusercontent.com/ygtdgn/codebase-indexer/main/install.sh | bash
```
### Manual Setup
#### Prerequisites
- [Node.js](https://nodejs.org) >= 18
- [Docker](https://www.docker.com) (for Qdrant)
- [Ollama](https://ollama.com) running locally
#### 1. Set up infrastructure
```bash
npx codebase-indexer init
```
This starts a Qdrant container via Docker Compose, verifies your Ollama connection, and pulls the embedding model if needed.
#### 2. Index your project
```bash
npx codebase-indexer index ./your-project
```
#### 3. Search
```bash
npx codebase-indexer search "authentication middleware"
```
#### 4. Use with Claude Code or Codex
```bash
# Set up Claude Code integration (writes CLAUDE.md + .mcp.json)
npx codebase-indexer index ./your-project --setup-claude
# Set up Codex integration (writes AGENTS.md + .codex/config.toml)
npx codebase-indexer index ./your-project --setup-codex
# Set up both interactively
npx codebase-indexer index ./your-project --setup
# Global MCP setup (user-level config files)
npx codebase-indexer index ./your-project --setup --setup-globally
```
## CLI Reference
### Global Options
| Option | Default | Description |
|--------|---------|-------------|
| `--ollama-url <url>` | `http://localhost:11434` | Ollama API URL |
| `--qdrant-url <url>` | `http://localhost:6333` | Qdrant API URL |
| `--model <name>` | `qwen3-embedding:0.6b` | Embedding model name |
| `--dim <number>` | `512` | Embedding vector dimension |
| `--dir <path>` | `.` | Directory to index/watch |
| `--collection <name>` | `codebase` | Qdrant collection name |
| `--no-watch` | — | Disable file watching in MCP mode |
### Commands
#### `init`
Set up Qdrant (Docker) and check Ollama connection.
```bash
codebase-indexer init
```
- Creates `~/.codebase-indexer/docker-compose.yml`
- Starts Qdrant container (`qdrant/qdrant:latest`)
- Waits for health check (30s timeout)
- Verifies Ollama and auto-pulls the embedding model
#### `index [directory]`
Index a directory for semantic search.
```bash
codebase-indexer index ./my-project [options]
```
| Option | Description |
|--------|-------------|
| `--setup` | Interactively choose setup targets (Claude/Codex) |
| `--setup-claude` | Write `CLAUDE.md` + `.mcp.json` for Claude Code |
| `--setup-codex` | Write `AGENTS.md` + `.codex/config.toml` for Codex |
| `--setup-globally` | Write MCP config to user-level files instead of project-local |
| `--force` | Re-index all files, ignoring cached hashes |
#### `search <query>`
Semantic search across the indexed codebase.
```bash
codebase-indexer search "database connection pooling" -k 5
codebase-indexer search "error handling" -l typescript
```
| Option | Default | Description |
|--------|---------|-------------|
| `-k, --top-k <number>` | `10` | Number of results |
| `-l, --language <lang>` | — | Filter by language |
#### `status`
Check health of Ollama and Qdrant, show index statistics.
```bash
codebase-indexer status
```
#### `config`
Interactively edit persistent settings.
```bash
codebase-indexer config
```
Opens an interactive menu to edit Ollama URL, Qdrant URL, embedding model, dimension, and collection name. Settings are saved to `~/.codebase-indexer/config.json` and loaded by all commands automatically.
#### Default (no subcommand)
Start the MCP server over stdio.
```bash
codebase-indexer --dir ./my-project
```
## MCP Server
When run without a subcommand (or via an MCP config), codebase-indexer starts as an MCP server using stdio JSON-RPC transport. It exposes five tools:
| Tool | Description |
|------|-------------|
| `search_code` | Semantic search with optional `language` and `file_path_prefix` filters |
| `index_file` | Index or re-index a single file |
| `index_directory` | Incrementally index an entire directory |
| `get_index_status` | Health check and index statistics |
| `delete_file` | Remove a file from the index |
### Example `.mcp.json`
```json
{
"mcpServers": {
"codebase-indexer": {
"command": "npx",
"args": ["codebase-indexer", "--dir", "/absolute/path/to/project"]
}
}
}
```
### Example usage in Claude Code
```
search_code({ query: "retry logic with exponential backoff", top_k: 5 })
search_code({ query: "error handling", language: "typescript", file_path_prefix: "src/api/" })
index_file({ path: "src/new-module.ts" })
index_directory({})
get_index_status({})
delete_file({ path: "src/old-module.ts" })
```
## Configuration
Settings are resolved in this order (last wins):
```
Hardcoded defaults → ~/.codebase-indexer/config.json → Environment variables → CLI flags
```
### Environment Variables
| Variable | Maps to |
|----------|---------|
| `OLLAMA_URL` | `--ollama-url` |
| `QDRANT_URL` | `--qdrant-url` |
| `EMBEDDING_MODEL` | `--model` |
| `EMBEDDING_DIM` | `--dim` |
| `COLLECTION_NAME` | `--collection` |
### Persistent Config
Run `codebase-indexer config` to interactively set values, or manually create `~/.codebase-indexer/config.json`:
```json
{
"ollamaUrl": "http://localhost:11434",
"qdrantUrl": "http://localhost:6333",
"model": "qwen3-embedding:0.6b",
"embeddingDim": 512,
"collectionName": "codebase"
}
```
### Collection Name Auto-Derivation
When using the default collection name (`codebase`) and indexing a specific directory, the collection name is automatically derived from the directory name:
```bash
codebase-indexer index ./my-cool-project
# → collection: "codebase-my-cool-project"
```
## Architecture
```
index.ts (CLI entry, commander.js)
→ cli/commands.ts (command handlers)
→ core/indexer.ts (orchestrator)
→ core/chunker.ts (symbol-based splitting, sliding window fallback)
→ core/embedder.ts (Ollama /api/embed client, MRL truncation + L2 normalize)
→ core/vectorstore.ts (Qdrant client, cosine similarity search)
→ mcp/server.ts (MCP stdio transport, 5 tools)
→ watcher/watcher.ts (chokidar, 500ms debounce, feeds into indexer)
```
### Pipeline
```
Discover files → Chunk code → Embed via Ollama → Store in Qdrant
```
1. **File discovery** — uses `git ls-files` (fast, respects `.gitignore`) with glob fallback. Filters by 54 code extensions, skips lock files, respects size limits (1 MB default).
2. **Chunking** — dual strategy per file:
- **Symbol-based**: regex patterns detect functions, classes, interfaces, etc. for 18 languages
- **Sliding window fallback**: used when symbols cover <50% of the file. Default 1500 chars with 200-char overlap.
3. **Embedding** — batches of 16 chunks sent to Ollama's `/api/embed` endpoint. Vectors are MRL-truncated to the target dimension and L2-normalized. Retry with exponential backoff (3 attempts).
4. **Storage** — chunks upserted to Qdrant with deterministic IDs (`MD5(path:startLine:endLine)`). Payload indices on `file_path`, `language`, and `chunk_type` for filtered search. Cosine similarity.
5. **Incremental indexing** — each file's content hash is stored in the Qdrant payload. On re-index, unchanged files are skipped entirely.
### Supported Languages (Symbol Detection)
| Language | Detected Symbols |
|----------|-----------------|
| TypeScript | functions, classes, interfaces, types, enums, arrow functions |
| JavaScript | functions, classes, arrow functions, module.exports |
| Python | functions, classes |
| Go | functions, types (struct, interface) |
| Rust | functions, structs, enums, traits, impl blocks |
| Java | classes, interfaces, methods |
| Kotlin | functions, classes, interfaces, objects |
| Ruby | functions, classes, modules |
| PHP | functions, classes, interfaces, traits |
| Swift | functions, classes, structs, protocols, enums |
| C# | methods, classes, interfaces |
| Scala | functions, classes, traits, objects |
| C | functions, structs, typedefs |
| C++ | functions, classes, structs, namespaces, templates |
| Elixir | functions, private functions, modules |
| Haskell | type signatures, data types, classes, instances |
| Dart | functions, classes, mixins |
| Zig | functions, const structs |
All other recognized file types fall back to sliding window chunking.
### File Watcher
In MCP mode, the file watcher is enabled by default:
- Watches for file `add`, `change`, and `unlink` events
- 500ms debounce before processing
- 300ms write-finish stability detection
- Batch processing with retry (max 3 attempts, exponential backoff)
- Automatically re-indexes modified files and removes deleted ones
Disable with `--no-watch`.
## Development
```bash
git clone https://github.com/ygtdgn/codebase-indexer.git
cd codebase-indexer
npm install
npm run dev # tsx watch mode (auto-rebuild on save)
```
### Build
```bash
npm run build # tsc → dist/
```
### Test
```bash
npm test # run once (vitest)
npm run test:watch # watch mode
```
Test coverage includes chunker (symbol detection, sliding window), embedder (truncation, normalization), file utilities (extension mapping, discovery), and hash functions (MD5, chunk IDs).
### Project Structure
```
src/
├── index.ts # CLI entry point (commander.js)
├── config/
│ └── config.ts # Config interface, defaults, env vars, persistent config
├── cli/
│ ├── commands.ts # Command handlers (init, index, search, status, config)
│ ├── mascot.ts # Squirrel ASCII art with gradient colors
│ └── ui.ts # Spinners, progress formatting, result display
├── core/
│ ├── indexer.ts # Central orchestrator
│ ├── chunker.ts # Symbol-based + sliding window chunking
│ ├── embedder.ts # Ollama embedding client
│ └── vectorstore.ts # Qdrant CRUD operations
├── mcp/
│ └── server.ts # MCP stdio server (5 tools)
├── watcher/
│ └── watcher.ts # File change detection + auto-reindex
├── utils/
│ ├── files.ts # File discovery, language detection
│ ├── hash.ts # MD5, chunk IDs, index hashing
│ └── logger.ts # stderr logging (warn, error)
└── __tests__/
├── chunker.test.ts
├── embedder.test.ts
├── files.test.ts
└── hash.test.ts
```
## License
MIT
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues