Configuration¶
Xclif can read parameter values from config files and environment variables using
WithConfig[T]. When a parameter is not supplied on the command line, Xclif checks
these sources in order:
CLI flag (highest priority)
Environment variable
Local config file (cwd — only when
local_configis set)User config file (TOML or JSON in the OS config directory)
Default value (lowest priority)
Basic usage¶
Annotate parameters with WithConfig[T] to opt into config/env resolution:
from xclif import WithConfig, command
@command()
def _(name: WithConfig[str], template: WithConfig[str] = "Hello, {}!") -> None:
"""Greet someone by name."""
print(template.format(name))
Now name and template can be set via the CLI, environment variables, or a config
file — without changing any command logic.
Environment variables¶
By default, the env var name is <PREFIX>_<PARAM>, where PREFIX is the uppercased
app name:
# For an app named "greeter", the param "name" maps to:
export GREETER_NAME=Alice
greeter greet # uses "Alice" from env
Override the prefix on Cli:
cli = Cli.from_routes(routes, env_prefix="MYAPP")
# Now looks for MYAPP_NAME instead of GREETER_NAME
Config files¶
User config (global)¶
Xclif looks for a user config file in the OS-appropriate config directory (via platformdirs):
Linux:
~/.config/<app>/config.tomlmacOS:
~/Library/Application Support/<app>/config.tomlWindows:
C:\Users\<user>\AppData\Local\<app>\config.toml
TOML is preferred. If no TOML file exists, Xclif falls back to config.json in the
same directory. If neither exists, config resolution is skipped.
Example TOML config:
name = "Alice"
template = "Hello, {}!"
Override the app name used for the config directory:
cli = Cli.from_routes(routes, config_name="my-greeter")
Local config (per-project)¶
You can also load a config file from the current working directory by setting the
local_config parameter to a filename. This is useful for per-project configuration
that lives alongside the project files:
cli = Cli.from_routes(routes, local_config=".myapp.toml")
With this, Xclif looks for .myapp.toml in the current directory. If found, its values
are deep-merged over the user config — local values win, but user-level keys not present
in the local file are preserved. The file must have a .toml or .json extension.
If the file does not exist, it is silently skipped. When local_config is not set
(the default), no cwd lookup is performed.
Auto-injected config subcommands¶
When any parameter in your app uses WithConfig, Xclif automatically adds a config
subcommand group with three commands:
myapp config get [KEY...]— print all config values, or specific keysmyapp config set KEY VALUE— write a value to the config filemyapp config path— print the config directory path
config set creates a TOML file if none exists. If only a JSON config file exists, it
writes to JSON instead.
If your app already defines a config subcommand, the auto-injection is skipped.
To suppress the config subcommand entirely, pass config_command=False:
cli = Cli.from_routes(routes, config_command=False)
Conflict detection¶
Xclif checks for conflicts at startup (and at compile time with xclif compile). Two
parameters sharing the same config key or env var with different types is an error:
WithConfig conflict: config key 'name' is used as str (in 'greet')
and int (in 'farewell').
To fix, rename one of the parameters.
Same key with the same type is allowed — the parameters share the config value intentionally.
Full example¶
# routes/greet.py
from xclif import WithConfig, command
@command()
def _(name: WithConfig[str] = "", template: WithConfig[str] = "Hello, {}!") -> None:
"""Greet someone by name."""
if not name:
print("Error: provide a name or set one with `myapp config set name <name>`")
return
print(template.format(name))
# __main__.py
from xclif import Cli
from . import routes
cli = Cli.from_routes(routes, local_config=".myapp.toml")
if __name__ == "__main__":
cli()
# CLI flag (highest priority)
myapp greet --name Alice
# Environment variable
export MYAPP_NAME=Alice
myapp greet
# Local config file (.myapp.toml in cwd)
echo 'name = "Alice"' > .myapp.toml
myapp greet
# User config file (OS config directory)
myapp config set name Alice
myapp greet
# Check config
myapp config get
myapp config path