User-level global config
The same .gwm.toml schema may also live at a user-level location, applied to every repo on the machine. Set a preference once (a theme, a worktree base, a keymap) and every repo inherits it unless its own .gwm.toml overrides it (issue #190).
Location
Section titled “Location”~/.config/gwm/config.toml$XDG_CONFIG_HOME, when set, is honoured outright ($XDG_CONFIG_HOME/gwm/config.toml): an explicit config home wins whether or not the file exists there. Otherwise gwm considers the cross-platform ~/.config/gwm/config.toml and the platform config dir (dirs::config_dir(), so Application Support on macOS and %APPDATA% on Windows), and the first that exists wins; with neither present, ~/.config/gwm/config.toml is the canonical location on every platform (issue #372; before it, macOS silently looked only under Application Support). It accepts the identical schema to .gwm.toml. See .gwm.toml schema.
[theme]preset = "catppuccin"
[tui]sidebar_position = "left"Merge semantics
Section titled “Merge semantics”The global file is merged underneath each repo’s .gwm.toml as a deep TOML overlay, then a single validation pass runs on the merged result. The repo always wins on conflict:
- Scalars: the repo value overrides the global value.
- Tables (
[theme],[worktree],[tui], …): merged key-by-key recursively, so disjoint sections from both files coexist and a nested override keeps the untouched sibling keys. - Arrays (
[[labels]],[[bootstrap.copy]],[[milestones]], …): replaced wholesale by the repo when present. They are never element-wise unioned: a repo’s[[labels]]fully supersedes the global set rather than producing a confusing concatenation.
In this example, global sets a theme and a couple of labels; the repo overrides one theme role and declares its own label set:
[theme]preset = "catppuccin"focus = "#89b4fa"
[[labels]]name = "global-label"# <repo>/.gwm.toml[theme]focus = "cyan" # scalar — repo wins
[[labels]] # array — repo replaces the global set wholesalename = "bug"Resolved result: theme.preset = "catppuccin" (from global, untouched), theme.focus = "cyan" (repo wins on the conflicting scalar, the other catppuccin roles survive), and exactly one label bug (the global global-label is gone, because the array was replaced, not merged).
No global file
Section titled “No global file”With no global file present, loading is identical to before #190: repo-only, then the built-in default. The absent-global case is preserved byte-for-byte.
Opting out
Section titled “Opting out”Set GWM_NO_GLOBAL_CONFIG=1 to force strictly repo-only loading, ignoring any global file that happens to exist. CI uses this for deterministic runs so a runner’s stray ~/.config/gwm/config.toml can’t perturb a build.
GWM_NO_GLOBAL_CONFIG=1 gwm listValidation
Section titled “Validation”Validation (theme, keymap, aliases, labels, bootstrap guards, …) runs on the merged result, not on each layer in isolation, so a global preset combined with a repo override is checked as the user will actually see it. The same load-time errors apply (.gwm.toml schema → validation rules).
Related
Section titled “Related”.gwm.tomlschema: the schema both layers share.[theme]: the most common thing to set once globally.[tui.keys]: a global keymap that follows you across repos.