Skip to content

Settings

The settings module provides type-safe configuration management using Pydantic Settings.

Overview

Configuration is loaded from multiple sources in priority order: 1. Environment variables (highest priority) 2. ./config.toml (project directory) 3. ~/.config/imbi/config.toml (user directory) 4. /etc/imbi/config.toml (system directory) 5. Built-in defaults (lowest priority)

Loading Configuration

from imbi_common import settings

# Load full configuration
config = settings.load_config()

# Access individual settings sections
postgres_config = settings.Postgres()
clickhouse_config = settings.Clickhouse()
auth_config = settings.Auth()

API Reference

load_config

load_config() -> Configuration

Load configuration from config.toml files with environment overrides.

Checks for config files in priority order: 1. ./config.toml (project root) 2. ~/.config/imbi/config.toml (user config) 3. /etc/imbi/config.toml (system config)

Environment variables always override config file values.

Returns:

Type Description
Configuration

Configuration object with merged settings

Source code in src/imbi_common/settings.py
def load_config() -> Configuration:
    """Load configuration from config.toml files with environment overrides.

    Checks for config files in priority order:
    1. ./config.toml (project root)
    2. ~/.config/imbi/config.toml (user config)
    3. /etc/imbi/config.toml (system config)

    Environment variables always override config file values.

    Returns:
        Configuration object with merged settings

    """
    return Configuration.model_validate(load_config_data())

get_auth_settings

get_auth_settings() -> Auth

Get the singleton Auth settings instance.

This ensures the JWT secret remains stable across requests when auto-generated (i.e., when IMBI_AUTH_JWT_SECRET is not set in env).

Returns:

Type Description
Auth

The singleton Auth settings instance.

Source code in src/imbi_common/settings.py
def get_auth_settings() -> Auth:
    """Get the singleton Auth settings instance.

    This ensures the JWT secret remains stable across requests when
    auto-generated (i.e., when IMBI_AUTH_JWT_SECRET is not set in env).

    Returns:
        The singleton Auth settings instance.

    """
    global _auth_settings
    if _auth_settings is None:
        _auth_settings = Auth()
    return _auth_settings

Configuration

Bases: BaseModel

Root configuration combining all shared settings sections.

Supports loading from config.toml files with environment variable overrides. Config files are checked in this priority order: 1. ./config.toml (project root) 2. ~/.config/imbi/config.toml (user config) 3. /etc/imbi/config.toml (system config)

Environment variables always take precedence over config file values.

Example config.toml: [postgres] url = "postgresql://postgres:secret@db-prod:5432/imbi"

[auth]
jwt_secret = "your-secret-here"
access_token_expire_seconds = 7200

merge_env_with_config classmethod

merge_env_with_config(
    data: dict[str, Any],
) -> dict[str, typing.Any]

Merge environment variables with config file data.

For each BaseSettings submodel, instantiate it with the config file data as kwargs. This allows BaseSettings to use environment variables as defaults for any fields not provided in the config file.

Parameters:

Name Type Description Default
data dict[str, Any]

Raw config data from TOML file

required

Returns:

Type Description
dict[str, Any]

Config data with BaseSettings instances properly constructed

Source code in src/imbi_common/settings.py
@pydantic.model_validator(mode='before')
@classmethod
def merge_env_with_config(
    cls, data: dict[str, typing.Any]
) -> dict[str, typing.Any]:
    """Merge environment variables with config file data.

    For each BaseSettings submodel, instantiate it with the config file
    data as kwargs. This allows BaseSettings to use environment variables
    as defaults for any fields not provided in the config file.

    Args:
        data: Raw config data from TOML file

    Returns:
        Config data with BaseSettings instances properly constructed

    """
    settings_fields: dict[str, type[pydantic_settings.BaseSettings]] = {
        'auth': Auth,
        'clickhouse': Clickhouse,
        'embeddings': Embeddings,
        'postgres': Postgres,
        'releases': Releases,
        'ssl': SSL,
        'valkey': Valkey,
    }
    for field, settings_cls in settings_fields.items():
        if field in data and data[field] is not None:
            # Skip if already an instance (e.g., from direct construction)
            if isinstance(data[field], settings_cls):
                continue
            data[field] = settings_cls(**data[field])
    return data

Postgres

Bases: BaseSettings

PostgreSQL connection settings.

Clickhouse

Bases: BaseSettings

Auth

Bases: BaseSettings

Authentication settings shared across Imbi services.

Contains only JWT and encryption configuration needed by any service that verifies tokens or handles encrypted data.

generate_encryption_key_if_missing

generate_encryption_key_if_missing() -> Auth

Generate encryption key if not provided (Phase 5).

Auto-generates a Fernet encryption key if IMBI_AUTH_ENCRYPTION_KEY is not set in the environment. Logs a warning since this key should be stable across restarts in production.

Source code in src/imbi_common/settings.py
@pydantic.model_validator(mode='after')
def generate_encryption_key_if_missing(self) -> Auth:
    """Generate encryption key if not provided (Phase 5).

    Auto-generates a Fernet encryption key if IMBI_AUTH_ENCRYPTION_KEY
    is not set in the environment. Logs a warning since this key should
    be stable across restarts in production.
    """
    if self.encryption_key is None:
        from cryptography import fernet

        self.encryption_key = fernet.Fernet.generate_key().decode('ascii')
        LOGGER.warning(
            'Encryption key auto-generated. Set IMBI_AUTH_ENCRYPTION_KEY '
            'in production for stable key across restarts.'
        )
    return self

SSL

Bases: BaseSettings

SSL configuration settings.

configure

configure() -> None

Configure the default SSL context if cert_dir is set.

Patches ssl.create_default_context and ssl._create_default_https_context to load CA certificates from cert_dir on every call.

Source code in src/imbi_common/settings.py
def configure(self) -> None:
    """Configure the default SSL context if cert_dir is set.

    Patches ssl.create_default_context and
    ssl._create_default_https_context to load CA certificates from
    cert_dir on every call.
    """
    if self.cert_dir is None:
        return
    import ssl

    cert_dir = str(self.cert_dir)
    _orig = ssl.create_default_context

    def _patched(*args: object, **kwargs: object) -> ssl.SSLContext:
        ctx = _orig(*args, **kwargs)  # type: ignore[arg-type]
        ctx.load_verify_locations(capath=cert_dir)
        return ctx

    ssl.create_default_context = _patched
    ssl._create_default_https_context = _patched