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 includinghost,port, anddebugmode flags.backend_modules: Plugin-style enable/disable lists with keys forenabled,disabled, andunavailablemodules.- Storage paths:
base_dir,database_path,screenshots_dir, andattachments_dirdefine core data storage locations. logging: Controls log levels and output destinations vialevel,console_level,file_level,quiet_modules, andlog_path.scheduler: APScheduler configuration withenabled,database_path,max_workers, andtimezonesettings.jobs: Background job definitions (recorder, OCR, audio processing) where each job specifiesid,name,enabled,interval, andparams.vector_db: Vector store configuration includingenabled,collection_name,embedding_model, andpersist_directory.chat: Chatbot behavior settings likeenable_historyandhistory_limit.llm: Large language model credentials and defaults includingapi_key,base_url,model,vision_model,temperature,max_tokens, andmodel_prices.tavily: Internet search integration withapi_key,search_depth,max_results,include_domains, andexclude_domains.audio: Real-time audio transcription settings includingis_24x7and ASR/storage subsections.observability: Tracing and metrics configuration for Phoenix/OpenInference withenabled,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 fromdefault_config.yamlon 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.pyuses Dynaconf with ordered file loading (defaults first, user overrides second), environment variable support viaLIFETRACE__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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →