LifeTrace config.yaml Structure and Loading Mechanism: A Complete Guide

LifeTrace uses a hierarchical YAML configuration system where config.yaml is automatically generated from built-in defaults and loaded via Dynaconf with environment variable overrides and hot-reload support.

LifeTrace stores its runtime configuration in a YAML file named config.yaml. This file is created automatically from the built-in default configuration (default_config.yaml) the first time the application starts. Understanding the structure of this file and how LifeTrace loads it is essential for customizing server settings, LLM credentials, scheduler jobs, and storage paths.

Understanding the config.yaml File Structure

The configuration file is organized into logical sections that control distinct subsystems of the LifeTrace application.

Core Configuration Sections

The config.yaml file follows a strict hierarchy defined in lifetrace/config/default_config.yaml:

  • server: HTTP server settings including host, port, and debug mode flags.
  • backend_modules: Plugin-style enable/disable lists with keys for enabled, disabled, and unavailable modules.
  • Storage paths: base_dir, database_path, screenshots_dir, and attachments_dir define core data storage locations.
  • logging: Controls log levels and output destinations via level, console_level, file_level, quiet_modules, and log_path.
  • scheduler: APScheduler configuration with enabled, database_path, max_workers, and timezone settings.
  • jobs: Background job definitions (recorder, OCR, audio processing) where each job specifies id, name, enabled, interval, and params.
  • vector_db: Vector store configuration including enabled, collection_name, embedding_model, and persist_directory.
  • chat: Chatbot behavior settings like enable_history and history_limit.
  • llm: Large language model credentials and defaults including api_key, base_url, model, vision_model, temperature, max_tokens, and model_prices.
  • tavily: Internet search integration with api_key, search_depth, max_results, include_domains, and exclude_domains.
  • audio: Real-time audio transcription settings including is_24x7 and ASR/storage subsections.
  • observability: Tracing and metrics configuration for Phoenix/OpenInference with enabled, mode, and connection details.

Default vs. User Configuration

LifeTrace maintains a strict separation between default and user configurations:

  • lifetrace/config/default_config.yaml: Contains the full schema with sensible defaults and extensive comments. This file ships with the package and should never be modified by users.
  • config.yaml: The user-specific configuration file created automatically on first run. Located in the user configuration directory (typically ~/.config/lifetrace/ on Linux/macOS or the OS-specific equivalent), this is the only file users should edit.

The application never writes back to default_config.yaml, ensuring that updates to the package can introduce new default keys without overwriting user customizations.

How LifeTrace Loads config.yaml: The Loading Mechanism

The loading logic lives in lifetrace/util/settings.py and implements a sophisticated multi-stage initialization process using the Dynaconf library.

Configuration Directory Resolution

The system first locates both built-in and user configuration directories using helper functions from lifetrace/util/base_paths.py:

from lifetrace.util.base_paths import get_config_dir, get_user_config_dir

# Default config → package resources

# User config → ~/.config/lifetrace (or OS-specific equivalent)

The get_user_config_dir() function returns the platform-appropriate path using operating system conventions (XDG directories on Linux, Application Support on macOS, AppData on Windows).

File Initialization and Population

Before loading settings, the system ensures the configuration directory structure exists and populates missing files:


# Create directory if needed

user_config_dir.mkdir(parents=True, exist_ok=True)

# Copy default_config.yaml if missing (for reference)

if not (user_config_dir / "default_config.yaml").exists():
    shutil.copy2(default_config_path, user_config_dir / "default_config.yaml")

# Create config.yaml from defaults if user has no config yet

if not (user_config_dir / "config.yaml").exists():
    source = user_config_dir / "default_config.yaml" if (user_config_dir / "default_config.yaml").exists() else default_config_path
    shutil.copy2(source, user_config_dir / "config.yaml")

This ensures that first-time users receive a fully populated config.yaml with all available options commented and explained.

Dynaconf Integration and Settings Composition

The system composes an ordered list of configuration files and instantiates a Dynaconf object with advanced options:

_settings_files = [
    default_config_path,           # Base defaults

    user_config_dir / "config.yaml" # User overrides

]

settings = Dynaconf(
    settings_files=_settings_files,
    envvar_prefix="LIFETRACE",       # LIFETRACE__SERVER__PORT

    nested_separator="__",           # Double-underscore for nesting

    merge_enabled=True,              # Dicts merged, not replaced

    load_dotenv=True,                # Also read .env file

    lowercase_read=True,             # Case-insensitive access

    validators=[...]                 # Type checking and defaults

)

The loading order ensures that values in config.yaml override defaults while merge_enabled=True allows partial overrides of nested dictionaries (such as updating only llm.temperature without redefining the entire llm section).

Validation and Hot-Reloading

The validators defined in lifetrace/util/settings.py (lines 92-149) enforce type checking and provide fallback defaults when user-provided values are missing.

Access patterns throughout the codebase use the global settings object:

from lifetrace.util.settings import get_settings

cfg = get_settings()
port = cfg.server.port  # Returns 8001 unless overridden

Hot-reload is supported via the reload_settings() function:

from lifetrace.util.settings import reload_settings

if reload_settings():
    print("Configuration reloaded from disk")

This allows live changes to config.yaml without restarting the LifeTrace process.

Practical Code Examples

Accessing Nested Configuration Values

from lifetrace.util.settings import get_settings

cfg = get_settings()

# Access nested values using dot notation

print("LLM model:", cfg.llm.model)          # → qwen-plus (or user-defined)

print("Server port:", cfg.server.port)        # → 8001

print("Scheduler enabled:", cfg.scheduler.enabled)

Overriding Settings via Environment Variables

LifeTrace supports environment variable overrides using double underscores to denote nesting:


# Override server port

export LIFETRACE__SERVER__PORT=9000

# Override LLM API key

export LIFETRACE__LLM__API_KEY="sk-..."

# Override specific job interval

export LIFETRACE__JOBS__RECORDER__INTERVAL=300
from lifetrace.util.settings import get_settings

cfg = get_settings()
print(cfg.server.port)  # → 9000 (from environment)

Reloading Configuration at Runtime

from lifetrace.util.settings import reload_settings, get_settings

# User edits config.yaml on disk...

success = reload_settings()
if success:
    cfg = get_settings()
    print("New port after reload:", cfg.server.port)
else:
    print("Failed to reload configuration")

Summary

  • LifeTrace uses a hierarchical YAML configuration system centered on config.yaml, automatically generated from default_config.yaml on first run.
  • The configuration structure includes sections for server settings, LLM credentials, scheduler jobs, storage paths, logging, vector databases, and observability.
  • The loading mechanism in lifetrace/util/settings.py uses Dynaconf with ordered file loading (defaults first, user overrides second), environment variable support via LIFETRACE__ prefix, and dictionary merging for partial overrides.
  • Hot-reload is supported through reload_settings(), allowing configuration changes without process restart.
  • User configurations reside in the OS-specific user config directory (e.g., ~/.config/lifetrace/), while the built-in defaults remain untouched in the package directory.

Frequently Asked Questions

Where is config.yaml located on my system?

LifeTrace stores config.yaml in your operating system's standard user configuration directory. On Linux, this is typically ~/.config/lifetrace/; on macOS, it's ~/Library/Application Support/lifetrace/; and on Windows, it's %APPDATA%\lifetrace\. The exact path is determined by lifetrace/util/base_paths.py using platform-specific conventions.

How do I override config.yaml settings with environment variables?

LifeTrace supports environment variable overrides using the LIFETRACE__ prefix and double underscores (__) to denote nested keys. For example, to change the server port, set LIFETRACE__SERVER__PORT=9000. To override the LLM API key, use LIFETRACE__LLM__API_KEY. These variables take precedence over values in config.yaml but do not modify the file on disk.

Can I modify config.yaml while LifeTrace is running?

Yes, LifeTrace supports hot-reloading of configuration files. After editing config.yaml on disk, you can call reload_settings() from lifetrace/util/settings.py to re-read the files without restarting the application. Alternatively, if the application exposes a reload endpoint or you restart the process, the new configuration will take effect. Note that some settings (like server port) may require a restart to take effect depending on implementation.

What happens if I delete my config.yaml file?

If you delete config.yaml, LifeTrace will not automatically recreate it until the next time the application initializes its configuration system. On the next startup, the initialization logic in lifetrace/util/settings.py detects the missing file and copies the default configuration from default_config.yaml (located in the package resources) to the user config directory as config.yaml. You will lose any customizations made to the deleted file, reverting to default settings.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →