Semantic search over project documentation for AI coding agents
Project description
gy-doc-search
gy-doc-search is a reusable CLI and MCP server for building a local retrieval layer over project documentation and other UTF-8 text sources.
It is designed for AI coding workflows where "search the docs" needs to mean more than keyword grep. gy-doc-search turns documentation into stable, source-aware chunks, keeps them incrementally indexed, and serves the most relevant sections back through either a CLI or an MCP interface. That makes it suitable both as a developer tool you run in a terminal and as infrastructure behind coding agents that need grounded answers.
A few characteristics make it distinct:
- local-first operation with a simple project-level config and no required external service
- dual interface: direct CLI for humans, MCP server mode for agent integrations
- resilient retrieval stack with semantic search, optional hybrid BM25 fusion, and optional reranking
- per-source chunking profiles, so API references, ADRs, runbooks, and specs can be indexed differently
- incremental indexing with file change detection, plus a fallback local store when Chroma is not installed
- evaluation tooling for measuring retrieval quality before changing chunking or embedding settings
Markdown is the primary target because headings, sections, and front matter are preserved as metadata. In practice, the indexer can ingest any UTF-8 text file that matches a configured glob. Files without Markdown headings are still indexed as plain-text documents, but Markdown-shaped sources produce the best chunk boundaries and retrieval quality.
Quickstart
pip install gy-doc-search
gy-doc-search init --sources ./docs
gy-doc-search index
gy-doc-search query "how authentication works"
Supported File Types
gy-doc-search does not enforce a fixed list of extensions. Each source entry chooses which files are indexed through its filter glob:
- best-supported:
.md,.mdx, and other Markdown-like text with#headings - also workable:
.txt,.rst,.adoc, or project-specific text formats, as long as they are UTF-8 - skipped at chunking time: non-UTF-8 files
Examples:
sources:
- path: "./docs"
filter: "*.md"
sources:
- path: "./docs"
filter: "*.mdx"
sources:
- path: "./handbook"
filter: "*.txt"
sources:
- path: "./specs"
filter: "*.rst"
You can mix source types by declaring multiple entries:
sources:
- path: "./docs"
filter: "*.md"
profile: "docs"
- path: "./guides"
filter: "*.mdx"
profile: "docs"
- path: "./runbooks"
filter: "*.txt"
profile: "plain_text"
- path: "./specs"
filter: "*.rst"
profile: "plain_text"
chunking:
default_profile: "docs"
profiles:
docs:
min_chunk_tokens: 60
max_chunk_tokens: 240
target_chunk_tokens: 160
overlap_tokens: 30
heading_levels: [1, 2, 3, 4]
plain_text:
min_chunk_tokens: 80
max_chunk_tokens: 260
target_chunk_tokens: 180
overlap_tokens: 40
heading_levels: [1, 2]
If you want to include multiple extensions from the same directory, declare multiple source entries with different filter values:
sources:
- path: "./content"
filter: "*.md"
- path: "./content"
filter: "*.mdx"
- path: "./content"
filter: "*.txt"
CLI Interface
# Initialize in a new project
gy-doc-search init # Creates .doc-search/ with default config
gy-doc-search init --sources ./docs ./specs # Pre-fill source paths
# Indexing
gy-doc-search index # Full reindex
gy-doc-search index --incremental # Only changed files
gy-doc-search index --dry-run # Show what would change without indexing
# Querying
gy-doc-search query "payment auth flow"
gy-doc-search query "error codes" --top-k 10 --path "api/"
gy-doc-search query "deployment" --files-only
# Read a specific file
gy-doc-search get docs/api/payments.md
# List indexed sources
gy-doc-search list
gy-doc-search list --prefix "api/"
# MCP server mode (for Claude Code)
gy-doc-search serve # Starts MCP server on stdio
gy-doc-search serve --transport sse --port 8080 # SSE transport
# Maintenance
gy-doc-search status # Shows config, index freshness, stats
gy-doc-search clean # Wipes the vector store
gy-doc-search verify # Checks that indexed files still exist
# Evaluation
gy-doc-search eval --cases eval_cases.yaml
gy-doc-search eval --cases eval_cases.yaml --json
gy-doc-search eval --cases eval_cases.yaml --skip-index
Notes
- Project configuration lives in
.doc-search/config.yaml. gy-doc-searchauto-selects a storage backend:chromadbinstalled: persistent Chroma collection in.doc-search/.chroma/- no
chromadb: local JSON-backed store in.doc-search/.index/
- If
sentence-transformersis installed, semantic embeddings use the configured transformer model. Without it,gy-doc-searchfalls back to a built-in lexical hash embedder. - If
mcpis installed,gy-doc-search servestarts the MCP server for Claude Code or other MCP clients. gy-doc-search indexnow prints explicit phases during indexing, including config loading, file scanning, chunking, embedding, and index writes.
Evaluation
gy-doc-search eval is an offline benchmark command for tuning chunking and retrieval settings against labeled queries.
It exists because retrieval quality is highly project-specific. A documentation set full of API references behaves differently from architecture decision records, onboarding guides, incident runbooks, or product specs. The same chunk sizes, overlap, heading boundaries, embedding model, and retrieval settings will not perform equally well across all repositories.
The evaluation feature was built to address those differences directly. Instead of tuning gy-doc-search by intuition, you can define a representative set of queries for your own project, label the files and headings that should be retrieved, and measure how configuration changes affect actual outcomes. This makes the retrieval layer more defensible and much easier to adapt as a codebase grows or documentation habits change.
That is especially useful for coding agents. An agent can be prompted to use gy-doc-search eval as a feedback loop:
- establish a baseline with the current configuration
- adjust one part of the config, such as chunk sizing, heading levels, hybrid retrieval, or reranking
- rerun the evaluation
- compare hit rates, ranking quality, chunk counts, and latency
- keep the change only if the results improve for the project’s real query set
In other words, eval turns configuration tuning into an iterative workflow instead of a one-shot guess. That helps agents and humans converge on settings that are specific to the repository they are working in.
It measures:
- retrieval quality: primary hit rate, file hit rate, heading hit rate, MRR, and nDCG@k
- runtime behavior: index duration, average query latency, and peak RSS
- index shape: total files, total chunks, average chunk words, storage backend, and embedding model
The evaluation command uses a YAML file that defines expected files and headings for each query.
Example:
cases:
- id: payments-auth
query: "authorization funds"
relevant_files:
- "docs/payments.md"
relevant_headings:
- "Payments"
- id: settlement-close
query: "day closing settlement"
relevant_files:
- "docs/settlement.md"
relevant_headings:
- "Settlement"
Run it like this:
gy-doc-search eval --cases eval_cases.yaml
gy-doc-search eval --cases eval_cases.yaml --json
gy-doc-search eval --cases eval_cases.yaml --skip-index
Options:
--cases: path to the YAML evaluation file--top-k: override the retrieval depth for all evaluation queries--skip-index: reuse the current index instead of rebuilding it before evaluation--json: emit the full structured evaluation report as JSON
Recommended tuning workflow:
- Create 20-50 representative queries with labeled
relevant_filesand, when possible,relevant_headings. - Run
gy-doc-search evalwith the current configuration to establish a baseline. - Change one variable at a time, such as
min_chunk_tokens,max_chunk_tokens,target_chunk_tokens,overlap_tokens,heading_levels,hybrid_search, orreranking. - Rerun the evaluation and compare hit rate, MRR, nDCG, chunk counts, and latency across runs.
- Keep only changes that improve retrieval for the project’s labeled queries.
- Tune
embedding.batch_sizeseparately for runtime stability rather than retrieval quality.
Example agent prompt:
Use gy-doc-search eval to tune the retrieval config for this repository.
Start by running a baseline evaluation against the existing labeled cases.
Then iteratively adjust one retrieval or chunking parameter at a time.
After each run, compare the metrics and explain whether the change improved project-specific retrieval quality.
Stop when further changes no longer produce a clear improvement, and summarize the recommended config updates.
For lower-memory machines, start conservatively:
embedding:
provider: "sentence-transformers"
model_name: "all-MiniLM-L6-v2"
batch_size: 1
Co-authored by Taner Esme, Claude Code, and Codex.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gy_doc_search-0.1.0.tar.gz.
File metadata
- Download URL: gy_doc_search-0.1.0.tar.gz
- Upload date:
- Size: 32.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3e6e2a634b9a4dc22beb99101398c4688a68f95a863a98400f4919d0e2de1ce3
|
|
| MD5 |
b5aecfb6d91b10cdd5794857056af93f
|
|
| BLAKE2b-256 |
279f7627aa86eaed2143bc1c04af917bc1507fe22658eaeef62981918f361da0
|
Provenance
The following attestation bundles were made for gy_doc_search-0.1.0.tar.gz:
Publisher:
publish.yml on taneresme/gy-doc-search
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gy_doc_search-0.1.0.tar.gz -
Subject digest:
3e6e2a634b9a4dc22beb99101398c4688a68f95a863a98400f4919d0e2de1ce3 - Sigstore transparency entry: 1300115398
- Sigstore integration time:
-
Permalink:
taneresme/gy-doc-search@a8b7e2d1aabcd9832a16900f05cb534b1eeb9da9 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/taneresme
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a8b7e2d1aabcd9832a16900f05cb534b1eeb9da9 -
Trigger Event:
push
-
Statement type:
File details
Details for the file gy_doc_search-0.1.0-py3-none-any.whl.
File metadata
- Download URL: gy_doc_search-0.1.0-py3-none-any.whl
- Upload date:
- Size: 30.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff7e4a5e241346a81fb3d52c527f961c9725d1fdfdc2b160ff286d2a12c9b584
|
|
| MD5 |
60a1f256ce4b332448ec433553b753d1
|
|
| BLAKE2b-256 |
07a8fbda39557bc36a944c1593c8eea84b10e0c8ce4b5c239319f5f5f5ca6e51
|
Provenance
The following attestation bundles were made for gy_doc_search-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on taneresme/gy-doc-search
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gy_doc_search-0.1.0-py3-none-any.whl -
Subject digest:
ff7e4a5e241346a81fb3d52c527f961c9725d1fdfdc2b160ff286d2a12c9b584 - Sigstore transparency entry: 1300115565
- Sigstore integration time:
-
Permalink:
taneresme/gy-doc-search@a8b7e2d1aabcd9832a16900f05cb534b1eeb9da9 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/taneresme
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a8b7e2d1aabcd9832a16900f05cb534b1eeb9da9 -
Trigger Event:
push
-
Statement type: