@signalridge/pi-statusline1.5.0
Signalridge's polished, theme-native statusline for Pi.
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-statusline — quiet text footer for Pi
@signalridge/pi-statusline is a theme-native footer for the Pi coding agent. Its default Signalridge profile is a restrained, text-first two-line hierarchy: model and thinking state, workspace and branch metadata, active work, and context usage. Context is placed at the right edge when the terminal is wide enough.
Typical output is similar to:
gpt-5.6-sol · think max · main ctx 42%
There are no persistent branch icons, emoji, powerline blocks, hard-coded backgrounds, or ornamental per-segment symbols in the default profile. A single dim · separator is used between text fields. Normal metadata is muted; accent and warning/error colors are reserved for current or abnormal state.
Install
pi install npm:@signalridge/pi-statusline
Use from this checkout
From the repository root:
pi -e ./packages/pi-statusline
The package is publishable and stable.
Profiles and settings
The canonical settings file is:
${PI_CODING_AGENT_DIR:-~/.pi/agent}/pi-statusline.json
When it exists, the canonical file always wins. Older installations using pi-statusline-settings.json remain readable and are never rewritten or deleted. If only the legacy file exists, statusline reads it and writes future changes to the canonical filename.
With neither file present, PI_STATUSLINE_PRESET=classic selects the Signalridge default (as does an unset or unknown value):
PI_STATUSLINE_PRESET=classic pi
PI_STATUSLINE_PRESET=tokyo-night remains an explicit opt-in to the richer powerline renderer. Existing canonical or legacy JSON settings always take precedence over the environment. The settings editor and /statusline menu can choose the optional named palettes, information profiles, custom layout, and foreground/background palette values.
Settings writes validate recognized fields, preserve unknown fields, publish through a same-directory temporary file and atomic rename, and fail closed on malformed input or publication errors. Existing files are not replaced when a save fails.
Useful commands:
/statusline open the interactive menu in TUI mode
/statusline inspect inspect current extension statuses (also Ctrl+Alt+S)
/statusline settings edit and apply the canonical JSON document
/statusline status show the effective source and diagnostics
/statusline help show configuration help
Inspect extension statuses
Use Inspect extension statuses in /statusline, /statusline inspect, or Ctrl+Alt+S to open a compact, read-only list of the current extension statuses. Arrows and Pi's configured selection bindings navigate; Enter opens the selected owner's detail view when that extension cooperates. Other statuses show bounded, sanitized, wrapped plain text inside the inspector. Esc closes without changing the editor draft. Inspection does not change status visibility or settings, execute slash commands, or send model messages. /statusline status remains the settings report.
The shortcut opens only when the host's public focus capabilities identify an editor without autocomplete and no overlay is active. Hosts without these capabilities fail closed; use the slash command instead. The footer itself is unchanged. Lists and pending requests retire with their footer/session owner; removed rows lose selection rather than activating a neighbor.
Optional owner-detail protocol (v1)
Statusline is a consumer, not a command dispatcher. Providers implement these pi.events channels locally; no cross-package source imports are needed. The exported wire types and consumer helpers live in src/status-actions.ts.
- Query channel:
pi-ui:status-actions:v1:query, request{version:1,requestId,sessionId}. - Reply channel:
${channel}:reply:${requestId}, reply{success:true,data:{version:1,providerId,surfaceId,sessionId,entries:[{statusKey,actionId,label}]}}. - Open channel:
pi-ui:status-actions:v1:open, request{version:1,requestId,providerId,surfaceId,sessionId,actionId}. - Open reply:
{success:true,data:{accepted:true}}on its request's reply channel means admission, not completion. Providers reply on admission, then asynchronously open their owner-local view.
Providers answer queries synchronously only for their active TUI session/branch, and handle opens only for their matching, unique owned surface; mismatches are ignored. Identifiers are nonempty strings of at most 128 characters; labels/status keys are at most 512. Snapshots use exact own data fields (no extra, inherited, or accessor fields), with unique status keys/action IDs. Discovery collects for 50 ms, at most 32 providers/64 entries in total. Exact repeated snapshots deduplicate; conflicting snapshots/surfaces suppress that provider, and multiply claimed status keys have no action. Aggregate overflow fails closed. Only exact current status keys match.
Before opening, statusline fully disposes the selector, re-queries to validate the selected action identity, and rechecks session generation, live branch prefix, context and status key. Open admission times out after two seconds. Both requests support cancellation and clean up timers/listeners. Provider data grants no command-execution or session-control authority.
Default information hierarchy
The balanced Signalridge profile shows, in order:
- current model;
- active thinking level, only when it is not
off; - compact cwd/repository location;
- branch and semantic Git state;
- active tool or streaming activity, only while active;
- context percentage, right-aligned where possible.
Narrow terminals progressively drop lower-priority fields and truncate long model names without emitting partial ANSI sequences. Extension statuses appear on a separate wrapped line. They are text-only by default; explicit extensionStatusIcons entries can add a badge for a selected active state, and an empty string suppresses one.
Model ids, provider ids, active tool names, directory names, and Git branch names are sanitized before display. Escape sequences are removed with their DCS/OSC/PM/APC/SOS payloads, and control characters and bidirectional overrides are dropped rather than replaced, so spoofed text can neither reverse the footer nor shift its layout. An introducer with no terminator drops only itself: consuming the rest of the string would let one byte in a branch name erase the tail of the footer. The branch is sanitized before the optional GitHub PR context is composed in, so the PR hyperlink stays clickable.
Lifecycle behavior
The footer is installed only for TUI sessions. Git status is collected asynchronously and cached outside rendering, with stale cwd/branch results discarded. Usage totals are maintained by a runtime-owned incremental snapshot: rendering does not rescan session history; session replacement, branch/compaction boundaries rebuild it and message/turn events update it. Standalone usage entries (including cache warming) count toward historical tokens, cache, and cost. When tokens, cache, or cost is configured, the footer checks the session leaf every five seconds (including while idle), copying history only after the leaf changes and inspecting only entries appended since its last check. Presets without those segments skip the usage check. Context percentage still comes from ctx.getContextUsage(). Footer timers, branch listeners, pending Git work, command menus, and session ownership are cleaned up on footer disposal, session replacement, compaction, and shutdown. Context usage refreshes after session_compact.
Retained footer callbacks also check the live mode and UI eligibility before work: a headless rebind retires both clocks, branch subscriptions, and pending Git requests even while an earlier session handler is awaited. This resource-only cleanup neither clears a replacement footer nor renders or emits status/settings notifications through the retained UI.
The JSON editor honors Pi's configured external editor. Session replacement or reload retires the dialog without killing that program or restoring its obsolete draft; when the program exits, the surviving terminal may resume. Quit suppression requires statusline to remain loaded in the replacement session. If a reload removes the extension, no replacement instance can observe later quit, so the pending editor retains the host's native restart behavior.
Package layout
packages/pi-statusline/
├── src/
│ ├── statusline.ts # thin Pi lifecycle entrypoint
│ ├── commands.ts # settings and menu workflows
│ ├── status-inspector.ts # owned, read-only status navigation
│ ├── status-actions.ts # bounded owner-detail protocol consumer
│ ├── render.ts # data-to-segment projection
│ ├── powerline.ts # restrained text and optional powerline renderers
│ ├── settings.ts # canonical/legacy loading and atomic saves
│ ├── git-status.ts # argv-based asynchronous Git status
│ ├── extension-status.ts # text-only extension status projection
│ └── presets/ # optional palette ramps
├── test/
├── README.md
├── LICENSE
└── package.json
Local divergence
Signalridge maintains the modular port, canonical/legacy settings behavior, session-safe refresh cleanup, and the restrained text-first default appearance described above.
License
MIT. See LICENSE.