# CLI

Commands, flags, and exit codes of the kogut binary.

The same binary runs the server and the agent. Settings come from
[environment variables](https://docs.kogut.dev/reference/environment-variables/) and [kogut.toml](https://docs.kogut.dev/reference/configuration/); no
flag sets the config path or the port.

```text
kogut <command> [options]
```

| Command | Purpose |
|---|---|
| `serve` | Start the server. |
| `agent` | Report this host to a server. Accepts `--server` and `--token`. |
| `agent check-file [<file>]` | Check the agent's command checks file. |
| `backup <file>` | Write a consistent SQLite backup. |
| `restore <file> [--force]` | Restore a backup. |
| `export` | Print what was created in the panel as `kogut.toml`. |
| `run -- <command>` | Run a command and send its heartbeat a ping with the exit code. |
| `healthcheck` | Check the local server's health. |
| `check [<url>]` | Run one check now and print what it found. |
| `status` | Print open incidents and what is not up, from a running server. |
| `incidents [<id>]` | List incidents, or print one, from a running server. |
| `checks` | List checks and heartbeats with their status, from a running server. |
| `config check [<file>]` | Check `kogut.toml` without starting the server. |
| `version`, `--version`, `-V` | Print the version as `kogut <version>`. |
| `completions <shell>` | Print a completion script for `bash`, `zsh`, or `fish`. |
| `help [<command> \| <topic>]`, `--help`, `-h`, no command | Print help, or a page of these docs. |

`-h` or `--help` on any command prints its usage, flags, the environment variables they
override, exit codes, and examples. `kogut help <command>` prints the same text.

A flag that takes a value accepts a space or `=`, as in `--token <token>` or
`--token=<token>`. `--` ends the options, so `kogut backup -- -odd.db` writes to
`-odd.db`.

## The agent-only build

Releases also ship a smaller build for monitored hosts: the
`kogut-agent-<target>.tar.gz` archives and the `ghcr.io/piotrkowski/kogut-agent` image.
Its binary is also named `kogut` and has the same agent, but only these commands:
`agent`, `agent check-file`, `run`, `version`, `completions`, and `help`. Its
`kogut help` has no docs pages. Any other command exits with code 2:

```text
kogut: this build only contains the agent; 'serve' needs the full kogut binary
```

The full binary can replace it on any host. [Install the agent](https://docs.kogut.dev/agent/installing/)
says which one the install script downloads.

## Shared flags

These flags can come before or after the command, as in `kogut -q backup x.db`. Other
commands refuse them.

| Flag | Commands | Effect |
|---|---|---|
| `--json` | `version`, `healthcheck`, `check`, `status`, `incidents`, `checks`, `config check`, `help topics` | Print one JSON object on standard output. See [Machine-readable output](#machine-readable-output). |
| `-q`, `--quiet` | `agent check-file`, `backup`, `restore`, `config check` | Print no confirmations or warnings. Errors still go to standard error. |
| `--no-color` | `serve`, `agent`, `config check` | Write no colour codes. |

`--quiet` changes neither exit codes nor results. `serve` and `agent` take no `--quiet`;
[`RUST_LOG`](https://docs.kogut.dev/reference/environment-variables/#server) sets what they log.

kogut writes colour codes only to a terminal, so logs in a file, journald, or
`docker logs` and JSON never have them. `NO_COLOR` set to a non-empty value,
`TERM=dumb`, or `--no-color` turns them off. The only colour in command output is the
`ok` of `config check` and the bold headings of the help.

## Usage errors

A mistake on the command line prints the error, the usage line, and where to find help
to standard error, and exits with code 2:

```text
kogut: unknown option --verbose for 'agent'
usage: kogut agent [--server <url>] [--token <token>] [--no-color]
run 'kogut agent --help' for more
  see https://docs.kogut.dev/reference/cli/#kogut-agent
```

An unknown command shows `usage: kogut <command> [options]`, points to `kogut --help`,
and names the closest command when one is near.

Errors in `kogut.toml`, environment variables, and the command line end with a
`  see <url>` line that links to the docs section about them. `serve` logs the same link
in the `docs` field of its startup error.

## Exit codes

The codes are the same for every command and stable across releases. Each command's
`--help` lists the ones it returns. Once its command has started,
[`kogut run`](#kogut-run) exits with the command's code.

| Code | Meaning |
|---|---|
| `0` | Success, or the answer is yes. |
| `1` | The answer is no, or the command failed, such as an unreadable file, a refused restore, or an unhealthy server. |
| `2` | Usage error. |
| `3` | kogut's server cannot be reached or did not answer in time. |
| `4` | The server refused the token. |
| `5` | What the command line names, such as an incident id, does not exist on the server. |

## Machine-readable output

With `--json`:

- Standard output carries exactly one JSON object on one line. Logs, warnings, and other
  messages go to standard error.
- The exit code is the same as without `--json`.
- Every object has a boolean `ok`. When it is false, `error` has a `code`, a `message`,
  and a `docs_url`.
- A usage error is JSON too, with code `usage` and exit code 2, including `--json` on a
  command that does not take it.
- Times are UTC epoch milliseconds. Durations are integers in fields ending in `_ms`, as
  in the [HTTP API](https://docs.kogut.dev/reference/http-api/).
- Key order is not significant.

```json
{"ok":false,"error":{"code":"usage","message":"unknown option --json for 'backup'","docs_url":"https://docs.kogut.dev/reference/cli/#kogut-backup"}}
```

| `error.code` | Meaning | Commands |
|---|---|---|
| `usage` | The command line is wrong. | All |
| `config_invalid` | `kogut.toml` or an environment variable is invalid. | `config check`, `healthcheck`, `check` |
| `not_found` | A file named on the command line, or an incident or service, does not exist. | `config check`, `incidents`, `checks` |
| `io` | A file cannot be read. | `config check` |
| `check_failed` | The check is down or unknown. | `check` |
| `unhealthy` | The server answered but is unhealthy. | `healthcheck` |
| `unreachable` | kogut's server cannot be reached or did not answer in time. | `healthcheck`, `status`, `incidents`, `checks` |
| `unauthorized` | The server refused the token. | `status`, `incidents`, `checks` |

Fields may be added in any release. Within a minor version, no field is renamed or
removed. See [Versioning](https://docs.kogut.dev/project/versioning/).

## `kogut serve`

Runs the panel, API, checks, ingest, and notifications.

```sh
KOGUT_DATA=/var/lib/kogut KOGUT_URL=https://kogut.acme.com kogut serve
```

With no account, it logs a setup token and writes it to `$KOGUT_DATA/setup-token`; see
[Passwords](https://docs.kogut.dev/sign-in/passwords/). With
[`KOGUT_LOCAL_AGENT=1`](https://docs.kogut.dev/reference/environment-variables/#server), it also runs the agent for its
own host.

On `SIGTERM` or `SIGINT`, the server stops that agent, stops accepting requests, allows
10 seconds for open requests and tasks, flushes queued writes, and exits with code 0.

| Flag | Overrides | Meaning |
|---|---|---|
| `--no-color` | `NO_COLOR` | Write logs without colour codes. |

| Exit code | Meaning |
|---|---|
| `0` | Stopped on `SIGTERM` or `SIGINT`. |
| `1` | Cannot start: invalid settings or `kogut.toml`, or the data directory is in use. |
| `2` | Usage error. |

## `kogut agent`

```sh
kogut agent --server https://kogut.acme.com --token <token>
```

| Flag | Overrides | Meaning |
|---|---|---|
| `--server <url>` | `KOGUT_SERVER` | The server's URL, or comma-separated URLs tried in order. |
| `--token <token>` | `KOGUT_TOKEN`, `KOGUT_TOKEN_FILE` | The host token from the panel. |
| `--no-color` | `NO_COLOR` | Write logs without colour codes. |

Other settings are [environment variables](https://docs.kogut.dev/reference/environment-variables/#agent). The agent
needs no inbound port. See [Installing the agent](https://docs.kogut.dev/agent/installing/).

| Exit code | Meaning |
|---|---|
| `0` | Stopped on `SIGTERM` or `SIGINT`. |
| `1` | Invalid settings, or the agent stopped on an error. |
| `2` | Usage error. |

## `kogut agent check-file`

```sh
kogut agent check-file /etc/kogut-agent/checks.toml
```

Checks a [command checks](https://docs.kogut.dev/agent/command-checks/) file as the agent does at start,
without starting it. Without a path, it checks the file in `KOGUT_CHECKS`, or
`/etc/kogut-agent/checks.toml`. It prints each check's name, service, interval, and
timeout. A mistake prints the line and key. A file its group or others can write is
refused too. The owner is not checked, since this command may run as another user than
the agent. A missing default file means no command checks.

| Flag | Meaning |
|---|---|
| `-q`, `--quiet` | Print only errors. |

| Exit code | Meaning |
|---|---|
| `0` | The agent can use the file, or there is no default file. |
| `1` | The file is invalid, cannot be read, or others can change it. |
| `2` | Usage error. |

## `kogut backup`

```sh
kogut backup /var/backups/kogut.db
```

Writes a complete, consistent copy of the SQLite database in `KOGUT_DATA` while the
server runs, and prints `kogut: wrote <file>`. See
[Backups and restore](https://docs.kogut.dev/high-availability/backups/).

| Flag | Meaning |
|---|---|
| `-q`, `--quiet` | Print no confirmation. |

| Exit code | Meaning |
|---|---|
| `0` | The copy is written. |
| `1` | The database cannot be read or the file cannot be written. |
| `2` | Usage error. |

## `kogut export`

```sh
kogut export >> /var/lib/kogut/kogut.toml
kogut export --checks --heartbeats
```

Prints what was created in the panel as `kogut.toml`: `[[service]]`, `[[check]]`, and
`[[heartbeat]]` blocks, named `[[alert]]` blocks for channels, and `[edge]` and
`[server] heartbeat_url` when the panel set them. After the text is added to the file,
the next reload [takes each object over](https://docs.kogut.dev/reference/configuration/#file-handling) with its
history.

It opens the database in `KOGUT_DATA` read-only, so it can run beside a live server, and
reads the file `serve` reads to leave out what that file already defines. A second export
after the move prints none of the moved objects. Only the TOML goes to standard output.

| Flag | Prints only |
|---|---|
| `--checks` | Checks, and the services they need. |
| `--heartbeats` | Heartbeats, and the services they need. |
| `--channels` | Notification channels. |
| `--edge` | `[edge]` and `[server] heartbeat_url`. |

Flags can be combined. Without any, everything is printed, and what has no form in
`kogut.toml` is listed as comments at the end: silences, maintenance windows, sites,
people, API tokens, and the ping URLs, which keep working after the move.

No secret is printed. Channel URLs, tokens, and passwords, request header values, the
kogut edge token, and the heartbeat URL become `${NAME}` placeholders, such as
`${OPS_PHONE_TOKEN}` for the token of the channel `ops-phone`, each listed at the top as
`#   NAME: what it is`. Set those variables for kogut before the reload.

The output is checked with kogut's config parser before it is printed. A check whose
`json` assertion compares with `null`, which TOML cannot write, is left out with a note.

| Exit code | Meaning |
|---|---|
| `0` | The TOML is printed. |
| `1` | There is no database, it cannot be read, or another kogut version wrote it. |
| `2` | Usage error. |

## `kogut restore`

```sh
kogut restore /var/backups/kogut.db --force
```

Refuses to run while a server uses the same data directory. The source must be a kogut
database no newer than the binary. Prints
`kogut: restored <file> into <data directory>`.

| Flag | Meaning |
|---|---|
| `--force` | Replace an existing database. It can come before or after the path. |
| `-q`, `--quiet` | Print no confirmation. |

| Exit code | Meaning |
|---|---|
| `0` | The database is restored. |
| `1` | A server uses the data directory, a database exists without `--force`, or the file is not a kogut backup. |
| `2` | Usage error. |

## `kogut run`

```sh
KOGUT_PING_URL=https://kogut.acme.com/ping/btp_... kogut run -- /usr/local/bin/backup.sh
kogut run --timeout 30s -- pg_dump -Fc -f /var/backups/acme.dump acme
```

Runs a command for a [heartbeat](https://docs.kogut.dev/monitoring/heartbeats/): `GET <url>/start`, then
the command with this process's standard input, output, error, and environment, then
`GET <url>/<exit code>`. Everything after `--` is the command and its arguments.

| Flag | Overrides | Meaning |
|---|---|---|
| `--ping <url>` | `KOGUT_PING_URL` | The heartbeat's ping URL, `https://<kogut>/ping/<token>`, from **Ping URL** in the panel. |
| `--timeout <duration>` | | How long each ping may take, retries included, such as `10s` or `500ms`. `10s` by default. |

Prefer `KOGUT_PING_URL`: other users on the host can see a `--ping` URL in `ps`.

A ping is tried up to 5 times within its timeout when the server cannot be reached,
times out, or answers `429` or `5xx`. A `404` means no heartbeat has the URL and is not
retried. A failed ping prints `kogut: ping <signal> failed: <reason>` to standard error,
without the token. The command still runs, and its exit code stays the result.

| Result of the command | Ping | Exit code of `kogut run` |
|---|---|---|
| Exits with a code | `/<code>` | The command's code. |
| Cannot be found | `/fail` | `127` |
| Found but cannot be run | `/fail` | `126` |
| Ended by a signal | `/fail` | `128` plus the signal number |

These cases print `kogut: cannot run <command>: <reason>` or
`kogut: <command> was stopped by signal <n>`. `SIGINT` and `SIGTERM` sent to `kogut run`
are passed on to the command, and `kogut run` waits for it so the last ping is sent.

Only the command writes to standard output. kogut's own messages go to standard error
and start with `kogut:`. There is no `--json`, no log capture, and no request body.

| Exit code | Meaning |
|---|---|
| `0` | The command exited with 0. |
| `2` | Usage error, such as a missing `--`, command, or ping URL. Nothing ran and no `/start` was sent. |
| Any other | The command's own code, or `126`, `127`, or `128` plus a signal as above. |

## `kogut healthcheck`

Sends `GET /healthz` to the local server, at the address from
[`KOGUT_LISTEN` or `PORT`](https://docs.kogut.dev/reference/environment-variables/), then
[`[server] listen`](https://docs.kogut.dev/reference/configuration/#server), then the default. `0.0.0.0` and `::` mean
the local machine.

| Flag | Meaning |
|---|---|
| `--json` | Print the result as one JSON object. |

| Exit code | Meaning |
|---|---|
| `0` | `/healthz` returned 200. |
| `1` | The server answered but is unhealthy, or a setting such as `KOGUT_LISTEN` is invalid. The message says which; with `--json`, `error.code` is `unhealthy` or `config_invalid`. |
| `2` | Usage error. |
| `3` | The request failed or timed out after 5 seconds. |

Docker reserves exit code 2 for `HEALTHCHECK` commands, so `healthcheck` returns 3 when
nothing answers.

`--json` prints what it found, with the same exit codes:

```json
{"ok":false,"state":"unhealthy","address":"127.0.0.1:8484","reason":"the database writer is not keeping up","error":{"code":"unhealthy","message":"the server at 127.0.0.1:8484 answered but is unhealthy","docs_url":"https://docs.kogut.dev/reference/cli/#kogut-healthcheck"}}
```

`state` is `healthy`, `unhealthy`, or `unreachable`. `address` is the address asked.
`reason` is what an unhealthy server said in its `/healthz` reply, or `null`.

The distroless image has no `curl` and no built-in `HEALTHCHECK`. The Compose templates
use this command:

```yaml title="compose.yml"
healthcheck:
  test: ["CMD", "/usr/local/bin/kogut", "healthcheck"]
```

## `kogut check`

```sh
kogut check https://acme.com
kogut check https://acme.com/health --expect 'status = "2xx"' --expect 'json = "$.db", equals = "ok"'
kogut check --tcp db.internal:5432 --timeout 2s
kogut check --name "API health" --json
```

Runs one check now from this machine and prints what it found, judged by the same rules
as scheduled checks. It needs no server and changes nothing.

| Flag | Meaning |
|---|---|
| `<url>` | An HTTP check of this URL. |
| `--tcp <host:port>` | A TCP check. |
| `--dns <name>` | A DNS check. |
| `--ping <host>` | A ping check. |
| `--domain <name>` | A domain registration check. |
| `--name <check>` | The `[[check]]` with this name in `kogut.toml`, exactly as defined, request headers and `${NAME}` secrets included. |
| `--method <method>` | The HTTP method. `GET` by default. |
| `--timeout <duration>` | As in `kogut.toml`, such as `5s` or `800ms`, between `100ms` and `1m`. `10s` by default. |
| `--expect <assertion>` | One assertion, written as the inside of an [`expect`](https://docs.kogut.dev/reference/configuration/#expect) inline table, so it can be copied into the file. Repeat it for more. |
| `--json` | Print the result as one JSON object. |

Give exactly one target: a URL, `--tcp`, `--dns`, `--ping`, `--domain`, or `--name`.
Only HTTP checks take `--method`, and only HTTP and ping checks take `--expect`. A
mistake, such as a bad URL or a timeout out of range, is a usage error with the message
the panel shows.

`--name` reads the file `serve` reads,
[`KOGUT_CONFIG`](https://docs.kogut.dev/reference/environment-variables/#server) or `$KOGUT_DATA/kogut.toml`, with
`${NAME}` values from the environment or `$CREDENTIALS_DIRECTORY`. Checks created in the
panel cannot be run by name. A check with `from` runs here anyway, with a note; to see
what the agent sees, run `kogut check --name <check>` on that agent host. `--name` takes
no other options.

The result is one line, then one indented line for each failed assertion or the probe's
error:

```text
down  https://acme.com/health  200 in 142 ms, certificate expires in 61 days
  $.db is "degraded", expected "ok"
```

A certificate within 14 days of expiry gets its own line. It changes the certificate's
state, not the check's, as on the server. A domain check is degraded 30 days before the
registration expires, down once it has, and unknown when the registry gives no date.

| Exit code | Meaning |
|---|---|
| `0` | The check is up or degraded. |
| `1` | The check is down or unknown, or `kogut.toml` cannot be read for `--name`. |
| `2` | Usage error, including a `--name` that `kogut.toml` does not define. |

`--json` prints one object:

```json
{"ok":false,"state":"down","type":"http","target":"https://acme.com/health","status":200,"duration_ms":142,"failures":["$.db is \"degraded\", expected \"ok\""],"assertions":[{"expect":"status = \"2xx\"","ok":true,"message":null},{"expect":"json = \"$.db\", equals = \"ok\"","ok":false,"message":"$.db is \"degraded\", expected \"ok\""}],"certificate_expires_at":1767225600000,"certificate_state":"up","registration_expires_at":null,"error":{"code":"check_failed","message":"$.db is \"degraded\", expected \"ok\"","docs_url":"https://docs.kogut.dev/monitoring/checks/"}}
```

| Field | Meaning |
|---|---|
| `state` | `up`, `degraded`, `down`, or `unknown`. |
| `type` | `http`, `tcp`, `dns`, `ping`, or `domain`. |
| `status` | The HTTP status, or `null`. |
| `duration_ms` | How long the probe took. |
| `failures` | The failed assertions and the probe's error, as the panel shows them. |
| `assertions` | Each assertion in order, with `ok` and the failure `message`. `ok` is `null` when it was not judged: the probe failed, or a `429` or `503` skipped the body assertions. |
| `certificate_expires_at`, `certificate_state` | For HTTPS: when the certificate expires, and its state by the 14-day and 7-day rule. |
| `registration_expires_at` | For domain checks: when the registration expires. |

## `kogut status`

```sh
KOGUT_API_TOKEN_FILE=/run/secrets/kogut-read kogut status
kogut status --url https://kogut.acme.com --token "$TOKEN" --json
```

Reads a running server over its [HTTP API](https://docs.kogut.dev/reference/http-api/) and prints the open incidents,
then the services and hosts that are not up. It sends only `GET` requests. The text
matches the MCP `status` tool:

```text
1 open incident(s)
  #12 API is down (id 0123456789abcdef), since 2026-10-17 14:07 UTC, open for 5 min; likely cause: the deploy of api v42

Not up:
  service api: down (status 503, expected 2xx)
```

`status`, [`incidents`](#kogut-incidents), and [`checks`](#kogut-checks) take the same
two flags:

| Flag | Overrides | Meaning |
|---|---|---|
| `--url <url>` | `KOGUT_URL` | The server's address, with `http://` or `https://`. |
| `--token <token>` | `KOGUT_API_TOKEN`, `KOGUT_API_TOKEN_FILE` | A `read` or `write` token from **Settings → Tokens**. |

The address comes from `--url`, then
[`KOGUT_URL`](https://docs.kogut.dev/reference/environment-variables/#command-line-client), then the address of a
server on the same machine, found as [`healthcheck`](#kogut-healthcheck) finds it. The
token comes from `--token`, then `KOGUT_API_TOKEN`, then the file in
`KOGUT_API_TOKEN_FILE`; the agent's `KOGUT_TOKEN` is never read. The token is sent only
in the `Authorization` header and never printed. Prefer the variables: other users see a
token on the command line in `ps`.

Requests time out after 10 seconds and follow no redirects. A proxy with
[forward auth](https://docs.kogut.dev/sign-in/forward-auth/) in front of kogut must let requests with an
`Authorization: Bearer` header through.

| Exit code | Meaning |
|---|---|
| `0` | Nothing is open or down. Degraded, unknown, and maintenance are listed but count as fine. |
| `1` | An incident is open, or a service or host is down. |
| `2` | Usage error. |
| `3` | The server cannot be reached, timed out, answered with an error, or is not kogut. |
| `4` | The server refused the token: none was given, or its scope is wrong. |

`--json` prints `{"ok":true,"response":...}`, where `response` is the body of
`GET /api/v1/overview` as the server sent it; its fields may change between minor
versions, as in the API. A failure prints `{"ok":false,"error":{...}}` with the code
`unreachable`, `unauthorized`, or `not_found`.

## `kogut incidents`

```sh
kogut incidents
kogut incidents --range 7d --json
kogut incidents 0123456789abcdef
```

Lists open incidents and those resolved in the range, open first, one per line. With an
incident's id, 16 hex characters, it prints that incident with its likely causes and its
timeline, newest first, as the MCP `incident` tool does. `--json` prints the body of
`GET /api/v1/incidents` or `GET /api/v1/incidents/{id}` as `response`.

It takes `--url`, `--token`, and `--json` as [`status`](#kogut-status) does, and:

| Flag | Meaning |
|---|---|
| `--range <range>` | Resolved incidents of the last `1h`, `24h`, `7d`, `30d`, or `1y`. `30d` by default. Only for the list. |

| Exit code | Meaning |
|---|---|
| `0` | No incident shown is open. |
| `1` | An incident shown is open. |
| `2` | Usage error. |
| `3` | The server cannot be reached or gave no usable answer. |
| `4` | The server refused the token. |
| `5` | No incident has the id. |

## `kogut checks`

```sh
kogut checks
kogut checks --service api --json
```

Lists every check and heartbeat with its status, service, type, target, last run, and
where it runs, from `GET /api/v1/services` and `GET /api/v1/services/{name}`. `--json`
prints the checks as an array under `response`, each object as in the service's `checks`
with its `service` added. It takes `--url`, `--token`, and `--json` as
[`status`](#kogut-status) does, and:

| Flag | Meaning |
|---|---|
| `--service <name>` | Only the checks of this service. |

| Exit code | Meaning |
|---|---|
| `0` | No check is down. |
| `1` | A check is down. |
| `2` | Usage error. |
| `3` | The server cannot be reached or gave no usable answer. |
| `4` | The server refused the token. |
| `5` | No service has the name. |

## `kogut config check`

```sh
kogut config check
kogut config check --allow-unset ./kogut.toml
```

Checks `kogut.toml` as `serve` does at startup and on reload, without starting anything.
It takes no lock, runs no migrations, and writes nothing, so it can run beside a live
server. With no file, it checks the file `serve` reads:
[`KOGUT_CONFIG`](https://docs.kogut.dev/reference/environment-variables/#server), or `$KOGUT_DATA/kogut.toml`. `-`
reads standard input. `${NAME}` values come from the environment, then from
`$CREDENTIALS_DIRECTORY`, as at startup; see [Secrets](https://docs.kogut.dev/reference/configuration/#secrets).

| Flag | Overrides | Meaning |
|---|---|---|
| `<file>` | `KOGUT_CONFIG` | The file to check, or `-` for standard input. |
| `--allow-unset` | | Use placeholders for unset `${NAME}` variables. |
| `--json` | | Print the result as one JSON object. |
| `-q`, `--quiet` | | Print errors only. |
| `--no-color` | `NO_COLOR` | Write the `ok` without colour. |

A valid file prints one line to standard output:

```text
ok: /etc/kogut/kogut.toml (3 services, 5 checks, 2 heartbeats, 2 channels)
```

Services include those that only checks or heartbeats name. Errors go to standard error
as `<file>:<line>:<column>: <key>: <message>`, as at startup. Warnings start with
`warning: `.

| Exit code | Meaning |
|---|---|
| `0` | The file is valid. Warnings may be printed. |
| `1` | The file is invalid or cannot be read, or an environment variable is invalid. |
| `2` | Usage error. |

A missing default file is valid, with a warning, because `serve` starts with the
defaults. A missing file named on the command line is an error.

When `$KOGUT_DATA/kogut.db` exists, it is opened read-only to report checks, heartbeats,
and channels whose names the panel uses with another definition, as at startup. With the
same definition there is no error: the reload takes the object over. A database from
another kogut version skips this with a warning.

`--allow-unset` replaces each unset `${NAME}` with a placeholder and reports it as a
warning, so CI can check `kogut.toml` without the secrets:

```sh
kogut config check --allow-unset kogut.toml
```

The placeholder is `https://placeholder.invalid/` for names that contain `URL` or
`WEBHOOK`, and `placeholder` otherwise. A key that expects another form, such as a
duration, can still fail; set such variables to sample values in CI.

`--json` prints one object, valid or not:

```json
{
  "ok": false,
  "file": "/etc/kogut/kogut.toml",
  "errors": [
    {
      "line": 14,
      "column": 3,
      "key": "check[2].every",
      "message": "5s is too often; checks run at most every 10s",
      "docs_url": "https://docs.kogut.dev/reference/configuration/#check"
    }
  ],
  "warnings": [],
  "error": {
    "code": "config_invalid",
    "message": "/etc/kogut/kogut.toml:14:3: check[2].every: 5s is too often; checks run at most every 10s",
    "docs_url": "https://docs.kogut.dev/reference/configuration/#check"
  }
}
```

`file` is `null` for standard input. Warnings have the same shape. `line` and `column`
are `null` for a problem with the file itself, such as a missing file. `errors` holds the
first problem in the file, then any names used in the panel.

## `kogut version`

```sh
kogut version
kogut version --json
```

Prints `kogut <version>`. With `--json`:

```json
{"ok":true,"version":"0.1.0","commit":"9c0e7f2b4d1a3e5f6a7b8c9d0e1f2a3b4c5d6e7f","agent_protocol":{"min":1,"max":1},"os":"linux","arch":"x86_64"}
```

`commit` is the Git commit a release was built from, or `null` in a local build.
`agent_protocol` is the range of agent protocol versions the binary speaks. `os` and
`arch` are the platform it was built for.

| Exit code | Meaning |
|---|---|
| `0` | The version is printed. |
| `2` | Usage error. |

## `kogut help`

```sh
kogut help config check
kogut help heartbeats
kogut help installation/docker
kogut help topics --json
```

`kogut help`, `kogut --help`, and `kogut` alone print the same overview: the version,
the docs at `https://docs.kogut.dev` and `https://docs.kogut.dev/llms.txt` for AI
assistants, the commands grouped by purpose, the shared options, and the docs topics
under the sections of the docs sidebar. Lines fit 80 columns. On a terminal, the
headings are bold. `kogut help <command>` prints the same text as
`kogut <command> --help`.

`kogut help <topic>` prints one page of these docs as Markdown to standard output,
without a pager. The pages are built into the binary, so they match the installed
version and need no network. The text is the page's `.md` version on docs.kogut.dev,
with links to other pages as full URLs, and a last line with the page's URL.

A topic is the page's path, such as `monitoring/heartbeats`, or its last part when no
other page has it, as in `kogut help heartbeats`. The two `docker` pages need their full
paths: `installation/docker` and `agent/docker`. `env` stands for
`reference/environment-variables` and `api` for `reference/http-api`. Command names come
first: `kogut help config` explains the `config` commands and `kogut help checks` the
`checks` command; their pages are `kogut help configuration` and
`kogut help monitoring/checks`.

| Form | Prints |
|---|---|
| `kogut help topics` | Every topic and its title, under the sections of the docs sidebar. Each topic is named by the shortest word that prints it. |
| `kogut help topics --json` | `{"ok":true,"topics":[...]}`, each topic with `topic`, `title`, `description`, `url`, and `section`, the sidebar section. |
| `kogut help --all` | Every page in sidebar order, each headed by its URL, as in `llms-full.txt`, and then the pages the sidebar leaves out. |

| Flag | Meaning |
|---|---|
| `--all` | Print every page. |
| `--json` | With `topics`, print the list as one JSON object. |

An unknown or ambiguous topic, or a word after the topic, is a usage error that lists the
matching or closest topics:

```text
kogut: 'docker' names more than one topic: installation/docker, agent/docker
```

| Exit code | Meaning |
|---|---|
| `0` | The help is printed. |
| `2` | Usage error, including an unknown or ambiguous topic. |

## `kogut completions`

```sh
kogut completions bash > ~/.local/share/bash-completion/completions/kogut
```

Prints a completion script for `bash`, `zsh`, or `fish`. It completes commands, flags,
file arguments, and the commands `kogut help` explains.
[Shell completion](https://docs.kogut.dev/installation/linux/#shell-completion) says where each shell looks
for it.

| Exit code | Meaning |
|---|---|
| `0` | The script is printed. |
| `2` | Usage error, such as a shell other than `bash`, `zsh`, or `fish`. |
