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


Twenty years of Nagios plugins exist: `check_mk` agents, vendor scripts,
the Perl thing a former colleague wrote in 2009. A `legacy` check runs any
of them unmodified, because the protocol they speak (exit code, stdout,
perfdata after a `|`) is frozen in jaque and supported forever. The cost is
one process per execution and code running with the engine's own
permissions; the benefit is the sector's largest check ecosystem, working
on day one, with nothing rewritten.

## 1. The protocol, unchanged

A `legacy` check executes a binary and reads its result the way Nagios
always has. Exit code 0, 1, 2 or 3 maps to OK, WARNING, CRITICAL or
UNKNOWN. Stdout is the check output; the first `|`
splits it into text and perfdata, the same convention every other check
type in jaque follows.

```cue
services: disk: check: {
	type: "legacy"
	path: "/usr/lib/nagios/plugins/check_disk"
	args: ["-w", "20%", "-c", "10%", "-p", "/"]
}
```

`path` is executed directly with `args` as its argument vector. There is
no shell in between; a plugin invocation that needs a pipe or a redirect
is a [command check](https://jaque.sh/docs/checks/command-checks.md) with `shell: true`.

## 2. Perfdata grammar

The text after `|` is parsed as zero or more whitespace-separated metrics,
each of the form:

```
label=value[UOM];warn;crit;min;max
```

### 2.1 Label

`label` is everything before the first `=`. A label that starts with a
single quote (`'`) runs to the next unescaped `'` and may contain spaces;
a doubled `''` inside a quoted label is a literal quote, not a close.
Space inside an unquoted label ends the token early and is not supported.

### 2.2 Value and unit

`value` is an int or float, optionally signed, optionally with an exponent
(`1`, `-0.5`, `1e3`), immediately followed by an optional `UOM` made only
of letters, `%` and `/`. A token whose unit contains anything else fails
to parse.

### 2.3 Thresholds and bounds

`;warn;crit;min;max` are semicolon-separated and optional from the right:
`label=value` alone is valid, as are `label=value;warn`,
`label=value;warn;crit` and so on up to all four. `warn` and `crit` are
Nagios threshold range specs; `min` and `max` are plain
floats. A token with more than five `;`-separated fields fails to parse.

### 2.4 Error handling

Metrics are separated by whitespace outside quoted labels. A malformed
token is dropped without failing the metrics around it, so one bad field
from a plugin does not cost the sink the rest of the line.

```
time=0.125s;1.0;2.0;0;5 'packet loss'=0%;20;40
```

## 3. Process isolation

Each execution runs in its own process group (`Setpgid`). On timeout jaque
kills the whole group, not the immediate child, so a plugin that forks a
helper and then hangs leaves no orphan behind. `timeout` is per check and
defaults to `10s` from `#Schedule`. A plugin that times out, cannot be
found, is not executable, or dies on a signal is reported as UNKNOWN with
the reason in its output; it is never retried into a false OK.

## 4. Permanent, not a bridge

Legacy exec support is not a migration aid to be outgrown. Anything that
speaks the exit-code protocol keeps working indefinitely; this is the same
commitment the landing page makes and the status page tracks. [WASM
checks](../checks/wasm-checks.md) exist beside it for code written new,
that should be one file and sandboxed by construction; they do not
replace it.

## 5. Security considerations

A legacy plugin is arbitrary code with the engine process's user, ambient
environment and network position. jaque constrains its lifetime (the
process group and `timeout`) and nothing else; what it may read or reach
is the operator's job, through the user jaque runs as. `args` are passed
as an argument vector, never through a shell, so a value in config cannot
inject a second command.
