grepai

Configuration

Reference for .grepai/config.yaml - embedder, vector store, chunking, ignore rules (.gitignore, .grepaiignore), search tuning and API keys.

This page documents .grepai/config.yaml, the per-project configuration file. Read it when you want to change the embedding provider, the storage backend, what gets indexed, or how results are ranked.

Config File Location

grepai stores its configuration in .grepai/config.yaml at your project root. grepai init creates it with defaults. Commands look for .grepai/ in the current directory and then in each parent directory, so you can run them from any subfolder.

The most common change is switching the embedder. For example, to use OpenAI instead of Ollama:

embedder:
  provider: openai
  model: text-embedding-3-small
  endpoint: https://api.openai.com/v1
export OPENAI_API_KEY="sk-..."
grepai index

Note: Changing the embedder model or dimensions makes existing vectors incompatible. Delete the index (rm .grepai/index.gob for the GOB store) and re-index. The same applies to chunking changes: files already indexed are not re-chunked until they change.

Multi-project workspaces use a separate file, ~/.grepai/workspace.yaml. See Workspace Management.

Full Configuration Reference

This is the file that grepai init --yes generates, shortened and annotated. Keys you omit fall back to defaults when the file is loaded, except where noted.

version: 1

embedder:
  provider: ollama              # ollama | lmstudio | openai | openrouter | synthetic | requesty
  model: nomic-embed-text
  endpoint: http://localhost:11434
  dimensions: 768               # vector size; see "Embedder Options"
  # api_key: ""                 # cloud providers; prefer an environment variable
  # parallelism: 4              # concurrent requests (openai only), default 4
  # request_timeout_seconds: 60 # HTTP timeout per request; default 60 (90 for synthetic), ignored by requesty
  # max_retries: 5              # retries on HTTP 429/5xx (openai only)
  # max_batch_size: 2000        # inputs per request (openai only)
  # max_batch_tokens: 280000    # estimated tokens per request (openai only)

store:
  backend: gob                  # gob | postgres | qdrant
  # postgres:
  #   dsn: postgres://user:pass@localhost:5432/grepai
  # qdrant:
  #   endpoint: localhost
  #   port: 6334
  #   use_tls: false
  #   collection: ""            # default: derived from the project path
  #   api_key: ""               # for Qdrant Cloud

chunking:
  size: 512                     # chunk budget in tokens (estimated as 4 characters per token)
  overlap: 50                   # tokens shared by neighboring chunks
  strategy: fixed               # fixed | ast (experimental)
  # custom_extensions:          # extra file extensions to index
  #   - .tengo
  #   - .prisma

framework_processing:           # pre-processing of framework single-file components
  enabled: true
  mode: auto                    # auto | require | off
  node_path: node               # command in PATH or absolute path outside the project
  frameworks:
    vue:
      enabled: true
    svelte:
      enabled: false
    astro:
      enabled: false
    solid:
      enabled: false

watch:
  debounce_ms: 500              # wait time before processing a burst of file events
  # discover_worktrees: true    # also watch linked git worktrees (read from the main worktree only)
  # last_index_time: ...        # written by grepai watch/index, do not edit
  rpg_persist_interval_ms: 1000 # RPG settings, see the RPG page
  rpg_derived_debounce_ms: 300
  rpg_full_reconcile_interval_sec: 300
  rpg_max_dirty_files_per_batch: 128

search:
  boost:
    enabled: true
    penalties:                  # 17 default rules (tests, mocks, fixtures, generated code, docs)
      - pattern: _test.
        factor: 0.5
    bonuses:                    # 3 default rules (/src/, /lib/, /app/)
      - pattern: /src/
        factor: 1.1
  hybrid:
    enabled: false
    k: 60
  dedup:
    enabled: true               # keep only the best chunk per file

trace:
  enabled_languages:            # extensions included in the symbol index
    - .go
    - .js
    - .ts
    # ... .jsx .tsx .vue .py .php .lua .gd .rb .c .h .cpp .hpp .cc .cxx .hxx
    #     .rs .zig .cs .java .fs .fsx .fsi .pas .dpr

rpg:
  enabled: false                # Repository Planning Graph, see the RPG page
  feature_mode: local
  drift_threshold: 0.35
  max_traversal_depth: 3
  llm_provider: ollama
  llm_endpoint: http://localhost:11434/v1
  llm_timeout_ms: 8000
  feature_group_strategy: sample

ignore:                         # directory or file names skipped everywhere
  - .git
  - .grepai
  - node_modules
  - vendor
  - bin
  - dist
  - __pycache__
  - .venv
  - venv
  - .idea
  - .vscode
  - target
  - .zig-cache
  - zig-out
  - qdrant_storage

# external_gitignore: "~/.config/git/ignore"

Notes on specific keys:

  • ignore replaces the default list when you set it. Copy the defaults if you want to keep them.
  • search has no load-time defaults. If your config has no search: section (for example, an older file), boost and deduplication are off. Run grepai init in a scratch directory to get the current defaults.
  • Older config files may still contain trace.mode, trace.exclude_patterns, update.check_on_startup or rpg.store_path. These keys never had any effect and were removed; grepai ignores them and drops them the next time it saves the file.
  • framework_processing runs a Node.js script to compile Vue single-file components before embedding and tracing. Only the Vue processor is implemented; the Svelte, Astro and Solid entries are placeholders. With mode: auto, grepai falls back to the raw file if Node or the Vue compiler is missing. require fails instead, and off disables processing.
  • The rpg section and watch.rpg_* keys are described in Repository Planning Graph.

Embedder Options

The embedder turns code chunks and queries into vectors. If you do not set endpoint, grepai uses the provider’s default. dimensions must match the vector size of your model:

ProviderDefault modelDefault endpointDefault dimensionsAPI key environment variable
ollamanomic-embed-texthttp://localhost:11434768none
lmstudiotext-embedding-nomic-embed-text-v1.5http://127.0.0.1:1234768none
openaitext-embedding-3-smallhttps://api.openai.com/v1model’s native sizeOPENAI_API_KEY
openrouteropenai/text-embedding-3-smallhttps://openrouter.ai/api/v1model’s native sizeOPENROUTER_API_KEY, then OPENAI_API_KEY
synthetichf:nomic-ai/nomic-embed-text-v1.5https://api.synthetic.new/openai/v1768SYNTHETIC_API_KEY, then OPENAI_API_KEY
requestyopenai/text-embedding-3-smallhttps://router.requesty.ai/v1model’s native sizeREQUESTY_API_KEY, then OPENAI_API_KEY

For openai, openrouter and requesty, leave dimensions unset to use the model’s native size: 1536 for text-embedding-3-small, 3072 for text-embedding-3-large, 4096 for qwen/qwen3-embedding-8b. For local providers, set dimensions yourself when you use a model other than the default.

See Embedders for setup details for each provider.

embedder:
  provider: ollama
  model: nomic-embed-text
  endpoint: http://localhost:11434
  dimensions: 768

Pull the model first with ollama pull nomic-embed-text. To use another model, pull it and set model and dimensions to match. Common choices:

ModelDimensionsNotes
nomic-embed-text768Default, English
nomic-embed-text-v2-moe768Multilingual
bge-m31024Multilingual
mxbai-embed-large1024Larger, slower
all-minilm384Small and fast

For example, for a codebase with comments in several languages:

embedder:
  provider: ollama
  model: nomic-embed-text-v2-moe
  endpoint: http://localhost:11434
  dimensions: 768

LM Studio (Local)

Start the LM Studio local server and load an embedding model, then:

embedder:
  provider: lmstudio
  model: text-embedding-nomic-embed-text-v1.5
  endpoint: http://127.0.0.1:1234
  dimensions: 768

Set model to the identifier LM Studio shows for the loaded model, and dimensions to its vector size.

OpenAI (Cloud)

embedder:
  provider: openai
  model: text-embedding-3-small   # or text-embedding-3-large
  endpoint: https://api.openai.com/v1
  parallelism: 4                  # concurrent requests, lowered automatically on rate limits

Set your key in the environment with export OPENAI_API_KEY="sk-...". You can also put the key in api_key, but then it is stored in plain text in config.yaml.

Azure OpenAI / Microsoft Foundry

The openai provider works with any endpoint that implements the OpenAI embeddings API. grepai sends POST <endpoint>/embeddings with an Authorization: Bearer <api_key> header.

embedder:
  provider: openai
  model: text-embedding-ada-002     # your deployment's model name
  endpoint: https://YOUR-RESOURCE.openai.azure.com/v1
  dimensions: 1536

Provide the key with api_key. OPENAI_API_KEY is only sent to the official api.openai.com endpoint, never to a custom one.

Storage Options

The store keeps the vectors and runs similarity search.

GOB (File-based - Default)

store:
  backend: gob

The index is a single file, .grepai/index.gob, next to the symbol index .grepai/symbols.gob. No server is needed. This is the right choice for most single-developer projects.

PostgreSQL with pgvector

store:
  backend: postgres
  postgres:
    dsn: postgres://user:pass@localhost:5432/grepai

On startup, grepai runs CREATE EXTENSION IF NOT EXISTS vector and creates its tables. The database user needs permission to do this, or an administrator must create the vector extension first. A shared database lets several projects or worktrees use one index.

Note: grepai init -b postgres --yes writes the default DSN postgres://localhost:5432/grepai. Change store.postgres.dsn if your database uses another host, user or name.

Qdrant

store:
  backend: qdrant
  qdrant:
    endpoint: localhost
    port: 6334          # gRPC port
    use_tls: false

To start Qdrant locally with Docker:

docker run -p 6333:6333 -p 6334:6334 qdrant/qdrant

For Qdrant Cloud, set use_tls: true and api_key. If collection is empty, grepai derives a collection name from the project path.

See Vector Stores for detailed configuration options.

Ignoring Files

grepai indexes files with a supported source extension (Go, Python, JavaScript/TypeScript, Java, C/C++, Rust, PHP, Ruby, Markdown and more). It skips binary files, minified files (such as *.min.js) and files larger than 1 MB. To index another extension, add it to chunking.custom_extensions (with the leading dot).

To exclude files, grepai combines these sources:

  1. .gitignore files at any level of the project.
  2. ignore in config.yaml: names or gitignore-style patterns applied from the project root.
  3. .grepaiignore files at any level of the project. They use gitignore syntax and take precedence over .gitignore.
  4. external_gitignore: an extra gitignore file outside the project (see External Gitignore).

Use .grepaiignore to exclude files from grepai without touching .gitignore, or to index files that Git ignores:

# .grepaiignore
# Do not index generated fixtures
testdata/golden/

# Index this file even though .gitignore excludes it
!config/local.example.go

A negation (!pattern) in .grepaiignore overrides a .gitignore at the same level or above. A .gitignore in a deeper directory still wins.

Chunking Tuning

chunking:
  size: 512    # tokens per chunk
  overlap: 50  # tokens shared between neighboring chunks

grepai estimates tokens as 4 characters per token.

  • Larger chunks: more context per result, fewer chunks to embed.
  • Smaller chunks: more precise matches, more chunks to embed.
  • More overlap: better continuity across chunk boundaries, larger index.

Chunking Strategy

Experimental: the ast strategy may change in future releases, which can require re-indexing. fixed is the default and recommended strategy.

chunking:
  strategy: ast  # "fixed" (default) or "ast"
  • fixed (default): splits files into windows of chunking.size tokens, with chunking.overlap tokens shared between neighboring chunks.
  • ast: parses the file with tree-sitter and splits it along syntax boundaries (functions, classes, declarations) using the cAST algorithm. Small neighboring nodes are merged up to the size budget, and nodes larger than the budget are split into their children. A chunk is usually a whole function or a group of related declarations.

With ast, chunking.size is still the budget, counted in non-whitespace characters (4 per token), and chunking.overlap is not used. Supported files are .go, .py, .js, .jsx, .ts and .tsx. Other files, and files nested too deeply to split, use the fixed chunker.

Note: ast requires a build with the treesitter build tag and CGO (go build -tags treesitter ./cmd/grepai). The prebuilt release binaries do not include it. Without it, or with an unknown strategy name, grepai logs a warning and uses fixed.

Changing the strategy does not re-chunk files that are already indexed. To apply it to the whole project, delete the index (rm .grepai/index.gob for the default GOB store) and run grepai index or grepai watch again.

Automatic Re-chunking

If a chunk is larger than the embedder’s context limit, grepai splits it and retries:

  1. grepai sends the chunk to the embedder.
  2. If the embedder returns a context-length error, grepai splits that chunk into smaller pieces (half the size).
  3. It retries, with up to 3 re-chunking attempts in total.

You will see log messages like:

Re-chunking large_file.go chunk 0 (attempt 1/3): context limit exceeded
Split chunk into 2 sub-chunks

This is a safety net: with the default size: 512, you should rarely see it.

Search Options

These settings change how results are ranked. They apply to grepai search and the MCP search tool in single-project mode. Workspace searches use the built-in defaults.

Search Boost (enabled by default)

Multiplies each result’s score by a factor based on its file path. Patterns are case-sensitive substring matches on the project-relative path. When several rules match, their factors are multiplied. The default rules lower the score of tests, mocks, fixtures, generated code and docs, and raise /src/, /lib/ and /app/.

search:
  boost:
    enabled: true
    penalties:
      - pattern: "_test."
        factor: 0.5
    bonuses:
      - pattern: "/src/"
        factor: 1.1

See Search Boost for full documentation.

Hybrid Search (disabled by default)

Combines vector similarity with text matching using Reciprocal Rank Fusion (RRF). k is the RRF constant.

search:
  hybrid:
    enabled: true
    k: 60

See Hybrid Search for full documentation.

Result Deduplication (enabled by default)

When search.dedup.enabled is true, grepai keeps only the highest-scoring chunk for each file, so one large file cannot fill all the results.

search:
  dedup:
    enabled: true

External Gitignore

Use external_gitignore to apply a gitignore file that lives outside the project, such as your global Git ignore file:

external_gitignore: "~/.config/git/ignore"

Common locations:

  • ~/.config/git/ignore (XDG default)
  • ~/.gitignore_global (older convention)

A leading ~ expands to your home directory. Patterns apply from the project root. If the file does not exist, grepai logs a warning and continues.

Environment Variables

grepai does not expand variables inside config.yaml. A value such as api_key: ${OPENAI_API_KEY} is sent literally as the key. Instead, leave api_key empty and set the provider’s environment variable:

ProviderVariables read (in order)
openaiOPENAI_API_KEY
openrouterOPENROUTER_API_KEY, OPENAI_API_KEY
syntheticSYNTHETIC_API_KEY, OPENAI_API_KEY
requestyREQUESTY_API_KEY, OPENAI_API_KEY
export OPENAI_API_KEY="sk-..."
grepai watch

These variables are only used when endpoint is the provider’s official endpoint (api.openai.com, openrouter.ai, api.synthetic.new, router.requesty.ai, over HTTPS). With a custom endpoint, set api_key in the config: grepai refuses to send an environment key to it and stops with an error.

An api_key set in config.yaml takes precedence over the environment. Other settings, such as the provider or the backend, cannot be overridden with environment variables: edit config.yaml instead.