The guide · explanation
The host API
The host API is the set of wscript modules config-weave registers for every script it runs: resources, gatherers, verify scripts and scenario drivers. A script reaches the host through these modules and nothing else. This chapter explains what is registered, why the surface is the same on every platform, how scripts import shared helpers, and how to get your editor to type-check against the exact surface. Each module has its own reference chapter.
One surface on every platform
Every module is registered on every platform. A Windows-only function such as registry::read exists on Linux too, and returns a runtime error there. The reason is that compilation, validation and interface emission must be identical everywhere: a playbook validated on a Linux workstation is the same playbook that runs on a Windows host, and a script that references a foreign-platform function still compiles. Guard platform-specific calls with a step condition, for example os.family == "windows", or inside the script with sys::family().
Import a module with use <module>. Every fallible function returns Result[..., string] and composes with ?, so a resource whose entry point returns Result[CheckResult, string] can propagate a host error as the step's Error status with one character. The registered types Value, CheckResult, ApplyResult, CmdOutput, HttpResponse and ComObject are ambient, so they need no use.
The modules
Cross-platform modules, available to every script.
- log writes structured output at a level. print and println in a script are routed into log::info so stdout stays clean for the JSON report.
- fs reads, writes, copies and removes files and directories.
- path joins, splits and normalises paths.
- shell runs commands. shell::run splits its command with shell-words and executes the program directly, with no shell interpretation. bash and powershell are the escape hatches for shell features; powershell tries powershell and then pwsh, so it also works on Linux with PowerShell Core.
- http fetches and downloads over HTTP.
- hash computes digests of strings and files.
- archive extracts archives.
- env reads and writes environment variables.
- sys reports the platform: family, OS name, CPU count and similar facts.
- data parses and writes INI.
- template renders a Tera template against a map of variables, with autoescape off because the output is config files, not HTML.
- time reads the clock and formats timestamps.
- json, toml and xml parse and emit those formats. They are wscript-std modules registered as they are.
- regex matches patterns. Every function takes (pattern, text) in that order; swapping them compiles and then silently never matches. An invalid pattern is a fault, not an Err, and surfaces as the step's Error status.
Windows-only modules, registered everywhere and functional only on Windows.
- registry reads and writes registry keys and values.
- service queries and controls Windows services.
- com drives COM objects through IDispatch and runs WMI queries. Each WMI row is flattened into a property map host-side, so scripts never touch enumerators.
One further module, testlab, is registered only for scenario driver scripts. It provides the Lab and Machine handles a scenario uses to bring VMs up, apply config-weave and reboot them. See The testlab.
Templates and WCL interpolation
Author a Tera template body as a raw WCL heredoc, <<'TMPL', so WCL's own $"...${}" interpolation leaves Tera's {{ }} and {% %} untouched, and feed dynamic data through the vars map.
Shared helpers in lib/
Common code lives in a lib/ directory, either a package's own pkgs/<pkg>/lib/ or the playbook's lib/, which every package can see. A script imports a helper by its file stem, or by a relative path.
use helpers // pkgs/<pkg>/lib/helpers.ws, then <playbook>/lib/helpers.ws
use "./shared.ws" // relative to the importing script
A bare use name resolves in this order, and the first match wins.
- A registered host module. use fs always means the host API, even when a lib/fs.ws exists.
- The importing script's own directory, as <dir>/name.ws.
- The declaring package's lib/. A package can shadow a playbook-wide helper.
- The playbook's lib/, shared across every package.
Helper files are ordinary .ws scripts and may import each other. The whole import graph compiles into one unit, and only the entry file exports functions. A resource with helpers therefore satisfies the check and apply contract exactly as a single-file one does, and a helper cannot accidentally supply check. The bare form resolves helpers.ws; a path import carries its own extension, so write use "./shared.ws" in full.
config-weave validate compiles every lib/*.ws, imported or not. A broken helper fails validation on its own, and an error inside a helper is reported against that helper's file and line, not against the script that imported it.
Editor support
config-weave wscripti [outdir] emits weave.wscripti, the full host interface, plus a starter wscript.toml. The interface file is generated from the same Rust modules the binary registers, so it is the authoritative description of the host surface. With both files next to your scripts, wscript check and the wscript language server type-check against the exact config-weave surface instead of wscript's own standard library. A misuse of the host API becomes an error in the editor, and the same error is caught by config-weave validate. See config-weave wscripti.
The interface names keep their upstream spelling
Scripts use the .ws extension, but the two interface files are named weave.wscripti and wscript.toml, matching the wscript command-line tools that read them.
Where to go next
The language itself is covered in wscript: values, types and functions. The dynamic Value type every entry point receives is in The Value type, and the functions a script cannot use are listed in What scripts cannot use.