vike
Tools

discover_params

Read back the tunable param() knobs a Rhai strategy declares, with their defaults, in declaration order — offline, with no server of any kind.

discover_params compiles a Rhai strategy and tells you which knobs it exposes: the exact keys a profile's [strategy.params] or a [sweep] grid may override, in declaration order. It is how an agent finds those names without asking the human who wrote the script.

Call it on a script you wrote, too. The description used to read as an inspection tool for somebody else's code, and an agent that had just authored a strategy answered "which parameters can I tune" from memory of what it had written instead of calling this. It happened to be right and had no way to know it was: validate_strategy answers {ok: true} and says nothing about params, and this tool runs the top level only — so the one mistake worth catching, a param() reached from inside a hook, is invisible to the author as well as to the reader. The tool's own text now says both things (tools_spec in crates/vike-cli/src/cmd/mcp.rs).

Offline. tools_spec annotates it readOnlyHint: true, idempotentHint: true and openWorldHint: false — the only one of the three that is unusual is the last: this tool touches no datahub and no node, so a session with neither configured can still call it.

Arguments

ParameterTypeRequiredNotes
scriptstringyesRhai strategy source

A missing or non-string script is a tool error before anything is compiled — the message names the argument it wanted.

What comes back

{ "params": [ { "name": "fast", "default": 5.0 }, { "name": "slow", "default": 20.0 } ] }

tool_discover_params calls vike_script::discover_params and maps each (name, default) pair into that object. Defaults are always numbers — ScriptCtx::params_seen is an IndexMap<String, f64>, so a knob is an f64 and nothing else.

Order is declaration order, not alphabetical. discover_params's own doc says "in declaration order", and the IndexMap behind params_seen is what makes that true rather than incidental.

How the knobs are found

vike_script::discover_params builds the engine, compiles the source, and runs its top level exactly once with an empty scope and no overrides. It is broker-agnostic: no Strategy<B> is mounted, so nothing trades and nothing needs a venue.

The recording happens inside the host function itself. build_engine registers param(name, default) to record the pair into params_seen — first seen wins — and return the injected override if one is present, else the default. Discovery injects no overrides, so what comes back is the declared default in every case.

param() takes an integer default too

The registration comment is explicit that the default argument is a rhai::Dynamic, not an f64, and says why: registered as f64 it accepted param("fast", 5.0) and rejected param("fast", 5) with a Rhai "Function not found" naming an i64 — a knob that worked or did not depending on whether the author typed a decimal point. Every shipped template happens to write 5.0, which is why it went unnoticed.

Because only the top level runs, only the param() calls the top level reaches are recorded. That is the shape the engine documents for the call — let fast = param("fast", 5.0); at the top level, so the one-time run bakes the value in — and a knob buried inside a hook is invisible to discovery. That is not only a reporting gap: a [sweep] grid built from what this tool answers can never name that knob, so it is driven only by somebody who already knows it is there. The override map itself is not the limit — crates/vike-script/src/engine.rs registers param to read overrides on every call, so a name you do type into the grid reaches a hook-level param() like any other.

A compile error is a tool error here

This is the one place discover_params and validate_strategy differ, and they run the same compile path. validate_strategy turns a bad script into an ok: false answer the agent reads and fixes; discover_params returns a tool error, rhai compile error: …. If you are checking whether a script is sound, call validate_strategy; call this one when you want the knobs.

Compiling is a much weaker signal than it looks

Rhai resolves a registered function when its line runs, not at compile time, and this tool runs only the top level — so every call inside on_bar is unchecked. Three mistakes land in that blind spot: an unbound name (a typo, or any name outside the host-bound set), a wrong arity, and a wrong argument type on a concretely-typed binding — Rhai's resolve_fn hashes each argument's TypeId and performs no int-to-float coercion for a registered function, so market(1, 1) misses as hard as a typo, while the indicators and param take a rhai::Dynamic and accept either. Each raises a runtime error on every bar — function-not-found for the first two, and crates/vike-script/src/engine.rs's bad_arg message for a non-numeric indicator argument. RhaiStrategy's hook runner swallows it (fail-safe: zero orders that bar) and self-disables after 10 consecutive errors. The strategy looks mounted and silently never trades. Check the names against list_indicators, which reports the set the host actually binds.

Where it sits in a session

Start from list_templates or your own source, call this to see the knobs, then name those knobs in a [sweep] table and hand the profile to run_sweep — each key there overrides strategy.params.<key> across a value grid. The language itself is documented under Scripting, and the engine's registered surface in The engine.

Here is my Rhai strategy — what knobs does it expose, and what are their defaults?

On this page