# How Agent Reach's Config Class Merges Settings from YAML Files and Environment Variables

> Learn how Agent Reach's Config class merges YAML and environment variables. Understand the priority order and fallback mechanisms for seamless configuration management.

- Repository: [Pnant/Agent-Reach](https://github.com/Panniantong/Agent-Reach)
- Tags: internals
- Published: 2026-06-20

---

**The `Config` class in Agent Reach prioritizes YAML file values over environment variables, only falling back to upper-cased environment variables when keys are absent from the configuration file.**

The Agent Reach configuration system, implemented in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py), provides a lightweight mechanism for managing settings across different deployment environments. This utility class resolves configuration values by merging YAML-based files with environment variables using a deterministic precedence order that treats user-maintained files as the authoritative source of truth.

## Loading Configuration from YAML Files

When a `Config` instance is created, the `load()` method reads the YAML configuration from `~/.agent-reach/config.yaml` by default, or from a custom path if specified during instantiation. According to the implementation in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py), the method uses `yaml.safe_load` to parse the file contents and stores the resulting dictionary in `self.data`, providing the foundation for all subsequent lookups.

The loader handles missing files gracefully, allowing the system to operate entirely from environment variables when no configuration file is present.

## The Merge Strategy: File Precedence Over Environment

The `get(key, default=None)` method implements the core merging logic that determines how Agent Reach resolves configuration values. As defined in the source code, this method follows a strict three-step resolution hierarchy:

1. **YAML File Check**: The method first checks if the requested key exists in `self.data`. If present, that value is returned immediately, giving file-based configurations top priority.
2. **Environment Variable Fallback**: If the key is absent from the file, the system searches for an environment variable with the upper-cased key name (e.g., `EXA_API_KEY` for the key `exa_api_key`).
3. **Default Value**: If neither source provides a value, the method returns the supplied default parameter or `None`.

This read-only merge strategy ensures that explicit file entries are never overwritten by environment variables, simplifying debugging and maintaining clear configuration boundaries. Users can override missing entries with `export EXA_API_KEY=...` without editing the YAML file, while existing file values remain protected.

## Secure Persistence and Updates

When configuration changes occur via `set()` or `delete()` methods, the `save()` method persists modifications back to the YAML file. The implementation enforces strict file permissions (`0o600`), ensuring that sensitive credentials like API keys are readable only by the file owner and not exposed to other system users.

This security-conscious approach ensures that even if the configuration contains secrets, they remain protected on disk while the application runs.

## Practical Implementation Examples

The following examples demonstrate the precedence behavior when merging YAML files and environment variables:

```python
import os
from agent_reach.config import Config

# Example 1: Value present in the YAML file takes precedence

cfg = Config(config_path="my_config.yaml")

# Assume my_config.yaml contains: exa_api_key: "file-key"

print(cfg.get("exa_api_key"))  # → "file-key"

# Example 2: Missing in file falls back to environment variable

os.environ["EXA_API_KEY"] = "env-key"
cfg = Config(config_path="empty.yaml")  # empty or non-existent file

print(cfg.get("exa_api_key"))  # → "env-key"

# Example 3: Neither source provides a value returns default

print(cfg.get("nonexistent_key", default="fallback"))  # → "fallback"

```

## Summary

- **File precedence**: The `Config` class checks `self.data` (loaded from YAML) before consulting environment variables, ensuring explicit file configurations act as the source of truth.
- **Environment fallback**: Missing keys trigger a lookup for upper-cased environment variables (e.g., `exa_api_key` becomes `EXA_API_KEY`), allowing runtime overrides without file modifications.
- **Secure storage**: The `save()` method writes configuration changes with `0o600` permissions, protecting sensitive credentials from unauthorized access.
- **Deterministic resolution**: The merge strategy is read-only, meaning environment variables never overwrite existing file values, creating predictable configuration behavior.

## Frequently Asked Questions

### What is the precedence order when Agent Reach merges configuration sources?

Agent Reach follows a strict hierarchy: YAML file values take highest precedence, followed by upper-cased environment variables for missing keys, and finally the default value supplied to the `get()` method. This ensures that user-maintained configuration files remain the authoritative source while allowing environment-based overrides for unset values.

### How does Agent Reach handle sensitive configuration data?

When the `save()` method writes changes to disk, it sets file permissions to `0o600` (read/write for owner only). This prevents other users on the system from accessing API keys or other credentials stored in the YAML configuration file, even if the underlying filesystem permissions would otherwise allow broader access.

### Can environment variables override values in the YAML configuration file?

No, environment variables cannot override existing values in the YAML file. The `get()` method implements a read-only merge where environment variables are consulted only when a key is absent from `self.data`. To change a value present in the file, you must edit the YAML directly or use the `set()` method to update the file contents.

### Where does Agent Reach store the default configuration file?

By default, the `Config` class looks for `~/.agent-reach/config.yaml` in the user's home directory. However, you can specify a custom path by passing the `config_path` parameter when instantiating the `Config` class, allowing per-project configuration files or alternative storage locations.