# How dcg's Layered Configuration System Prioritizes Settings: A Technical Deep Dive

> Learn how dcg's layered configuration system prioritizes settings. Discover how environment variables override project user and system settings while respecting defaults.

- Repository: [Jeff Emanuel/destructive_command_guard](https://github.com/Dicklesworthstone/destructive_command_guard)
- Tags: deep-dive
- Published: 2026-07-14

---

**Environment variables override project-specific settings, which override user-level settings, which override system-level settings, with built-in defaults serving as the final fallback.**

Destructive Command Guard (dcg) implements a deterministic configuration hierarchy that merges settings from multiple sources at startup. Understanding how **dcg's layered configuration system** prioritizes settings is essential for managing security policies across different environments. The system uses a strict precedence order where the most specific source always wins, ensuring that local overrides take precedence over global defaults.

## The Five Precedence Layers

The configuration loader applies settings in a strict hierarchy from most specific to least specific. When conflicts occur, the higher-precedence layer overwrites values from lower layers.

### 1. Environment Variable Overrides

Individual settings supplied via `DCG_<SECTION>_<KEY>` variables take highest precedence. For example, `DCG_GENERAL_VERBOSE=false` disables verbose output even if configuration files enable it. These variables are parsed into a temporary `ConfigLayer` and merged on top of all other layers.

### 2. Project-Specific Configuration

The file located at `<repo-root>/.dcg/config.toml` defines settings for the specific repository where the command executes. Alternatively, the `DCG_CONFIG` environment variable can specify a custom path to a project-specific file.

### 3. User-Level Configuration

Settings in `$HOME/.config/dcg/config.toml` apply to all dcg invocations by the current user account. This layer loads once per user and provides account-specific defaults.

### 4. System-Level Configuration

Global defaults for every user on the host reside in [`/etc/dcg/config.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main//etc/dcg/config.toml). Administrators use this layer to enforce baseline security policies across the entire system.

### 5. Built-In Defaults

Hard-coded `Default::default()` implementations for each sub-struct (such as `GeneralConfig` and `PacksConfig`) provide fallback values when no other source defines a setting. These ensure the application always has valid configuration values.

## How the Merge Algorithm Works

The merging process preserves whether a value was explicitly present or absent in each configuration file using Rust's `Option<T>` type.

Each TOML file deserializes into a **partial representation** called `ConfigLayer`. All scalar fields in these layer structs are `Option<T>`, which tracks explicitly set values versus omitted fields. This distinction prevents lower-precedence layers from overwriting higher-precedence explicit settings.

The merging routine walks the hierarchy sequentially—system → user → project → environment. For every configuration field, the algorithm applies the value from the first layer containing `Some(value)`. Because later layers visit after earlier ones, a value from a higher-precedence layer overwrites any lower-precedence setting.

Finally, the system builds the complete `Config` struct by taking the merged `ConfigLayer` and filling any remaining `None` fields with hard-coded defaults from `Config::default()`.

## Configuration File Locations and Environment Variables

The environment variable prefix `DCG_` and the special `DCG_CONFIG` variable are defined at the top of [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs). When `DCG_CONFIG` is set, dcg loads that specific file instead of performing the standard layered search.

The standard resolution order searches:
1. The path specified by `DCG_CONFIG` (if set)
2. [`./.dcg/config.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/./.dcg/config.toml) (project-specific)
3. `$HOME/.config/dcg/config.toml` (user-level)
4. [`/etc/dcg/config.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main//etc/dcg/config.toml) (system-level)

## Practical Implementation Examples

Override a single setting via environment variable:

```bash
export DCG_GENERAL_VERBOSE=false
dcg scan ./                 # Verbose output disabled regardless of file settings

```

Define project-level settings in [`.dcg/config.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/.dcg/config.toml):

```toml
[general]
verbose = true

[packs]
enabled = ["cloud.aws", "git"]

```

Use a custom configuration file path:

```bash
export DCG_CONFIG=/path/to/custom-dcg.toml
dcg scan .                  # Loads custom file instead of default hierarchy

```

Access the merged configuration programmatically:

```rust
let cfg = dcg::config::load();      // Returns fully merged `Config`
println!("Verbose? {}", cfg.general.verbose);

```

## Key Source Files

Understanding the configuration system requires examining these specific files in the `Dicklesworthstone/destructive_command_guard` repository:

- **[`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs)** — Defines the `Config` and `ConfigLayer` structs, environment variable constants, and the full merge implementation including the `load_config` function with the "Config file layering" logic.
- **[`src/cli.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/cli.rs)** — Parses command-line flags such as `--config <path>` that affect which configuration file loads.
- **[`src/main.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/main.rs)** — Entrypoint that calls `config::load()` before any other subsystem initializes.
- **[`src/allowlist.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/allowlist.rs)** and **[`src/packs/mod.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/packs/mod.rs)** — Consume the merged `Config` to determine active allowlist files and pattern packs.

## Summary

- **dcg's layered configuration system** uses five precedence levels: environment variables, project-specific, user-level, system-level, and built-in defaults.
- The merge algorithm uses `Option<T>` fields in `ConfigLayer` structs to distinguish between explicitly set values and omissions.
- Higher-precedence layers overwrite lower-precedence layers in a sequential merge (system → user → project → environment).
- The `DCG_CONFIG` environment variable bypasses the standard hierarchy to load a specific file directly.
- All configuration logic resides in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs), with the `ConfigLayer` struct enabling presence-aware merging.

## Frequently Asked Questions

### How does dcg handle conflicting settings between different configuration files?

The system applies a strict precedence order where the most specific source wins. When `dcg::config::load()` executes, it merges layers sequentially starting with system-level settings and ending with environment variables. Any field defined in a higher-precedence layer overwrites the same field from lower layers, ensuring environment variables always override file-based settings.

### Can I use environment variables to override only specific fields without creating a full configuration file?

Yes. Individual fields support override via `DCG_<SECTION>_<KEY>` format variables. These variables parse into a temporary `ConfigLayer` that merges on top of all file-based configurations. This approach allows targeted overrides—such as disabling verbose mode with `DCG_GENERAL_VERBOSE=false`—without modifying any TOML files.

### What happens if a configuration file is missing or has syntax errors?

The `ConfigLayer` deserialization uses `Option<T>` for all fields, meaning missing files simply result in empty layers that contribute no values. The merge continues with lower-precedence layers until reaching built-in defaults. However, syntax errors in TOML files would typically cause the deserialization to fail, which the implementation in [`src/config.rs`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/src/config.rs) handles during the `load_config` process.

### Where does dcg look for configuration files by default?

The loader searches four standard locations in order of increasing precedence: [`/etc/dcg/config.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main//etc/dcg/config.toml) (system), `$HOME/.config/dcg/config.toml` (user), [`./.dcg/config.toml`](https://github.com/Dicklesworthstone/destructive_command_guard/blob/main/./.dcg/config.toml) (project), and any path specified by the `DCG_CONFIG` environment variable. If `DCG_CONFIG` is set, the system loads that specific file instead of performing the standard layered search.