@rokiy/pi-ui
Custom pi terminal UI with themes, layout, and message rendering
Package details
Install @rokiy/pi-ui from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@rokiy/pi-ui- Package
@rokiy/pi-ui- Version
1.7.0- Published
- Oct 29, 2026
- Downloads
- 152/mo · 40/wk
- Author
- rokiy
- License
- MIT
- Types
- extension, theme
- Size
- 168.7 KB
- Dependencies
- 0 dependencies · 4 peers
Pi manifest JSON
{
"image": "https://img.dog/file/1779944542014_image.webp",
"themes": [
"./themes"
],
"extensions": [
"./src/index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
📋 Features
pi-ui is a pi-package extension for the pi coding agent that enhances your terminal with a custom status bar, rich theming, and improved editing experience.
- 🖥️ Custom Status Bar — Real-time footer display showing model name, thinking level, current working directory, git branch, context usage (%), token usage (↑input ↓output), and API cost — all in one glance
- 📚 Readable Startup Resources — Skills and extensions show item counts in lists that adapt to terminal width. Package names and installed npm/Git versions are aligned in separate columns; long names wrap within their list column, preserving multiple columns whenever space allows. Empty Context, Prompts, and Themes sections are hidden. Skills are listed by name.
- 🌀 Native Startup Initialization Progress — Run
pinormally: its first screen shows a gentle sweep beneath the PI logo in a centered layout with breathing room. pi-ui initializes first, and extensions appear progressively with measured session initialization times. - 🟢 Inline Version Updates — When Pi or an npm extension has a newer release, its version changes to
v1.2.0->v1.2.1, with the new version highlighted in green. Update checks run in the background; packages without a welcome-screen row use a compact notice. - 🎨 Catppuccin Dark Theme — A meticulously crafted dark theme based on Catppuccin Mocha with 64+ color mappings covering syntax highlighting, markdown rendering, thinking levels, UI components, and export backgrounds
- ✨ Boxed Editor — Unicode border editor (
╭─╮style) replacing the default editor with elegant rounded corners - ⏳ Adaptive Working Indicator — Animated spinner (→) at 120ms with 3-tone adaptive coloring (green→yellow→red based on token recency). Shows cumulative output tokens and elapsed time for the current task (
Working... (↓ 1.2k tokens · 12s)), including thinking and tool-call arguments. - 📊 Per-Message Usage Stats — After each assistant reply, a token/cost/duration summary is displayed inline (
↑271 ↓50 · $0.0017 · 4.1s) with a matching-width separator line. Stats are displayed only — automatically stripped from LLM context to avoid polluting the conversation. - 🧰 Compact Tool Cards — Rounded frames with execution state, recorded duration, and a four-row result preview. Shell output keeps its latest lines; successful file reads collapse to a hidden-line hint. Expand with your configured tool shortcut or a click; native diffs and extension tools share the same frame (Pi 1.4+).
- 💬 Message Cards — User messages occupy the right half and assistant replies the left, with rounded frames matching tool cards. Recorded local times appear at the user's bottom right and the assistant's bottom left; native Markdown, streaming and thinking controls are retained.
- 🔌 Zero Dependencies — Pure peer-dependency package; no additional npm packages required
- ⚡ TypeScript Native — Source code loaded directly via jiti — no build step needed
- 🧩 Modular Architecture — Focused modules cover the entry point, UI setup, footer, editor, welcome layout, installed package versions, update notices, and startup progress.
📦 Installation
Option 1: Install from npm (Recommended)
pi install npm:@rokiy/pi-ui
Option 2: Install from GitHub
pi install git:github.com/DragonYH/pi-ui
Option 3: Local Development
git clone https://github.com/DragonYH/pi-ui.git
cd pi-ui
pi install ./
Verify Installation
Restart pi. You should see the custom footer appear at the bottom of your terminal, with the Catppuccin dark theme applied automatically.
🚀 Usage
Once installed, pi-ui works completely automatically — no configuration required:
- On session start — the custom UI initializes: footer, editor, spinner, message renderer
- On agent activity (
agent_start→message_update→agent_end) — the working indicator adapts its color in real-time, and the footer stats refresh - On thinking level change (
thinking_level_select) — the thinking level indicator in the footer updates - On session shutdown (
session_shutdown) — all working timers are cleaned up gracefully
Startup Progress
Run pi normally after installation. No additional entry point or command alias is needed. Verified with Pi 1.4.0 in regular and fullscreen mode.
- The extension factory adapts the SDK lifecycle in the current process and mounts the animation in Pi's existing UI tree, so the native terminal's first frame already contains the PI animation.
- Only the
session_startemission snapshot puts pi-ui first, installing the welcome screen, editor, and footer before other extensions initialize. Other extensions keep their relative order, and other event ordering stays unchanged. - A gentle sweep beneath the PI logo updates every 80 ms, easing back and forth over a 3.2-second cycle. Loading and welcome screens share outer spacing and expand to the terminal's available width; the brand column stays within 30 columns so extra space goes to the resource lists. Each extension appears when its initialization begins, showing its current state and elapsed time.
- Timings accumulate all of an extension's
session_starthandlers. Extensions without a handler take 0 ms; earlier module imports and factory registration are excluded. - Startup completion stops the animation and restores the welcome screen without initialization times beside extension names or versions. Errors retain Pi's native reporting and also appear in the progress list.
/reloadand session changes start a fresh timing run, shutdown clears timers, narrow terminals stack the logo and list, and noninteractive modes skip the animation.
Module import boundary: Pi imports extensions and runs their factories before it creates the terminal UI and emits session_start. Its loader provides no event that hands the remaining import queue to a plugin, so initialization progress cannot reconstruct those earlier timings. This project does not rewrite installed Pi files or global settings and has no alternative startup command. Synchronous code can block animation until it returns control to the event loop.
Development checks: npm test exercises the real SDK emitter for ordering, timing, errors, and layout. python3 tests/startup-pty.py directly runs native pi with isolated fixtures inside this project, covering regular/fullscreen mode, /reload, initialization failures, and unchanged installed files/global settings. The integration depends on SDK UI and event implementation details; rerun these checks after upgrading Pi.
Status Bar Layout
The two-line footer displays at the bottom of your terminal:
| provider/model thinking_level cwd branch context% ↑input ↓output cost
| extension-status-1 extension-status-2 ...
Each section uses Nerd Font icons and adaptive color theming. The footer gracefully shrinks to fit your terminal width — non-critical sections are dropped first, ensuring the most important info (cwd, branch) always stays visible.
Editor
The default message editor is replaced with a BoxedEditor that uses Unicode box-drawing characters:
╭──────────────────────────────────────────╮
│ Your message content goes here... │
╰──────────────────────────────────────────╯
Message Cards
User messages occupy the right half of the transcript, with “You” in the top-right corner, and assistant replies occupy the left half. Both use rounded frames and reserve the scrollbar column. User frames and titles use the theme's purple thinkingHigh color, assistant frames and titles use its green success color, and tool cards use borderAccent. Long text wraps within its half of the screen.
╭─────────────────────────────── You ─╮
│ Please check the build. │
╰────────────────────────── 12:34:56 ─╯
╭─ Assistant ─────────────────────────╮
│ The build passed. │
╰─ 12:34:58 ──────────────────────────╯
Times use HH:mm:ss in the local timezone from the original message timestamp, so restoring or reloading a conversation keeps them stable. Assistant cards update during streaming and retain native Markdown, code highlighting, links, thinking controls and error messages. Tool-call-only assistant messages do not add empty cards.
With Pi installed, node tests/message-cards-runtime.mjs verifies native message rendering, themes, resizing, streaming, thinking clicks and reload behavior; python3 tests/tool-cards-pty.py checks resumed messages and tool interaction in regular and fullscreen terminals.
Tool Cards
Tool calls use the same rounded visual language as the editor:
╭─ ✓ $ npm test ──────────────────────── done · 100 ms ─╮
│ … 16+ lines hidden │
│ test 17 passed │
│ test 18 passed │
│ test 19 passed │
│ test 20 passed │
╰─────────────────────────────────────── ctrl+o expand ─╯
- The single top border distinguishes preparing, queued, running,
done, andfailcalls. Its right-hand area uses 13 terminal columns by default (done · 100 ms), with one outer space on each side, and aligns withctrl+o expandbelow.foldkeeps the expanded control within the same width. Long custom shortcuts enlarge both areas together; narrow cards prioritize the shortcut. All widths use terminal display columns. Missing durations use—; longer durations use compact units. - Collapsed results show at most four visual rows, plus an omission hint in the body. Shell tools place the hint above their tail preview; other tools place it below their head preview. Successful
readcalls collapse to an omission hint. Errors retain a visible preview, and output truncation and full-log paths are shown separately. - Use the configured tool expansion shortcut (normally Ctrl+O) or click the card to expand/collapse through Pi. Expanded built-in results retain native syntax highlighting; image display stays under Pi's control.
- The frame aligns with the input editor on the left and leaves one column clear on the right for the scrollbar. Tool names use a warm heading color, commands use cyan/teal, and paths use muted text; frame accents and output retain separate colors. The bottom border contains only the expansion control in the theme's lowest-contrast
dimtext color; total line counts are omitted. - Native edit/diff previews and custom extension tools, including
skill_manageandtodo, use the same frame while retaining their content and controls. Interactive controls remain visible when collapsed. - Completed output parsing is cached. Collapsed results only wrap their preview lines, and cards add no polling timers.
Cards require Pi's registerToolRenderer API, verified on Pi 1.4.0. Older versions retain their existing tool rendering. The renderer changes display only; tool definitions, execution, model context, and stored results are preserved.
Development checks: npm test, npm run typecheck, and npm run lint. With Pi installed, run node tests/tool-cards-runtime.mjs to exercise its real loader and tool components across themes, terminal widths, errors, and expansion; an ANSI preview is saved under .pi/.
Working Indicator
The default "Working..." indicator is replaced with an animated spinner sequence ( ) cycling every 120ms. The spinner features 3-tone adaptive coloring:
| Tone | Condition | Meaning |
|---|---|---|
| 🟢 Green | Last token received < 10s ago | Active streaming |
| 🟡 Yellow | 10–30s since last token | Thinking / idle |
| 🔴 Red | > 30s since last token | Possible stall |
The indicator starts on agent_start, resets its color on incoming assistant stream events (message_update), and stops on agent_end.
Following the pi-cc-extensions Working row, it also displays the current task's cumulative output tokens and elapsed time:
Working... (↓ 1.2k tokens · 12s)
Text, thinking, and tool-call argument deltas contribute to a live token estimate. Provider-reported output usage corrects that estimate when available, including hidden reasoning; input and cached tokens are excluded. Counts continue across tool calls and reset for the next agent run. The timer includes model and tool waits, uses seconds/minutes/hours, and updates every 100ms. Before any output, only waits of at least 3 seconds show a timer. Shutdown, reload, and session replacement clear the working state and timers.
🎨 Themes
| Theme | Description |
|---|---|
catppuccin-dark |
Full Catppuccin Mocha dark theme — 64+ color mappings for syntax highlighting, markdown, UI components, thinking levels, and export backgrounds |
Color Palette
The Catppuccin Dark theme maps 24 distinct palette variables across every visual layer:
| Category | Colors |
|---|---|
| UI | primary secondary accent surface overlay text subtext0 subtext1 |
| Semantic | green red yellow blue mauve teal sky pink peach maroon lavender flamingo |
| Thinking Levels | Each level gets a distinct color: off→subtext0, minimal→accent, low→blue, medium→teal, high→mauve, xhigh→red |
| Export | Page/card/info export backgrounds for sharing conversations (light #11111b, #1e1e2e, #313244) |
Using Themes
pi-ui themes are automatically registered when installed. You can switch themes in pi:
/theme catppuccin-dark
See the pi themes documentation for more details.
🏗️ Project Structure
pi-ui/
├── src/
│ ├── index.ts # Extension entry — registers events
│ ├── ui.ts # UI setup — footer, BoxedEditor, message renderer
│ ├── tool-cards.ts # Compact tool frames, result previews, renderer compatibility
│ ├── working.ts # Working row — output tokens, elapsed time, adaptive spinner
│ ├── footer.ts # Footer rendering — model, usage, context, git branch
│ ├── editor.ts # BoxedEditor component — Unicode border decoration
│ ├── welcome.ts # Startup header — resource counts and adaptive lists
│ ├── welcome-layout.ts # Shared loading/welcome margins and column proportions
│ ├── resource-versions.ts # Installed package versions from local metadata
│ ├── update-notices.ts # Inline Pi/package updates with green target versions
│ └── startup/ # Native UI lifecycle integration, initialization timings, PI animation
├── tests/ # Timing/layout tests and real-terminal verification
├── themes/
│ └── catppuccin-dark.json # Catppuccin Mocha dark theme (64+ color mappings)
├── .github/
│ └── workflows/
│ └── release.yml # CI/CD — auto-publishes to npm on version tag
├── LICENSE # MIT license
├── README.md # English documentation
├── README.zh-CN.md # Chinese documentation
└── package.json # Node.js and pi package manifest
🧠 How It Works
┌──────────────────────────────────────────────────────────────┐
│ pi Coding Agent │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ╭────────────────────────────────────────────╮ │ │
│ │ │ [Chat Interface with BoxedEditor] │ │ │
│ │ ╰────────────────────────────────────────────╯ │ │
│ │ │ │
│ ├────────────────────────────────────────────────────────┤ │
│ │ | deepseek/deepseek-chat medium my-project │ │
│ │ main 45% ↑1.2k ↓3.4k 0.0012 │ │
│ └────────────────────────────────────────────────────────┘ │
│ │
│ ┌── Extension: pi-ui ──────────────────────────────────┐ │
│ │ session_start ──► setupCustomUI() ──► footer │ │
│ │ editor │ │
│ │ spinner │ │
│ │ messageRenderer │ │
│ │ agent_start ──► reset tokens, start timer │ │
│ │ message_update ──► count tokens, update color │ │
│ │ agent_end ──► stop timer, reset message │ │
│ │ ──► rerenderFooter() │ │
│ │ thinking_level_select ──► rerenderFooter() │ │
│ │ session_shutdown ──► dispose working state │ │
│ └───────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
Events Handled
| Event | Handler | Description |
|---|---|---|
session_start |
setupCustomUI() / working lifecycle |
Registers footer, BoxedEditor, message renderer, and working UI context |
session_shutdown |
dispose working state | Cleans up timers and UI context on session end |
agent_start |
reset working state | Resets task token totals, starts the adaptive spinner and elapsed timer; re-renders footer |
message_start |
reset message estimate | Starts a fresh output-token estimate for each assistant response |
message_update |
count output tokens | Counts text/thinking/tool-call deltas, incorporates provider usage, and refreshes color and working text |
message_end |
finalize output usage / append usage stats | Adds assistant output usage to task totals; also displays existing per-message token/cost/duration stats |
agent_end |
stop working timer | Stops refreshing, restores the default working message, and re-renders footer |
thinking_level_select |
rerenderFooter() |
Updates the thinking level label in the footer |
context |
strip usage stats | Filters out the usage stats text blocks before messages are sent to the LLM, keeping context clean |
🛠️ For Developers
Development
Since pi-ui uses zero dependencies and TypeScript is loaded via pi's built-in jiti transformer, there's nothing to build. Just clone and install:
git clone https://github.com/DragonYH/pi-ui.git
cd pi-ui
pi install ./
Publish Checklist
This project publishes through GitHub Actions when a version tag is pushed.
Before publishing, verify the package contents:
npm pack --dry-run
Then create and push a tag that matches package.json:
git tag vX.Y.Z
git push origin vX.Y.Z
Before pushing the tag, configure npm Trusted Publishing for this package:
- Publisher: GitHub Actions
- Owner:
DragonYH - Repository:
pi-ui - Workflow:
release.yml - Environment: leave empty
Adding a New Theme
Create a JSON theme file in themes/ following the pi theme schema. It will be automatically discovered by pi at startup.
Compatibility
- Node.js >= 20
- pi runtime loads TypeScript directly via jiti — no build step required
- Works with any model provider supported by pi
