Agent Wranglers

DEV-14Recommended

Read settings in one documented order from standard folders

Take each setting from the first source that sets it. The order is flag, environment variable, project file, user file, system file and built-in default. On Linux and BSD, find files through the XDG base directory variables.

How to do it

A user who cannot tell why a value applies loses an afternoon, and an agent guesses. Write the order in the help text and keep it fixed. The XDG Base Directory Specification puts user settings in $XDG_CONFIG_HOME, which defaults to ~/.config. System settings go in $XDG_CONFIG_DIRS, which defaults to /etc/xdg. Caches go in $XDG_CACHE_HOME and history or logs in $XDG_STATE_HOME. The specification says to ignore a relative path in these variables. On Windows, use %APPDATA% for settings and %LOCALAPPDATA% for caches. On macOS, follow the XDG rules or use ~/Library/Application Support, and document which. Never write a dotfile straight into the home folder. Offer a command such as example config list --show-origin that prints each value and the source it came from. Secrets never come from flags, as Take secrets from the environment or a file instead of a flag says.

Examples

Python example

import os
from pathlib import Path

def user_config_dir(app: str = "example") -> Path:
    if os.name == "nt":
        return Path(os.environ["APPDATA"]) / app
    xdg = os.environ.get("XDG_CONFIG_HOME", "")
    base = Path(xdg) if os.path.isabs(xdg) else Path.home() / ".config"
    return base / app

def resolve(name, flags, env, project, user, system, defaults):
    for source in (flags, env, project, user, system, defaults):
        if name in source:
            return source[name], source.origin
    raise KeyError(name)

Go example

func userConfigDir(app string) string {
	if runtime.GOOS == "windows" {
		return filepath.Join(os.Getenv("APPDATA"), app)
	}
	base := os.Getenv("XDG_CONFIG_HOME")
	if !filepath.IsAbs(base) {
		home, _ := os.UserHomeDir()
		base = filepath.Join(home, ".config")
	}
	return filepath.Join(base, app)
}

How to check

A test sets one setting in all six sources, then removes them one at a time from the top. Each time the value comes from the next source in the order. With XDG_CONFIG_HOME=/tmp/x the tool reads /tmp/x/example/config.toml, and with XDG_CONFIG_HOME=relative it reads ~/.config/example/config.toml. A run with an empty home folder creates no file directly in it.

Sources

For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/developer-tools/configuration-and-telemetry/config-precedence">Agent Wranglers developer tools, SDKs and CLIs playbook</a>. In code you write, add a comment next to it with the same link.