This document covers every configuration knob in semcode: environment variables read from .env, the config.yaml service definitions, and the startup validation that fires when the embedding provider and Qdrant collection dimensions conflict.
semcode is configured through two files:
.env— environment variables for infrastructure settings (embedding provider, Qdrant URL, GitHub token, server port). Loaded bypydantic-settingsat startup.config.yaml— service definitions: which GitHub repositories to index, under what names, and with what filters. Loaded on demand bysettings.load_services().
A config.example.yaml is provided in the repository root as a starting point.
All variables are optional with the shown defaults, except where marked required.
| Variable | Default | Description |
|---|---|---|
EMBEDDINGS_PROVIDER |
jina |
Dense embedding provider. One of: jina, jina-api, voyage, openai, ollama. |
Only one provider is active at a time. Changing this variable requires a server restart. If the existing Qdrant collection was created with a different provider's dimension count, a startup error will occur on the next index run (see Startup Validation).
Used when EMBEDDINGS_PROVIDER=jina. Requires a running HuggingFace Text Embeddings Inference server.
| Variable | Default | Description |
|---|---|---|
JINA_URL |
http://localhost:8087 |
TEI server base URL |
JINA_MODEL |
jinaai/jina-embeddings-v2-base-code |
Model name (informational — the TEI server manages the loaded model) |
JINA_DIMENSIONS |
768 |
Output vector size. Must match the model loaded in TEI. |
Used when EMBEDDINGS_PROVIDER=jina-api.
| Variable | Default | Description |
|---|---|---|
JINA_API_KEY |
— | Required. Jina AI API key. |
JINA_API_MODEL |
jina-embeddings-v2-base-code |
Model name. Known models: jina-embeddings-v2-base-code (768), jina-code-embeddings-0.5b (896), jina-code-embeddings-1.5b (1536). |
JINA_API_DIMENSIONS |
None |
Optional Matryoshka truncation. When set, the API shrinks vectors to this size. |
Used when EMBEDDINGS_PROVIDER=voyage.
| Variable | Default | Description |
|---|---|---|
VOYAGE_API_KEY |
— | Required. Voyage AI API key. |
VOYAGE_MODEL |
voyage-code-3 |
Model name. Known models and native dims: voyage-code-3 (1024), voyage-3 (1024), voyage-3-large (1024), voyage-3-lite (512), voyage-large-2 (1536), voyage-code-2 (1536). |
VOYAGE_DIMENSIONS |
None |
Optional output dimension override (Matryoshka). |
Used when EMBEDDINGS_PROVIDER=openai.
| Variable | Default | Description |
|---|---|---|
OPENAI_API_KEY |
— | Required. OpenAI API key. |
OPENAI_EMBEDDING_MODEL |
text-embedding-3-large |
Model name. Known models and native dims: text-embedding-3-large (3072), text-embedding-3-small (1536), text-embedding-ada-002 (1536). |
OPENAI_DIMENSIONS |
None |
Optional Matryoshka truncation. |
Used when EMBEDDINGS_PROVIDER=ollama. Requires a running Ollama instance with the target model pulled.
| Variable | Default | Description |
|---|---|---|
OLLAMA_URL |
http://localhost:11434 |
Ollama server base URL |
OLLAMA_MODEL |
nomic-embed-text |
Model name. Known models and dims: nomic-embed-text (768), mxbai-embed-large (1024), all-minilm (384), snowflake-arctic-embed (1024), bge-m3 (1024). |
OLLAMA_DIMENSIONS |
None |
Required for unknown models — set to the model's output dimension. |
| Variable | Default | Description |
|---|---|---|
QDRANT_URL |
http://localhost:6333 |
Qdrant server URL |
QDRANT_COLLECTION |
code_symbols |
Collection name for code symbol vectors |
QDRANT_COMMITS_COLLECTION |
git_commits |
Collection name for git commit history vectors |
| Variable | Default | Description |
|---|---|---|
MCP_TRANSPORT |
streamable-http |
Transport protocol. One of: streamable-http, sse, stdio. |
MCP_HOST |
127.0.0.1 |
Bind address |
MCP_PORT |
8090 |
Listen port |
| Variable | Default | Description |
|---|---|---|
GITHUB_TOKEN |
"" |
GitHub personal access token. Required for all indexing operations. Without it, GitHub API calls return 403. |
CONFIG_PATH |
./config.yaml |
Path to the services config file. Relative to the working directory at server start. |
GIT_HISTORY_MAX_COMMITS |
500 |
Maximum number of commits fetched per service for git history indexing. |
EMBEDDING_MAX_CHARS |
provider-aware — see below | Max characters of a symbol's dense-embedding text (preamble + signature + docstring + source). Oversized symbols are truncated (with a logged WARNING). Set this explicitly to override the derived default for any provider. |
Since providers differ hugely in context window (2K–32K tokens), EMBEDDING_MAX_CHARS defaults to a value derived from EMBEDDINGS_PROVIDER's default model (~3 chars/token, ~10% safety margin for the preamble). This is a per-provider default, not per-model — if you change *_MODEL to a model with a smaller or larger window than the provider's default, set EMBEDDING_MAX_CHARS explicitly.
EMBEDDINGS_PROVIDER |
Default model | Max input tokens | Derived EMBEDDING_MAX_CHARS default |
|---|---|---|---|
jina |
jinaai/jina-embeddings-v2-base-code |
8,192 | 22,000 |
jina-api |
jina-embeddings-v2-base-code |
8,192 | 22,000 |
voyage |
voyage-code-3 |
32,000 | 86,000 |
openai |
text-embedding-3-large |
8,192 | 22,000 |
ollama |
nomic-embed-text |
2,048 | 5,500 |
Note: self-hosted Jina TEI (jina) does not trim oversized inputs server-side and will error past the model's true token limit, so avoid setting EMBEDDING_MAX_CHARS far above the default for that provider. voyage/openai/jina-api trim oversized inputs server-side, so headroom there is safer.
config.yaml defines the services (repositories) to index. It is read fresh on every indexing request — changes take effect on the next index run without a server restart.
services:
- name: catalog-service # required — used as path prefix in Qdrant
github_repo: my-org/my-repo # required — GitHub repo in "org/repo" format
github_ref: main # optional — branch, tag, or commit SHA (default: "main")
root: services/catalog # optional — only index files under this path prefix
exclude: # optional — glob patterns to skip
- "**/test/**"
- "**/target/**"
- "**/*.generated.java"name — becomes the service prefix in all stored file paths ({name}/{path_in_repo}) and in Qdrant payload service field. Must be unique across services.
github_ref — can be a branch name, tag, or full commit SHA. Using a commit SHA pins the index to a specific snapshot.
root — useful for monorepos. Only files under root/ are indexed; the root/ prefix is stripped from stored paths.
exclude — fnmatch glob patterns matched against both the full file path and the basename. Common patterns: **/test/**, **/target/**, **/build/**, **/*.generated.*.
QdrantStore.ensure_collection() runs in the server's lifespan context (server/main.py:39) — at boot, before any requests are served. If the Qdrant collection already exists, its vector dimension is compared against the configured provider's dimensions value. A mismatch raises:
RuntimeError: Qdrant collection 'code_symbols' was created with vector size 768,
but the configured embedding provider produces vectors of size 1024. Either revert
EMBEDDINGS_PROVIDER to the original setting, or drop the collection (this deletes
the existing index) and reindex.
This error aborts server startup — the server will not accept connections until the mismatch is resolved.
To switch embedding providers on an existing index:
- Stop the server
- Drop the Qdrant collection (via Qdrant dashboard or API)
- Update
EMBEDDINGS_PROVIDER(and related vars) in.env - Start the server —
ensure_collection()will recreate the collection with the new dimensions - Trigger a full reindex
load_services() reads from disk on every call — there is no in-memory cache for config.yaml. Adding, removing, or renaming services takes effect on the next index run without restarting. The downside is a file I/O operation on every indexing request.
API keys are not validated at startup — unlike dimension validation (which crashes startup), JINA_API_KEY, VOYAGE_API_KEY, and OPENAI_API_KEY are checked only in the provider constructor, which is deferred to first use. A missing key causes a RuntimeError on the first embedding request, not at boot. A server configured with a valid Qdrant collection but a missing API key will start successfully and fail only when indexing is first attempted.
CONFIG_PATH is cwd-relative — the default ./config.yaml is resolved relative to the working directory at server start, not relative to the binary or the project root. If the server is started from a different directory, the config file will not be found.
GITHUB_TOKEN defaults to empty string — a missing token doesn't prevent server startup; it causes a 403 from the GitHub API on the first indexing request.
No Qdrant authentication configuration — only the URL is configurable. There is no way to configure a Qdrant API key, TLS certificates, or authentication headers. Qdrant running with authentication enabled requires code changes.