> Section: [3. Checks](https://jaque.sh/docs/checks/native-checks.md)
> Next: checks/command-checks
> Index: https://jaque.sh/llms.txt


A `wasm` check is a WASI module that jaque instantiates inside its own
process, on the WASM runtime embedded in the binary (nothing to install
beside it, consistent with the single-binary invariant). It speaks the
same exit-code and stdout protocol as a legacy plugin, so any language
that compiles to `wasip1` writes a jaque plugin with no jaque-specific
code. What it buys over a fork is a module that is one portable file,
sandboxed by construction rather than by convention, and runnable without
spawning a process. What it costs is a compile target: existing plugins do
not become WASM, and were never meant to.

## 1. The sandbox

`#WASMCheck`, the CUE shape a `wasm` check is written against, accepts
`module` and `args` and nothing else.

```cue
services: custom: check: {
	type:   "wasm"
	module: "checks/disk-usage.wasm"
	args:   ["/", "80", "95"]
}
```

`module` is a path to a `.wasm` file, read and compiled once at startup.
A module declared in config gets no filesystem and no network, full stop.
There is no config field for a directory mount or a network grant; the
only way to mount a directory is the embedding API (`WithDirMount`,
`WithReadOnlyDirMount`) on a runner that an embedder constructs directly,
which a CUE config file cannot reach. A module that hangs is stopped when
its context expires, the same `timeout` from `#Schedule` every other check
type obeys.

## 2. ABI

A check module is a `wasip1` command module: it exports `_start` and is
instantiated fresh per run; a module without `_start` is rejected at load.
Exit code 0 to 3 maps to OK, WARNING, CRITICAL or UNKNOWN,
and stdout is the check output with an optional `|`
splitting off perfdata, parsed by the grammar in [Legacy exec
plugins](../checks/legacy-exec-plugins.md), section 2.

## 3. Memory cap

Guest linear memory is capped at 128 MiB (2048 wasm pages of 64 KiB) by
default. Growth past the cap fails inside the guest, never outside it: a
runaway allocation in a module cannot take the engine with it. An
embedder may raise or lower the cap per runner; nothing in `#WASMCheck`
exposes it to a CUE config.

## 4. Why this exists beside legacy exec

WASM checks are not a replacement for the Nagios exec protocol, which
stays supported forever. They are the option for something written new,
where distributing one file and trusting the host less matter more than
reusing a binary that already exists.

## 5. Security considerations

The sandbox is the default and the only thing a config file can express:
no filesystem, no network, a bounded heap and a deadline. The one
exception is an embedder that mounts a directory through the embedding
API, and that decision is made in code, by whoever links jaque, not by a
config
edit. `args` reach the guest as its argument vector and nothing else.
