vike
Set up

vike-cli config

Two verbs over one settings directory: show discloses every setting and where its value came from, check judges the same tree and makes the exit code the product.

config has two verbs. They read the same directory through the same loader and differ in what they produce.

usage: vike-cli config <verb> [options]

verbs:
  show    every setting, its effective value, and WHERE that value came from
  check   validate this box's settings tree + credential store; the EXIT CODE is the product

run `vike-cli config <verb> --help` for a verb's own options

show's product is a table; its exit code says only whether the loader refused, so nothing there can be put in front of a daemon. check's product is the exit code, which is what the shipped deploy/*.service units put in an ExecStartPre= (crates/vike-cli/src/cmd/config.rs, crates/vike-cli/src/cmd/config_check.rs).

config show — provenance

usage: vike-cli config show [--json] [--filter <substr>] [--changed-only] [--section files|env|all]
flagmeaning
--sectionwhich half to print. files = the settings TOMLs; env = the environment-variable registry; all (default) = both. The env half is several hundred rows, and the question that motivated the files half — did my policy.toml get read? — should not require scrolling past them
--filter <substr>case-insensitive substring match on the setting name or key, or on the reading crate or file, so --filter reconcile, --filter bridges/okx and --filter policy all work
--changed-onlyonly rows something actually configured — the "what have I set?" view
--jsonone object carrying the settings directory, the per-file status, both row sets and the loader's warnings

The files half covers <project>/settings/{policy,config,preferences,flags}.toml, and its provenance is exact: an origin is decided by key presence in a parsed layer, so a policy.toml that sets a key to the same number as the code default still reports policy.toml. That half is why the command exists in this shape — a risk ceiling can only be set in a file, and until this existed nothing anywhere printed whether that file had been read. A typo'd filename, or a directory resolved from the wrong project, produced a silently uncapped node. See settings and policy.

The env half is the registry of every environment variable the workspace reads. Precedence there is process env > the credential store > documented default, and the printed source is the store that won, not the highest store that merely holds a key. Presence wins, not non-emptiness: an exported NAME= overrides the store with an empty string and is reported honestly.

`source` is what the stores support; `READS` is what the reader does

Most consumers read exactly one store, so a source word alone would assert a provenance the tool cannot verify. Each row therefore prints READS: env for a direct env::var, caller-map for a map the caller supplies, unknown for a computed name. A row whose value came only from the credential store while its reader calls env::var is named in a warning under the table — a real case that used to print a flat, confident dotenv. The Layer column is not that signal: it records where a read lives, not which store it consults.

Every row in the files half also carries READ, and the cell names the binary where one can be derived. Attributing a value to a file and printing its origin asserts the value is in force; when nothing reads it, that assertion is positive confirmation of something false. A clean install found five keys in exactly that state, and a later one on a headless box found three more reporting READ: yes whose only reader is the GUI, which will never run there. A NO is followed by what reads the key's environment variable instead; policy.* keys are exempt, having their own gate.

The default env table discloses which venues and tiers this box holds credentials for

The registry declares the whole {VENUE}_{TIER}_API_* grid, so the table names every one of those keys and marks each <set> or <unset>. No value can leak: redaction happens inside the resolver rather than in either printer, so --json cannot leak what the tables hide, and a secret-shaped row prints <set>/<unset> while still reporting its true source. --changed-only is the wrong instinct here and reads like the right one — it keeps precisely the rows something set, so on this table it prints exactly that list. The narrow view for a paste is --filter.

Store keys matching no registry row print as a complement under the env table — credential-shaped ones counted and never named, everything else named outright — because a typo'd variable used to look exactly like one that was never set.

config check — the pre-flight

usage: vike-cli config check [--json] [--strict]

  --json      the same report as one JSON object
  --strict    promote every WARNING to a failure. For an operator asking `is this box fully
              configured?`, NOT for a systemd ExecStartPre= — it refuses a paper deployment
              over an absent-but-legitimate configuration

exit 0 = nothing is broken; exit 1 = something the operator believes is configured is not

The three levels are not severities anyone tuned. Each row is an argument, decided by the same rule startup preflight applies: refuse when a silent difference would leave the operator believing a protection is armed when it is not; degrade when "unconfigured" is a legitimate state the operator may have chosen.

findinglevel
a removed environment variable is setfail — the operator asked for a ceiling and does not have it
a settings file fails to loadfail — the same refusal a daemon performs
the credential store exists and cannot be readwarn, or fail when this box is armed for live
VIKE_SETTINGS_DIR names a path that is not a directoryfail — set-but-unhonoured
no settings directory at allwarn — the ordinary state of a fresh clone and of CI
the credential store is absentok — absent credentials are the live gate
the store is readable beyond its ownerwarn — a finding is never a refusal
a pre-one-store <project>/.env beside an absent storewarn

The absent-store row is what makes the verb installable at all: every shipped unit is a paper deployment with an empty store, so failing there would make a correct fresh install unstartable.

The one arming-aware row reads two independent sources and never the credential store — the store is the thing that could not be read. One is the venue-scoped arming table over the process environment; the other is the resolved flags.tradehub_live, which is node-scoped and so speaks for the switchless venues that pick their tier from a credential prefix inside the unreadable file. A settings tree that did not load yields an undetermined verdict, which refuses: answering "not armed" from a missing signal is the bug this row exists to catch. See risk and arming.

Output is OK/WARN/FAIL per finding, then N error(s), M warning(s)., followed by a verdict sentence when anything failed or warned. On failure one line also goes to stderr, so journalctl -p err catches an ExecStartPre= refusal without anyone reading the whole report; the report stays on stdout whatever the verdict.

On one shipped layout --strict calls a correct install an error

A recorder needs no credentials, so its runbook creates a <project>/.env and no secrets.env. Absent store plus a <project>/.env is exactly the pair the legacy-store warning fires on — a pre-one-store leftover and a systemd EnvironmentFile are the same file to anything that does not read it. So --strict there exits 1 with a single credential store warning. That is audit mode being literal; the units run the default disposition.

Both verbs answer --help on stdout with exit 0, at the verb level and at the show/check level alike — see global flags. For the credential store itself, vike-cli secrets is the surface that names keys.

On this page