> Section: [10. Reference](https://jaque.sh/docs/reference/cli-flags.md)
> Next: api/command-and-query-service
> Index: https://jaque.sh/llms.txt


This is a systematic reference for the on-disk/on-wire shape of the event
log: the envelope every codec wraps a fact in, and every payload type the
log can carry. For the concepts behind event sourcing in jaque, see
[Event sourcing](https://jaque.sh/docs/concepts/event-sourcing.md) instead.

## 1. The envelope

Every persisted event is a `Payload` plus the fields the log itself owns --
the `Envelope`:

| Field | Type | Meaning |
|---|---|---|
| `Version` | `int` | Envelope version, bumped only for envelope-shape changes. Currently `2`. |
| `Seq` | `uint64` | Assigned by the transport on append; `0` until then. |
| `Epoch` | `uint64` | The membership epoch the appending engine held at append time. |
| `Payload` | `Payload` | The domain fact itself -- one of the types in section 2. |

The default codec frames the
envelope, payload included, as one JSON object per line:

```json
{"v":2,"type":"state_changed","seq":42,"epoch":1,"object_id":"web1/http","occurred_at":"2026-08-04T10:00:00Z","data":{...}}
```

Short, snake_case keys -- `v`, `type`, `seq`, `epoch` (omitted when zero),
`object_id`, `occurred_at`, `data` -- because this is a public contract
read by `jq` and by ClickHouse, not internal struct field names leaking
through a serializer's defaults. `type` is the wire discriminator; a codec other
than JSON is free to use a different discriminator shape (an integer tag,
a protobuf oneof) -- nothing above is JSON-specific except the object
itself.

## 2. Payload types

One row per payload type, transcribed from the implementation. Every
payload implements `ObjectID()` and
`OccurredAt()`; `ObjectID()` is empty for the two reload events, which
are not about one object.

| Type | Wire `type` | Emitted when | Key fields |
|---|---|---|---|
| `StateChanged` | `state_changed` | `Status`, `Type`, `Attempt`, or `Flapping` changed on an object. | `ID`, `From State`, `To State`, `At` |
| `ReachabilityChanged` | `reachability_changed` | Once per object the reachability graph marks affected when a host goes down or comes back up. | `ID`, `Reachable bool`, `At` |
| `CheckExecuted` | `check_executed` | Every completed check. | `Result CheckResult`, `Origin` (`active`/`passive`/`stale`) |
| `NotificationRequested` | `notification_requested` | Before any delivery attempt -- the intent to notify is durable before the attempt exists. | `ID`, `NotificationID`, `Kind NotifyKind`, `Level`, `Contacts []string`, `At` |
| `NotificationSent` | `notification_sent` | Delivery for a prior `NotificationRequested` succeeds. | `ID`, `NotificationID`, `Contact`, `At` |
| `NotificationFailed` | `notification_failed` | A delivery attempt for a prior `NotificationRequested` fails. | `ID`, `NotificationID`, `Contact`, `Attempt`, `Err string`, `Terminal bool`, `At` |
| `AcknowledgementSet` | `acknowledgement_set` | Operator runs `ACKNOWLEDGE_HOST_PROBLEM`/`ACKNOWLEDGE_SVC_PROBLEM`. | `ID`, `Author`, `Comment`, `Sticky bool`, `At` |
| `AcknowledgementCleared` | `acknowledgement_cleared` | Operator runs `REMOVE_HOST_ACKNOWLEDGEMENT`/`REMOVE_SVC_ACKNOWLEDGEMENT`. | `ID`, `Author`, `At` |
| `DowntimeScheduled` | `downtime_scheduled` | Operator runs `SCHEDULE_HOST_DOWNTIME`/`SCHEDULE_SVC_DOWNTIME`. | `ID`, `DowntimeID string`, `Author`, `Comment`, `Start`, `End`, `At` |
| `DowntimeCancelled` | `downtime_cancelled` | Operator runs `DEL_HOST_DOWNTIME`/`DEL_SVC_DOWNTIME`. | `ID`, `DowntimeID string`, `At` |
| `ConfigReloaded` | `config_reloaded` | A SIGHUP-triggered reload applies successfully. | `Added`, `Removed`, `Changed`, `Unchanged int`, `At` (no `ID`) |
| `ConfigReloadRejected` | `config_reload_rejected` | A SIGHUP-triggered reload fails validation; the old config keeps running. | `Err string`, `At` (no `ID`) |
| `ObjectRetired` | `object_retired` | A reload removes an object from the config. | `ID`, `At` |

## 3. Why the archive is readable without jaque

Every field above is a plain string, number, bool, or timestamp -- no
opaque blob, no jaque-internal type leaking onto the wire -- and the
codec is the only thing that knows how to turn a `Payload` into bytes, so
the shape above *is* the format, not an approximation of it. That is what
lets the [archive sink](https://jaque.sh/docs/observability/archive.md) hand its
zstd-compressed JSON lines to `jq`, ClickHouse, or DuckDB directly: reading
the log back never requires running jaque or linking against its code,
only knowing the table above.

## 4. Security considerations

The event log, `-events-out`, `-snapshot-out` and the archive all carry
the same plaintext payload fields listed in section 2 -- there is no
field-level encryption or redaction in the codec. `Comment` on
`AcknowledgementSet` and `DowntimeScheduled`, and `Err` on
`NotificationFailed` and `ConfigReloadRejected`, are free-form
operator-supplied or upstream-error strings: avoid putting a credential in
an acknowledgement comment or a check command's error output, because it
will be written to the log, to any configured archive sink, and to
whatever reads the archive downstream. `Author` on the acknowledgement and
downtime events is whatever the command API caller supplied and is not an
authenticated identity beyond the `-api-token` bearer check on
`CommandService` (see [CLI flags](https://jaque.sh/docs/reference/cli-flags.md), section 9,
and [Command and query service](https://jaque.sh/docs/api/command-and-query-service.md)) --
it is an audit label, not a verified principal.
