pi-affix-prompt
Affix-pin the active user prompt at the top of the transcript (antd-style Affix) with unified maxRows truncation — fullscreen TUI mode / 用户输入消息吸顶(类似 antd Affix),统一 maxRows 缩略模型
Package details
Install pi-affix-prompt from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-affix-prompt- Package
pi-affix-prompt- Version
1.0.5- Published
- Aug 20, 2026
- Downloads
- 495/mo · 187/wk
- Author
- hellokidder
- License
- MIT
- Types
- extension
- Size
- 49.6 KB
- Dependencies
- 0 dependencies · 2 peers
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
affix-prompt
Affix pinned prompts for the pi coding agent — keeps the current user message (your prompt) pinned at the top of the transcript while you scroll (fullscreen TUI mode only).
What it does
When you scroll up through a long conversation, your own prompts scroll out of view and you lose track of what was asked. affix-prompt pins the active user message to the top of the transcript:
- Peel & stick — as the message scrolls off the top, its off-screen lines are "peeled" into the pin, 1:1 with the scroll. Once fully scrolled off, the pin shows the complete message — same height, same content, same theme.
- Takeover — when the next user message reaches the top, the pin switches to it seamlessly (height jumps are absorbed by a same-frame scroll compensation, so content never jumps).
- Hand-back — scroll back up and the pin hands back to the previous message, with hysteresis to prevent oscillation at takeover boundaries.
- Optional truncation — set a max content-row limit (
maxrows N); the pin then shows the first N content lines (with padding borders) instead of the full message.
The pinned copy is a live render of the real message component, so it always matches the current theme, width, and markdown styling — no hardcoded colors, works with any pi theme.
Requirements
- pi ≥ 0.84
- Only the fullscreen TUI mode is supported (
--tui-mode fullscreenor via/settings). The regular mode (terminal scrollback) has no layout system to pin into — the extension is inert there (settings still persist and take effect when you switch back to fullscreen).
Installation
Recommended: install from npm (pi package gallery)
pi install npm:pi-affix-prompt
Then run /reload in pi (or restart pi). To update later: pi update npm:pi-affix-prompt.
From git
pi install git:github.com/hellokidder/affix-prompt@v1.0.0
Manual / development
Clone or copy this repository into the pi extensions directory (useful when developing):
mkdir -p ~/.pi/agent/extensions
# Option A: clone the repository
git clone https://github.com/hellokidder/affix-prompt ~/.pi/agent/extensions/affix-prompt
# Option B: copy the source files
# copy index.ts and state-machine.ts into ~/.pi/agent/extensions/affix-prompt/
# Option C: symlink a local checkout (auto-syncs on /reload)
# ln -s /path/to/affix-prompt ~/.pi/agent/extensions/affix-prompt
Usage
/affix-prompt toggle on/off
/affix-prompt on|off enable/disable
/affix-prompt maxrows N set max content rows (pin shows N content lines, total height N+2)
/affix-prompt 5 shorthand for "maxrows 5"
/affix-prompt 0 full mode (no truncation, default)
maxrows 0(default): full mode — the pin grows to the message's full height.maxrows N(N ≥ 1): truncation — the pin shows the first N content lines with symmetric padding borders (like a compact bubble).maxrows 1is a single-line bubble.
Settings persist across sessions in ~/.pi/agent/affix-prompt.json:
{ "enabled": true, "maxRows": 0 }
maxRowsis the number of content lines; the pin's total height ismaxRows + 2(top/bottom padding is handled internally).Default behavior: the extension is enabled by default with
maxRows: 0(full mode) — after installation it starts working the first time you enter fullscreen mode. Disable with/affix-prompt off.
Behavior details
- Peel boundary: pin starts growing when
scrollTop = message.start(message top touches the TUI top edge). - Pin height:
h = clamp(scrollTop − start, 0, min(H, maxRows + 2, totalSpace − 2))— where H is the message's rendered height andtotalSpace − 2reserves at least 2 transcript rows (monster-prompt guard). - Takeover:
scrollTop ≥ start_next— the next message takes over the pin. Height jumps at handover are absorbed by a same-framescrollTocompensation: content position stays continuous. - Hand-back:
scrollTop < start − takeoverDrop(hysteresis) — prevents ping-pong oscillation at the takeover boundary.
Themes
The pin renders through pi's own UserMessageComponent, so colors always come from the current pi theme (userMessageBg, userMessageText, md* tokens). No color values are hardcoded — switching themes updates the pin automatically. Any theme that passes pi's schema validation works.
Known limitations
- Monster prompts (taller than the screen): the pin caps at
totalSpace − 2rows so the transcript always keeps ≥ 2 visible rows. - Truncation mode (
maxrows N< message height): the symmetric padding borders occupy 2 rows, so the pin showsNcontent lines; the remainder of the message scrolls in the transcript below. - Images: user messages with inline terminal images are not specially handled in the pin (rare — user message markdown normally doesn't render images).
Debugging
AFFIX_PROMPT_DEBUG=1 pi
Logs go to /tmp/affix-prompt-debug.log (rebuild measurements, state-machine transitions, compensation deltas).
Development
node --test "tests/**/*.test.ts" # state-machine unit tests (no pi runtime needed)
The state machine lives in state-machine.ts as pure functions with deterministic tests; index.ts contains the pi integration (layout hook, scroll compensation, command).
License
MIT