# Rex

Rex is Workrex's terminal host. A Rex session is a workspace, a Rex CLI window
is a tab in that session, and each terminal pane is a block. Workrex connects to
the selected Rex server and records the stable IDs of the targets it creates.

workrex needs a Rex server that speaks API revision 8 or 9. On first use it reads the server's `server.version` and stops with `unsupported Rex <version>` when the server's supported revisions miss that range.

## Rex concepts

| Concept       | Rex identity         | Workrex use                          |
| ------------- | -------------------- | ------------------------------------ |
| Workspace     | `session:<uuid>`     | One session per worktree by default  |
| Tab           | `window:<uuid>`      | A window within a session            |
| Terminal pane | `block:<uuid>`       | An agent, shell, or sidebar terminal |
| Server        | `REX_SERVER` address | Scope for every terminal operation   |

- **Tabs.** A workrex window is a Rex window, labeled with the window name. New windows open right after the current one.
- **Panes.** Each pane is a Rex block. Splits keep the configured `size` or `percentage`.
- **Respawning.** Rex cannot restart the program in a block. When workrex needs to restart a pane, it opens a new block in the same place and closes the old one, so the pane ID changes.
- **Status.** Agents that report Rex program status (OSC 7501), such as Claude Code, show their status without hooks. See [Status tracking](https://kong109.github.io/workrex/guide/status-tracking/#rex-program-status).
- **Capture.** `workrex capture` reads the block's full scrollback and keeps the last lines.
- **The app.** Rex.app keeps its own shown tab, apart from the window the Rex session makes active. Rex does not report which session an app shows now, so `add` and `open` never move the app: the new window becomes the session's active window, and the app keeps showing what it showed. You open the new tab in the app yourself.
- **Jumps.** The dashboard, `last-agent` and `last-done` do move the app. They ask the Rex.app client that owns your pane, which is the app that last showed it, to show the target.
- **Shells.** workrex starts each block's shell directly as a login shell (`$SHELL -l`). It does not go through `/usr/bin/login`, so the environment of the Rex server reaches the pane unchanged.

## Session mode

Under Rex, workrex uses [session mode](https://kong109.github.io/workrex/guide/session-mode/) unless you set `mode` or pass `--mode`. Each worktree gets its own Rex session. Set `mode: window` to get tabs in the current session instead.

- **Adding.** `workrex add` creates the session and focuses its pane in that session, but leaves Rex.app where it is, because the command may run in a background agent's pane. It prints `Rex.app stays put: to see feat-a, press Enter on its row in workrex dashboard.`, naming the worktree because an agent may rename its Rex session. Enter on a worktree row in the dashboard moves Rex.app to that session. `--background` prints nothing.
- **Closing.** When `remove`, `close` or `merge` closes a session that Rex.app shows, the app lands on the destination: the managed session of the merge target, then [`default_session`](https://kong109.github.io/workrex/guide/session-mode/#returning-to-a-default-session), then the session the worktree was added from. Rex.app shows the first session in the order when the session it shows closes, so workrex moves the destination first for the close and then back next to its old neighbors. Closes take a lock, so two closes never interleave, and a close that is killed midway leaves the order for the next close to put back. A close gives up on a move after 2 s. Rex may still apply that move later, so later closes keep putting the destination back for 10 s after it timed out. An app showing another session stays where it is. Without a destination, the app lands on the first session.
- **Renamed sessions.** Agents may rename their Rex session (Rex tells Claude Code to name its session after the task). workrex records each session it creates by its Rex session ID under `$XDG_STATE_HOME/workrex/rex-sessions.json`, so it still finds the session after a rename.

### Remote Control

A jump needs Remote Control, which you turn on in Rex Settings. Without it, the app refuses the jump and the target is not focused. The dashboard stays open and shows the fix in its footer until you press a key and at least 5 s have passed. The [dashboard layer](#dashboard) shows its own hint instead. `last-agent` and `last-done` print `Rex.app did not switch: Remote Control is off. Turn it on in Rex Settings.` once. `add` and closing a session do not need Remote Control.

## Dashboard

The [dashboard](https://kong109.github.io/workrex/guide/dashboard/) opens in a floating layer over the current tab. Copy [`resources/rex/workrex.lua`](https://github.com/kong109/workrex/blob/main/resources/rex/workrex.lua) to `~/.config/rex/workrex.lua` and load it from `~/.config/rex/init.lua`:

```lua
require("workrex")
```

Check the file and reload the configuration:

```bash
rex config check ~/.config/rex/workrex.lua
rex config reload
```

Press `Shift+Cmd+D`, or run **workrex: Open Dashboard** from the command palette. Pressing the key again while the dashboard is open focuses it instead of opening a second one. The key replaces Rex's default for **Split Pane Down**, which keeps `Shift+Cmd+Down`. To use another key, change the `rex.bind` line at the end of the file.

- **Jumping.** Choosing an agent switches the app to the agent's tab, focuses its block, and closes the layer. With [Remote Control](#remote-control) off, you can still jump to an agent in the tab the dashboard is open over. Choosing an agent in any other tab or session keeps the dashboard open with `Turn on Remote Control in Rex Settings to jump across tabs` in its footer until you press a key and at least 5 s have passed. If the app does not answer within 1 s, a jump within the tab still lands and closes the layer. A jump to any other tab or session keeps the dashboard open with `Rex.app did not respond; jump not made` in its footer, so the keyboard never goes to a block the app may not show. If the app switches late anyway, the keyboard follows the tab it shows.
- **Peeking.** Press `p` to look at an agent while the keyboard stays on the dashboard. An agent in the dashboard's tab shows around the layer. A floating layer belongs to one tab, so peeking at an agent in another tab shows `Peek works only for agents in this tab`; press `Enter` to jump there instead.
- **Closing.** Press `q` to close the layer. Focus returns to the block you were in.
- **Options.** The action passes `args` to `workrex dashboard`, for example `rex.bind("shift+cmd+d", "workrex_dashboard", { args = { "--session" } })`.
- **Binary.** The action runs `workrex` from your login shell's `PATH`. To run another binary, set `WORKREX_BIN` in the Rex server's environment.

## Requirements

- The `rex` CLI. Inside a Rex pane it is already on `PATH`.
- macOS or another Unix-like OS (named pipes for handshakes)

## Choosing the server

workrex talks to the server named by `REX_SERVER`. When `REX_SERVER` is unset, it uses the server the `rex` CLI finds by default, and asks it for its address with `rex whoami`.

workrex never starts a Rex server and never stops one. Every call passes `--autostart=false`.

:::note
If you run a second Rex server on its own socket, set `REX_SERVER` in that server's environment before starting it. Rex panes inherit the server's environment, and without `REX_SERVER` the `rex` CLI in those panes reaches the default server instead.
:::

## Agent state across restarts

workrex identifies the server by its address, which stays the same across restarts, and detects a restart from the server instance ID that `rex whoami` reports. After a restart, `workrex resurrect` reopens the agent windows that were running.

## Sidebar

`workrex sidebar` works under Rex. Each window in scope gets a full-height block labeled `workrex-sidebar` on its left, added without moving focus. Use `--session` to scope the sidebar to the caller's Rex session. `on`, `off`, navigation, filters, groups, and views are native Rex operations.

- **New windows.** The sidebar daemon follows `rex events`, and adds a sidebar to a new window as soon as Rex reports it. A sidebar you close in one window stays closed there until the next `workrex sidebar on`.
- **Width.** The daemon keeps each sidebar at the configured `sidebar.width`. Without one, dragging a sidebar border saves the new width and applies it to every other sidebar. A `--width` given to `sidebar on` holds until the sidebar is turned off.
- **Jumps.** Jumping to an agent from the sidebar moves the app, like the dashboard. If Rex.app refuses the jump, the sidebar shows `Rex.app did not switch: Remote Control is off. Turn it on in Rex Settings.` above its list until you press a key, and for at least 5 seconds. `workrex sidebar next`, `prev` and `jump` print it once and exit with status 1.
- **Position.** The sidebar opens on the left. Top-positioned sidebars are not supported.
- **State.** Rex has no window options, so sidebar preferences are kept in files under `~/.local/state/workrex/sidebar/`, one set per server.
- **Daemon.** Rex has no hooks to restart the daemon. If it dies, the next `workrex sidebar` command or sidebar start brings it back. The daemon keeps retrying a Rex server that is slow or busy. It exits when nothing listens at the server's socket any more.

## Known limitations

- `add` and `open` do not move Rex.app to the new window or session
