ADR-0021: Plain-text configuration in XDG locations, never executed
- Status: Accepted; session storage amended by ADR-0031
- Date: 2026-06-25
- Deciders: jka
- Decision: D21
Context
Tcl makes it tempting to use a Tcl script as a configuration file. That runs arbitrary code at start-up and turns a typo into a start-up failure. rio also holds different kinds of state (human-written settings, machine-written session data, secrets) that have different owners and different handling needs.
Decision
State is kept in three separate kinds of file.
- User settings are a flat
key = valuefile with[section]headers and#comments, UTF-8. They are data. rio parses them and neversources them. The parser isrio::conf, shared with themes, manifests and other conf files. - Session and workspace state is written by rio as JSON and is not meant for hand editing.
- Secrets (API keys) are kept apart from both, in a store under the data
directory with the directory at 0700 and each file at 0600
(
rio-core/secret.tcl).
Locations follow the XDG Base Directory specification:
$XDG_CONFIG_HOME/rio/ (default ~/.config/rio/) for configuration and
$XDG_DATA_HOME/rio/ (default ~/.local/share/rio/) for data. A project may carry
its own settings in .rio/ at its root.
Consequences
- Configuration is diff-friendly, readable, and cannot execute code.
- A broken configuration file degrades to defaults rather than stopping rio; this rule is applied to every later file rio reads (key maps, preferences, allow-lists, certificate exceptions).
- ADR-0031 moved personal session state out of the project tree, so
.rio/holds only project-level, committable material (prompts, allow-lists, plans). - The intended Windows locations (
%APPDATA%,%LOCALAPPDATA%) were never implemented. On Windows 11 Tcl derivesHOMEfromHOMEDRIVEandHOMEPATH, so the XDG fallback resolves under%USERPROFILE%and works. The cost is that the 0600/0700 permissions are a no-op on NTFS; the key file inherits the profile's permissions.