@underactive/pi-topping0.12.0
A Pi extension that adds quality of life improvements to Pi's UX: a high-vis user prompt, a shimmering working loader with token activity meter and elapsed timer, an end-of-turn completion marker, and selectable output styles
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-topping
We garnish our pies. It seemed rude not to extend Pi the same courtesy. This is a Pi extension that adds some quality of life improvements to Pi's UX, while looking good in the process:
User Prompt — high-vis bordered prompt box with configurable border color and style, pi icon toggle, timestamp, and provider/model label. The box, timestamp, and provider/model label do not change the prompt Pi sends to the model, so they do not affect LLM prompt caching. Explicit /skill:name invocations also get a display-only box while Pi expands the skill natively; Pi's [skill] entry remains visible beside it. Prompts submitted while Pi is working (steer / Alt+Enter follow-up) are left undecorated so Pi's native Steering: / Follow-up: queue rows still render.

“Working” Loader — animated spinner (with color choice), randomized activity word, optional word packs, shimmer, token activity monitor with an adjustable full-scale rate, elapsed timer, output token display, live output-token rate, and the response model when it meaningfully differs from the selected model — all arrangeable left to right. For raw Responses-API stream events, it can also include Ramp Router's gateway backend as <model> via <backend>, or just via <backend> when the served model restates the selection. Under a Pi virtual model such as pi-topping-routesense's routesense/auto, the response model is the routed physical model. During a blocking extension prompt, the loader switches to a stable dim waiting line with a pulsing indicator, then resumes afterward.

Completion Marker — end-of-turn marker with icon, randomized verb (or Worked; matching past tense when Randomize "Worked" text is on), token consumption display, and optional marker-style, border-style, and border-color decorations spanning the full terminal width. It can append the response model when it differs from the selected model, with its own color option. It can also append per-call service-tier counts (e.g. flex tier ×3), but only for calls whose provider reports a tier. The default elite style trails the summary with tapering dashes; bookend fills the remaining width to a closing corner glyph. Hooks into Pi's agent_settled event. A cancelled run (for example, one stopped with Escape) shows Interrupted instead of the random verb, with the word and any border in the warning color; time, tokens, and other enabled details still appear. Show completion marker also controls this marker.

Output Styles — choose prompt-instruction styles such as Explanatory or Simplified Technical English to guide how the model responds. Styles are instructions, not output formatters.
Install
pi install npm:@underactive/pi-topping
Restart Pi (or run /reload) to pick it up.
Sibling toppings
Run /topping-setup in TUI mode to selectively install missing Pi Topping sibling extensions or uninstall sibling packages recorded in Pi's user settings. Installation rows are selected by default; removal rows are unchecked by default. Restart Pi after applying package changes. Use /topping-setup disable-side-toppings-check to suppress missing-topping notices, or enable-side-toppings-check to restore them.
Settings
Run /topping-settings (TUI only) to customize your toppings. Settings persist to
~/.pi/agent/pi-topping/settings.json; hand edits are tolerated on load.
╔═[ Pi Topping: Settings ]══════════════════════════════════════╗
╟─ Preview ─────────────────────────────────────────────────────╢
║ ║
║ ⠋ Crafting ⣠⣤⣶⣶⣤⣠⣀⢀ 28 tps · 3s · ↓ 84 tokens · test-model ║
║ ║
╟─ User Prompt ─────────────────────────────────────────────────╢
║ [■] High-vis prompt ON ║
║ [■] Border style ‹ double › ║
║ [■] Border color ‹ thinkingLevel › ║
║ [■] Pi icon ON ║
║ [■] Timestamp ON ║
║ [■] Provider ON ║
║ [■] Model ON ║
║ ║
╟─ “Working” Loader ────────────────────────────────────────────╢
║ [■] Animated spinner ON ║
║ ❯ [■] Animated spinner color ‹ thinkingLevel › ║
║ [■] Randomize “Working” text ON ║
║ [■] Text shimmer ON ║
║ [■] Invert shimmer OFF ║
║ [■] Text shimmer direction ‹ Left to Right › ║
║ [■] Text shimmer speed ‹ Normal › ║
║ [■] Token activity monitor ON ║
║ [■] Token activity monitor color ‹ accent › ║
║ [■] Token activity monitor direction ‹ Right to Left › ║
║ [■] Token activity monitor dimmed OFF ║
║ [■] Token activity monitor upper bound ‹ 80 tps › ║
║ [■] Elapsed time since prompt ON ║
║ [■] Show output tokens ON ║
║ [■] Token rate ON ║
║ [■] Token rate color ‹ warning › ║
║ [■] Token rate dimmed OFF ║
║ [■] Response model ON ║
║ [■] Response model color ‹ accent › ║
║ [■] Response model dimmed OFF ║
║ ║
╟─ Elements Order ──────────────────────────────────────────────╢
║ [ ] Animated spinner ║
║ [ ] “Working” text ║
║ [ ] Token activity monitor ║
║ [ ] Token rate ║
║ [ ] Elapsed time ║
║ [ ] Output tokens ║
║ [ ] Response model ║
║ ║
╟─ Completion Marker ───────────────────────────────────────────╢
║ [■] Show completion marker ON ║
║ [■] Marker style ‹ elite › ║
║ [■] Border style ‹ none › ║
║ [■] Border color ‹ thinkingLevel › ║
║ [■] Pi icon ON ║
║ [■] Randomize “Worked” text ON ║
║ [■] Tokens spent ON ║
║ [■] Mid-turn inputs ON ║
║ [■] Service tier ON ║
║ [■] Response model ON ║
║ [■] Response model color ‹ muted › ║
║ [■] Response model dimmed OFF ║
║ ║
╟─ Word Packs ──────────────────────────────────────────────────╢
║ [ ] Doctor Who OFF ║
║ [ ] Firefly OFF ║
║ [ ] Hitchhiker's Guide OFF ║
║ [ ] The Lord of the Rings OFF ║
║ [ ] The Matrix OFF ║
║ [ ] Portal OFF ║
║ [ ] SimCity OFF ║
║ [ ] Star Trek OFF ║
║ [ ] Star Wars OFF ║
║ ║
║ [■] Include default/random “Working” text ON ║
║ ║
╟─ Output Style ────────────────────────────────────────────────╢
║ [■] Style ‹ Default › ║
║ ║
╟─ Options ─────────────────────────────────────────────────────╢
║ [■] Use NerdFont icons ON ║
║ [ ] Response model footer OFF ║
╟───────────────────────────────────────────────────────────────╢
║ ↑↓ move PgUp/PgDn page ←→ select ║
║ ␣ toggle ⏎ apply esc cancel ║
╚═══════════════════════════════════════════════════════[ 9/59 ]╝
Output styles
Choose an output style with ←/→ in the Output Style section of /topping-settings. The selected style changes the model's prompt instructions from your next message.
- Explanatory requests brief Insight blocks before and after coding. This is a prompt instruction, not a formatter, so a turn may have no Insight.
- Simplified Technical English instructs the model to write all English prose (not code or quoted text) using ASD-STE100 Simplified Technical English (controlled language rules, active voice, simple tenses, short sentences, and small noun clusters).
While a non-default style is active, each prompt also carries a one-line hidden reminder of the style; the model receives it, but the transcript does not show it.
Output styles also apply in print and RPC modes. Set "outputStyle": "explanatory" (or "simplified") in ~/.pi/agent/pi-topping/settings.json; if you edit the file while an interactive session is running, use /reload to load the change. Switching styles changes one system-prompt section. Pi appends that change to the conversation, so providers that support mid-conversation prompt updates keep their cached prefix; other providers may re-read the full prompt once.
The Explanatory prompt is copied word for word from Claude Code's output styles, with two Pi clarifications: a lead-in that frames the instructions for Pi, and an exception allowing Insight blocks despite Pi's conciseness rule. The Simplified Technical English prompt adapts the ASD-STE100 writing rules but does not include the STE dictionary of approved words. A more specific instruction from you, your project instructions, a skill, or the file being edited takes precedence over it. When migrating from pi-topping-insights, its saved style is imported until you next save /topping-settings. Remove the old extension to avoid duplicate hidden reminders. /insights is gone; use /topping-settings.
Word packs
Base activity words are included by default. All word packs, including the shipped Doctor Who, Firefly, Hitchhiker's Guide, The Lord of the Rings, The Matrix, Portal, SimCity, Star Trek, and Star Wars packs and custom packs, are disabled by default. Enable packs in /topping-settings to add their entries to the same uniformly selected pool. With at least one pack enabled, turn off Include default/random “Working” text to draw only from enabled packs; with none enabled the option is locked on. When Randomize “Worked” text is on, the completion marker uses the selected entry’s matching past tense; otherwise it uses Worked.
Bundled packs live in wordpacks/. Copy wordpacks/doctor-who.json, wordpacks/firefly.json, wordpacks/hitchhikers-guide.json, wordpacks/lord-of-the-rings.json, wordpacks/matrix.json, wordpacks/portal.json, wordpacks/simcity.json, wordpacks/star-trek.json, or wordpacks/star-wars.json to ~/.pi/agent/pi-topping/word-packs.json, then change the pack id (the bundled doctor-who, firefly, hitchhikers-guide, lord-of-the-rings, matrix, portal, simcity, star-trek, and star-wars IDs are reserved), name, and words:
{
"packs": [{
"id": "cooking",
"name": "Cooking",
"description": "Kitchen operations.",
"words": [{ "present_tense": "Sautéing onions", "past_tense": "Sautéed" }]
}]
}
Pack IDs must start with a lowercase letter, contain only lowercase letters, digits, and -, and be at most 64 characters. Each pack needs a non-empty name and at least one word with non-empty present_tense and past_tense strings. An optional description appears in the settings preview when the pack row is selected, and an optional attribution records the source. Invalid entries are ignored. Packs reload when a session starts and whenever /topping-settings opens, not while a turn is running. Preferences for missing packs are retained so they apply when the pack returns.
Colors and loader details
Every color setting offers thinking-level (shown as thinkingLevel in /topping-settings); it is the default for the animated spinner, the prompt border, and the completion marker border. The spinner, token activity monitor, token rate, and response model follow Pi's current thinking level. The prompt border uses the level captured when the prompt was submitted, and the completion marker uses the level captured when the turn settled, so earlier entries keep their color after you change level. When hand-editing settings.json, write thinking-level; the legacy default spelling is only recognised for spinnerColor and doneMarkerBorderColor.
Under Elements Order, press ␣ to grab a row, then ↑/↓ to slide that element
left or right within the loader. Elapsed time, output tokens, token rate, and response model are joined with
· separators whenever adjacent. When reordering separates them, each adjacent run is rendered
without a separator before or after it.
The N tps token rate uses the selected theme color and
remains reorderable. Active rates below 1,000 are padded to three characters so updates do not shift the other
segments; larger rates may shift later segments. When inactive, it remains as the dim --- tps placeholder. After its last update it holds
full brightness for 1.5 seconds, then fades through five theme-aware shades to the dim text color over
the next 0.25 seconds before returning to the placeholder; a new count restores full brightness and
restarts the cycle.
The token activity monitor reaches full ⣿ at or above its configurable upper bound (80 tps by default), with lower levels scaled proportionally to that bound. In /topping-settings, ←/→ cycle through presets spanning 10–1000 tps, and ␣ (Space) lets you enter any whole number from 10–1000. Invalid typed entries show an inline error and keep the editor open without changing the current value; invalid hand-edited meterUpperBoundTps values in settings.json revert to 80 on load.
The response model is captured from assistant responses and raw Responses-API stream events, displayed as its sanitized value with no label only when it meaningfully differs from the selected model, and defaults to the final loader detail after output tokens. When Ramp Router reports a gateway backend in the raw event, the label can include it as <model> via <backend>, or via <backend> alone when the served model restates the selection. Under a Pi virtual model such as pi-topping-routesense's routesense/auto, it is the routed physical model: taken from the router's pi-topping-routesense:routed-model announcement when present, which arrives before the first token (announcements for direct routes such as compaction are ignored), and otherwise from the assistant message's model. There only a failed route, which reports the virtual model itself, is hidden, and a bare routed id never displaces a provider-reported decorated form of itself such as a dated name. While pi-topping-statusline embeds the loader in its status bar, the model slides out tail first from behind its separator over 0.3 seconds when it first appears in a run, like that bar's embedded status; elsewhere it appears at once, and a different model replacing it always swaps in place. Equivalent local paths and decorated filenames are suppressed, as is the selected model's id or display name written with other case and separators; trailing parenthesized notes in the display name, such as (Local), are ignored. Its loader display can be hidden, recolored, permanently dimmed, or reordered. The independent Response model footer option is disabled by default; when enabled, the final model appears under the editor after settlement, remains visible for 3 seconds, fades through five theme-aware shades over 0.5 seconds, then clears. New work cancels the pending fade. When the active provider is switchyard, the loader and footer hold/fade use NVIDIA green (#84c51a, matching pi-topping-statusline) regardless of the configured Response model color; the dim setting still applies.
Requirements
- Pi ≥1.2.0. Output styles rely on Pi running the agent-start hook for the run that the decorated prompt starts, which Pi 1.2.0 added. On an older host pi-topping shows a one-time warning at session start, and output styles do not reach decorated prompts.
- The working indicator is embedded in the default editor border and long loaders are truncated to the border width instead of wrapping; custom editors that do not opt in keep the standalone wrapping indicator.
- Node.js ≥22.19.0
Development
npm install
npm test
npm run typecheck
Tests cover the word/shimmer rendering, prompt box and completion marker rendering, activity meter behavior and its configurable upper bound, timer resets, settings persistence and schema migrations, word-pack parsing, loading, and default-text selection, output-style selection and prompt integration, response-model loader and footer behavior, served-model and service-tier extraction, the menu.ts component and its typed number entry, the settings menu wiring end to end, and the /topping-setup command's install and uninstall flows.
Limitations
- Token counts are a streaming word-count estimate, not an exact tokenizer count — they self-correct when each message finishes, so you'll see a small jump at that point.
- Elapsed time normally starts when you submit a prompt; for auto-continuations without that event, it starts slightly later instead.
- If another extension also customizes the working message, whichever one runs last wins.
- Service-tier details and Responses-API served-model/backend labels depend on Pi's
provider_stream_event; SDK adapters that do not expose raw events show neither.
Author
Eric Sison