# Events

Rex emits an event whenever something changes: a window opens, a terminal changes directory, a program exits, a session is destroyed. Events can be handled in Lua with [`rex.on` and `rex.wait`](/content/rex/docs/automate/lua-events/index.html), or streamed from the CLI with `rex events`.

Events come from three places:

| Kind | Describes | Lua name |
| --- | --- | --- |
| [Session events](/content/rex/docs/reference/events#session-events/index.html) | Changes to one session’s windows, blocks, and clients. | The event’s type, such as `block_closed`. |
| [Terminal events](/content/rex/docs/reference/events#terminal-events/index.html) | Things a terminal reports. | `terminal.` and the event, such as `terminal.bell`. |
| [Server events](/content/rex/docs/reference/events#server-events/index.html) | Changes to the server as a whole. | The event’s type, such as `session_created`. |

## Events in Lua

A handler is called with `ctx` and `ev`. The fields listed for each event on this page are found directly on `ev`:

```
rex.on("terminal.child_exited", function(ctx, ev)
  print(ctx.block_id, ev.exit_code)
end)
```

Every `ev` also has these fields:

| Field | Description |
| --- | --- |
| `ev.type` | The event’s type. For every terminal event this is `block_event`. |
| `ev.session_id` | The session the event happened in. Absent for most server events. |
| `ev.payload` | The event’s own fields again, as a table of their own. |

A terminal event, and any other block event, adds:

| Field | Description |
| --- | --- |
| `ev.block_id` | The block the event came from. |
| `ev.creator_name` | The kind of block, such as `com.superlogical.terminal`. |
| `ev.name` | The event’s name without the creator, such as `bell`. |

`ctx.session_id` and `ctx.block_id` hold the same IDs, and are what API calls in the handler default to.

Register for `block_event` to receive every event from every block, and use `ev.creator_name` and `ev.name` to tell them apart.

## Session Events

These describe one session. A script hears them for the session it runs against, or for every session with `--all`.

| Event | When | Fields |
| --- | --- | --- |
| `window_created` | A window is created. | `window_id`, `label` |
| `window_closed` | A window is closed. | `window_id` |
| `window_label_changed` | A window is renamed. | `window_id`, `label` |
| `active_window_changed` | A different window becomes the active one. | `window_id` |
| `block_created` | A block is created. | `block_id` |
| `block_closed` | A block is closed. | `block_id` |
| `session_label_changed` | The session is renamed. | `label` |
| `session_view_changed` | The session’s layout changes in any way. | `revision` |
| `client_connected` | A client attaches to the session. | `client_id`, `principal`, `connected_at` |
| `client_disconnected` | A client detaches from the session. | `client_id`, `principal` |
| `client_connection_changed` | An attached client’s connection is lost or restored. | `client_id`, `principal`, `connection_state` |
| `creator_changed` | The kinds of block the session can create have changed. |  |

`session_view_changed` follows almost every other event in this table, because most of them change the layout. Handle it to react to any structural change, and call `rex.session.view` to get the new layout.

## Terminal Events

These come from terminal blocks. In Lua, write them as `terminal.` followed by the name, or in full as `com.superlogical.terminal.` followed by the name.

| Event | When | Fields |
| --- | --- | --- |
| `terminal.child_exited` | The terminal’s program exits. | `exit_code`, and `error` when it is not zero |
| `terminal.pwd_changed` | The program reports a new working directory. | `pwd`, `owner` |
| `terminal.title_changed` | The terminal’s title changes. | `title`, `owner` |
| `terminal.bell` | The terminal receives a bell character. |  |
| `terminal.process_changed` | The foreground process changes. | `generation`, `foreground`, `ancestors` |
| `terminal.desktop_notification` | The program asks for a desktop notification. | `title`, `body` |
| `terminal.progress_report` | The program reports progress. | `state`, `progress` |
| `terminal.clipboard_written` | The program writes to the clipboard. | `text` |
| `terminal.program_status_changed` | A program reports or updates its status. | `id`, `record`, `reason` |
| `terminal.program_status_removed` | Program status records are removed. | `ids`, `reason` |

## Server Events

These describe the server rather than one session. In Lua, a script hears them when run with `--all`.

| Event | When | Fields |
| --- | --- | --- |
| `session_created` | A session is created. | `session`, a table with `session_id` and `label` |
| `session_destroyed` | A session is destroyed. | `session_id` |
| `client_joined` | A client connects to the server. | `client` |
| `client_left` | A client disconnects from the server. | `client_id` |
| `client_changed` | A connected client’s details change. | `client` |
| `keymap_changed` | The configuration file is reloaded. | `generation`, `hash` |
| `hosts_changed` | The list of hosts changes. | `hash` |
| `tailscale_status_changed` | The server’s Tailscale status changes. |  |

`client` is a table with the client’s `client_id`, `info` (its `kind`, `name`, `platform`, and `version`), `principal`, and `connected_at`.

## Events on the CLI

`rex events --json` prints one JSON object per line. Each has a `type` and a `payload` holding the fields listed on this page:

```
{"type":"session_created","payload":{"session":{"session_id":"session:01a1...","label":"work"}}}
```

A session event arrives wrapped in a `session_event`, which adds the session it belongs to. A terminal event is wrapped once more, in a `block_event` (shown here on several lines):

```
{"type":"session_event","payload":{
  "session_id":"session:01a1...",
  "event":{"type":"block_event","payload":{
    "block_id":"block:01a1...",
    "creator_name":"com.superlogical.terminal",
    "name":"child_exited",
    "payload":{"exit_code":2,"error":"exit status 2"}}}}}
```

Lua removes both layers of wrapping, which is why a handler sees `exit_code` directly on `ev`.

What `rex events` prints depends on its scope:

| Command | Prints |
| --- | --- |
| `rex events` | Sessions being created, destroyed, and changed. |
| `rex events -s SESSION` | Everything in one session, including terminal events. |
| `rex events --all` | Everything, including clients joining and leaving. |

## Unknown Events

New versions of Rex add events and fields. Rex never checks an event name against a list, so a handler can be registered for an event that only a newer server sends. Ignore fields you don’t recognize rather than failing on them.
