Summary
Introduce a user-level TOML configuration file so operators can persist common settings (hostfile path, update interval, alert thresholds, $/kWh, theme) without retyping CLI flags on every invocation. Provide a well-defined precedence chain (CLI flag > env var > config file > compiled default), plus all-smi config print and all-smi config init helpers.
Motivation
all-smi has accumulated many run-time options across the three subcommands (local, view, api) and will acquire more as upcoming features land (alerts, energy pricing, record defaults, themes, agentless SSH). All of them currently live on the CLI. For a power user managing a fleet, retyping flags each session is friction; for a team, sharing a config file is far simpler than sharing a shell alias. A config file also provides the single natural home for the [alerts] and [energy] sections referenced by the threshold-alerts issue and the energy-accounting issue.
Current state
src/common/config.rs contains compile-time constants in AppConfig/EnvConfig.
- No config file reader exists.
- CLI flags are the only user-facing input.
Proposed design
File location
Standard platform locations, with --config <path> always overriding.
- Linux:
$XDG_CONFIG_HOME/all-smi/config.toml (fallback ~/.config/all-smi/config.toml)
- macOS:
~/Library/Application Support/all-smi/config.toml (fallback ~/.config/all-smi/config.toml accepted for parity)
- Windows:
%APPDATA%\all-smi\config.toml
Schema
# all-smi config — all fields optional; omitted fields fall back to the built-in default.
[general]
default_mode = "local" # "local" | "view" | "api"
theme = "auto" # "auto" | "light" | "dark" | "high-contrast" | "mono"
locale = "en"
[local]
interval_secs = 2 # 0 = adaptive default
[view]
hostfile = "~/.config/all-smi/hosts.csv"
hosts = []
interval_secs = 0 # 0 = adaptive based on host count
[api]
port = 9090
socket = false # bool or path
processes = false
interval_secs = 3
[alerts]
enabled = true
temp_warn_c = 80
temp_crit_c = 90
util_idle_pct = 5
util_idle_warn_mins = 15
hysteresis_c = 2
bell_on_critical = false
webhook_url = ""
[energy]
price_per_kwh = 0.12
currency = "USD"
show_cost = true
wal_path = "~/.cache/all-smi/energy-wal.bin"
[display]
color_scheme = "default" # "default" | "colorblind" | "mono"
gauge_style = "blocks" # "blocks" | "braille"
show_led_grid = true
[record]
output_dir = "~/.cache/all-smi/records"
compress = "zstd" # "zstd" | "gzip" | "none"
[snapshot]
default_format = "json"
default_pretty = true
Precedence
From highest to lowest priority:
- Explicit CLI flag (e.g.,
--port 9091).
- Environment variable (
ALL_SMI_API_PORT=9091).
- Config file.
- Compiled default.
Implementation: parse CLI into a struct with Option<T> fields, merge env into same struct, merge config file, finally fill remaining None with defaults. Keep the merge order explicit; document precedence in the error message when a conflict is ambiguous.
Helpers
all-smi config init [--force] writes a commented example config to the default path. Does not overwrite unless --force.
all-smi config print [--format toml|json] prints the final merged effective configuration. Useful for debugging flag interaction.
all-smi config validate [<path>] parses a config file and reports errors (with line/column numbers from the toml crate). Returns exit 0 on valid, 2 on parse error.
Env var mapping
Canonical pattern: ALL_SMI_<SECTION>_<KEY> (upper-snake). Examples:
ALL_SMI_VIEW_HOSTFILE=/etc/hosts.csv
ALL_SMI_ALERTS_TEMP_CRIT_C=95
ALL_SMI_ENERGY_PRICE_PER_KWH=0.18
Env var parsing uses the same schema; unknown names produce warnings in config print.
Implementation plan
Files to add / modify:
- New
src/common/config_file.rs — Settings root struct, typed sections, serde derives, validators, load(path: Option<Path>) returning the merged Settings.
- Add
toml = "0.9" (or latest compatible) to Cargo.toml, gated by the cli feature alongside clap since config is a runtime concern.
src/common/config.rs — refactor constants into Defaults and expose both the Defaults and the loaded Settings for call sites. All mutable runtime behaviors pull from Settings.
src/cli.rs:
- Add global
--config <path> argument.
- Add new subcommand
Config(ConfigArgs) with Init/Print/Validate variants.
- Rewire
LocalArgs/ViewArgs/ApiArgs so interval, hostfile, hosts, port, etc. are Option<T> and fall back through the precedence chain.
src/main.rs — after parsing CLI, load config, merge env, build a single Settings handle passed to each mode entry point.
- New
src/common/paths.rs — helpers for XDG / macOS / Windows config paths, ~ expansion.
- Each subcommand entry (local/view/api/snapshot/doctor/record) reads its parameters from
Settings with --flag overrides — update all entry points accordingly.
src/api/server.rs, src/view/runner.rs, src/view/data_collection/* — consume Settings rather than passing around ad-hoc args.
Acceptance criteria
Edge cases & non-goals
- Unknown keys:
print warns, validate without --strict accepts them (forward compat); validate --strict rejects.
- Schema version: include
schema_version = 1 at the top level; raise an error for unsupported future versions rather than silently loading.
- Config reload: out of scope — restart to pick up changes. Document this explicitly.
- Secret handling:
webhook_url may contain tokens. print redacts by default (webhook_url = "<redacted>"); --show-secrets prints fully.
- Non-goal: JSON or YAML support. TOML only for consistency and human-editability.
- Non-goal: per-user merged configs (system-wide + user). Keep just user-level for v1; a
/etc/all-smi/config.toml fallback can follow later.
Soft dependencies
- The alerts/filter issue and the energy issue assume
[alerts] and [energy] sections; they can ship independently with CLI/env overrides, but gain ergonomics once this lands.
Summary
Introduce a user-level TOML configuration file so operators can persist common settings (hostfile path, update interval, alert thresholds, $/kWh, theme) without retyping CLI flags on every invocation. Provide a well-defined precedence chain (CLI flag > env var > config file > compiled default), plus
all-smi config printandall-smi config inithelpers.Motivation
all-smihas accumulated many run-time options across the three subcommands (local,view,api) and will acquire more as upcoming features land (alerts, energy pricing, record defaults, themes, agentless SSH). All of them currently live on the CLI. For a power user managing a fleet, retyping flags each session is friction; for a team, sharing a config file is far simpler than sharing a shell alias. A config file also provides the single natural home for the[alerts]and[energy]sections referenced by the threshold-alerts issue and the energy-accounting issue.Current state
src/common/config.rscontains compile-time constants inAppConfig/EnvConfig.Proposed design
File location
Standard platform locations, with
--config <path>always overriding.$XDG_CONFIG_HOME/all-smi/config.toml(fallback~/.config/all-smi/config.toml)~/Library/Application Support/all-smi/config.toml(fallback~/.config/all-smi/config.tomlaccepted for parity)%APPDATA%\all-smi\config.tomlSchema
Precedence
From highest to lowest priority:
--port 9091).ALL_SMI_API_PORT=9091).Implementation: parse CLI into a struct with
Option<T>fields, merge env into same struct, merge config file, finally fill remainingNonewith defaults. Keep the merge order explicit; document precedence in the error message when a conflict is ambiguous.Helpers
all-smi config init [--force]writes a commented example config to the default path. Does not overwrite unless--force.all-smi config print [--format toml|json]prints the final merged effective configuration. Useful for debugging flag interaction.all-smi config validate [<path>]parses a config file and reports errors (with line/column numbers from thetomlcrate). Returns exit 0 on valid, 2 on parse error.Env var mapping
Canonical pattern:
ALL_SMI_<SECTION>_<KEY>(upper-snake). Examples:ALL_SMI_VIEW_HOSTFILE=/etc/hosts.csvALL_SMI_ALERTS_TEMP_CRIT_C=95ALL_SMI_ENERGY_PRICE_PER_KWH=0.18Env var parsing uses the same schema; unknown names produce warnings in
config print.Implementation plan
Files to add / modify:
src/common/config_file.rs—Settingsroot struct, typed sections, serde derives, validators,load(path: Option<Path>)returning the mergedSettings.toml = "0.9"(or latest compatible) toCargo.toml, gated by theclifeature alongside clap since config is a runtime concern.src/common/config.rs— refactor constants intoDefaultsand expose both theDefaultsand the loadedSettingsfor call sites. All mutable runtime behaviors pull fromSettings.src/cli.rs:--config <path>argument.Config(ConfigArgs)withInit/Print/Validatevariants.LocalArgs/ViewArgs/ApiArgssointerval,hostfile,hosts,port, etc. areOption<T>and fall back through the precedence chain.src/main.rs— after parsing CLI, load config, merge env, build a singleSettingshandle passed to each mode entry point.src/common/paths.rs— helpers for XDG / macOS / Windows config paths,~expansion.Settingswith--flagoverrides — update all entry points accordingly.src/api/server.rs,src/view/runner.rs,src/view/data_collection/*— consumeSettingsrather than passing around ad-hoc args.Acceptance criteria
all-smi config initcreates a commented config at the default path; does not overwrite without--force.all-smi config printshows the merged effective config. With--format json, output is valid JSON.all-smi config validatereports line/column for TOML parse errors and semantic errors (e.g.,theme = "rainbow").~expansion and$XDG_CONFIG_HOME/%APPDATA%all resolve correctly on the respective platforms.local,view,apicontinues to work with identical semantics.print, reject invalidate --strict), path expansion.Settingsrefactor.Edge cases & non-goals
printwarns,validatewithout--strictaccepts them (forward compat);validate --strictrejects.schema_version = 1at the top level; raise an error for unsupported future versions rather than silently loading.webhook_urlmay contain tokens.printredacts by default (webhook_url = "<redacted>");--show-secretsprints fully./etc/all-smi/config.tomlfallback can follow later.Soft dependencies
[alerts]and[energy]sections; they can ship independently with CLI/env overrides, but gain ergonomics once this lands.