opencode-codebase-index 0.5.2 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,6 +10,24 @@
10
10
 
11
11
  **opencode-codebase-index** brings semantic understanding to your [OpenCode](https://opencode.ai) workflow — and now to any MCP-compatible client like Cursor, Claude Code, and Windsurf. Instead of guessing function names or grepping for keywords, ask your codebase questions in plain English.
12
12
 
13
+ ## šŸ“Œ Quick Navigation
14
+
15
+ - [⚔ Quick Start](#-quick-start)
16
+ - [🌐 MCP Server (Cursor, Claude Code, Windsurf, etc.)](#-mcp-server-cursor-claude-code-windsurf-etc)
17
+ - [šŸŽÆ When to Use What](#-when-to-use-what)
18
+ - [🧰 Tools Available](#-tools-available)
19
+ - [šŸŽ® Slash Commands](#-slash-commands)
20
+ - [āš™ļø Configuration](#ļø-configuration)
21
+ - [šŸ¤ Contributing](#-contributing)
22
+
23
+ ## šŸ‘‹ Choose Your Path
24
+
25
+ - **I want to try it now** → go to [Quick Start](#-quick-start)
26
+ - **I use Cursor/Claude Code/Windsurf** → go to [MCP Server setup](#-mcp-server-cursor-claude-code-windsurf-etc)
27
+ - **I’m comparing tools and workflows** → go to [When to Use What](#-when-to-use-what)
28
+ - **I’m tuning behavior/cost/performance** → go to [Configuration](#ļø-configuration)
29
+ - **I want to contribute** → go to [Contributing](#-contributing)
30
+
13
31
  ## šŸš€ Why Use This?
14
32
 
15
33
  - 🧠 **Semantic Search**: Finds "user authentication" logic even if the function is named `check_creds`.
@@ -168,7 +186,7 @@ graph TD
168
186
 
169
187
  1. **Parsing**: We use `tree-sitter` to intelligently parse your code into meaningful blocks (functions, classes, interfaces). JSDoc comments and docstrings are automatically included with their associated code.
170
188
 
171
- **Supported Languages**: TypeScript, JavaScript, Python, Rust, Go, Java, C#, Ruby, Bash, C, C++, JSON, TOML, YAML
189
+ **Supported Languages**: TypeScript, JavaScript, Python, Rust, Go, Java, C#, Ruby, PHP, Bash, C, C++, JSON, TOML, YAML
172
190
  2. **Chunking**: Large blocks are split with overlapping windows to preserve context across chunk boundaries.
173
191
  3. **Embedding**: These blocks are converted into vector representations using your configured AI provider.
174
192
  4. **Storage**: Embeddings are stored in SQLite (deduplicated by content hash) and vectors in `usearch` with F16 quantization for 50% memory savings. A branch catalog tracks which chunks exist on each branch.
@@ -290,6 +308,7 @@ The plugin automatically registers these slash commands:
290
308
  | ------- | ----------- |
291
309
  | `/search <query>` | **Pure Semantic Search**. Best for "How does X work?" |
292
310
  | `/find <query>` | **Hybrid Search**. Combines semantic search + grep. Best for "Find usage of X". |
311
+ | `/call-graph <query>` | **Call Graph Trace**. Find callers/callees to understand execution flow. |
293
312
  | `/index` | **Update Index**. Forces a refresh of the codebase index. |
294
313
  | `/status` | **Check Status**. Shows if indexed, chunk count, and provider info. |
295
314
 
@@ -329,6 +348,20 @@ Zero-config by default (uses `auto` mode). Customize in `.opencode/codebase-inde
329
348
  }
330
349
  ```
331
350
 
351
+ String values in `codebase-index.json` can reference environment variables with `{env:VAR_NAME}` when the placeholder is the entire string value. Variable names must match `[A-Z_][A-Z0-9_]*`. This is useful for secrets such as custom provider API keys so they do not need to be committed to the config file.
352
+
353
+ ```json
354
+ {
355
+ "embeddingProvider": "custom",
356
+ "customProvider": {
357
+ "baseUrl": "{env:EMBED_BASE_URL}",
358
+ "model": "nomic-embed-text",
359
+ "dimensions": 768,
360
+ "apiKey": "{env:EMBED_API_KEY}"
361
+ }
362
+ }
363
+ ```
364
+
332
365
  ### Options Reference
333
366
 
334
367
  | Option | Default | Description |
@@ -365,7 +398,7 @@ Zero-config by default (uses `auto` mode). Customize in `.opencode/codebase-inde
365
398
  | `logBranch` | `true` | Log branch detection and switches |
366
399
  | `metrics` | `false` | Enable metrics collection (indexing stats, search timing, cache performance) |
367
400
 
368
- ### Retrieval ranking behavior (Phase 1)
401
+ ### Retrieval ranking behavior
369
402
 
370
403
  - `codebase_search` and `codebase_peek` use the hybrid path: semantic + keyword retrieval → fusion (`fusionStrategy`) → deterministic rerank (`rerankTopN`) → filtering.
371
404
  - `find_similar` stays semantic-only: semantic retrieval + deterministic rerank only (no keyword retrieval, no RRF).
@@ -374,6 +407,135 @@ Zero-config by default (uses `auto` mode). Customize in `.opencode/codebase-inde
374
407
  - baseline (versioned): `benchmarks/baselines/retrieval-baseline.json`
375
408
  - latest candidate run (generated): `benchmark-results/retrieval-candidate.json`
376
409
 
410
+ ## šŸ“ Evaluation Harness
411
+
412
+ This repository includes a first-class eval system for retrieval quality with versioned golden sets, compare mode, parameter sweeps, CI budgets, and run artifacts.
413
+
414
+ ### Commands
415
+
416
+ ```bash
417
+ npm run eval
418
+ npm run eval:ci
419
+ npm run eval:ci:ollama
420
+ npm run eval:compare -- --against benchmarks/baselines/eval-baseline-summary.json
421
+ ```
422
+
423
+ CI usage split:
424
+
425
+ - `npm run eval:smoke`: harness smoke check with local mock embeddings (used in main CI)
426
+ - `npm run eval:ci`: real quality gate against baseline/budget (for scheduled/manual quality workflow)
427
+
428
+ For `eval-quality.yml`, the default CI path uses **GitHub Models** with the workflow `GITHUB_TOKEN` plus `models: read`, so you do not need a separate OpenAI API key just to run the scheduled gate.
429
+
430
+ That default GitHub Models path uses `benchmarks/budgets/github-models.json`, which applies stable absolute thresholds instead of the stricter baseline-regression budget used for explicit external providers.
431
+
432
+ Optional override secrets for another OpenAI-compatible endpoint:
433
+
434
+ - `EVAL_EMBED_BASE_URL`
435
+ - `EVAL_EMBED_API_KEY`
436
+ - `EVAL_EMBED_MODEL` (optional, default `text-embedding-3-small`)
437
+ - `EVAL_EMBED_DIMENSIONS` (optional, default `1536`)
438
+
439
+ If you override the provider, set both `EVAL_EMBED_BASE_URL` and `EVAL_EMBED_API_KEY`. Otherwise the workflow falls back to GitHub Models automatically. Override providers continue to use the baseline-driven budget in `benchmarks/budgets/default.json`.
440
+
441
+ No OpenAI API access? Use Ollama quality gate locally:
442
+
443
+ - Config: `.github/eval-ollama-config.json`
444
+ - Script: `npm run eval:ci:ollama`
445
+
446
+ Prerequisites: Ollama installed, `ollama serve` running on `127.0.0.1:11434`, and `nomic-embed-text` pulled.
447
+
448
+ Examples:
449
+
450
+ ```bash
451
+ # Run against small golden set
452
+ npm run eval -- --dataset benchmarks/golden/small.json
453
+
454
+ # Compare against baseline
455
+ npm run eval:compare -- --against benchmarks/baselines/eval-baseline-summary.json --dataset benchmarks/golden/medium.json
456
+
457
+ # Sweep retrieval parameters
458
+ npm run eval -- --dataset benchmarks/golden/small.json --sweepFusionStrategy rrf,weighted --sweepHybridWeight 0.3,0.5,0.7 --sweepRrfK 30,60 --sweepRerankTopN 10,20
459
+ ```
460
+
461
+ ### What it reports
462
+
463
+ - Hit@1, Hit@3, Hit@5, Hit@10
464
+ - MRR@10, nDCG@10
465
+ - Latency p50/p95/p99
466
+ - Token estimates, embedding call counts, estimated embedding cost
467
+ - Failure buckets (`wrong-file`, `wrong-symbol`, `docs-tests-outranking-source`, `no-relevant-hit-top-k`)
468
+
469
+ ### Artifacts
470
+
471
+ Each run writes:
472
+
473
+ `benchmarks/results/<timestamp>/`
474
+
475
+ - `summary.json`
476
+ - `summary.md`
477
+ - `per-query.json`
478
+ - `compare.json` (when baseline/sweep used)
479
+
480
+ ### Golden sets and budgets
481
+
482
+ - Golden datasets:
483
+ - `benchmarks/golden/small.json`
484
+ - `benchmarks/golden/medium.json`
485
+ - `benchmarks/golden/large.json`
486
+ - CI budgets:
487
+ - `benchmarks/budgets/github-models.json` for the default GitHub Models workflow path
488
+ - `benchmarks/budgets/default.json` for explicit external provider overrides with baseline comparison
489
+
490
+ Full docs: `docs/evaluation.md`
491
+
492
+ ### Cross-repo benchmark results snapshot
493
+
494
+ Recent representative runs (plugin vs `ripgrep` vs `ast-grep`) on two medium repos:
495
+
496
+ Methodology for the snapshot below:
497
+
498
+ - Dataset: auto-generated cross-repo golden sets for `axios` + `express`
499
+ - Repeats: **20** per mode
500
+ - Aggregation: **median** metric per tool (then averaged across repos)
501
+ - Reindex behavior: when enabled, index reset applies on repeat #1 only; subsequent repeats measure warm-index query behavior
502
+ - Sampling note: repository parsing can be capped; benchmark reports include truncation metadata
503
+ - ast-grep scope note: sg metrics are computed on its compatible query subset (`definition`, `keyword-heavy`) with scoped denominators shown in run reports
504
+
505
+ #### Without reindex (`--no-reindex`, default)
506
+
507
+ | Metric | Plugin | ripgrep | ast-grep (5/10 queries) |
508
+ |---|---:|---:|---:|
509
+ | Hit@5 | 50% | 5% | 100% |
510
+ | MRR@10 | 0.48 | 0.04 | 0.90 |
511
+ | nDCG@10 | 0.48 | 0.08 | 0.93 |
512
+ | Latency p50 (ms) | 17.5 | 36.9 | 66.6 |
513
+ | Latency p95 (ms) | 30.9 | 44.1 | 70.7 |
514
+
515
+ #### With reindex (`--reindex`)
516
+
517
+ | Metric | Plugin | ripgrep | ast-grep (5/10 queries) |
518
+ |---|---:|---:|---:|
519
+ | Hit@5 | 50% | 5% | 100% |
520
+ | MRR@10 | 0.48 | 0.04 | 0.98 |
521
+ | nDCG@10 | 0.48 | 0.07 | 0.98 |
522
+ | Latency p50 (ms) | 17.1 | 35.9 | 69.1 |
523
+ | Latency p95 (ms) | 30.4 | 43.7 | 75.1 |
524
+
525
+ ast-grep metrics are computed on its compatible query subset only (`definition` + `keyword-heavy`, 5/10 queries per repo). Plugin and ripgrep are scored on all 10 queries.
526
+
527
+ Interpretation:
528
+
529
+ - ast-grep dominates on its scoped subset (structural definition queries), but only handles 50% of query types. Plugin handles all query types including natural language.
530
+ - Plugin leads on rank-sensitive quality (MRR/nDCG) vs ripgrep across all query types.
531
+ - ripgrep remains a useful speed-oriented lexical baseline but has significantly lower retrieval relevance for intent-style queries.
532
+ - Plugin is the fastest tool at p50 (~17ms), ahead of ripgrep (~36ms) and ast-grep (~67ms).
533
+ - Reported numbers are rounded to avoid false precision; use report artifacts for full per-repeat audit trails.
534
+
535
+ For reproducible setup and commands (including with/without reindex), see:
536
+
537
+ - `docs/benchmarking-cross-repo.md`
538
+
377
539
  ### Embedding Providers
378
540
  The plugin automatically detects available credentials in this order:
379
541
  1. **GitHub Copilot** (Free if you have it)
@@ -411,79 +573,22 @@ ollama pull nomic-embed-text
411
573
 
412
574
  ## šŸ“ˆ Performance
413
575
 
414
- The plugin is built for speed with a Rust native module. Here are typical performance numbers (Apple M1):
415
-
416
- ### Parsing (tree-sitter)
417
-
418
- | Files | Chunks | Time |
419
- |-------|--------|------|
420
- | 100 | 1,200 | ~7ms |
421
- | 500 | 6,000 | ~32ms |
422
-
423
- ### Vector Search (usearch)
424
-
425
- | Index Size | Search Time | Throughput |
426
- |------------|-------------|------------|
427
- | 1,000 vectors | 0.7ms | 1,400 ops/sec |
428
- | 5,000 vectors | 1.2ms | 850 ops/sec |
429
- | 10,000 vectors | 1.3ms | 780 ops/sec |
430
-
431
- ### Database Operations (SQLite with batch)
576
+ The plugin is built for speed with a Rust native module (`tree-sitter`, `usearch`, SQLite). In practice, indexing and retrieval remain fast enough for interactive use on medium/large repositories.
432
577
 
433
- | Operation | 1,000 items | 10,000 items |
434
- |-----------|-------------|--------------|
435
- | Insert chunks | 4ms | 44ms |
436
- | Add to branch | 2ms | 22ms |
437
- | Check embedding exists | <0.01ms | <0.01ms |
578
+ - Typical query latency: ~800-1000ms (mostly embedding API time)
579
+ - Incremental indexing: only changed files are re-embedded
580
+ - Batch DB operations: significant write-speed improvements for large indexes
438
581
 
439
- ### Batch vs Sequential Performance
440
-
441
- Batch operations provide significant speedups:
442
-
443
- | Operation | Sequential | Batch | Speedup |
444
- |-----------|------------|-------|---------|
445
- | Insert 1,000 chunks | 38ms | 4ms | **~10x** |
446
- | Add 1,000 to branch | 29ms | 2ms | **~14x** |
447
- | Insert 1,000 embeddings | 59ms | 40ms | **~1.5x** |
448
-
449
- Run benchmarks yourself: `npx tsx benchmarks/run.ts`
582
+ For reproducible measurements on your machine, run: `npx tsx benchmarks/run.ts`.
450
583
 
451
584
  ## šŸŽÆ Choosing a Provider
452
585
 
453
- Use this decision tree to pick the right embedding provider:
586
+ Quick recommendation:
454
587
 
455
- ```
456
- ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
457
- │ Do you have Copilot? │
458
- ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
459
- ā”Œā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”
460
- YES NO
461
- │ │
462
- ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā–¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” │
463
- │ Codebase < 1k │ │
464
- │ files? │ │
465
- ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ │
466
- ā”Œā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā” │
467
- YES NO │
468
- │ │ │
469
- ā–¼ │ │
470
- ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” │ │
471
- │ Copilot │ │ │
472
- │ (free) │ │ │
473
- ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ │ │
474
- ā–¼ ā–¼
475
- ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
476
- │ Need fastest indexing? │
477
- ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
478
- ā”Œā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”
479
- YES NO
480
- │ │
481
- ā–¼ ā–¼
482
- ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
483
- │ Ollama │ │ OpenAI or │
484
- │ (local) │ │ Google │
485
- ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
486
- ```
588
+ - **Want local + private + fast indexing** → use **Ollama**
589
+ - **Already have Copilot and a smaller repo** → use **GitHub Copilot**
590
+ - **General cloud setup** → use **OpenAI** or **Google**
591
+ - **Custom/OpenAI-compatible endpoint** → use **custom** provider
487
592
 
488
593
  ### Provider Comparison
489
594
 
@@ -499,35 +604,13 @@ Use this decision tree to pick the right embedding provider:
499
604
 
500
605
  ### Setup by Provider
501
606
 
502
- **Ollama (Recommended for large codebases)**
503
- ```bash
504
- ollama pull nomic-embed-text
505
- ```
506
- ```json
507
- { "embeddingProvider": "ollama" }
508
- ```
509
-
510
- **OpenAI**
511
- ```bash
512
- export OPENAI_API_KEY=sk-...
513
- ```
514
- ```json
515
- { "embeddingProvider": "openai" }
516
- ```
607
+ Set the provider in `.opencode/codebase-index.json`:
517
608
 
518
- **Google**
519
- ```bash
520
- export GOOGLE_API_KEY=...
521
- ```
522
609
  ```json
523
- { "embeddingProvider": "google" }
610
+ { "embeddingProvider": "ollama" }
524
611
  ```
525
612
 
526
- **GitHub Copilot**
527
- No setup needed if you have an active Copilot subscription.
528
- ```json
529
- { "embeddingProvider": "github-copilot" }
530
- ```
613
+ Credentials (if required) are read from environment variables (for example `OPENAI_API_KEY` or `GOOGLE_API_KEY`).
531
614
 
532
615
  **Custom (OpenAI-compatible)**
533
616
  Works with any server that implements the OpenAI `/v1/embeddings` API format (llama.cpp, vLLM, text-embeddings-inference, LiteLLM, etc.).
@@ -535,16 +618,17 @@ Works with any server that implements the OpenAI `/v1/embeddings` API format (ll
535
618
  {
536
619
  "embeddingProvider": "custom",
537
620
  "customProvider": {
538
- "baseUrl": "http://localhost:11434/v1",
621
+ "baseUrl": "{env:EMBED_BASE_URL}",
539
622
  "model": "nomic-embed-text",
540
623
  "dimensions": 768,
541
- "apiKey": "optional-api-key",
624
+ "apiKey": "{env:EMBED_API_KEY}",
542
625
  "maxTokens": 8192,
543
- "timeoutMs": 30000
626
+ "timeoutMs": 30000,
627
+ "maxBatchSize": 64
544
628
  }
545
629
  }
546
630
  ```
547
- Required fields: `baseUrl`, `model`, `dimensions` (positive integer). Optional: `apiKey`, `maxTokens`, `timeoutMs` (default: 30000).
631
+ Required fields: `baseUrl`, `model`, `dimensions` (positive integer). Optional: `apiKey`, `maxTokens`, `timeoutMs` (default: 30000), `maxBatchSize` (or `max_batch_size`) to cap inputs per `/embeddings` request for servers like text-embeddings-inference. `{env:VAR_NAME}` placeholders are resolved before config validation for fields that are actually used and throw if the referenced environment variable is missing or malformed.
548
632
 
549
633
  ## āš ļø Tradeoffs
550
634
 
@@ -578,14 +662,33 @@ Be aware of these characteristics:
578
662
 
579
663
  ## šŸ¤ Contributing
580
664
 
581
- 1. Fork the repository
582
- 2. Create a feature branch: `git checkout -b feature/my-feature`
583
- 3. Make your changes and add tests
584
- 4. Run checks: `npm run build && npm run test:run && npm run lint`
585
- 5. Commit: `git commit -m "feat: add my feature"`
586
- 6. Push and open a pull request
665
+ For contribution workflow, standards, and release-label requirements, see [`CONTRIBUTING.md`](./CONTRIBUTING.md).
666
+
667
+ If you want to add support for a new language, see [`docs/adding-language-support.md`](./docs/adding-language-support.md) for the full Rust + TypeScript checklist.
668
+
669
+ Quick path:
670
+
671
+ 1. Fork + branch
672
+ 2. Implement + tests
673
+ 3. Run checks: `npm run build && npm run typecheck && npm run lint && npm run test:run`
674
+ 4. Open PR with a release category label
675
+
676
+ ### Release process (structured + complete notes)
677
+
678
+ To ensure release notes reflect all merged work, this repo uses a draft-release workflow.
679
+
680
+ 1. **Label every PR** with at least one semantic label:
681
+ - `feature`, `bug`, `performance`, `documentation`, `dependencies`, `refactor`, `test`, `chore`
682
+ - and (when relevant) `semver:major`, `semver:minor`, or `semver:patch`
683
+ - PRs are validated by CI (`Release Label Check`) and fail if no release category label is present
684
+ 2. **Let Release Drafter build the draft notes** automatically from merged PRs on `main`.
685
+ 3. **Before publishing**:
686
+ - copy/finalize relevant highlights into `CHANGELOG.md`
687
+ - bump `package.json` version
688
+ - run: `npm run build && npm run typecheck && npm run lint && npm run test:run`
689
+ 4. **Publish release** from the draft (or via `gh release create` after reviewing draft content).
587
690
 
588
- CI will automatically run tests and type checking on your PR.
691
+ PRs labeled `skip-changelog` are intentionally excluded from release notes.
589
692
 
590
693
  ### Project Structure
591
694
 
@@ -0,0 +1,24 @@
1
+ ---
2
+ description: Find where a symbol is defined in the codebase
3
+ ---
4
+
5
+ Find the authoritative definition of a symbol in the codebase.
6
+
7
+ User input: $ARGUMENTS
8
+
9
+ The input is a symbol name or description of what to find the definition of.
10
+
11
+ Look for optional parameters:
12
+ - `limit=N` or "top N" → set limit
13
+ - `dir=X` or "in folder X" → set directory filter
14
+ - File extensions like ".ts", ".py" → set fileType
15
+
16
+ Call `implementation_lookup` with the parsed arguments.
17
+
18
+ Examples:
19
+ - `/definition validateToken` → query="validateToken"
20
+ - `/definition payment handler` → query="payment handler"
21
+ - `/definition createSystem dir=packages/react` → query="createSystem", directory="packages/react"
22
+
23
+ This prioritizes real implementation files over tests, docs, and examples.
24
+ If no definition is found, suggest using `codebase_search` for broader discovery.