vike

Global flags

The one flag grammar every vike-cli verb shares — both spellings, the rule that a token beginning with -- is never a value, and where help becomes exit 0.

Every vike-cli verb drains the same flag iterator. crates/vike-cli/src/cmd/args.rs owns only the mechanics: the two spellings, value resolution with a clean dangling-flag error, bare-boolean rejection of inline values, the -h/--help short-circuit, and the one place a parser's Err becomes an exit code and a stream. Each command keeps its own Args struct and its own match over flag names. There is no clap — the crate deliberately adds no dependency for this.

The module exists because the same split_once('=') / take_value loop had been hand-copied across backtest, sweep and walkforward and re-rolled as closures in mcp and trade, already drifting in shape.

Both spellings resolve

--flag value and --flag=value are equivalent. Flags::next_flag splits on the first = only, so an inline value may itself contain = (--script=a=b.rhai is the script a=b.rhai). A value taken from the next argument is consumed raw and never re-split, so --profile k=v.toml is the path k=v.toml.

A value-taking flag with nothing after it is a clean error naming the flag:

--profile requires a value

A token beginning with -- is a flag, never a value

This rule is why a mistyped line fails instead of running the wrong thing

Without it a valued flag ate whatever followed, including another flag. vike-cli backtest --script --json took the literal --json as the script path and then ran with JSON output off; --profile --addr 1.2.3.4:9 put --addr in the profile path and died on the address as an unknown argument, naming a token the operator had written correctly. Both errors now name the unfed flag and the token it would have eaten (crates/vike-cli/src/cmd/args.rs's is_flag_token).

The test is --, not a bare -, and that half is load-bearing: a negative number is a real value in this workspace's parsers, so a starts_with('-') test would turn every signed field into a usage error. --qty -5 resolves to -5. The residual is stated rather than implied — a single-dash token (-h, -5) is still accepted as a value.

The rule is applied to the inline =value form as well, deliberately: one rule, one sentence, no per-spelling exception to remember. The cost is that a value which genuinely begins with -- has no flag-attached spelling; a path is still reachable as ./--weird.

A bare boolean rejects an inline value

--json, --strict, --list-params, --yes and their siblings take no value, and args::no_value refuses one rather than reading it as a silent true:

--json takes no value

Help is a success; its text is stdout

-h and --help short-circuit a parser through the Err channel — these parsers return Result, so "the user asked for help" has to travel back somehow — carrying the sentinel args::HELP_SENTINEL, spelled once so the parsers and the exit path cannot disagree about it. It is control flow, never a diagnostic, and must never reach a terminal.

args::exit_for_parse_error is the one place that decision is made:

outcomestreamexit
-h / --helpthe usage, on stdout — help is normal output a user pipes into a pager0
a usage errorvike-cli <command>: <msg> and the usage, on stderr1

Nothing else is printed on the help path, and the sentinel appears nowhere. Every non-interactive command used to inline the error arm and route the help short-circuit straight into it, so --help exited 1 and printed vike-cli backtest: help requested. Sharing the decision is what stops the spellings drifting apart again: config had already been fixed at its verb level and not at its show --help level, in the same file. The shipped-binary gate is crates/vike-cli/tests/help_cli.rs, which asserts the status, the stream and the absence of the token; see the dispatcher.

The trade REPL is the one deliberate outlier — it records help = true and prints its verb reference instead of short-circuiting, because its help is a reference to an interactive grammar rather than a usage line.

Flags that mean the same thing everywhere

These are conventions across the verbs rather than shared code, but they are spelled the same way by every command that has them:

flagmeaning
--profile <path>a backtest profile .toml, read locally and shipped to the server — verbatim for sweep and walkforward, while backtest rewrites it first if --preset or --script was given
--addr <host:port>the data service address, default 127.0.0.1:7878
--node <host:port>a running vike-tradehub node — trade, mcp
--jsonprint the machine view: the server's report verbatim, or the command's own report as one object — including data, which describes the fetch or the seed and quotes the engine's report verbatim

A verb that produces a document prints it on success only: a failure is a sentence on stderr plus a rung on the exit ladder, and stdout carries nothing, so a caller reads the exit code first and parses second. None of them wraps the answer in an {"ok": false} shape that would duplicate what the code already said. config check is the deliberate exception, and for a reason its own page gives — there the exit code is the product, so its report is meant to be read on a failing run too and is printed either way.

Before any of this is parsed, the dispatcher has already refused a removed environment variable and resolved this box's settings — see environment variables and settings.

On this page