@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.

Packages

Package details

extension

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 with Wrktree—.
  • A tab label is generated when it is Window <id>, such as Window 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 holds rex 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 ran pi -e ./packages/pi-rex resumes 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