Add artifact vault contents
This commit is contained in:
232
projects/dotfiles/063-pi-ui-customization-spec-task.md
Normal file
232
projects/dotfiles/063-pi-ui-customization-spec-task.md
Normal file
@@ -0,0 +1,232 @@
|
||||
---
|
||||
status: resolved
|
||||
parent: "[[057-pi-ui-customization-map]]"
|
||||
blocked-by:
|
||||
- "[[062-pi-ui-quota-status-prototype]]"
|
||||
- "[[067-pi-ui-flex-spacer-bottom-anchor-prototype]]"
|
||||
resolved-at: "2026-08-01T08:20:00-04:00"
|
||||
tags:
|
||||
- ticket/task/afk
|
||||
---
|
||||
|
||||
# Specify permanent Pi UI customization
|
||||
|
||||
## Question
|
||||
|
||||
Turn the resolved research and prototype verdicts into an implementation-ready specification for the permanent dotfiles-managed Pi UI customization, including what to build, what to leave out, and how to verify it after reload.
|
||||
|
||||
## Decision
|
||||
|
||||
Build the permanent customization as two pieces:
|
||||
|
||||
1. A dotfiles-managed Pi extension that owns the compact status surface.
|
||||
2. A small local Pi layout patch that inserts flexible space above the prompt area when the TUI stack is shorter than the terminal.
|
||||
|
||||
Do not try to solve bottom anchoring with an extension spacer widget.
|
||||
The prototype showed the correct behavior comes from the layout layer, not from guessing terminal height in a widget.
|
||||
|
||||
Do not use `terminal.clearOnShrink` as the primary fix.
|
||||
The flex-spacer layout makes the prompt area continue to occupy the terminal bottom after transient autocomplete rows disappear.
|
||||
`terminal.clearOnShrink` can remain a separate rendering knob for unrelated stale-row cases.
|
||||
|
||||
## Compact status extension specification
|
||||
|
||||
The extension should be installed through the dotfiles Pi module under the managed Pi extension directory.
|
||||
The throwaway file at `~/.pi/agent/extensions/compact-status-prototype.ts` is not the deployment target.
|
||||
|
||||
The extension should use in-code defaults only.
|
||||
It should not write a default config file.
|
||||
|
||||
The extension should hide the built-in footer by default with an empty custom footer renderer.
|
||||
It should place the compact status widget above the editor.
|
||||
|
||||
The status widget has three rows:
|
||||
|
||||
```text
|
||||
~/dotfiles main gpt-5.5 • medium
|
||||
▃▃▃▃▃▃▃▃▃▃▃▃───────────────────────────────────────────────────────────────
|
||||
▔▔▔────────────────────────────────────────────────────────────────────────
|
||||
```
|
||||
|
||||
Row 1 shows location and runtime state.
|
||||
The left side is a visual cwd and branch indicator using ` <short-cwd> <branch>`.
|
||||
The right side is `<model> • <thinking>`.
|
||||
Use the session cwd when available, not `process.cwd()` as the primary source.
|
||||
Use the current git branch when available.
|
||||
If no branch exists, omit the branch segment.
|
||||
|
||||
Row 2 is the context-window usage bar.
|
||||
It is unlabeled.
|
||||
It uses full width.
|
||||
It uses the lower three-eighths block glyph `▃`.
|
||||
It fills by `ctx.getContextUsage().percent`.
|
||||
It uses the theme success color under 70%, warning at 70%, and error at 90%.
|
||||
The unfilled track uses the dim color.
|
||||
If context usage is unknown, render a muted full-width track rather than inventing a percentage.
|
||||
Do not show numeric context usage in the default status surface.
|
||||
Do not attempt exact current-context category breakdown in the permanent default, because Pi does not expose that exact public data.
|
||||
|
||||
Row 3 is the ChatGPT Codex weekly quota consumed bar.
|
||||
It is unlabeled.
|
||||
It uses full width.
|
||||
It uses the upper one-eighth block glyph `▔`.
|
||||
It fills by consumed weekly quota, meaning `100 - weeklyRemaining`.
|
||||
It starts empty when quota is unused.
|
||||
It uses the theme border blue below 50% consumed so it contrasts with the green context bar.
|
||||
It uses warning at 50% and error at 80%.
|
||||
The unfilled track uses the dim color.
|
||||
If quota is unknown, render a muted full-width track rather than inventing a percentage.
|
||||
|
||||
The extension should provide `/codex-quota`.
|
||||
The command forces a quota refresh and shows a notification with normalized non-secret details.
|
||||
The notification may include weekly remaining and any short-window value returned by the endpoint.
|
||||
The default status surface should still show only the bars.
|
||||
|
||||
The extension may provide a development toggle command only if useful during implementation.
|
||||
The finished default behavior should not require cycling modes.
|
||||
|
||||
## Quota data specification
|
||||
|
||||
The quota source is Pi's local OpenAI Codex OAuth credential at `~/.pi/agent/auth.json`, provider key `openai-codex`.
|
||||
The extension must read only the fields it needs.
|
||||
It must not log, display, or persist the access token, refresh token, account id, or raw response body.
|
||||
It must not send OpenAI API keys to ChatGPT subscription quota endpoints.
|
||||
|
||||
The primary endpoints are:
|
||||
|
||||
```text
|
||||
https://chatgpt.com/backend-api/wham/usage
|
||||
https://chatgpt.com/backend-api/codex/usage
|
||||
```
|
||||
|
||||
Requests use `Authorization: Bearer <access-token>`.
|
||||
Requests include `ChatGPT-Account-Id` when the local OAuth credential has an account id.
|
||||
|
||||
Parsing must be defensive.
|
||||
Accept snake_case and camelCase window fields.
|
||||
Recognize the weekly window by approximately 604,800 seconds or by week-like names if duration is unavailable.
|
||||
Recognize a short window only for the `/codex-quota` notification or fallback state.
|
||||
The default status bar should prefer weekly quota.
|
||||
|
||||
Cache only normalized non-secret quota state in memory.
|
||||
A five-minute refresh interval is acceptable for the status widget.
|
||||
Manual `/codex-quota` refresh bypasses the freshness check.
|
||||
Network errors, missing credentials, expired credentials, and unrecognized responses should produce an unknown/error state without throwing extension-load errors.
|
||||
|
||||
Do not add an app-server fallback in the first permanent version unless direct endpoint parsing proves unreliable during implementation.
|
||||
The researched Codex app-server `account/rateLimits/read` path remains the preferred fallback if a fallback becomes necessary.
|
||||
|
||||
## Flex-spacer layout patch specification
|
||||
|
||||
Patch Pi's interactive TUI layout so normal content and prompt-area content are rendered as two groups.
|
||||
|
||||
Flow content:
|
||||
|
||||
- header container
|
||||
- loaded resources container
|
||||
- chat transcript container
|
||||
|
||||
Pinned prompt-area content:
|
||||
|
||||
- pending messages container
|
||||
- terminal log container, if present in the installed Pi version
|
||||
- status container
|
||||
- above-editor widget container
|
||||
- editor container
|
||||
- below-editor widget container
|
||||
- footer
|
||||
|
||||
During render, compute the rendered line count of both groups.
|
||||
If `flowLines.length + pinnedLines.length` is less than the terminal row count, insert blank spacer rows between the groups.
|
||||
If the combined line count is greater than or equal to the terminal row count, insert no spacer.
|
||||
|
||||
The patch should preserve the current visual behavior for long conversations.
|
||||
It should only move spare empty space from below the editor to above the prompt area in underfilled screens.
|
||||
|
||||
The patch should recompute on each render and terminal resize.
|
||||
It must not accumulate spacer rows as state.
|
||||
|
||||
The patch should keep autocomplete behavior otherwise unchanged.
|
||||
Autocomplete may still render below the editor in the first permanent version.
|
||||
Because the flex spacer fills the terminal, closing autocomplete should not leave the prompt visually floating above a blank bottom gap.
|
||||
|
||||
The patch should be implemented as a small local Pi package patch or upstreamable patch.
|
||||
It should not be a runtime extension hack.
|
||||
|
||||
## Tool lookup hardening
|
||||
|
||||
The flex-spacer prototype exposed a NixOS-specific Pi tool lookup issue.
|
||||
Pi can select `~/.pi/agent/bin/fd` before `PATH`, and that downloaded generic Linux binary can fail on NixOS with the stub-ld error.
|
||||
|
||||
The permanent Pi patch should also harden tool lookup if the local patch touches Pi internals.
|
||||
A local tool path should count as available only if running `<tool> --version` exits with status 0.
|
||||
If the local tool fails, Pi should continue to system `PATH`, where the Nix wrapper provides working `fd` and `rg`.
|
||||
|
||||
This hardening is not a UI feature, but it prevents `@` autocomplete from breaking under the patched Pi package.
|
||||
|
||||
## Dotfiles deployment specification
|
||||
|
||||
The finished extension must be promoted into the dotfiles Pi module's managed extension source tree.
|
||||
It must not remain only under `~/.pi/agent/extensions`.
|
||||
|
||||
The finished Pi patch must be delivered through the flake-managed Pi package path.
|
||||
The exact Nix module structure can be chosen during implementation, but the result should make the ordinary `pi` command use the patched layout after rebuild.
|
||||
|
||||
Do not manage `~/.pi/agent/auth.json`.
|
||||
Login credentials remain user state.
|
||||
|
||||
Do not add a generated config file for this feature.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Do not replace Pi's whole TUI.
|
||||
Do not maintain an unrelated long-lived Pi fork.
|
||||
Do not add opinionated quota policies or notifications beyond the manual `/codex-quota` command and passive status bar.
|
||||
Do not display quota numbers in the default compact status surface.
|
||||
Do not attempt to make exact token-category context breakdown claims from cumulative session usage.
|
||||
|
||||
## Verification
|
||||
|
||||
After implementation, run the repository's normal verification seam:
|
||||
|
||||
```bash
|
||||
nix flake check
|
||||
```
|
||||
|
||||
After switching to the new generation, launch normal Pi with:
|
||||
|
||||
```bash
|
||||
pi
|
||||
```
|
||||
|
||||
Verify after `/reload` that no extension load errors appear.
|
||||
|
||||
Verify the compact status visual shape:
|
||||
|
||||
- row 1 shows cwd/branch on the left and model/thinking on the right
|
||||
- row 2 is an unlabeled `▃` context bar
|
||||
- row 3 is an unlabeled `▔` Codex consumed weekly quota bar
|
||||
- the built-in footer is hidden by default
|
||||
|
||||
Verify `/codex-quota`:
|
||||
|
||||
- it forces a refresh
|
||||
- it shows a non-secret normalized notification
|
||||
- it does not print tokens, account ids, or raw JSON
|
||||
- it degrades to unknown/missing/error without crashing when credentials or network are unavailable
|
||||
|
||||
Verify flex-spacer behavior:
|
||||
|
||||
- a short conversation leaves spare rows above the status/editor area, not below the editor
|
||||
- a long conversation behaves like stock Pi and does not insert visible spacer rows inside the transcript
|
||||
- resizing the terminal recomputes the spacer
|
||||
- `/` autocomplete and `@` autocomplete still work
|
||||
- closing autocomplete leaves the editor visually bottom-aligned
|
||||
|
||||
## Follow-up implementation tickets
|
||||
|
||||
Implement this specification through:
|
||||
|
||||
- [[068-pi-ui-compact-status-extension-task]]
|
||||
- [[070-pi-ui-flex-spacer-pi-patch-task]]
|
||||
- [[071-pi-ui-final-deployment-verification-task]]
|
||||
Reference in New Issue
Block a user