Skip to content

Configuration ​

codemap uses XDG-style paths with CODEMAP_* environment overrides and an ecosystem fallback.

$XDG_CONFIG_HOME/codemap/config.yaml     # config        (~/.config/codemap/…)
$XDG_DATA_HOME/codemap/                   # graph DB, veclite store, project registry
$XDG_CACHE_HOME/codemap/                  # caches

If ~/.codemap/ already exists it is used (back-compat with the vecgrep/noted ecosystem). codemap init --local drops a .codemap marker so a repo-local codemap.yaml is picked up from any subdirectory (the project-file step below); the index itself stays central — set CODEMAP_DATA to a path inside the repo if you want a repo-local index too.

Precedence (highest → lowest) ​

  1. CLI flags (per-setting override flags — see Command-line flags below)
  2. Environment variables (CODEMAP_* — see Environment variables below)
  3. Project-root codemap.yaml / codemap.yml
  4. Project .config/codemap.yaml
  5. Global $XDG_CONFIG_HOME/codemap/config.yaml
  6. ~/.codemap/config.yaml (legacy, if present)
  7. Built-in defaults

Most config-file settings are reachable all three ways — config file, env var, and flag — with the flag winning when explicitly set. Four knobs are exceptions: daemon.embed_cache_size is file + flag only (no env var), index.extract_concurrency is file + env only (no flag), semantic.fusion_weights.* (the per-profile weight floats) is file-only (no env var, no flag) — semantic.backend and semantic.fusion are reachable all three ways — and embedding.api_key is file + env only (no flag, deliberately): flag values show up in ps/shell history, which a secret should never do. Use the config file or CODEMAP_OLLAMA_API_KEY instead (see Authenticated Ollama endpoints / Ollama Cloud).

Environment variables ​

Each overrides the corresponding config-file value (and takes precedence over it):

VariableOverrides
CODEMAP_CONFIGpath to a specific config file
CODEMAP_CONFIG_DIRthe config directory
CODEMAP_DATAthe data directory (graph DB, veclite store, project registry)
CODEMAP_CACHEthe cache directory
CODEMAP_EMBEDDING_PROVIDERembedding.provider (e.g. ollama)
CODEMAP_EMBEDDING_MODELembedding.model (e.g. nomic-embed-text)
CODEMAP_OLLAMA_URLembedding.ollama_url
CODEMAP_OLLAMA_API_KEYembedding.api_key (bearer token for Ollama Cloud or an authenticated Ollama-compatible endpoint)
CODEMAP_EMBEDDING_DIMENSIONSembedding.dimensions
CODEMAP_EMBEDDING_DISTANCEembedding.distance (e.g. cosine)
CODEMAP_EXCLUDE_EXTRAindex.exclude_extra (comma-separated; appended)
CODEMAP_EMBED_BATCH_SIZEindex.embed_batch_size
CODEMAP_EMBED_CONCURRENCYindex.embed_concurrency
CODEMAP_EXTRACT_CONCURRENCYindex.extract_concurrency (parallel Go extraction workers; LSP stays serial; no flag)
CODEMAP_EMBED_MAX_CHARSindex.embed_max_chars
CODEMAP_VECGREP_ENABLEDvecgrep.enabled
CODEMAP_VECGREP_BINvecgrep.bin
CODEMAP_DAEMON_DEBOUNCE_MSdaemon.debounce_ms
CODEMAP_DAEMON_IDLE_TIMEOUT_MINdaemon.idle_timeout_min
CODEMAP_DAEMON_PRECISEdaemon.precise (keep exact call edges current after watched edits)
CODEMAP_DAEMON_EMBED_RPSdaemon.embed_rps
CODEMAP_DAEMON_EMBED_MAX_IN_FLIGHTdaemon.embed_max_in_flight
CODEMAP_SEMANTIC_BACKENDsemantic.backend (fallback, local, or vecgrep)
CODEMAP_SEMANTIC_FUSIONsemantic.fusion (auto or balanced)
CODEMAP_MCP_PROFILEmcp.profile (agent, core, or full — see MCP tool profiles)

Typed environment values are validated when configuration loads. Invalid integers, numbers, or booleans stop the command with an error that names the variable; codemap does not silently fall back to a lower-precedence value. The rejected value is not echoed in the error message.

Command-line flags ​

Each config knob also has a flag, which wins over the file and env when set:

FlagSettingCommand(s)
--embed-provider / --embed-model / --ollama-url / --embed-dimensions / --embed-distanceembedding.*all (persistent)
--excludeindex.exclude (replaces defaults)index
--exclude-extraindex.exclude_extra (appended)index, daemon start
--max-file-bytesindex.max_file_bytesindex
--embed-batch-size / --embed-concurrency / --embed-max-charsindex.embed_*index
--debounce / --idle-timeout / --precisedaemon.debounce_ms / daemon.idle_timeout_min / daemon.precisedaemon start
--embed-rps / --embed-max-in-flight / --embed-cache-sizedaemon.embed_*daemon start
--backendsemantic.backendsemantic, search
--fusionsemantic.fusionsemantic, search
--profilemcp.profile (agent, core, or full)serve
bash
codemap index --exclude-extra migrations,db/migrations,**/testdata
codemap daemon start --debounce 800ms --embed-rps 2

config.yaml ​

Config files are decoded strictly. A misspelled or unknown key is an error instead of an ignored setting, and filesystem/read/parse errors are surfaced. Missing global and project config files remain optional; a path supplied through --config or CODEMAP_CONFIG must exist and be readable.

Numeric settings must be non-negative, and floating-point settings must also be finite. Zero keeps its documented special meaning: no limit/cap for file size, embed text, or rate; no idle shutdown; the built-in default for batch, concurrency, debounce, in-flight, cache, and individual fusion weights.

yaml
embedding:
  provider: ollama
  model: nomic-embed-text
  ollama_url: http://localhost:11434
  api_key: ""       # bearer token; empty = today's unauthenticated local Ollama (default)
  dimensions: 768
  distance: cosine
index:
  max_file_bytes: 1048576 # 0 = 64 MiB hard safety cap; never unbounded
  exclude:                # REPLACES the built-in defaults — set only to override wholesale
    - .git
    - node_modules     # JS/TS deps (any depth)
    - venv/            # Python virtualenvs — root-anchored (also env/, dist/, build/, target/, coverage/)
    - __pycache__      # any depth
    - vendor           # Go deps (any depth)
    - dist/            # root-anchored
    - "*.min.js"
  exclude_extra:          # APPENDED to the defaults — add your own without restating them
    - migrations
    - db/migrations
    - "**/testdata"
  embed_batch_size: 64    # node texts per request (0 = default 64)
  embed_concurrency: 4    # concurrent requests (0 = default 4)
  extract_concurrency: 4 # parallel Go (go/parser) extraction workers; LSP indexing is always serial per server
  embed_max_chars: 0      # cap per-node embed text (0 = no cap); lower = faster, less body recall
daemon:                   # background indexer (codemap daemon)
  debounce_ms: 500        # coalesce edit bursts (0 = default 500)
  idle_timeout_min: 0     # shut down after N minutes idle (0 = never)
  precise: false          # opt in to exact Go/LSP edges on every watched edit
  embed_rps: 0            # background embed rate to Ollama (0 = unlimited)
  embed_max_in_flight: 2  # max concurrent embed calls (0 = default 2)
  embed_cache_size: 4096  # dedup cache entries (0 = default 4096)
vecgrep:                  # sibling-tool integration (see Ecosystem)
  enabled: true           # allow the one-hop vecgrep search/memory adapter
  bin: ""                 # path to the vecgrep binary (resolved via $PATH if empty)
semantic:
  backend: fallback       # fallback (local, then vecgrep if absent) | local | vecgrep
  fusion: auto            # auto (classify query shape) | balanced (equal weights, pre-F7 behavior)
  fusion_weights:          # file-only (no env/flag) — advanced tuning
    identifier:
      vector: 0.5
      text: 1.5
    natural_language:
      vector: 1.5
      text: 0.5
mcp:
  profile: full            # full (default, 43) | agent (25 taught + docs = 26) | core (compatible 26)

Semantic owner ​

semantic.backend makes retrieval ownership explicit while keeping migration back-compatible:

  • fallback (default) reads codemap's local veclite collection and asks vecgrep only when this project has no local embeddings.
  • local never invokes vecgrep and preserves codemap's original embedded-index behavior.
  • vecgrep delegates every semantic query to the sibling CLI. In this mode codemap index skips and removes unused local vectors while continuing to index the structural graph; a missing vecgrep binary or invalid response is a visible error, not a silent owner switch.

The adapter is one process hop (vecgrep search ... --format json), not shared packages, shared databases, or MCP-to-MCP recursion. find and grep remain offline structural/text fallbacks in every mode.

The full built-in default list is:

  • Any-depth (bare, matches at every path level): .git, node_modules, vendor, __pycache__, site-packages, dist-*, build-* (build-output variants like dist-chrome/build-web), .next, .nuxt, *.min.js, *.gen.go, *_gen.go, *.pb.go, *_pb.go, *.lock. None of these are plausible source-directory names in Go/TS/JS/Python, so matching them anywhere is safe — and it's required to also catch nested cases like a workspace's per-package node_modules or a virtualenv's deeply-nested site-packages.
  • Root-anchored (trailing slash, matches only at the project root): dist/, build/, target/, coverage/, venv/, env/. These names collide with real source packages often enough to be a footgun at any depth — Go's standard library ships go/build, a Go project commonly has internal/env or internal/coverage, and dist/target are plausible package names too. Root anchoring keeps the common build-output/venv case (at the project root) excluded while leaving a same-named source subpackage alone. The trade-off: a monorepo with a nested per-package build output (e.g. packages/foo/dist/) needs its own exclude_extra: ["dist"] (bare, any-depth) if it wants that excluded too — that's opt-in bloat-avoidance, not a silently-dropped-code footgun.

Any dot-prefixed directory (.git, .venv, .tox, …) is also skipped automatically by the walker, independent of the exclude list.

exclude vs exclude_extra ​

exclude replaces the defaults (include the ones you still want); exclude_extra is appended to whatever exclude resolves to — use it to skip your own folders (migrations, fixtures, generated code) without losing node_modules/vendor/.git.

Both use the same path-aware glob semantics:

  • No slash anywhere (migrations, *.min.js) — matches that file/dir name at any depth.
  • A slash anywhere — leading, trailing, or embedded (db/migrations, env/, /dist) — anchored at the project root. db/migrations matches db/migrations and everything under it, but not app/db/migrations. A lone trailing slash like env/ anchors that single segment the same way — it matches a root-level env/ (and everything under it) but leaves a nested internal/env/ alone. This is the important gotcha the trailing slash exists to signal: writing env (no slash) would match internal/env too, silently dropping real code — always use a trailing slash to root-anchor a single directory name.
  • **/ prefix (**/testdata, **/gen/protobuf) — un-anchors a slash pattern so it matches at any depth, including multi-segment patterns.
  • A leading ./ is stripped and treated as an explicit root marker, equivalent to a trailing slash (./env behaves like env/). A pattern that normalizes to nothing (/, ./, **/) is a no-op.

Indexing performance ​

Indexing structure (the graph) is fast — the time in a full index is almost entirely embedding (turning each symbol into a vector). If indexing feels slow, in order of impact:

  1. Don't --reindex for routine updates. Plain codemap index is incremental: it content-hashes every file and skips unchanged ones, re-embedding only what changed. On a typical repo a no-op codemap index is well under a second, while --reindex re-embeds everything. Reserve --reindex for changing the embedding model or recovering a corrupt index.
  2. --no-embed indexes structure only (no Ollama) — near-instant, and callers/impact/hotspots still work; you only lose semantic search until a later embed.
  3. Embedder throughput. With a local Ollama, embedding is GPU-bound, so:
    • --embed-max-chars N (e.g. 512) caps the text per symbol — embedding cost is ~linear in tokens, so this is a near-linear speedup, trading some long-function-body recall (the docstring + signature are always kept first).
    • Raise Ollama's own parallelism: OLLAMA_NUM_PARALLEL=8 ollama serve, then --embed-concurrency can overlap requests. A smaller model (e.g. all-minilm) embeds several times faster at some quality cost.
    • With a remote Ollama endpoint (for example, an authenticated team GPU box), per-request latency can dominate, so --embed-batch-size and --embed-concurrency matter more. Codemap batches and parallelizes Ollama requests by default; other embedding-provider adapters are not implemented yet.

If the embedder is unreachable mid-index, the structural index still succeeds — codemap reports embeddings skipped: … and you can re-run later to add the vectors.

Authenticated Ollama endpoints / Ollama Cloud ​

embedding.ollama_url doesn't have to be localhost. Point it at any Ollama-compatible HTTP endpoint — a teammate's shared server behind a reverse proxy, or Ollama Cloud — and set embedding.api_key (or CODEMAP_OLLAMA_API_KEY) so codemap sends Authorization: Bearer <key> on every embed request. The wire format (POST /api/embed, {model, input} in, {embeddings: [...]} out) is unchanged — same code path as local Ollama, just with one extra header.

yaml
embedding:
  ollama_url: https://ollama.com
  api_key: ""   # set via CODEMAP_OLLAMA_API_KEY instead — see below
  model: nomic-embed-text
bash
export CODEMAP_OLLAMA_API_KEY="$(cat ~/.config/secrets/ollama-key)"  # never paste it inline
codemap index

Notes, verified against Ollama's docs as of this writing:

  • Host and auth: Ollama Cloud is served at https://ollama.com (not a subdomain), using the same /api/* surface as a local server. Create a key at ollama.com/settings/keys and send it as Authorization: Bearer <key> — this is exactly what embedding.api_key does.
  • No cloud embedding model today: as of this writing, Ollama Cloud's catalog has no embedding model (ollama.com/search?c=cloud&c=embedding returns none) — cloud models there are chat/generation models (gpt-oss:120b-cloud and similar). nomic-embed-text remains a local pull. This feature is therefore chiefly useful today for an authenticated self-hosted/team Ollama (e.g. a shared GPU box behind a reverse proxy that requires a bearer token) — and it costs nothing to support Ollama Cloud too, so a future embedding model on their cloud tier will work without a codemap change.
  • Never put the key on the command line. There is intentionally no --ollama-api-key flag — command-line arguments are visible to other processes on the same machine (ps). Use the config file or CODEMAP_OLLAMA_API_KEY.
  • Secrets hygiene: codemap config show and codemap doctor never print the key — config show masks it (****+last 4 characters, or (set) for short values; empty stays empty), and doctor reports only whether embedding auth is configured or not.

Embedding profile guard ​

The embedding provider, model, dimensions, and distance metric are stored with the vector collection. If any of them changes, codemap fails the next index with a clear "reindex" message rather than silently corrupting the vector space — run codemap index --reindex to rebuild.

Privacy and network access ​

The codemap binary sends no product-usage telemetry. Its SQLite graph and local veclite collection stay on disk. Language-server traffic stays between codemap and local subprocesses over stdio. Embedding requests send symbol source text to embedding.ollama_url; that is localhost by default, but the text leaves your machine if you explicitly configure a remote endpoint. An explicit vecgrep semantic backend follows vecgrep's own configuration and process boundary.

This documentation website is separate from the CLI and uses cookie-free Vercel Web Analytics. It does not change the binary's telemetry behavior. Maintainers must also enable Web Analytics for the Vercel project in the Vercel dashboard; installing the client package alone does not activate collection.

This docs site uses cookie-free Vercel Web Analytics. codemap sends no usage telemetry.