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, or streamed from the CLI with rex events.

Events come from three places:

KindDescribesLua name
Session eventsChanges to one session’s windows, blocks, and clients.The event’s type, such as block_closed.
Terminal eventsThings a terminal reports.terminal. and the event, such as terminal.bell.
Server eventsChanges 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:

FieldDescription
ev.typeThe event’s type. For every terminal event this is block_event.
ev.session_idThe session the event happened in. Absent for most server events.
ev.payloadThe event’s own fields again, as a table of their own.

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

FieldDescription
ev.block_idThe block the event came from.
ev.creator_nameThe kind of block, such as com.superlogical.terminal.
ev.nameThe 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.

EventWhenFields
window_createdA window is created.window_id, label
window_closedA window is closed.window_id
window_label_changedA window is renamed.window_id, label
active_window_changedA different window becomes the active one.window_id
block_createdA block is created.block_id
block_closedA block is closed.block_id
session_label_changedThe session is renamed.label
session_view_changedThe session’s layout changes in any way.revision
client_connectedA client attaches to the session.client_id, principal, connected_at
client_disconnectedA client detaches from the session.client_id, principal
client_connection_changedAn attached client’s connection is lost or restored.client_id, principal, connection_state
creator_changedThe 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.

EventWhenFields
terminal.child_exitedThe terminal’s program exits.exit_code, and error when it is not zero
terminal.pwd_changedThe program reports a new working directory.pwd, owner
terminal.title_changedThe terminal’s title changes.title, owner
terminal.bellThe terminal receives a bell character.
terminal.process_changedThe foreground process changes.generation, foreground, ancestors
terminal.desktop_notificationThe program asks for a desktop notification.title, body
terminal.progress_reportThe program reports progress.state, progress
terminal.clipboard_writtenThe program writes to the clipboard.text
terminal.program_status_changedA program reports or updates its status.id, record, reason
terminal.program_status_removedProgram status records are removed.ids, reason

A few notes on these:

  • terminal.child_exited is about the program the terminal started, which is usually your shell. It doesn’t fire for each command you run inside a shell. A terminal started with a command fires it when that command exits.
  • pwd is a URL such as file://hostname/Users/you/src, not a plain path. It is only reported by shells set up to report it.
  • owner is a table with the pid and name of the process that made the change.
  • foreground is a table describing the process in the foreground, with name, cwd, pid, and more. It can be nil.

Server Events

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

EventWhenFields
session_createdA session is created.session, a table with session_id and label
session_destroyedA session is destroyed.session_id
client_joinedA client connects to the server.client
client_leftA client disconnects from the server.client_id
client_changedA connected client’s details change.client
keymap_changedThe configuration file is reloaded.generation, hash
hosts_changedThe list of hosts changes.hash
tailscale_status_changedThe 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:

CommandPrints
rex eventsSessions being created, destroyed, and changed.
rex events -s SESSIONEverything in one session, including terminal events.
rex events --allEverything, 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.