# How the Agent Reach Config Class Prioritizes Config Files Over Environment Variables

> Learn how the Agent Reach Config class prioritizes YAML config files over environment variables for settings. Discover its fallback logic and default value options.

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

---

**The Agent Reach Config class resolves every setting by first checking the YAML configuration file, then falling back to environment variables, and finally returning an optional default value.**

The `Config` class in the [Panniantong/Agent-Reach](https://github.com/Panniantong/Agent-Reach) repository serves as the single source of truth for all user-defined settings. According to the source code in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py), the Agent Reach Config class prioritizes config files over environment variables by enforcing a strict three-layer lookup hierarchy. This design ensures that persistent YAML-based configuration always masks identically-named environment variables unless the file entry is removed.

## Configuration Precedence Hierarchy

The `Config` class defines an explicit lookup order inside [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py). When you request a key, the resolution follows this sequence:

1. **Configuration file** — Values loaded from `~/.agent-reach/config.yaml` into the internal dictionary `self.data`.
2. **Environment variables** — If the key is absent from `self.data`, the class searches `os.environ` for an upper-cased version of the key.
3. **Default argument** — If neither source yields a value, the `default` parameter passed to `get()` is returned.

Because the file dictionary is checked first with `if key in self.data:`, any entry stored in the YAML file **overrides** a matching environment variable automatically.

## Loading and Storing File Configuration

On instantiation, the `Config` class calls its `load()` method (lines 40–46 of [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py)) to read `~/.agent-reach/config.yaml` — or a custom path if provided — into the internal `self.data` dictionary. This dictionary becomes the primary lookup table for all subsequent `get()` requests.

If the file does not exist or is empty, `self.data` starts as an empty dictionary, causing the class to skip directly to environment variable resolution.

## The `get()` Method Implementation

The precedence logic lives in the `get()` method (lines 68–77 of [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py)). The implementation performs the following checks in order:

- It first tests whether the requested key exists in `self.data`.
- If not found, it queries `os.environ.get(key.upper())`.
- If still unresolved, it returns the user-supplied `default`.

This design lets users persist credentials and other settings safely in the local YAML file while still supporting temporary overrides via environment variables whenever the file entry is missing.

## Modifying and Persisting Settings

The class exposes several helper methods that operate on the same internal dictionary and persist changes back to disk:

- **`set(key, value)`** — Updates `self.data` and triggers `save()`.
- **`delete(key)`** — Removes a key from `self.data` and persists the change.
- **`is_configured()`** — Checks whether the configuration has been populated.
- **`get_configured_features()`** — Returns a list of configured feature keys.

All mutations are written immediately to `~/.agent-reach/config.yaml` via the `save()` method, ensuring the file remains the authoritative source.

## Practical Code Examples

The following examples demonstrate the precedence behavior in practice:

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

# -------------------------------------------------

# Example 1 – Normal lookup (file takes priority)

# -------------------------------------------------

# Assume ~/.agent-reach/config.yaml contains:

#   exa_api_key: "file-key-123"

cfg = Config()
print(cfg.get("exa_api_key"))          # -> "file-key-123"

# Even if an env var is set, the file value wins

os.environ["EXA_API_KEY"] = "env-key-456"
print(cfg.get("exa_api_key"))          # still -> "file-key-123"

# -------------------------------------------------

# Example 2 – Fallback to environment variable

# -------------------------------------------------

# Remove the key from the config file (or use a fresh Config instance)

cfg.delete("exa_api_key")
print(cfg.get("exa_api_key"))          # -> "env-key-456"

# -------------------------------------------------

# Example 3 – Providing a default value

# -------------------------------------------------

print(cfg.get("nonexistent_key", default="default-value"))

# -> "default-value"

```

## Summary

- The `Config` class in [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py) enforces a fixed precedence: **config file > environment variable > default**.
- The `load()` method populates `self.data` from `~/.agent-reach/config.yaml` at instantiation.
- The `get()` method (lines 68–77) checks `self.data` before querying `os.environ.get(key.upper())`.
- Any key present in the YAML file automatically masks an identically-named environment variable.
- Mutations through `set()` and `delete()` are persisted back to the YAML file via `save()`.

## Frequently Asked Questions

### What happens if a key exists in both the config file and an environment variable?

The file entry always wins. Because [`agent_reach/config.py`](https://github.com/Panniantong/Agent-Reach/blob/main/agent_reach/config.py) checks `if key in self.data:` before querying `os.environ`, a value stored in `~/.agent-reach/config.yaml` completely overrides its environment counterpart.

### How does Agent Reach normalize environment variable names?

The `get()` method upper-cases the requested key when falling back to environment variables. A lookup for `exa_api_key` becomes a search for `EXA_API_KEY` in `os.environ`.

### Can I override a file-based setting temporarily without editing the YAML?

No, not through the standard `get()` path. Since the file takes priority, you must either delete the key from the config file using `cfg.delete(key)` or modify the YAML directly so that the environment variable is consulted instead.

### Where does Agent Reach store configuration data by default?

By default, the `Config` class reads from and writes to `~/.agent-reach/config.yaml` in the user's home directory. This path is loaded during `load()` at instantiation and updated on every `save()` call.