> Section: [4. Configuration](https://jaque.sh/docs/config/cue-in-practice.md)
> Next: config/hot-reload
> Index: https://jaque.sh/llms.txt


jaque has no hostgroup object. Hosts, services and contacts carry
key/value labels, a selector is a predicate over those labels, and a
saved view is a name bound to a selector. "Everything in prod" is one
selector, and an acknowledgement or a downtime that targets it is one
command rather than a loop over names. The cost is that there is no list
to edit when membership changes; the benefit is that there is no list to
go stale, because membership is whatever the labels currently say it is.

## 1. Labels are the model

```cue
hosts: web: {
	address: "10.0.0.1"
	check:   {type: "icmp", host: "10.0.0.1"}
	labels:  {env: "prod", role: "web"}
	services: api: {
		check:  {type: "tcp", address: "10.0.0.1:443"}
		labels: {env: "prod", tier: "backend"}
	}
}
```

Labels live in the core; groups do not. Membership is whichever objects
share a label, and nothing else has to be kept in sync with it. The
importer translates each Nagios hostgroup to a `hostgroup.<name>` label
on every member (see [From Nagios](https://jaque.sh/docs/get-started/from-nagios.md)), so
a group that existed in Nagios still exists as a selector. Contacts carry
labels too, so the importer has somewhere to put a contactgroup; nothing
indexes contact labels yet.

### 1.1 Key and value constraints

Keys and values are each constrained by a regex enforced in the CUE
schema, so a malformed label fails validation with a field-level error
naming the file and line, rather than a runtime error after decoding.

| Part | Pattern | Note |
|---|---|---|
| Key | `=~"^[a-z][a-z0-9_.-]*$"` | Lowercase only, so a label can never read like a `#Vars` macro name, which is uppercase-enforced and a different thing. |
| Value | `=~"^[a-zA-Z0-9][a-zA-Z0-9_.:/-]*$"` | Uppercase allowed. |

```cue
labels: {Env: "prod"}  // rejected: uppercase key
```

## 2. Selectors

A selector is a comma-separated list of requirements; the comma is AND.

```
env=prod, team=redes
```

A requirement is `key=value`, `key!=value`, `key in (a, b)`,
`key notin (a, b)`, a bare `key` (the key is present) or `!key` (the key
is absent). The empty selector is a parse error, not "everything": the
first consumer of selectors schedules downtime, and an empty string
arriving from an unset variable must not silence the estate. Everything
has to be said deliberately.

Any command that targets objects, `AcknowledgeProblem` or
`ScheduleDowntime` among them, accepts either one explicit object or a
selector matching many. "Downtime every service tagged `team=redes`" is
one `ScheduleDowntime` call with a selector target.

## 3. Saved views

A view is a name bound to a selector, never to a static membership list,
so it cannot go stale as objects come and go:

```cue
views: {
	prod: selector: "env=prod"
	"Web Servers": {
		selector:    "hostgroup.web-servers"
		description: "Nagios hostgroup \"Web Servers\""
	}
}
```

The map key is the display name and is deliberately unconstrained
(spaces and uppercase allowed) because it is never parsed: it is exactly
what an operator wrote, or exactly what a Nagios group's alias was before
import. `selector` is parsed at load time with the grammar above, so a
malformed one is a config error. `description` is free text, defaulting
to empty. The dashboard's `#/groups` page lists every saved view with a
live member count; see [Dashboard](https://jaque.sh/docs/ui/dashboard.md).

## 4. Security considerations

A selector is the blast radius of the command that carries it. A
selector that matches more than intended acknowledges or silences more
than intended, and jaque does not confirm: it matches. The empty-selector
refusal above is the one guard the grammar provides; the rest is the
operator's care with `ScheduleDowntime` over a broad label, and the
`-api-token` that protects the command surface (see [FIFO and
API](../ingest/fifo-and-api.md)).
