pi-sticky-last-prompt
Pins your last user message to the top of pi's fullscreen TUI; clicking the pinned bar jumps to that message in the transcript
Package details
Install pi-sticky-last-prompt from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-sticky-last-prompt- Package
pi-sticky-last-prompt- Version
0.1.3- Published
- Oct 26, 2026
- Downloads
- 528/mo · 266/wk
- Author
- tangentyh
- License
- MIT
- Types
- extension
- Size
- 28.1 KB
- Dependencies
- 0 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./sticky-last-prompt.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-sticky-last-prompt
Pins the most recent user message you have scrolled completely past as a one-line bar at the very top of pi's fullscreen TUI. Left-click the bar and the transcript scrolls so that message sits right below it — a quick way to jump back to what you asked.
Install
pi install ./extensions/sticky-last-prompt # local
pi install npm:pi-sticky-last-prompt # npm (if published)
pi's git sources clone a whole repository and install what its root
package.jsondeclares; the pi-collections root is never published and declares nopimanifest, so there is nogit:.../pi-collections/...form. To install just this extension from the repo, clone it andpi installthe subdirectory locally, or publish it to npm.
Or add it to the packages array in ~/.pi/agent/settings.json:
{
"packages": ["./extensions/sticky-last-prompt"]
}
Behavior
- The bar shows the latest prompt that has scrolled completely above the
top of the viewport — the newest message with not a single row left on
screen, so the pinned jump always targets something invisible. While a
prompt is crossing the top edge (head gone, tail still visible) the bar
hides rather than duplicate text sitting directly beneath it; scroll down
until the message is entirely out of view and it becomes the pin. While a
newer prompt is crossing, older fully-hidden prompts do not keep the pin —
the bar just stays blank until the newer one clears the edge. Text is
whitespace-collapsed to one line, ellipsized if too long, and themed with
your active theme (
accenticon on aselectedBgstrip). Skill invocations count as prompts too — pi renders them as collapsible[skill] nameblocks rather than user messages — and are pinned under that same[skill] <name>label. - Left-click anywhere on the bar to scroll the transcript to the message currently shown. The view lands just below the bar, and follow-tail is disabled so new output doesn't yank you back — exactly like pi's built-in search jump.
- Everything else keeps stock behavior: mouse wheel, text selection, scrollbar, right-click paste, middle click, drags. The extension swallows precisely one gesture — a left-button press inside the bar row.
- On
/reloador when starting on an existing session, the bar re-derives from the rendered transcript — no seeding step; it just tracks wherever the viewport opens.
Requires fullscreen TUI mode (pi ≥ 0.84); in regular mode the extension stays dormant.
How it works
The pin is a non-capturing full-width overlay anchored top-left; its text
is resolved from the live transcript tree on every paint (message offsets
cached per width + content height), with no polling timers. Click interception
wraps the renderer instance's internal selection handler: pi consumes clicks
centrally before the extension input APIs see them, so that handler is the seam
this extension uses. pi 1.4 also exposes a component-level handleMouse API to
overlays; the bar still goes through the renderer patch it was built on. The same
instance patching teaches hasOverlay() to ignore our non-capturing bar (and only
ours), so the stock scrollbar and text selection stay live while it is shown. All
internal access is defensive: if a future pi renames these pieces, clicking
stops working but nothing else breaks.
Known tradeoffs
- While the bar is visible, scrollbar dragging and mouse text selection keep working: the extension reports "no overlay" to pi while its own non-capturing bar is the only overlay shown. When another overlay is on top (search box, dialogs), stock pi suppression applies.
- The bar covers the top transcript row while shown.
- Message offsets are re-measured whenever content height changes (e.g. while a response streams in). The walk renders each message component individually instead of one chat-block render, so that cost grows with transcript length on every frame where the cache misses — which is exactly while streaming. Between those frames everything is cached.
- Transcript rebuilds (
/treenavigation, compaction, session load) swap the transcript container's children array wholesale; the offset cache keys on that identity, so the bar re-derives immediately from whatever messages the new branch renders — no stale labels even at identical heights.