vike
Reference

Reference

One core, several front ends — how the desktop app, the daemon, the CLI and the data service relate, and where each one's flags, binaries and settings live.

Vike Trader is not one program with a window bolted on. It is one core and several front ends that observe it, so the question of which binary to run is the question of which front end you want.

The core

crates/vike-core/src/lib.rs is the single-writer live core: one thread owns all mutable trading state, ingest arrives through the vike-exec lanes, and readers take a lossy arc-swap CoreSnapshot and never back-pressure the writer. Producer lanes live in vike_exec::lanes, so venue bridges never depend on the core crate at all. Nothing that renders, serves or reports gets to touch that state directly — every front end below is a reader of published snapshots and a sender of commands.

The front ends

The desktop app (crates/vike-desktop/src/main.rs) is a native egui multi-window shell. Market data flows feed threads to core ingest, the core-owned bar cache to the arc-swap snapshot, and the GUI converts each changed snapshot into its render model: "the GUI is a lossy observer; it never touches the core's state directly." The shipped build compiles out the whole local-core, DataFusion and venue-bridge subsystem, leaving an observer client. See the GUI section and vike-desktop.

The daemon (crates/vike-tradehub/src/lib.rs) is the same core, headless. Its testable internals live in a library so integration tests can drive them; the slim bin composes them into a process lifecycle — log init, node build, stdio control, bounded teardown. Two modules are the shape worth knowing: publish projects CoreSnapshot into WireSnapshot and runs the one publisher thread that fans coalesced frames to subscribers over bounded, drop-oldest mailboxes, never touching the hot fold; server is the authenticated node server, where a Scope::Control peer's request is lowered into the core's real Command/OrderIntent — and only when the daemon threads a command sink in. See the node protocol and vike-tradehub.

The CLI (crates/vike-cli/src/lib.rs) is a subcommand dispatcher in the git/cargo style. It routes and never grows command logic. run resolves settings first, so a removed environment variable is refused before any verb executes, and the credential-store read is lazy: no verb opens the file that holds every venue key on the box until it needs it — the node-facing arms (trade, mcp, strategy-status) for their node keys, and config show, config check and secrets list for their own disclosure reads. A backtest or provenance command never opens it at all. config check makes the exit code the product, which is what the shipped service units put in their ExecStartPre=. See the CLI reference.

The data service (crates/vike-datahub/src/lib.rs) inverts the direction: a client sends a small backtest profile over a localhost socket, the server runs the existing vike-backtest engine next to the data, and returns only the report. The heavy history never crosses the wire. It owns no engine — it is assembly of crates that already exist — and its transport is blocking std::net, thread-per-connection, with length-prefixed JSON frames: no async runtime, no second HTTP stack. See vike-datahub.

Library plus thin bin — and one executable that carries them all

Each tool's body lives in its crate's library and its main.rs is a shim, so a second dispatcher can reach the same code without a static copy of it. That dispatcher is crates/vike/src/lib.rs, and the reason is measured: 2026-09-01, release profile — vike-tradehub 128 MB, backtest 106 MB, vike-datahub 107 MB, while vike-cli is 9.6 MB and tearsheet 1.9 MB. The gap is one static copy of DataFusion/arrow/parquet per binary, and an image that ships all of them pays it every time. Folding the tools into one executable links that closure once.

One tool per process

Every tool owns process-global state that assumes it is alone — logging init where only the first configuration wins, signal handlers, a scripting one-shot, a dozen OnceLocks. A run that executed two tools in one process would silently give the second the first one's logging and signal handlers, so the dispatcher refuses a second call rather than documenting the hazard, and crates/vike-ops/tests/multicall_gate.rs holds the refusal by reading the source.

The dispatcher itself does nothing: no boot, no logging, no signal handler, no project resolution. That restraint is load-bearing. Every tool calls the shared startup sequence for itself, and a dispatcher that also resolved the project would make one process walk for its settings twice — where the second walk is blind to VIKE_SETTINGS_DIR and answers from whatever directory the process happens to sit above. What it does pass down is a context carrying the one environment sweep and the one working directory for the whole process.

Every front end starts the same way

crates/vike-boot/src/lib.rs owns the startup sequence once, because five composition roots used to hand-assemble the same ordered steps: refuse a removed environment variable, resolve <project>/settings, load the credentials, load the settings, derive the project-relative paths, build the log subscriber, then disclose what was resolved. One walk decides, and the log subscriber comes last deliberately — the log directory and both log levels are themselves settings, so a subscriber built first could only ever honour the environment. That crate therefore logs nothing at all and returns everything as data, which is also what lets a binary whose stdout is a protocol choose its stream.

In this section

  • CLI — the dispatcher and one page per verb.
  • Binaries — every bin target in the workspace, derived at build time.
  • Settings files — the four TOML files and alerts.json, key by key, with each key's consumer.
  • Environment variables — the registry, and the variables refused at startup.

On this page