vike-cli surface
Writes vike-cli's own backtest-plane command surface as the cli.json asset the docs site renders this reference from.
vike-cli surface writes this binary's own command-surface data as JSON. It runs anywhere vike-cli runs — a developer's prompt or a release workflow against a bare checkout — because it reads no settings, opens no credential store, and dials no daemon. The table it prints is compiled into the binary, so the answer is a property of the build, not of the environment it runs in.
What it writes
The verb is a thin writer over crates/vike-cli/src/surface.rs's rendered_files. The table and its rendering live entirely in that module; crates/vike-cli/src/cmd/surface.rs's run only decides where the bytes land (stdout, a directory, or nowhere but a name list), so a release workflow and a developer at a prompt reach identical output.
rendered_files returns one asset today: cli.json, named by crates/vike-cli/src/surface.rs's CLI_JSON constant. The docs site fetches published assets like this one from the public mirror's latest release and renders committed MDX from them at prebuild — the Rust-side obligation is to produce the asset, never to decide how a page looks.
crates/vike-cli/src/surface.rs's PLANE constant is "backtest". Everything cli.json describes today — sub-verbs, flags, rosters, refusals — is the vike-cli backtest plane. It says nothing about trade, mcp, datahub, or any other verb; there is no second plane wired in yet.
The schema version is a declaration, not a gate
crates/vike-cli/src/surface.rs's SCHEMA_VERSION is not checked against cli.json specifically — the docs site's own asset-freshness check reads only stats.json's version field, so a cli.json declaring a version the site can't read is rendered anyway. What actually protects the site is that its fetch is all-or-nothing: every published asset is fetched together, and any one of them failing to fetch or parse demotes every asset — cli.json included — to the last committed snapshot, silently. A malformed cli.json costs the site a release's worth of freshness for being malformed, not for its version number.
Usage
vike-cli surface [--out DIR] [--list]With neither flag, every asset prints to stdout, one after another. --list and --out are read in that order inside crates/vike-cli/src/cmd/surface.rs's run: if both are given, --list wins outright and nothing is written to disk.
| flag | takes a value | effect |
|---|---|---|
--out DIR | yes, --out DIR or --out=DIR | creates DIR if it doesn't exist, writes each asset into it under its own name, and reports each write to stderr as wrote <path> |
--list | no (--list=1 is refused) | prints each asset's name, one per line, and writes nothing |
-h, --help | no | prints the usage line above to stdout and exits 0 |
Print the current surface to stdout:
vike-cli surfaceList the published asset names without writing anything:
vike-cli surface --listWrite the assets to a directory, for a release workflow or a local docs-site checkout to pick up:
vike-cli surface --out distThat last form creates dist/ if needed, writes dist/cli.json, and logs wrote dist/cli.json to stderr.
An unrecognized flag is refused by name (crates/vike-cli/src/cmd/surface.rs's parse), the same shape every other verb's flag loop uses.
Why a subcommand, not --help --json
Help already has a channel: it travels back through the Err path as crates/vike-cli/src/cmd/args.rs's HELP_SENTINEL, and exit_for_parse_error turns that sentinel back into the static usage text on stdout at exit 0. That path carries no payload — it can print one fixed string, never a document. Making --help emit JSON would need a second sentinel, and any reply that isn't byte-equal to a sentinel falls through to the ordinary eprintln! usage-error arm — so a near-miss between the two sentinels would silently read as a usage error instead of as JSON, which is a failure exit_for_parse_error's own doc already records having happened. A separate subcommand has no sentinel to collide with: it returns its data through the normal exit path instead of hijacking the help path.
Why not a second binary
crates/vike-cli/Cargo.toml declares no [[bin]] section — there is exactly one binary in this crate. crates/vike-ops/tests/packaging_gate.rs polices that manifest, but against a different property: that its release-asset template cannot drift from what actually ships, not a one-binary invariant. An xtask-style side binary would face the same objection from the other direction: either shape joins the release matrix for the sake of producing one JSON file. Folding the writer into the existing binary as a subcommand means the release workflow's own vike-cli build is the thing that renders cli.json, with nothing extra to build, sign, or ship.