Skip to content

config

mytool config [show | get <PATH> | set <PATH> <VALUE> | schema | validate] [OPTIONS]

Feature: Config. Passthrough subtree — --output must appear after the word config.

config behaves differently depending on whether the host tool called Application::builder().config::<C>(...). Both paths are documented below; the difference is called out per subcommand.

Which file config reads and writes

The canonical user file is <config_dir>/config.yaml, where <config_dir> is directories::ProjectDirs::from("dev", "", <tool name>).config_dir():

Platform Path for a tool named mytool
Linux $XDG_CONFIG_HOME/mytool/config.yaml, else ~/.config/mytool/config.yaml
macOS ~/Library/Application Support/dev.mytool/config.yaml
Windows %APPDATA%\mytool\config\config.yaml

If a config directory cannot be derived — HOME unset, for instance — the command fails with no config directory available for tool <name>.

Only set and validate accept --config-file PATH to point somewhere else. show, get and schema do not.

File format is chosen by extension

Extension Format
.toml TOML
.json JSON
anything else, including none YAML

That default is a real trap for --config-file: a path with no extension, or with an unfamiliar one like .conf, is parsed and written as YAML.

config show

Prints the resolved configuration to stdout.

With typed config wired, it serialises the merged Config<C> value as YAML. Without, it prints two comment lines and exits 0:

$ mytool config show
# no typed configuration is installed on this App
# (call `Application::builder().config(C)` to wire it)

show is the default: mytool config with no subcommand runs it. It ignores --output; it is always YAML or the placeholder.

config get <PATH>

Reads one value and prints it.

The path accepts two spellings, both resolved to a JSON Pointer:

You write Pointer used
/server/port /server/port
.server.port /server/port
server.port /server/port

Where it reads from depends on wiring. With typed config, get reads the merged value — embedded defaults and env overlays included. Without, it reads the user file directly, and a missing file is an error rather than an empty result.

Output honours --output:

  • text (default) — a bare string prints unquoted; anything else prints as JSON.
  • json — pretty-printed JSON, including for strings.

A path that does not resolve is an error: path `<PATH>` not found in <source>, where <source> is either merged config or the quoted file path.

config set <PATH> <VALUE>

Writes a value into the user file (or --config-file PATH) and prints set `<PATH>` in `<file>`.

VALUE is parsed as JSON first. If that fails it is stored as a string. So config set .port 8080 stores the number 8080, config set .name alice stores the string "alice", and config set .name '"8080"' stores the string "8080".

Intermediate objects are created as needed. Missing files are created, along with their parent directories.

What set cannot write

  • Array elements. config set /hosts/0 example.com fails with cannot set `0` on a non-object value. There is no way to address an element of a list; rewrite the whole list as a JSON literal instead — config set /hosts '["a","b"]'.
  • Anything under a scalar. /foo/bar where foo is a number fails the same way.
  • A document whose top level is not a map. If the existing file parses to a list or a scalar, set replaces the whole document with a fresh map containing only the value being written. The previous contents are gone. Back up any hand-written file with an unusual shape before running set against it.

set validates before it writes, but only with a schema wired

When typed config is wired, the candidate document is validated against the tool's JSON Schema before anything is written. A rejection leaves the file untouched:

config set rejected: candidate value at `/port` fails the wired schema: <detail>

Without typed config there is no schema, so no validation happens at all — any JSON-shaped value lands in the file, and the tool discovers the problem the next time it loads its config.

config schema

Prints the JSON Schema for the tool's typed config, pretty-printed.

Without typed config wiring this is an error, not an empty document:

config schema is not available without a typed-config integration

with help pointing at Application::builder().config(...).

config validate

Validates a candidate document and prints one line on success.

Three sources, in order of preference:

  1. --config-file <PATH> — always wins. A path that does not exist is an error.
  2. No override, typed config wired — validates the in-memory merged value.
  3. No override, no typed config — validates the canonical user file. A missing file is an error.

What "validates" means also depends on wiring:

ok: `<file>` validates against the wired schema      # schema present
ok: `<file>` parses cleanly (no schema wired — format check only)

The second line is the whole story without typed config: it proves the file is well-formed YAML/TOML/JSON and nothing more. Unknown keys, wrong types and missing required fields all pass.

Failure prints config validation failed at <label>: <detail> and exits non-zero.