Skip to content

Configuration

Coverage roots

Configure coverage auditing under [index.coverage]. roots = [] uses the deterministic union declared by active analyzers; roots = ["-"] explicitly disables coverage auditing. Other values are repository-relative glob patterns. exclude_suffixes removes known, intentionally unsupported file types from coverage diagnostics after root selection; suffixes use lowercase dotted form such as .yml, or <no-suffix> for extensionless files. The first-party defaults cover Python (src, tests, scripts), Bash (scripts), C/C++ (src, include, tests), JSON (config, .github, scripts), and Markdown/text (docs, examples).

Codira can run without a config file. Runtime commands can create a default user-level config on first use when the platform user config directory is writable, and users can create or inspect config files explicitly with:

codira config init
codira config init --full
codira config dump
codira config explain embeddings.batch_size
codira config validate

Precedence

Effective configuration is resolved in this order:

CLI flags
-> CODIRA_* environment variables
-> repository config: .codira/config.toml
-> user config: platform user config directory
-> system config: platform system config directory
-> built-in defaults

Repository config lives at .codira/config.toml. The file can be committed, while normal .codira index artifacts remain ignored.

codira config init creates the repository config by default. Use codira config init --level user when the file should be written to the platform user config directory instead.

Most repository-scoped commands accept --config-file PATH. This option tells Codira which repo-level config file to merge instead of <output-dir>/.codira/config.toml; it does not move databases, indexes, model artifacts, or other runtime state. --output-dir DIR selects the Codira state root for a command, while --config-file PATH selects only the repo-level configuration source. When both are provided, state is written under --output-dir and configuration is read from --config-file.

Generated Config

The default generated file is:

config_version = 2

[backend]
name = "sqlite"

[plugins]
disable_third_party = false
disabled_analyzers = []
documentation_audit_routes = []

[embeddings]
enabled = true
engine = "sentence-transformers"
vector_store = "sqlite"
similarity_index = "exact"
similarity_profiles = [
  { name = "default", ef_search = 64, candidate_limit = 256, default_result_limit = 20, max_result_limit = 256 },
]
model = "sentence-transformers/all-MiniLM-L6-v2"
version = "1"
dimension = 384
device = "cpu"
batch_size = 32
torch_num_threads = 0
torch_num_interop_threads = 0

[embeddings.gpu]
device_id = 0
memory_limit_mb = 0

[embeddings.indexing]
mode = "immediate"
object_types = ["symbol", "documentation"]
max_text_chars = 0
work_batch_multiplier = 256
max_source_file_bytes = 33554432
include_paths = []
exclude_paths = []

[index.concurrency]
strategy = "auto"
max_workers = 0
min_files = 16

[index.coverage]
roots = []
exclude_suffixes = []

[daemon]
enabled = false
debounce_ms = 250
include_paths = []
exclude_paths = []

[query_daemon]
enabled = false

index.concurrency.strategy is one of "off", "auto", "process", or "thread". Auto mode prefers isolated process workers, falls back to serial analysis when an active analyzer has not declared process support, and starts only when at least min_files files are selected. max_workers = 0 resolves to at most four workers. Use codira index --concurrency STRATEGY or codira index --jobs N for one-run overrides; --jobs selects auto mode with an explicit cap. Backend writes and embedding persistence remain serial.

For example, to keep default coverage roots but suppress intentionally unsupported CI and documentation asset formats:

[index.coverage]
exclude_suffixes = [".yml", ".yaml", ".dot", ".js", ".svg"]

torch_num_threads = 0 and torch_num_interop_threads = 0 mean Codira leaves Torch defaults unchanged.

embeddings.gpu.memory_limit_mb = 0 means no explicit GPU memory limit is configured.

embeddings.engine selects the active embedding engine plugin. The first-party engines are "sentence-transformers" and "onnx".

embeddings.vector_store selects the active vector-store plugin. The first-party local stores are "sqlite" and "duckdb" and use separated files under .codira/embeddings.db or .codira/embeddings.duckdb.

Similarity index and query profiles

embeddings.similarity_index selects the one derived candidate-ranking implementation for the repository. "exact" is implemented in core and is always available. Install codira-similarity-index-faiss (or use the official bundle's faiss extra) before selecting "faiss".

embeddings.similarity_profiles owns query-time policy. Every configuration must define default; callers may select another name with codira emb --search-profile NAME QUERY, codira docs --search-profile NAME QUERY, or codira ctx --search-profile NAME QUERY. A profile has:

  • ef_search: the HNSW graph exploration breadth. It is not score fuzziness; larger values inspect more graph neighbors and can improve recall at higher latency. Exact indexes accept the value but do not need it.
  • candidate_limit: the number of similarity candidates requested before structural filtering such as a path prefix.
  • default_result_limit and max_result_limit: the output-result policy after structural filtering; command --limit values cannot exceed the maximum.

For example, keep the default interactive profile and add a more thorough batch profile:

[embeddings]
similarity_index = "faiss"
similarity_profiles = [
  { name = "default", ef_search = 64, candidate_limit = 256, default_result_limit = 20, max_result_limit = 256 },
  { name = "thorough", ef_search = 160, candidate_limit = 800, default_result_limit = 50, max_result_limit = 800 },
]

[plugins.similarity-index-faiss]
index_type = "hnsw"
M = 32
efConstruction = 160

M and efConstruction are build-time HNSW parameters; changing either, or changing index_type, requires codira emb rebuild. Changing only a named profile does not rebuild the artifact. The selected similarity-index identity is persisted with its derived artifact. After changing an incompatible index or vector-store format, discard the derived state with codira emb reset and then run codira index (or codira emb rebuild once durable vectors exist). Do not attempt to reuse or hand-edit old artifact files.

This is a breaking configuration format. Configurations with config_version = 1 are rejected: run codira config init --force, then select similarity_index = "exact" or an installed alternative explicitly.

Vector stores can retain vectors for older embedding or vector-store identities. Use codira emb purge to inspect or delete retained sets:

codira emb purge --stale --dry-run
codira emb purge --stale --backend warehouse --keep 1 --yes
codira emb purge --all --backend warehouse --yes

The command defaults to the configured [embeddings].vector_store. Pass any registered vector-store name through --backend to target that store without editing the repository config. Destructive runs require --yes; without it, purge runs as a dry run.

embeddings.indexing.mode = "immediate" computes embeddings during codira index. Set it to "deferred" to persist structural index rows first and queue embeddings for a later codira index --embeddings-only pass.

embeddings.indexing.object_types limits which persisted object types receive embeddings. Supported values are "symbol" and "documentation". An empty list skips all embedding rows while leaving structural indexing enabled.

embeddings.indexing.max_text_chars = 0 means no text-size limit. Positive values skip embedding payloads longer than the configured number of characters.

embeddings.indexing.max_source_file_bytes = 33554432 is the default 32 MiB source-ingestion ceiling. Larger supported files are skipped before hashing, parsing, or context rereads and appear as deterministic coverage diagnostics. Increase it only when the repository requires the additional memory budget.

embeddings.indexing.work_batch_multiplier bounds indexing work segments as a multiple of embeddings.batch_size. With the defaults, Codira processes at most 32 * 256 = 8192 embedding rows per segment before calling the embedding engine and vector-store flush path. Valid values are integers from 1 to 4096.

embeddings.indexing.include_paths and exclude_paths are repo-root-relative path prefixes. Include filters are evaluated first; exclude filters remove matching files from embedding computation.

Optional daemon contract

[daemon] declares configuration for Codira's optional automatic-indexing daemon. It does not enable a background process by itself, and explicit codira index remains authoritative.

  • enabled controls whether a later daemon runtime may start for the repository; the default is false.
  • debounce_ms is a positive filesystem-notification coalescing interval.
  • include_paths and exclude_paths are repo-root-relative watch prefixes; an empty include list watches every non-ignored path outside Codira and Git state directories. A matching change schedules the normal index operation; active analyzers still determine which files produce indexed records.

Set daemon.enabled = true and run codira daemon run to start foreground automatic indexing. The watchfiles runtime debounces configured source-path events, ignores Codira and Git state directories, and discards batches whose paths match active Git ignore rules (including .gitignore). It checks Git HEAD every second so a branch checkout is reconciled even when no source event is delivered. The scheduler records the HEAD observed after each successful index and queues a follow-up pass if it changes during indexing. On Windows, the same lifecycle commands manage a repository-scoped automatic start SCM service through the Windows-only pywin32 dependency. Installation requires permission to create a service and persists the canonical repository root in that service's SCM parameters.

On Linux with a systemd user manager, codira daemon install writes and enables a repository-scoped unit under the XDG user-unit directory. start, stop, status, and uninstall operate on that same unit. Installation does not enable systemd user lingering; use loginctl enable-linger separately if the daemon must survive logout.

On macOS, the same lifecycle commands manage a repository-scoped LaunchAgent under ~/Library/LaunchAgents. The agent runs while the user GUI session is available; it is not a system-wide LaunchDaemon.

The lifecycle commands are implemented on Linux, macOS, and Windows:

codira daemon run
codira daemon install
codira daemon start
codira daemon status
codira daemon stop
codira daemon uninstall

run and install require daemon.enabled = true; status, stop, and uninstall remain available to inspect or clean up an existing service. install creates the platform-specific service definition; use start when you want to start an installed service immediately.

When installed with --workspace NAME, the service definition records the workspace name, canonical repository and state roots, effective configuration, and descriptor fingerprint. Its launch command selects that workspace and checks the fingerprint before it runs, so a changed descriptor cannot retarget an automatic restart. start and status report definition drift and require install followed by start to regenerate the definition. Direct --path service definitions remain supported.

Every foreground daemon writes a current snapshot to .codira/daemon-status.json and appends state-transition snapshots to .codira/daemon-activity.jsonl below Codira's effective storage root. By default that is the repository root; with --output-dir, it is the selected output directory. The records contain no changed file paths. codira daemon status combines the platform service state with the latest durable reconciliation snapshot.

Optional warm query daemon contract

[query_daemon] configures the second, repository-local daemon that keeps read/query resources warm. It is disabled by default and does not change direct CLI or MCP behavior when the process is absent or degraded.

  • enabled permits codira query-daemon run. It defaults to false.

The query daemon will be fixed to one resolved repository root and effective output directory; it will never accept repository paths from requests. It is read-only: the indexing daemon remains the sole automatic index writer, and CLI and MCP will retain direct-core fallback when it is unavailable. This is separate from the indexing daemon, the MCP stdio server, and the future multi-repository catalogue work tracked by #51.

The reserved lifecycle hierarchy is:

codira query-daemon run
codira query-daemon install
codira query-daemon uninstall
codira query-daemon start
codira query-daemon stop
codira query-daemon status

With enabled = true, codira query-daemon run starts one foreground process for the resolved repository root and effective output directory. It warms only read resources and observes durable index generations; it never indexes or mutates the persistent backend. status remains safe to run while disabled and reports the repository-local durable snapshot when one exists.

With enablement, service management is available through the same lifecycle commands: Linux installs a systemd user unit, macOS installs a LaunchAgent, and Windows installs an SCM service. Each service name includes the resolved repository root, effective output directory, and daemon kind, so it cannot operate on a different repository's service. Installed commands use absolute executable, repository, and output-directory arguments.

Workspace-installed query services use the same persisted identity and drift check as indexing services. Regenerate the service with install after a workspace descriptor changes; direct-path query services remain compatible.

The indexing daemon and query daemon have distinct platform-service names and status records. MCP always discovers the compatible local daemon opportunistically. CLI routing is enabled only when both query_daemon.enabled = true and a compatible service is running.

Eligible CLI reads are ctx (without --prefix), embedding search through emb (never emb purge, and without --prefix), plugins, and caps. Indexing, configuration writes, vector-store purges, and every other command remain direct. The normal stdout and exit code are identical in warm and direct modes. Add --execution-mode to any eligible command to write one diagnostic to stderr: warm includes the served generation; direct means no compatible service was used; fallback means one failed daemon request was re-run directly. No command is ever routed to another repository or output directory identity.

Parallel repository isolation

An automatic indexing daemon and a warm query daemon are each scoped to the resolved repository root and effective output directory. Their persistent service identities include those values and the daemon kind. Consequently, each repository needs its own effective state root: use the default repository-local .codira state, or pass a distinct --output-dir for every direct-path command. Do not point two repositories at the same output directory.

For external state, a named workspace is preferred because it binds one repository root, state root, and optional repository configuration file before starting either daemon or MCP server:

codira workspace add repository-a \
  --path /path/to/repository-a \
  --state-root /path/to/codira-state/repository-a \
  --config-file /path/to/repository-a/.codira/config.toml

codira daemon --workspace repository-a install
codira daemon --workspace repository-a start
codira query-daemon --workspace repository-a install
codira query-daemon --workspace repository-a start

Use a different workspace name and state root for repository B. Start Codira MCP with the same workspace (codira-mcp --workspace repository-a) so it can discover only that workspace's compatible warm query daemon. See Local MCP: Parallel repositories for the corresponding project-scoped Codex configuration.

Repository Performance Profile

This repository commits an explicit .codira/config.toml with operational defaults for the checked-in ONNX profile:

  • backend.name = "sqlite" selects the backend with the best measured weighted operational cost for the current ONNX profile on this workstation.
  • embeddings.indexing.mode = "immediate" keeps a one-step indexing workflow as the default. Deferred mode remains available for operators who explicitly want a two-step structural/indexing workflow.
  • embeddings.indexing.object_types = ["symbol", "documentation"] keeps both retrieval channels active.
  • embeddings.indexing.max_text_chars = 0 keeps documentation embeddings uncapped.
  • embeddings.indexing.work_batch_multiplier = 256 caps the memory footprint of full-index embedding work while staying aligned with the configured model inference batch size.
  • embeddings.engine = "onnx", embeddings.model = "BAAI/bge-small-en-v1.5", embeddings.batch_size = 4, and ONNX Runtime default thread counts are the current project defaults.

Embedding performance is hardware-sensitive because throughput and memory pressure depend on CPU, RAM, GPU, and local model state. Reassess these values with the maintained retrieval-quality benchmark after a meaningful hardware or backend change; do not treat them as portable tuning advice.

Profiles

codira config init --profile default writes conservative defaults.

codira config init --full writes the core defaults plus every known first-party plugin option with its default value.

codira config init --profile low-memory lowers the embedding batch size and sets conservative Torch thread counts.

codira config init --profile gpu selects a GPU-oriented device and larger batch size. It includes GPU metadata defaults but does not auto-detect hardware.

Embedding Calibration

codira calibrate embeddings runs a bounded offline calibration workflow and prints a config-compatible TOML snippet by default:

codira calibrate embeddings
codira calibrate embeddings --print
make calibrate-embeddings-config
codira calibrate embeddings --output /tmp/codira-embeddings.toml
codira calibrate embeddings --write

--write is the only mode that mutates the user config file. --print and --output do not create or update user config.

Calibration benchmarks deterministic text payloads against locally available embedding model artifacts. It does not download models or contact external services. If the semantic dependency stack or local model artifact is missing, Codira emits safe CPU fallback values instead of failing the command.

The printed block includes the complete [embeddings] section plus [embeddings.gpu], including model identity fields and calibrated runtime parameters.

Model Candidate Manifest

benchmarks/embedding/model-candidates.json records the model/engine combinations used for embedding-engine campaigns. It includes the current MiniLM default, BAAI/bge-small-en-v1.5, nomic-ai/nomic-embed-text-v1.5, and jinaai/jina-embeddings-v2-base-code.

Inspect the manifest and render a config snippet for one entry:

uv run python scripts/embedding_model_manifest.py --list
uv run python scripts/embedding_model_manifest.py \
  --id bge-small-en-v1.5-onnx \
  --print-config

The manifest does not contain model weights. Use scripts/download_embedding_model.py to download the required Hugging Face artifacts, install ONNX files under the declared --install-root, and smoke-test each candidate before launching the long campaign. Remote-code entries require an explicit anonymous acknowledgement; see docs/scripts.md.

The current Jina candidate is ONNX-only because the jinaai/jina-embeddings-v2-base-code SentenceTransformers remote-code path is not compatible with the pinned Transformers API used by this repository.

ONNX embedding inputs are truncated before inference. The default plugins.embedding-onnx.max_tokens = 512 protects fixed-length exports from runtime shape errors. Set max_tokens = 0 only for dynamic-shape exports that are known to accept arbitrary sequence lengths. Changing max_tokens changes vectors for over-limit texts, so bump [embeddings].version when changing it for an existing index.

Environment Overrides

Existing process-local environment overrides still work and take precedence over config files:

Variable Config key
CODIRA_INDEX_BACKEND backend.name
CODIRA_DISABLE_THIRD_PARTY_PLUGINS plugins.disable_third_party
CODIRA_EMBED_BATCH_SIZE embeddings.batch_size
CODIRA_EMBED_DEVICE embeddings.device
CODIRA_TORCH_NUM_THREADS embeddings.torch_num_threads
CODIRA_TORCH_NUM_INTEROP_THREADS embeddings.torch_num_interop_threads

Validation

Config validation is strict. Unknown keys, invalid types, invalid enum values, and invalid numeric ranges fail before runtime work proceeds.

When validating the effective config, Codira also validates plugin tables against schemas exposed by loaded plugins. Configured plugin tables for unloaded plugins produce warnings and keep exit status 0; JSON output reports status = "ok_with_warnings".

Plugin Configuration

Plugin activation and plugin-specific settings live under namespaced tables:

[plugins.analyzer-python]
enabled = true
include_paths = ["src", "tests"]
exclude_paths = ["tests/fixtures"]
emit_imports = true

[plugins.backend-sqlite]
enabled = true

Common plugin keys:

Key Type Default Description
enabled bool true Disables the plugin when set to false.

Common analyzer keys:

Key Type Default Description
include_paths list[str] [] Repo-relative POSIX paths to include after suffix/family eligibility. Empty means include all otherwise eligible paths.
exclude_paths list[str] [] Repo-relative POSIX paths to exclude after suffix/family eligibility. Excludes win over includes.

Path filter values must be non-empty repo-relative paths. Absolute paths and .. traversal segments are invalid.

Documentation audit routing is explicit. Empty plugins.documentation_audit_routes = [] disables documentation audit execution; this is the compatibility mode for repositories that have not chosen a convention.

Each documentation audit route is an ordered inline table:

[plugins]
documentation_audit_routes = [
  { language = "python", convention = "numpy", plugin = "numpy", include_paths = ["src/**/*.py"], exclude_paths = ["tests/fixtures/**"] },
  { language = "python", convention = "google", plugin = "google", include_paths = ["tests/**/*.py"] },
  { language = "c", convention = "doxygen", plugin = "doxygen", include_paths = ["src/**/*.c", "include/**/*.h"] },
  { language = "cpp", convention = "doxygen", plugin = "doxygen", include_paths = ["src/**/*.cpp", "include/**/*.hpp"] },
]

Route keys:

Key Type Required Description
language str yes Analyzer language matched by the route, such as python, c, or cpp.
convention str yes Convention label passed to the selected audit plugin.
plugin str yes Documentation audit plugin name. First-party names are numpy, google, and doxygen.
include_paths list[str] no Repo-relative glob patterns accepted by this route. Empty means all paths for the language.
exclude_paths list[str] no Repo-relative glob patterns rejected by this route. Excludes win over includes.

A public artifact is audited only when exactly one route matches its language and path. Multiple matching routes emit an ambiguous_route diagnostic instead of guessing the convention.

codira audit --json includes persisted plugin and convention provenance for single-route matches:

{
  "audit_plugin": {
    "name": "numpy",
    "version": "1"
  },
  "audit_convention": {
    "name": "numpy",
    "version": "1"
  },
  "rule_id": "missing_parameter",
  "severity": "warning",
  "audit_route": {
    "language": "python",
    "convention": "numpy",
    "plugin": "numpy"
  }
}

First-party analyzer options:

Table Options
[plugins.analyzer-python] emit_module_documentation, emit_imports, emit_constants, emit_type_aliases
[plugins.analyzer-json] enabled_families = ["schema", "package", "release"], emit_dependencies, emit_scripts, emit_schema_properties
[plugins.analyzer-c] use_leading_comments, emit_doxygen_documentation, include_system_includes, emit_macros
[plugins.analyzer-cpp] use_leading_comments, emit_doxygen_documentation, include_system_includes, emit_namespaces, emit_macros, header_language (auto, c, cpp)
[plugins.analyzer-rust] include_paths, exclude_paths, emit_macros
[plugins.analyzer-javascript] include_paths, exclude_paths, emit_variables, emit_jsdoc_documentation
[plugins.analyzer-typescript] include_paths, exclude_paths, emit_variables, emit_tsdoc_documentation
[plugins.analyzer-go] include_paths, exclude_paths, emit_variables

Rustdoc audits are opt-in through an explicit route, for example:

[plugins]
documentation_audit_routes = [
  { language = "rust", convention = "rustdoc", plugin = "rustdoc", include_paths = ["src/**"] },
]

JSDoc audits use the same explicit routing model for JavaScript artifacts:

[plugins]
documentation_audit_routes = [
  { language = "javascript", convention = "jsdoc", plugin = "jsdoc", include_paths = ["src/**"] },
]

| [plugins.analyzer-bash] | emit_functions | | [plugins.analyzer-markdown] | strip_front_matter, emit_file_artifact_without_headings, min_heading_level, max_heading_level | | [plugins.analyzer-text] | include_root_files, include_docs_directories, exclude_generated, exclude_fixtures_logs |

First-party backend tables are schema-validated:

[plugins.backend-sqlite]
enabled = true

[plugins.backend-duckdb]
enabled = true
profiling_enabled = false
# Optional native resource controls; omission keeps DuckDB defaults.
memory_limit = "4 GiB"
threads = 4

Disabling the configured active backend is invalid. Disable an inactive backend only, or change [backend].name first.

When plugins.backend-duckdb.profiling_enabled = true, DuckDB index runs emit .codira/duckdb-profile.json with aggregate write-path timings. Leave it disabled for normal usage; enable it only when investigating backend performance. Optional memory_limit (a nonempty DuckDB size string) and threads (a positive integer) apply to initialization and cached read/write connections. Changing resource settings closes the backend's cached handles before reopening. These settings affect the native database instance; memory_limit covers the buffer manager, not Python/Arrow objects or total process RSS. A lower limit may spill to disk or fail a query. Neither option promises a performance improvement.

First-party embedding tables are also schema-validated:

[plugins.embedding-sentence-transformers]
enabled = true
trust_remote_code = false

[plugins.embedding-onnx]
enabled = true
model_path = ".codira/models/example/model.onnx"
tokenizer_path = ".codira/models/example/tokenizer.json"
provider = "CPUExecutionProvider"
precision = "float32"
normalize = true
max_tokens = 512
intra_op_num_threads = 0
inter_op_num_threads = 0

ONNX batching is controlled by the shared [embeddings].batch_size key, not by a plugin-local option.

Vector stores own durable snapshots only. Candidate breadth belongs to named embeddings.similarity_profiles, so legacy plugins.vector-store-*.candidate_limit settings are invalid. Keep vector store tables limited to store-specific options such as enabled.

C/C++ .h routing

The C++ plugin automatically claims .h files with C++ syntax evidence or a same-stem C++ translation unit and no C counterpart. Ambiguous headers remain with C. Parsed comments and string literals are not language hints.

[plugins.analyzer-cpp]
header_language = "cpp"
include_paths = ["include/cpp/**", "src/**/*.cpp"]

This explicit override claims .h files allowed by these filters. Use "c" to disable C++ claims for .h, or the default "auto" for inference. Filters also apply to non-.h C++ files, so include the source directories you need. Changed source or configuration is handled by normal index freshness and incremental analyzer selection. Compilation database flags are not inferred.