@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.

Packages

Package details

extension

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.
  • idle is hidden until it's at least 5 s.
  • tools shows 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 /reload wipes 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 setStatus API, 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