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


This page builds a real config against jaque's schema one addition at a
time: a host, a service, a shared template, contacts and a policy,
labels, zones, and finally how a config is validated. Every snippet is
loadable as written, with the schema filling each default it does not
state. [Why CUE](https://jaque.sh/docs/concepts/why-cue.md) is the argument for the
language; this page is the practice, and the [config
schema](../reference/config-schema.md) is the reference every key here
is documented in.

## 1. The smallest config

```cue
hosts: gw: {
	address: "192.168.1.1"
	check: {type: "icmp", host: address}
}
```

One host, ICMP checked every 60 seconds, which is `#Schedule`'s default
`check_interval`. `host: address` reuses the field set two lines up: CUE
resolves references within the same struct, so the IP is written once.

## 2. A host with a service

```cue
hosts: gw: {
	address: "192.168.1.1"
	check:   {type: "icmp", host: "192.168.1.1"}
	services: web: check: {type: "http", url: "http://192.168.1.1/"}
}
```

Every service under a host is checked independently, with its own
`#Schedule`. A service does not inherit its host's `check_interval`; what
it inherits is the host's reachability, through the dependency graph,
which is a different thing.

## 3. A shared template

Ten devices of the same kind should not repeat their check config ten
times. Anchor a partial struct on `#Host` (or `#Check`) and unify it at
each use site; [Why CUE](https://jaque.sh/docs/concepts/why-cue.md) walks the `#CastDevice`
example and explains why anchoring on the schema rather than a bare
struct is what keeps a typo in the template a validation error instead
of a silently ignored field.

## 4. Contacts, a policy, and an escalation

```cue
contacts: {
	alice: {type: "email", address: "alice@example.com"}
	oncall_hook: {type: "webhook", url: "https://hooks.example.com/oncall"}
}

notifications: business_hours: {
	period: [
		{weekday: "monday", start: "09:00", end: "17:00"},
	]
	levels: [
		{contacts: ["alice"], threshold: 3, renotify_interval: "30m"},
		{contacts: ["oncall_hook"], renotify_interval: "10m"},
	]
}

hosts: gw: {
	address: "192.168.1.1"
	check: {type: "icmp", host: "192.168.1.1"}
	notification: "business_hours"
}
```

`notification` names a policy in the top-level `notifications` map and
defaults to empty, which means the object never notifies: every config
written before policies existed keeps the behaviour it had. Every contact
type, the escalation semantics and the window grammar are in [Contacts
and policies](../notifications/contacts-and-policies.md) and
[Escalations and windows](https://jaque.sh/docs/notifications/escalations-and-windows.md).

## 5. Labels and views

```cue
hosts: web: {
	address: "10.0.0.1"
	check:   {type: "icmp", host: "10.0.0.1"}
	labels:  {env: "prod", role: "web"}
}

views: prod: selector: "env=prod"
```

[Labels and views](https://jaque.sh/docs/config/labels-and-views.md) has the key and value
constraints, the selector grammar and what a saved view is.

## 6. Zones

`zone` defaults to `"default"` on a host. A service's `zone` defaults to
`""`, which inherits the host's:

```cue
hosts: gw: {zone: "eu-west"}
services: web: {}  // inherits "eu-west"
```

A zone is the work queue a check dispatches to; it matters only in a
split topology with `-target worker` processes, and is documented there.

## 7. Validating a config

There is no separate `jaque validate` subcommand: loading is validating.

```sh
jaque -config yourfile.cue
```

Validation runs in two phases and the error differs by which one catches
the problem. A schema-constraint failure (an unknown field, a wrong type,
a `community` beside a `user`) is reported against the field. A
concretion failure (a value left unresolved, a required field with no
default such as a passive check's `freshness_threshold`) is reported
against the field that never became concrete. [Why
CUE](../concepts/why-cue.md) explains the two phases; the operator-facing
consequence is that the error names a field, never "config invalid".

## 8. Security considerations

A config file carries secrets in plain text: `vars` such as a host
password, `resources`, an SNMP community, a contact's webhook URL. File
permissions are their only protection, and a `command` template with
`shell: true` interpolates them into a shell line (see [Command
checks](../checks/command-checks.md), section 4). Credentials that are
per instance rather than per object, such as a Telegram bot token or SMTP
credentials, are process flags and not config fields, precisely so that
the config file can be shared more freely than the process environment.
