@tian.zuo/pi-rex
Tells the pi coding agent that it runs in a Rex terminal, names the Rex session after the project folder or worktree, names the tab from the first prompt, and resumes pi after a Rex restart.
Package details
Install @tian.zuo/pi-rex from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@tian.zuo/pi-rex- Package
@tian.zuo/pi-rex- Version
0.3.0- Published
- Nov 6, 2026
- Downloads
- 411/mo · 411/wk
- Author
- tian.zuo
- License
- MIT
- Types
- extension
- Size
- 31.6 KB
- Dependencies
- 0 dependencies · 1 peer
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
@tian.zuo/pi-rex
Release notes: changelog · GitHub releases
The Rex session-start hook for the pi coding agent. The extension also names the Rex session after the project folder or worktree, names the tab from the first prompt, and records each pane's pi session so pi can resume after a Rex restart.
pi install npm:@tian.zuo/pi-rex
How it works
rex skill setup writes a SessionStart hook for Claude Code and Codex. The hook tells the agent that it runs in a Rex terminal. The hook also supplies the session ID and the pane ID. Rex writes the skill for pi, but pi has no command hooks.
This extension supplies the hook for pi. When a session starts and REX_SESSION is set, the extension runs this command:
rex __internal session-start --agent pi
The extension adds the output to the system prompt as a <rex> section. Outside a Rex terminal, the extension does nothing. If the command fails, pi shows a warning. The system prompt does not change.
Run rex skill setup to install the skill. This extension does not install the skill.
Naming
Rex gives each session and each tab a generated name. The extension names the session after the project folder, and gives each tab a task name from the first prompt. The agent does not run a rename command.
The session name is the current folder name, as-is. In a linked git worktree, the name is Wrktree—<main repository folder>—<branch>, such as Wrktree—pi-tian-extensions—docs/pi-layerfs-spec. A detached worktree uses the first seven characters of the commit. The extension finds the worktree with git worktree list --porcelain. If git fails or the folder is not a git repository, the folder name is used.
On the first user prompt of a pi session, the extension runs rex whoami --json as a cheap check that the Rex server answers. If it does, the extension reads the folder and worktree, then makes one model call on the current session model. The call asks for a tab label: 2 to 4 lowercase English words, joined by hyphens. The call runs in the background, so the first response is not delayed. After the model replies, the extension reads the current labels and runs:
rex session inspect "$REX_SESSION" --json
rex session rename "$REX_SESSION" SESSION_LABEL # first tab only
rex window rename -s "$REX_SESSION" WINDOW_ID TAB_LABEL
The session name does not depend on the model. If the model call fails or returns no label, the session is still renamed; only the tab keeps its old name.
The labels are read after the model call. A rename made while the call runs wins.
Rex orders tabs by ID, which comes from the creation time. The first tab carries the session label. A later tab gets its own label and never renames the parent session.
The extension replaces a label only when the label is still generated:
- A session label is generated when it is two lowercase words, such as
shy-strait, or a worktree label from this extension that starts withWrktree—. - A tab label is generated when it is
Window <id>, such asWindow 629d2113.
A hand-set label is kept. A one-word folder label, such as repo, is not recognized as generated, so a later pi session in the same tab keeps it. Naming runs once per pi session. If a Rex command fails, the old name stays and the agent continues.
Because the extension names the session, it removes the Rex naming paragraph from the <rex> section. It adds one line instead: the names are automatic, and the agent must not rename them unless the user asks. This also overrides the rex skill rule that says to rename only when the user asks.
Resume after a Rex restart
Rex restores sessions, tabs, panes, and scrollback after a restart. Each pane keeps its block ID, but Rex starts a new shell in the pane, not pi. The extension records the pi session of each pane, so a shell hook can start pi again.
When REX_BLOCK is set in TUI mode, the extension writes ~/.pi/agent/rex-resume/<block id> (below PI_CODING_AGENT_DIR when it is set). It writes the record when a session starts and after each prompt, because pi creates the session file only after the first message. The record holds the working directory on line 1, then the command, one argument per line:
/Users/you/src/app
pi
--session
/Users/you/.pi/agent/sessions/--Users-you-src-app--/2026-11-05T05-52-27-656Z_01a1....jsonl
The record stays when pi stops because of SIGHUP or SIGTERM, or because the terminal is gone. A Rex restart does one of these. The record stays for /reload, /resume, and /fork, and the next session writes its own record. /new removes the record until the new session has a file, so a restart right after /new does not reopen the previous session. The record is removed when you quit pi (Ctrl+D, Ctrl+C twice, /quit). Print, JSON, and RPC runs write no record.
The extension cannot start a program in a Rex pane, so the shell must read the record. Add this hook to ~/.config/fish/config.fish (or a file in conf.d/):
if status is-interactive; and set -q REX_BLOCK
function __rex_resume --on-event fish_prompt
functions -e __rex_resume
set -l agent_dir $HOME/.pi/agent
# Expand ~ as pi does: fish does not expand it inside a variable.
set -q PI_CODING_AGENT_DIR; and set agent_dir (string replace -r -- '^~(?=/|$)' $HOME $PI_CODING_AGENT_DIR)
set -l file $agent_dir/rex-resume/(string replace -- 'block:' '' $REX_BLOCK)
test -f $file; or return
set -l record (cat $file)
test -n "$record[1]"; or return
cd -- $record[1]; or return
rm -f $file
$record[2..]
end
end
The hook runs once, before the first prompt, after the rest of the config is loaded. A new pane has a new block ID, so it has no record. Only a pane that Rex restored while pi ran in it has one. The hook removes the record before it starts pi, and pi writes a new one. The hook always runs pi --session <file>: it does not restore the flags of the first launch, so a pane that ran pi -e ./packages/pi-rex resumes with plain pi.
Settings
The extension reads the rex section of the pi settings file. Add the section to ~/.pi/agent/settings.json.
| Key | Type | Default | Description |
|---|---|---|---|
rex.autoName |
boolean | true |
Name the Rex session after the folder or worktree, and the tab from the first prompt. false keeps the Rex names and the Rex naming text. |
Example:
{
"rex": {
"autoName": false
}
}
Any value other than false keeps automatic naming on.
Known limits
- The extension decides "generated" from the shape of the label. A hand-set two-word session label, such as
fix-login, is replaced. - A one-word folder label is not recognized as generated. If you start a new pi session in another folder in the same Rex tab, the session keeps the old folder name.
- The model reply must be one tab label. A prose reply leaves the old tab name in place; the session is still renamed.
- The naming call uses the current session model. A reasoning model can spend part of the token budget before it writes the label.
- The
<rex>removal reads one string from the Rex output: the paragraph that holdsrex session rename. A change to that wording stops the removal. - Resume needs the shell hook. Without it, the records do nothing.
- The hook starts
pi --session <file>, so it does not restore the flags of the first launch. A pane that ranpi -e ./packages/pi-rexresumes without the local extension. - A second interactive fish in the same pane, started while pi runs, also reads the record. It can start a second pi on the same session and remove the record; the next prompt in the first pi writes the record again.
- When you close a pane while pi runs in it, pi gets SIGHUP and its record stays. The file is small, and Rex never reuses a block ID.
- A pi started by the fish hook runs inside a prompt event, so Ctrl+Z may not suspend it.
License
MIT © Tian Zuo