Remote runs
The Backend toggle sends a Run, Sweep or Walk-Forward to a vike-datahub server over TCP and folds the answer into the same results pane, with the one refusal the split-plane rule adds.
Every Run, Sweep and Walk-Forward in the Studio has a Backend: where it executes. The toggle sits
on the toolbar's second line. Local, the default, runs in-process over the Studio's own store —
crates/vike-studio/src/remote.rs's Backend doc calls it byte-identical to the Studio before the
backend existed. Remote offloads the run over TCP to a
vike-datahub server — the compute-to-data backtest
service, where the engine runs next to the data and only the answer crosses the wire — with an
address field beside it (host:port) that starts at DEFAULT_REMOTE_ADDR, 127.0.0.1:7878: the
localhost port an SSH-tunnelled data service serves on, and vike-cli's own default. The choice is a
runtime toggle held on the state struct, not persisted to disk.
The contract: a drop-in for the local path
The module header states it. Each spawn_*_remote returns the exact same receiver type as its
vike_studio_core::spawn_* twin, so StudioState::poll folds a remote outcome with zero changes and
the results pane renders it unchanged. The wire answer is mapped back
onto the same BacktestResult, StudioSweep and WalkForwardReport the local engine produces, and
every failure — a connect fault, a server-side error, a protocol desync — arrives as an
Err(RunError) on that receiver, never a panic.
The strategy and slice go out as DTOs, defined once, in the light vike-datahub-client crate (wire_studio), and the server — vike-datahub
behind its serve-datafusion feature — converts wire to engine and runs the same
vike_studio_core::run::run_slice the local path runs. A native strategy's parameters ride as TOML
text, the exact text the server parses back with StrategySpec::native_from_toml_str, so a local
and a remote native run resolve bit-identical params. Coming back, to_backtest_result fills the
rendered fields and leaves the rest at their default; each closed trade is reconstructed losslessly; a sweep's dsr or pbo the server
could not assess arrives as NaN, the sentinel the results pane already handles; the walk-forward
report is a full mirror.
Engine parameters are the defaults, on both backends
run_slice_remote's doc: params go out as None, and the server resolves every engine field from
EngineParams::default() — matching the local path, which uses the same default. The protocol
carries an optional cost and cash override; the Studio does not expose one yet.
Errors render like local ones
The server stringifies a run failure kind-first ("{kind}: {message}"), and parse_wire_run_error
recovers the prefix — compile, data, strategy — and rebuilds the matching RunError, so a
remote failure renders identically to the same failure run locally. A connect failure or a protocol-version mismatch becomes a
data error naming the address, shown in the Studio's existing error banner; the mismatch is legible
because DatahubClient::connect performs a Hello/Welcome handshake and, when the versions
disagree, fails naming both.
A keyed data service refuses the Studio's dial
The Studio dials with DatahubClient::connect, the unauthenticated constructor — its doc names the
Studio's Backend::Remote among the callers it keeps working untouched against a key-less server.
Against a server that requires authentication it fails at the handshake with a message naming
VIKE_DATAHUB_OBSERVE_KEY and VIKE_DATAHUB_CONTROL_KEY; the Run* verbs sit in the control
scope, because they compile client-supplied Rhai on the server.
The store and the backend are two different things
The backend is where compute runs. The store is where the Studio reads history from, and it can be
remote on its own: StudioState::store is the trait handle, either a local store or an RPC-backed
RemoteHistStore whose reads go over the same protocol — read-only, one fresh connection per read.
The desktop app decides which in open_studio_store, on the resolved datahub address: the explicit
config.datahub_addr key (see config.toml), else the address
the connected backend's Welcome advertises. With an address it opens a remote store; without one
there is no local store to open. The binary also sets
store_is_remote and seeds the backend after construction. There is no local
engine at all: the Studio is remote-only, and with no address its open fails naming both fixes —
set config.datahub_addr, or connect a backend whose daemon advertises a datahub.
Connect first, then open the Studio
open_studio_store's doc calls this the contract's sharp edge: the store is opened once and kept
for the session. A Studio opened before any backend connects resolves from the explicit key alone
and never picks up the advertisement. Every other datahub consumer re-resolves per read.
The one refusal: tick slices over a remote store
remote_store_tick_refusal is the split-plane rule: with a remote store, a tick slice runs only on
the Remote backend. A local tick replay would need the tick tape — scan_book_updates, scan_depth
— pulled over the wire, which is exactly what compute-to-data refuses; the RPC store keeps both verbs
as read-only errors. Instead of dispatching, the
Studio shows one line: switch Backend to Remote. The guard sits in front of Run, Sweep and
Walk-Forward alike, and never fires for a local store, a bar slice (its load_bars read is a served
verb — small, not the tape), or the Remote backend itself.
The same offload from a terminal is vike-cli backtest, sweep and walkforward —
Running a backtest covers the verb, and
Run a sweep on the data service walks one through.
Connect your own Claude
The chat pane's Connect to Claude button writes the claude mcp add line that registers vike-cli mcp against the datahub the Studio already dials — and what that button does in a build that left the feature off.
Data Manager
The tool window that shows what the history store holds — one shared catalog view mounted by both the desktop app and the Studio, and the sub-tabs around it.