@gondor/pi-pace
Footer stats for local-model pi sessions: tps, tpm, ttft, tool-time share, and idle — because with local inference, time is the cost.
Package details
Install @gondor/pi-pace from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@gondor/pi-pace- Package
@gondor/pi-pace- Version
1.0.1- Published
- Aug 14, 2026
- Downloads
- 144/mo · 25/wk
- Author
- gondorsolutions
- License
- MIT
- Types
- extension
- Size
- 14.2 KB
- Dependencies
- 0 dependencies · 1 peer
Pi manifest JSON
{
"extensions": [
"./extensions"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-pace
Footer stats for local-model pi sessions — how fast is your model actually working.
With local inference the usual cost metrics are all zero; time is the cost. pi-pace turns that into a compact readout in pi's footer:
idle 13s · tools 23% · ttft 1.2s · ↓2.2k tpm · ↓49.0 tps
Stats
| Stat | Meaning |
|---|---|
↓N tps |
Generation speed — live while streaming, then finalized per reply over its full duration and EWMA-smoothed (α=0.6) so short replies don't spike it |
↓N tpm |
Session output tokens per minute of active time (generation + tools; your thinking/typing time excluded) |
ttft |
Time to first token, last reply |
tools |
Share of active time spent in tool execution; absolute time when < 1%, hidden when < 100 ms |
idle |
Total idle wall time since the session started |
How they're computed
- Active time = generation time + tool execution time. Tool intervals are merged, so parallel tools are not double-counted. Everything else — your reading, typing, the gaps between replies — counts as idle.
- tpm = total session output tokens ÷ active minutes. Because pauses don't count, it's a stable session-level throughput number, not an average that your thinking time deflates.
- tps = per-reply rate (output tokens ÷ full reply duration), blended with the previous value (EWMA, α=0.6). Replies under 50 ms are ignored (the rate would spike).
- ttft = reply start → first streamed token. With local models this reflects prompt processing, so a long ttft is your signal that the prompt/context (or a cold model) is costing you time.
- idle = wall time − active time, since the session's first activity.
Display rules
- Rates (
tpm,tools) are hidden until there's at least 1 s of active time — sub-second numbers are noise. idleis hidden until it's at least 5 s.toolsshows a rounded percentage at ≥ 1%, an absolute duration below that (e.g.tools 830ms), and hides entirely under 100 ms (a "tools 0%" would read as broken).- Values stay static between events (never cleared at
agent_end) and reset only on in-process session transitions (e.g./new,/reload) — so/reloadwipes the session stats, by design.
Install
pi install npm:@gondor/pi-pace # from npm
pi install git:github.com/gondorsolutions/pi-pace@v1.0.0 # from git (pinned ref)
pi install /path/to/pi-pace # local path
Or try it without installing:
pi -e npm:@gondor/pi-pace
Manage it like any pi package:
pi list # show installed packages
pi update --extensions # update pi packages
pi remove npm:@gondor/pi-pace
Notes
- Additive — uses the
setStatusAPI, so pi's built-in footer line is preserved; pi-pace adds its stats to the dim status line. - Theme-aware — values bright, labels muted,
·separators dim; follows your active theme. - Purely local — no network calls, no telemetry, no runtime dependencies. All metrics come from pi's session events.
- Requirements — pi (peer dependency) and Node ≥ 22.18. The extension is a single TypeScript file, type-stripped natively — no build step.
Development
The whole extension is extensions/pi-pace.ts. It listens to message_start / message_update / message_end, tool_execution_start / tool_execution_end, and session_start, and renders via ctx.ui.setStatus. Footer status keys render alphabetically, so y-tpm and z-tps are named to keep the two rate stats together on the right.
Smoke-test without pi:
node --input-type=module -e "import('/path/to/extensions/pi-pace.ts').then(m => m.default({on: () => {}})).then(() => console.log('ok'))"
For a path-installed copy, /reload in pi picks up edits (and resets the session stats — see Display rules).
Publishing
Releases are published from GitHub CI via npm trusted publishing (OIDC — no long-lived tokens): a vX.Y.Z tag matching package.json triggers the publish, and every release carries a provenance attestation.
License
MIT — Copyright (c) 2026 Gondor Solutions SL