@powerfool/pi-timing
Per-step, per-turn, and per-run timing extension for the pi coding agent
Package details
Install @powerfool/pi-timing from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@powerfool/pi-timing- Package
@powerfool/pi-timing- Version
0.2.2- Published
- Aug 31, 2026
- Downloads
- 656/mo · 31/wk
- Author
- powerfool
- License
- MIT
- Types
- extension
- Size
- 63.5 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-timing
Timing extension for the pi coding agent: per-tool-step, per-turn, and per-run timing rendered directly in the transcript, plus a live elapsed clock in the Working status line and a navigable runs list.
Features
- Step timing in message bodies: built-in tool calls (read, edit, write,
grep, find, ls) show
⏱ started MM-DD HH:MM:SS · Nslive while running and⏱ started … · took Nswhen done. Bash is not wrapped — pi's own bash timing line stays as the single source of truth. - Per-tool recording: every tool execution is persisted as a
step-timingsession entry, which powers the stats view. Wrapped built-in tools (their timing renders in-box) and ignored tools render these entries as hidden data-only rows; extension tools (subagent, MCP, etc.) show a visible timing line. Ignore only controls transcript noise — stats always aggregates everything recorded. - Turn timing:
⏱ Turn N · HH:MM:SS · took Nsentries after each turn. - Run timing:
⏱ Run · HH:MM:SS · took Ns (llm Ns · tools Ns) · N turns · N tok · $Nonagent_settled(covers auto-retries and compaction). The llm/tools split is the union of all tool execution intervals within the run; tokens and cost come from pi's own per-message usage accounting. - Slow-run highlighting: run durations are colored by configurable
thresholds — below
fastdim, belowslownormal, at/aboveslowas a warning (defaults 5s / 30s). Applies to the run summary entry and the runs list. - Working status line:
Working... MM-DD HH:MM:SS · Nsticks once per second. Start clocks always carry a date —MM-DDwithin the same year,YYYY-MM-DDacross years. /timing:runs: flat single-line list of the current branch's runs — start clock, colored total duration, turn count, tokens, cost, and prompt summary per row (run-level only; per-tool and per-turn rows are omitted). The start clock isMM-DD HH:MM:SS(YYYY-MM-DD HH:MM:SSacross years), as are the run summary entry and the per-turn/per-tool timing lines in the transcript. Steering messages get their own rows, in-progress runs showrunning…. ↑↓ moves a cursor (full-width highlight). Ctrl+T cycles the detail level: off → detail → tools → off — detail adds the llm/tools time split, token usage detail (input / cache read / cache write / output), and the run's user/assistant conversation excerpt; tools interleaves tool calls (args, duration, error, result excerpt) into the timeline. Enter dives into the selected run: uncapped content with long messages wrapped to the terminal width — ↑↓ scrolls while reading, Enter/Esc collapses. ←/→ pages,g/Gtop/bottom, Esc to close. The detail level is remembered across opens and session switches for the lifetime of the process (not written to timing.json)./timing:stats: aggregated view — run count, total/avg/max duration and llm/tools split for the current branch, token and cost totals, plus per-tool count/total/avg/max/errors. Everything is sourced from the branch's persisted timing entries, so the view survives/reload.
Everything is display-only: the LLM context is never modified.
Usage
/timing show current settings
/timing steps on|off toggle in-box step timing (default on)
/timing turns on|off toggle turn entries (default on)
/timing run on|off toggle run summary entry (default on)
/timing status on|off toggle the Working status clock (default on)
/timing ignore add <tool> never show a timing entry for this tool
/timing ignore del <tool> remove from ignore list
/timing thresholds 5 30 set fast/slow duration coloring thresholds (seconds)
/timing:runs open the timing runs list (aliases: /timing runs, /timing tree)
/timing:stats open the aggregated stats view (alias: /timing stats)
Settings persist in ~/.pi/agent/timing.json. Default ignore list:
start_bg_task, bg_task_status, stop_bg_task, bash (pi's bash renderer
already shows its own timing).
Development
Requires Bun and a global pi install.
bun run link-deps # symlink the global pi packages into node_modules (once)
bun test # unit tests (bun:test)
bun run typecheck # strict tsc
link-deps points node_modules/@earendil-works/* at the globally installed
pi, so tests always run against the actual runtime version.
Install
pi install npm:@powerfool/pi-timing
Local development
bun run install-extension
This symlinks the repo as ~/.pi/agent/extensions/timing; pi discovers
<dir>/index.ts automatically. Use /reload inside pi after changes.
Notes
- Coexistence: if another extension has already replaced a built-in tool
(e.g. a bg-tasks extension overriding
bash), pi-timing yields instead of failing to load — pi rejects duplicate extension tool names. The yielded tool falls back to persistent timing entries (final duration only, no live ticking) and a notice is shown once per session. - Session entry custom types (
step-timing,step-timing-turn,step-timing-run) are persisted in.jsonlsession files — do not rename. - Bash is deliberately not wrapped: pi's bash renderer draws its own
Elapsed/Took line, and re-registering
bashwould collide with extensions that replace it (e.g. bg-tasks). Bash is in the default ignore list, so no duplicate fallback timing entries appear. No pi internals are touched.