Observed since 21 Oct, 08:58 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
quality of life pi extensions
Quality-of-life extensions for pi.
A small collection of opt-in extensions that smooth out everyday pi usage. Today
it ships auto_session_name — automatic, opencode-style session titling,
model_select — an interactive model picker, and custom_footer — a
compact configurable interactive footer.
Install the package from npm:
pi install npm:@0xkahi/pi-qol
Then register it in your pi configuration so pi loads ./src/index.ts as an
extension (see the pi.extensions field in package.json).
auto_session_nameAutomatically generates a short, human-readable title for a brand-new session from its first user prompt or whitelisted custom message, using a cheap model call that runs in the background and never blocks your turn (Pi >=1.2).
custom_message_whitelist; only messages sent with triggerTurn: true can
trigger naming. The default empty list allows only user prompts.<think> blocks, unwraps quotes, and truncates titles
to 100 characters.model_selectAdds /select-model, an interactive model picker with fuzzy search, permanent
Favourites, ordered custom group tabs, provider filtering, and inline or overlay layouts.
Ctrl+L switches to the next section and
Ctrl+H to the previous (both wrap). Ctrl+H needs a terminal that reports it
distinctly (Kitty, CSI-u, or modifyOtherKeys); otherwise it acts as Backspace.
Ctrl+L works everywhere. Tab/Shift+Tab stay within the active section.[Claude] [Codex] [OC-GO] tabs show every subscription rate window,
separated by blank lines, with a progress bar, used percentage, reset time,
pace, and data freshness. Fixed provider colors match the custom footer. Missing
credentials and request failures are shown explicitly. Usage shares the footer
cache and fetches only when visited; press r to refresh the active provider.
Navigate rows with j/k, arrows, gg/G; q or Esc closes without changing
the model. In Select Model, q still types in the filter.allow keybindings with pi-vim-keys with eventId of pi.vimKeys.event:pi-qol.model_select
custom_footerReplaces pi's built-in interactive footer with the same three-line layout, but
shows the current directory as an icon plus basename, supports hex color overrides,
can hide token/cache clusters, and adds a subscription-usage progress bar
for supported providers (Anthropic, OpenAI Codex, and OpenCode Go via model provider
opencode-go, not OpenCode Zen opencode). Usage colors are fixed: Claude
#D97706, Codex #10B981, and OC-GO #00ADD8; former usage-color overrides are ignored.
OpenCode Go shows 5h, Week, and Month windows and requires an opencode-go
entry of type api_key in ~/.pi/agent/auth.json, with the secret in key;
OPENCODE_API_KEY alone is not used. Claude and Codex require OAuth entries.
(sub) when on a subscription), context-window usage, and the
right-aligned model name (with provider prefix when multiple providers are
available).Known difference from pi's built-in footer: the (auto) compaction suffix is
omitted because extensions do not expose reliable live state for it.
pi-qol reads a JSON config file named config.json from two locations and merges
them (project overrides global):
| Scope | Path |
|---|---|
| Global | <agent-dir>/extensions/pi-qol/config.json |
| Project | <cwd>/.pi/extensions/pi-qol/config.json (trusted projects only) |
Project config is only loaded when the project is trusted.
{
"$schema": "https://raw.githubusercontent.com/0xKahi/pi-qol/main/assets/config.schema.json",
"auto_session_name": {
"enabled": true,
"custom_message_whitelist": [],
"model": {
"provider": "opencode",
"modelId": "gpt-5-nano",
"reasoning": "low"
}
},
"model_select": {
"enabled": true,
"layout": "overlay",
"favourite_label": "Pinned",
"provider_filter": ["anthropic", "openai"],
"groups": ["work", "fast"],
"favourite": [
{
"provider": "anthropic",
"modelId": "claude-sonnet-4-5",
"groups": ["work", "fast"]
}
],
"hide_tabs": { "groups": false, "search": false }
},
"context_view": {
"enabled": true,
"layout": "inline"
},
"custom_footer": {
"enabled": true,
"colors": {
"directory": "#A78BFA",
"modelName": "#60A5FA",
"agentName": "#FBBF24"
},
"display": {
"tokens": true,
"cache": true,
"agentName": true
},
"defaultAgentName": "DEFAULT"
}
}
auto_session_name| Key | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Turn the auto session naming feature on. |
custom_message_whitelist | string[] | [] | Allowed customType values for pi.sendMessage(..., { triggerTurn: true }) runs. Empty means only user prompts. |
model | object | — | Optional model used to generate titles. Falls back to the session model if omitted. |
model| Key | Type | Description |
|---|---|---|
provider | string | Model provider id (e.g. anthropic, openai). |
modelId | string | Model identifier as registered in pi's model registry. |
reasoning | enum | One of off, minimal, low, medium, high, xhigh. |
When model is set but cannot be found or authenticated, pi-qol automatically
falls back to the active session model and surfaces a warning notification.
model_select| Key | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Turn the model picker on. |
layout | enum | inline | Picker layout: inline or overlay. |
favourite_label | string | Favourites | Non-empty label for the permanent first tab. |
provider_filter | string[] | [] | Restrict Search models to these providers; favourite tabs are unaffected. |
groups | string[] | [] | Ordered custom group tabs. Exact duplicate names use their first occurrence. |
favourite | object[] | [] | Favourite models (provider, modelId, optional groups). |
favourite[].groups | string[] | [] | Exact, case-sensitive group memberships for a favourite. Unknown names are ignored. |
hide_tabs.groups | boolean | false | Hide all custom group tabs. |
hide_tabs.search | boolean | false | Hide the Search tab. Favourites cannot be hidden. |
The favourites tab is always first, even when empty, and uses favourite_label
as its display label. Unique groups follow in configured order, and Search is
last when visible. Use Tab to cycle forward and Shift+Tab to cycle backward
through visible tabs. A favourite can belong to multiple groups; group tabs
contain only resolved, authenticated favourites and preserve favourite order.
Duplicate favourite declarations remain first-entry-wins.
context_view| Key | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Enable the Context View capture and interface. |
layout | enum | inline | Context View presentation: inline or centered overlay. |
Context View is a fork of Dmitry Makarov's pi-context-view, adapted into one unified tabbed interface with Vim-friendly keybindings. Enable it, then run /context-view with no arguments. The Usage tab opens first; Tab and Shift+Tab switch between Usage and Injections. Use j/k or arrows to move, Ctrl+u/Ctrl+d to move by a page, gg/G to jump to the beginning/end, Enter to preview, and Esc or q to return or close. By default it opens inline; set context_view.layout to overlay for a centered overlay. Other extensions can open the same view by emitting pi.vimKeys.event:pi-qol.context_view.
custom_footer| Key | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Replace pi's built-in interactive footer. |
display.tokens | boolean | true | Show cumulative input/output token counts. |
display.cache | boolean | true | Show the custom cache read/write/hit cluster. |
display.agentName | boolean | false | Prefix the first line with a padded bold inverse agent badge. |
defaultAgentName | string | DEFAULT | Agent name restored at the start of each session. |
colors.directory | hex | — | Color the directory icon and basename. |
colors.modelName | hex | — | Color the right-aligned model name. |
colors.agentName | hex | — | Agent badge foreground color before inversion. |
icons.directory | string | nerd font | Glyph shown before the directory basename. |
icons.cache | string | nerd font | Glyph for the cache cluster. |
icons.cacheRead | string | nerd font | Glyph for cache-read tokens. |
icons.cacheWrite | string | nerd font | Glyph for cache-write tokens. |
icons.refresh | string | nerd font | Glyph shown before the subscription reset time. |
When enabled, the badge has no brackets, uses bold and inverse styling, and adds
one styled padding space on each side of the name. One normal, unstyled space
separates the trailing badge padding from the directory. Names are trimmed and
sanitized. Names wider than ten terminal columns are rendered as their first ten
visible columns plus ...; badge padding does not count toward that limit, and
wide Unicode characters are never split. Badge color precedence is a valid event
color,
colors.agentName, then pi's accent theme color. Event-selected names and
colors are session-scoped: every session_start restores defaultAgentName and
clears the event color.
Other extensions can update the current identity through pi's event bus:
pi.events.emit('pi.qol.event:set-agent-name', {
agentName: 'Reviewer',
color: '#FFFFFF', // optional; must be #RRGGBB
});
Invalid or empty names are ignored. A missing or invalid event color clears any previous event color and uses the normal fallback precedence.
Project config shallow-merges each top-level section over global config. Arrays
replace lower-precedence arrays, so project model_select.favourite or
model_select.groups replaces the corresponding global array. Nested objects are
also replaced as values during that section merge; for example, a project
hide_tabs object replaces the global one, then omitted groups or search
fields receive their default of false.
On before_agent_start, the auto_session_name extension checks a series of
guards before doing any work. It only proceeds when all of the following hold:
customType is in custom_message_whitelist and whose text is non-empty
(image blocks are ignored).Pi >=1.2 emits this event for both user and custom runs, before appending the starting message to the branch. Non-whitelisted custom runs are skipped before session guards and their messages do not block later naming.
If those pass, it resolves a model, generates a title via a dedicated
title-generation prompt, cleans the result, and persists it with
pi.setSessionName(). The work runs in a cancellable background task that is
aborted on session shutdown.
This project uses Bun and Biome.
bun install # install dependencies
bun run check # biome fix + type-check
bun test # run tests
bun run buildSchema # regenerate assets/config.schema.json from the zod schemas
src/
index.ts # extension entry — lifecycle wiring only
config-loader.ts # loads + merges global/project config
constants.ts # EXTENSION_ID
schemas/ # zod config schemas (full + partial)
utils/ # path + model-resolution helpers
extensions/
auto-session-name/ # the auto_session_name feature
model-select/ # the model_select feature
custom-footer/ # the custom_footer feature
scripts/ # JSON schema generation
assets/config.schema.json # generated config schema
See repository for license details.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 1.4.0Registry latest | 17 Oct 2026 | 11 | |
| 1.3.0 | 15 Oct 2026 | 11 | |
| 1.2.0 | 1 Oct 2026 | 11 | |
| 1.1.3 | 24 Sept 2026 | 11 | |
| 1.1.2 | 24 Sept 2026 | 11 | |
| 1.1.1 | 21 Sept 2026 | 11 | |
| 1.1.0 | 20 Sept 2026 | 11 | |
| 1.0.6 | 5 Sept 2026 | 12 | |
| 1.0.5 | 29 Aug 2026 | 11 | |
| 1.0.4 | 12 Aug 2026 | 11 | |
| 1.0.3 | 8 Aug 2026 | 11 | |
| 1.0.2 | 4 Aug 2026 | 11 | |
| 1.0.1 | 4 Aug 2026 | 11 | |
| 1.0.0 | 1 Aug 2026 | 11 | |
| 0.1.1 | 29 Jul 2026 | 11 | |
| 0.1.0 | 17 Jul 2026 | 11 | |
| 0.0.6 | 14 Jul 2026 | 11 | |
| 0.0.5 | 7 Jul 2026 | 10 | |
| 0.0.4 | 19 Jun 2026 | 10 | |
| 0.0.3 | 17 Jun 2026 | 10 |
This describes our collected data; it is not a security assessment.
Observed since 21 Oct, 08:58 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:cc9efee52f3e5a6ba84eabe9930f48e16738bb0c414546556d6d17ea895431cd