preferences.toml
Taste and tuning — the two independent log levels, the chart style and the sweep thread bound — the one settings file where nothing is a ceiling and both log levels apply without a restart.
crates/vike-config/src/preferences.rs is the authority for this file. Its header draws two lines.
Against config.toml: would a second machine need a different
value? — a log level or a chart style would not, they express what the operator likes. Against
policy.toml the line is sharper: policy sets the bound, a
preference sets the value inside it. settings/preferences.example.toml states the consequence
plainly — nothing here is a risk control. A preference may be wrong and cost you a readable screen;
it can never place a larger order.
Every key carries the full chain: environment variable, then this file, then the default — with one
reservation: vike_config::CONSUMPTION still marks preferences.sweep_threads unconsumed, because
crates/vike-backtest/src/harness/sweep.rs's sweep_threads reads VIKE_SWEEP_THREADS itself and
none of its callers load settings, so only the variable bites for that one key today.
| key | environment variable | default | hot-appliable |
|---|---|---|---|
log_level | RUST_LOG, then VIKE_LOG | DEFAULT_LOG_LEVEL = info | yes |
log_file_level | VIKE_LOG_FILE_LEVEL | DEFAULT_LOG_FILE_LEVEL = trace | yes |
chart_style | VIKE_STYLE | absent — the GUI's own default | no |
sweep_threads | VIKE_SWEEP_THREADS | absent — min(4, available_parallelism()) | no |
log_level is the console filter, in standard tracing directive syntax (info, warn, or a
targeted info,vike_exec=debug). RUST_LOG is checked first, matching vike_log::init, and
VIKE_LOG is the Vike-flavoured alias.
log_file_level is the JSON log file's own level, and it is independent of log_level,
which filters the console only.
This is the disk knob, and the surprise is that RUST_LOG does not touch it
The file layer defaults to trace and captures the log-to-tracing bridge, so a chatty
dependency writes at trace no matter how quiet the terminal looks. The example file carries the
measurements: one hour of pmxt_backfill wrote 6.4 GB, and one long range wrote 341 GB and
nearly filled the disk hosting a live trading node. Set this to warn for any long backfill or
replay run — off silences the file entirely — and still watch the size of config.log_dir. The
shipped systemd units all set it to warn. The default is kept at trace in
DEFAULT_LOG_FILE_LEVEL deliberately, so that introducing this file changed nothing; the field
exists so a deployment can finally turn it down in a file instead of an environment variable.
chart_style is the style vike-desktop opens new chart windows with. Absent means the GUI's own
default. It is read only by vike-desktop, so it does nothing on a headless daemon or a recorder box.
sweep_threads bounds the rayon pool a parameter sweep installs. Absent falls back to
vike-backtest's own min(4, available_parallelism()), and the example file notes it must not be
zero. It is the one key here the file cannot yet set: sweep_threads reads VIKE_SWEEP_THREADS
itself and none of its callers load settings, so today only the variable bites.
The two hot keys
crates/vike-tradehub/src/hot_reload.rs classifies every config, preferences and flags key as
hot-safe or restart-required, exhaustively against vike_config::provenance::setting_keys, and its
the_hot_set_is_exactly_the_two_log_levels test pins the hot set to exactly preferences.log_level
and preferences.log_file_level — a pin, so growing the set is a deliberate diff on that line plus
a reasoned table row rather than a drive-by. Every hot row must carry a written reason, checked for
length the way vike_config::consumed's gate checks its own; the module calls this the
power-granting class carrying its own justification.
A hot write does not apply on the server's connection thread. The accepted write enqueues an apply
job and blocks, bounded by HOT_APPLY_DEADLINE, while the daemon's existing periodic summary tick —
the same off-fold thread that prints the stdout summary and drives alerting — drains the queue and
executes the apply. One thread owns every runtime mutation, so two concurrent writes cannot race an
apply and nothing new touches the core fold. Response::SettingsWritten.restart_required is false
only when the tick confirmed the apply executed inside the deadline; a timeout, a failed apply, a
daemon without the seam wired and a restart-class key all answer true, which is always safe. The
one residual the module declares: an apply that lands after the deadline was already reported as
restart-required — conservative, never false the other way.
The rate_utilization tombstone
The field is gone and the key is now refused by name rather than ignored, and the story is worth
keeping because the example was wrong in the one way that matters. rate_utilization claimed to
replace the compiled-in vike_model::rate_limits::DEFAULT_UTILIZATION, and
policy.rate.max_utilization clamped it at the end of the load with a warning naming both halves.
Nothing read the result. Every pacer takes its target fraction from
vike_binance::family::klines::KlineSpec::utilization, and every construction site of that field
fills it with the constant. So an operator could set the preference, watch it validate, watch
vike-cli config show attribute it to their file, watch the policy ceiling clamp it, read a warning
about the clamp, and change nothing at all. There was also a --rate-utilization CLI override that
no binary parsed.
Both halves are tombstones now. The concept did not leave the product, only this file:
vike_model::rate_limits owns the number and its bounds, and — the part a single float in this
struct could never express — per-venue overrides through vike_model::RateLimitConfig. A pacing
knob that cannot say 40 % on binance, 20 % on aster is the wrong shape. The field also
deliberately never got a VIKE_RATE_UTILIZATION environment name, for a reason that still holds for
any future one: a program whose end state is no crate calls env::var except vike-config should
not open by minting a new environment variable.
With that field gone there is no policy-bounds-preference clamp left in the loader.
crates/vike-config/src/lib.rs's header says so outright, and crates/vike-config/src/load.rs's
layered load now ends at the CLI layer, carrying a comment where the clamp call used to sit. The
mechanism is not repudiated, only uninstanced — policy sets the bound, a preference sets the value
inside it is still the spine of the split, and the first real bound/value pair brings the pass
back, ideally with the gate that would have caught this one. vike-cli config show --filter preferences prints which layer won for each key — see the
config verb.
config.toml
Deployment settings — store roots, log and journal directories, and the three listen or dial addresses — each with its environment variable and whether a running daemon can apply it without a restart.
flags.toml
Operator toggles — every one a bool defaulting to false, every one carrying an owner, a review date and the disposition its review is expected to reach.