How Destructive Command Guard's Layered Configuration System Prioritizes Environment Variables vs Config Files
Environment variables prefixed with DCG_ override all configuration files, while settings cascade through project-level, user-level, system-level, and finally compiled defaults.
Destructive Command Guard (dcg) implements a deterministic layered configuration system that balances flexibility with predictability. Written in Rust, the tool loads settings from multiple sources according to strict precedence rules documented in the header of src/config.rs【L3-L9】, ensuring that environment variables always take precedence over file-based configurations.
The Five-Layer Configuration Hierarchy
The dcg configuration system builds settings from five distinct layers, applying a "higher-precedence wins" merge strategy:
Environment Variables (Highest Priority)
Any setting supplied via a DCG_… variable shadows values from all configuration files. The constant ENV_PREFIX is defined at line 44 in src/config.rs【L43-L45】, enabling per-run overrides without modifying persistent files.
Project-Level Configuration
The .dcg.toml file in the repository root provides project-specific settings. When running dcg inside a project directory, values here override user-level and system-level configurations but yield to environment variables.
User-Level Configuration
Settings specific to the current user are read from $XDG_CONFIG_HOME/dcg/config.toml (falling back to ~/.config/dcg/config.toml on most systems). This layer applies only when project-level files are absent or when specific fields remain unset.
System-Level Configuration
Global system defaults reside in /etc/dcg/config.toml on Linux/macOS or %ProgramData%\dcg\config.toml on Windows. These provide organization-wide defaults while allowing individual users and projects to override them.
Compiled Defaults (Lowest Priority)
When no configuration files exist and no environment variables are set, dcg uses the Rust Default implementations defined for each config struct (e.g., GeneralConfig::default() at line 46【L46-L48】).
The Merge Algorithm and ConfigLayer Structure
The merging logic centers on the ConfigLayer struct defined at line 84 in src/config.rs【L84-L90】. Each configuration field uses Option<T> to represent presence or absence:
- Some(T) indicates an explicit value from that layer
- None indicates the layer did not provide that setting
During initialization, dcg parses each file into a layer, then applies the merge algorithm: if a field is Some in a higher layer (e.g., environment variables), it shadows any Some value from lower layers. Only fields that remain None after evaluating all layers receive the compiled defaults.
Practical Override Examples
Overriding a Boolean via Environment Variable
The compiled default for verbose output is false. Setting the environment variable enables verbose logging for a single run regardless of file configurations:
DCG_VERBOSE=true dcg explain "git reset --hard"
Result: verbose is true regardless of values set in .dcg.toml, ~/.config/dcg/config.toml, or /etc/dcg/config.toml.
Selecting a Custom Config File
The special variable DCG_CONFIG selects an alternate TOML file, separate from per-setting overrides【L52-L56】:
DCG_CONFIG=/tmp/my-config.toml dcg --version
Result: dcg loads the specified file instead of the normal search order, then still applies any DCG_… overrides on top of that file.
Project-Level Precedence Over User Files
Assume the following scenario:
~/.config/dcg/config.tomlcontainscheck_updates = false- The project's
.dcg.tomlcontainscheck_updates = true
Running dcg inside the repository:
cd my-repo
dcg explain "rm -rf /"
Result: check_updates evaluates to true because the project file outranks the user file.
Core Implementation Files
src/config.rs– Contains theConfigLayerstruct,ENV_PREFIXconstant, and the layered merging logic that implements the precedence rules.src/main.rs– Parses command-line arguments and orchestrates the configuration loading sequence before applying environment variable overrides.src/trace.rs– Emits diagnostic messages indicating when a setting was overridden by the environment (e.g., "BLOCK: config override").src/cli.rs– Implements thedcg config showcommand, which respects the precedence rules to display active settings.
Summary
- Environment variables with the
DCG_prefix take precedence over all configuration files. - Configuration files apply in descending order: project (
.dcg.toml) → user (~/.config/dcg/config.toml) → system (/etc/dcg/config.toml). - Compiled defaults from Rust
Defaultimplementations serve as the final fallback. - The
ConfigLayerstruct usesOption<T>fields to implement the "higher-precedence wins" merge algorithm. - The
DCG_CONFIGenvironment variable can specify a custom configuration file path, which is then subject to additionalDCG_overrides.
Frequently Asked Questions
What happens if I set both DCG_CONFIG and specific DCG_ variable overrides?
Dcg first loads the file specified by DCG_CONFIG, then applies any additional DCG_ environment variable overrides on top of that file. Environment variables always represent the final authority regardless of which file was loaded initially.
How does dcg handle configuration on Windows versus Linux?
On Linux and macOS, dcg searches /etc/dcg/config.toml for system-level settings and $XDG_CONFIG_HOME/dcg/config.toml (or ~/.config/dcg/config.toml) for user-level settings. On Windows, the system-level path becomes %ProgramData%\dcg\config.toml, while user-level configuration follows the same XDG pattern if available, or falls back to the standard config directory.
Can I see which configuration layer provided a specific setting?
Yes. When running dcg with verbose or trace output enabled, the system emits messages via src/trace.rs indicating when a configuration value was overridden by an environment variable. This helps debug which layer is active for specific settings like verbose or check_updates.
What occurs if no configuration files exist at any level?
If dcg finds no .dcg.toml, user config, or system config, it initializes the configuration using only the compiled defaults defined in the Default trait implementations for each struct (e.g., color = "auto" and check_updates = true). You can then selectively override these defaults using DCG_ environment variables as needed.
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 →