pi-signal-footer
A readable status footer for Pi Coding Agent: model, tokens, cache, cost, context bar, streaming rate, and MCP/LSP status.
Package details
Install pi-signal-footer from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-signal-footer- Package
pi-signal-footer- Version
0.6.2- Published
- Oct 16, 2026
- Downloads
- 639/mo · 240/wk
- Author
- chengzhi-c
- License
- MIT
- Types
- extension
- Size
- 115.3 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
pi-signal-footer
English | 简体中文
A readable status footer for Pi Coding Agent: model, tokens, cache, cost, context bar, streaming rate, and MCP/LSP status.
Text examples below use a 160-column terminal. Colors follow the host theme, and narrower terminals reflow the layout. LSP appears on demand and is hidden without an active or failed status.
classic (default)
C:/Users/dev/agent-demo · fix-context-bar │ opencode-go › ◎ deepseek-v4-flash-0731 │ ✦ max │ ⎇ main ⎔ 12% [━━──────────────────] 36k/300k
↓ 220 ↑ 5.4k │ ↻ 51k (96.92%) ✎ 1.4k │ $0.087 │ ◷ 2m · 1 turn · 45 tok/s ⇄ MCP tools 2
vivid (/footer theme)
📁 C:/Users/dev/agent-demo · fix-context-bar │ opencode-go › 🐳 deepseek-v4-flash-0731 │ 🧠 max │ 🔀 main 📊 12% [━━──────────────────] 36k/300k
📥 220 📤 5.4k │ 🔄 51k (96.92%) 📝 1.4k │ 🪙 0.087 │ ⏳ 2m · 💬 1 turn · 🚀 45 tok/s 🔌 MCP tools 2
Requires Pi Coding Agent >=0.84.4. Older hosts keep the native footer.
Every line is truncated to the terminal width before it is returned. If a render throws, the footer falls back to the previous frame re-truncated to the current width, so a failure cannot stop the host's render loop. The legend keeps a line of headroom at 80 columns.
Readings
≈marks an approximation, not a lower bound: the live rate and the in-flight≈+Nsuffix on ↑ include visible text, thinking and tool-call arguments. Fixed densities (prose/thinking ≈4 chars/token, tool-call JSON ≈2, CJK/Hangul ≈1) can over- or underestimate; hidden reasoning is not observable. Changed positive provider output calibrates the live count, then only new visible content is estimated. A valid positive output at end becomes+Nuntil that same message lands — a message replaced by another extension or an entry array shortened by a fork ends the reading too. Missing, invalid or zero usage does not make a non-empty estimate exact. Persisted totals use recorded usage, not estimates.- The live rate uses token and time deltas over the same observed span; one sample has no rate, and empty updates do not start the first-output clock. It updates only on chunks, not renders. The continuous window excludes long pauses; a pause holds the last measurement, and the short resume period may reuse it. Sparse chunks without a mature window use a request-wide observed average. At end, output ÷ first-observed-output-to-end time is frozen (request start is the fallback if no output was observed). This is observed throughput, not a provider speed benchmark.
- Token, cache, cost and turn totals cover all entries in the current session file. Same-file
/treenavigation keeps spent tokens from abandoned paths./forkcreates a new file with the selected path: this is not a total across every fork. Turns = user messages, including steering. ◷is estimated agent work time. While enabled,agent_startandsession_before_compactappend a small work-start custom entry, outside LLM context, to exclude preceding idle time consistently live, on landing and after reload. Human gaps and gaps before model/thinking/name/label changes are excluded; each counted gap caps at 15 minutes. Old unmarked history still uses entry gaps and cannot reconstruct every idle boundary. Anabortedresponse rewinds entry-time minus message-start-time, at most its counted gap;errordoes not. Failed/cancelled compaction without a result leaves no added completed work.↻is accumulated cache-read tokens; the parentheses are the latest landed assistant request with usable input dimensions, not the current streaming request:cacheRead / (input + cacheRead + cacheWrite), to two decimals. All-zero or unreported input dimensions carry over the last known rate (stale, never a faked 0.00%). A request with usable input but no read reports 0.00%.- Context comes from the host’s current-branch
getContextUsage(), which may combine reported usage and new-message estimates; unknown values stay unknown. A reported window of 0 or NaN falls back to the model'scontextWindow;?shows only when neither is available. Cost sums recordedusage.cost.total, not a verified invoice. Colors follow the displayed rounded context percentage: ≥50% warns, ≥75% errors.
Install
pi install npm:pi-signal-footer
Pin with pi install npm:pi-signal-footer@<version>, update with pi update --extensions, or install from a tag: pi install git:github.com/chengzhi-c/pi-signal-footer@v<version>.
Configure
Settings live in pi-signal-footer.json under Pi's agent directory (usually ~/.pi/agent/); a missing or invalid file falls back to these defaults. Commands below write this file.
{
"enabled": true,
"locale": "auto",
"theme": "classic",
"showProject": true,
"showSessionName": true,
"showDuration": true,
"showTurns": true,
"showSpeed": true,
"showBranch": true,
"showCacheRatio": true
}
locale: auto / zh / en. theme: classic (neutral gray with a few semantic colors) or vivid (colorful emoji, dim separators and tracks, second example above).
Commands
/signal-footer and the short alias /footer work identically:
/footer show the metric legend (same as /footer legend)
/footer hide hide the legend (this session)
/footer help show every command
/footer off restore the native footer
/footer on enable this footer
/footer path|session|time|turns|speed|branch|cache [on|off]
show/hide one item (omit on|off to toggle)
/footer status show the current settings
/footer locale auto|zh|en set the UI language
/footer theme [classic|vivid]
switch theme (omit to toggle)
off and on persist across sessions. Turning off clears transient stream/rate/compaction state, skips tracking and work markers, and hides the legend. Turning on does not reconstruct chunks missed while disabled; changing theme or display settings while enabled keeps the active request.
The legend is session UI, independent of enabled: an explicit /footer off or /footer hide and session end clear it, while a settings file that turns the footer off externally does not.
MCP / LSP status
This footer reads public extension statuses and MCP tool inventories, not private connection state. Known LSP failures come first, then explicitly failed or partially connected MCP servers, then normal/unknown statuses in stable key order. Unknown text keeps its original colors. Zero MCP connections can mean idle lazy connections, not failure.
Status examples: explicit MCP attention states color the ratio and ✗N red; LSP failures are also red.
| State | classic | vivid |
|---|---|---|
| MCP needs attention | ⇄ MCP 1/2 ✗1 · tools 2 |
🔌 MCP 1/2 ✗1 · tools 2 |
| Tool inventory only | ⇄ MCP tools 2 |
🔌 MCP tools 2 |
| Active LSP | ⇄ MCP tools 2 · LSP typescript |
🔌 MCP tools 2 · 🛠️ LSP typescript |
| Failed LSP (shown first) | LSP ✗ typescript · ⇄ MCP tools 2 |
🛠️ LSP ✗ typescript · 🔌 MCP tools 2 |
- LSP: the footer displays published active or failed statuses in full (
LSP Active: …/LSP Failed: …) or compact (LSP ✓/LSP ✗) form. Failures take priority;LSP Inactiveor an unpublished status is hidden. Absence alone does not establish server health. If a published active/failed status is missing, widen the terminal to rule out clipping. - MCP health: a published connected/enabled status takes priority. The native status contract
MCP native C/E failed Frenders asMCP C/E, with a red✗Fwhen servers explicitly need attention (failed, disconnected, or awaiting authentication). Full connections use classic text / vivid success color; partial connections warn; zero without an explicit failure stays muted. Native health can include· tools Nfor discoveredmcp__tools. Compact ratio statuses are also supported; recognizedMCP 0/0is hidden and suppresses inventory fallback. A bareN/M connectedis read as a ratio only when its status key names MCP, so a connection pool under another key stays an ordinary status. Pi has never published a connected/enabled status, so built-in MCP shows only the tool count; the ratio appears when an extension publishes a supported status. - MCP inventory: without a recognized health status,
MCP tools Nshows publicgetAllTools()entries whose names start withmcp__. MCP tools join that list as their servers connect, so the count grows over the first seconds of a session. Labels stay muted; numbers use the theme's ordinary readout color. Inventories are not connection health counts. While this footer is active, public in-memory inventories are checked once per second; a tick that finds a different status than the last one any path read requests a redraw, and disposing the footer stops the check. No servers or network are polled; missing/unavailable APIs do not fabricate a zero.
Native health requires the host to publish a supported status; server configuration and tool discovery alone do not establish health. This package only reads status; it does not patch the host or create connections. Inventory can update without a health publisher when the extension is loaded and the host provides compatible public inventory APIs; this is not a guarantee for every future host version. A config-only server may have no indicator before discovery. Use the host’s /mcp command for server details and widen the terminal to rule out clipping.
Development checks
npm run check runs tests and strict type checking. npm run bench:footer includes the host’s shallow getEntries() copy; npm run bench:estimate measures controlled streams. These local microbenchmarks are not end-to-end Desktop performance measurements. npm run pack:check checks package contents.
npm run bench:reality -- <session-directory> performs read-only recorded-entry replay and formula/render consistency checks. Without a directory it scans nothing. Estimate/output statistics are descriptive, not independent tokenizer accuracy or ground truth.