From 72a3dbbe08d0f4b68733b2f570dbf0d6c20a51fd Mon Sep 17 00:00:00 2001 From: Frank Date: Sun, 18 Oct 2026 02:30:39 -0700 Subject: [PATCH] Docs: status line page truth-audited against bundle; four claims corrected Full-source re-verification of pi/statusline.md against dist/cli.js plus a live screenshot matrix. False and corrected: claude's top rule is NOT the context meter (meter is box/band only; rule elsewhere is a session-accent filler); 'Tern-only' composer-bar claim (real knob: composer.tokenRate); segmentOptions gated to preset custom (they merge under every preset - only the arrays are gated); mode segment yolo (states are Plan/Prewalk/Goal/ Vibe/Loop). Expanded: 7-preset defaults table, per-shape statusAttachment/ bottomBar model incl. plugin shape registry, contextLine per-value behavior, 27-segment catalog with triggers and options, segmentOptions schema, full statusLine.*/composer.* knob registry. Changelog entry added. Refs #5 --- omp-docs/log.md | 8 +- omp-docs/pi/statusline.md | 206 ++++++++++++++++++++++++++++---------- 2 files changed, 158 insertions(+), 56 deletions(-) diff --git a/omp-docs/log.md b/omp-docs/log.md index 9c348cf..d8846bd 100644 --- a/omp-docs/log.md +++ b/omp-docs/log.md @@ -11,11 +11,17 @@ timestamp: 2026-08-28 # Bundle Change Log +## 2026-10-18 — Status line docs truth audit (full-source re-verification) + +Exhaustive claim-by-claim re-audit of [OMP Status Line Customization](/pi/statusline.md) against the minified `dist/cli.js` bundle plus a live screenshot matrix (band × {off, percentage, embedded}, claude × off). Page carries an **Audit log** section; four first-pass claims were false and are corrected (see there): claude's rule is *not* the context meter (meter is `box`/`band` only; the "red rule" was the session-accent filler), the "Tern-only" composer-bar claim was bogus (the readout is `composer.tokenRate`, default off), `segmentOptions` are **not** gated to `preset: custom` (only the segment arrays are), and the `mode` segment's states are Plan/Prewalk/Goal/Vibe/Loop (no yolo). Page expanded with: the 7-preset defaults table, per-shape `statusAttachment`/`bottomBar` model (8 built-ins + plugin shape registry), `contextLine` per-value behavior, the 27-segment catalog with triggers/options, `segmentOptions` schema, and the full `statusLine.*`/`composer.*` knob registry. The bundle's own "(box composer only)" knob description for `contextLine` is upstream-wrong — band honors it. + +ServerAppConfigs-docs overlap census: flagged separately for the operator (morning report); no doc merged/changed on either side. + ## 2026-10-18 — Status line rebuilt on custom segments; frank-archon display name slimmed Interactive tune-up of the omp status bar (grilling session, live loop: config edit → watcher repaint → niri screenshot verify). New knowledge page: [OMP Status Line Customization](/pi/statusline.md). -* **Mechanics discovered:** `leftSegments`/`rightSegments` are inert unless `preset: custom` (fleet was on `nerd` with dead arrays); `composer.shape` routes them — `band` merges both arrays into one row above the editor (title rides the working row), `claude` splits them into top chip + bottom strip. The `claude` red rule **is** the context meter (length = usage); `contextLine` label variants render in `box`/`band` — `band` paints the labeled inline meter (`60% ——— × 200K`). Working row (`⠿ Working… + tok/s`) is hardcoded — model/thinking can never join it (Tern-only). Eight composer shapes registered in the bundle. +* **Mechanics discovered:** `leftSegments`/`rightSegments` are inert unless `preset: custom` (fleet was on `nerd` with dead arrays; `segmentOptions` *do* merge under named presets); `composer.shape` routes them — `band` merges both arrays into one row above the editor (title rides the working row), `claude` splits them into top chip + bottom strip. The context meter exists **only in `box`/`band`** — `contextLine`: `off` plain rule, `embedded` hoists the context segment into the labeled inline meter (`60% ——— × 200K`), `percentage`/`annotated` paint an unlabeled proportional rule meter (all four live-verified); every other shape's rule is a constant session-accent filler. Working row (session title + tok/s readout gated by `composer.tokenRate`, default off) is composer chrome — model/thinking can never join it. Eight composer shapes ship in the bundle; plugins can register more. * **Final bar (`band`, after a `claude` sojourn):** left = `session_name · vim · mode · hostname · path · git(no branch text) · pr`; right cluster in array order = `model · cost · time_spent` (`context_pct` hoists out of the run to paint the labeled inline meter `60% ——— × 200K` as a flexible spacer between the groups). Cut: tok/s duplicate, clock, cache trio, `context_total`, `subagents`, `session` hash, and `token_in`/`token_out` (cumulative totals live in `/session`). `path`: logical `project/worktree` label (`stripWorkPrefix: true`, kept after a live `false` trial of the full cwd); branch text dropped (worktree branches are autogenerated), dirty badges kept. * **models.yml:** frank-archon display `name` slimmed to `"frank-archon"` (endpoint suffix dropped; `id` untouched). * **Out of scope noted:** worktree name generation (`wt--`) is omp-internal; possible upstream feature request. diff --git a/omp-docs/pi/statusline.md b/omp-docs/pi/statusline.md index b0acc09..734945e 100644 --- a/omp-docs/pi/statusline.md +++ b/omp-docs/pi/statusline.md @@ -1,7 +1,7 @@ --- type: reference title: OMP Status Line Customization -description: How the omp status line actually works — presets vs custom arrays, composer-shape segment routing, the context meter, and the fleet's tuned segment layout. +description: How the omp status line actually works — presets vs custom arrays, composer-shape segment routing, the context meter (box/band only), the 27-segment catalog, and the fleet's tuned layout. tags: - omp - tui @@ -12,36 +12,89 @@ timestamp: 2026-10-18 # OMP Status Line Customization -Ground truth from the installed bundle (`@oh-my-pi/pi-coding-agent/dist/cli.js`) -verified live on blankpad 2026-10-18. All knobs live in -`agent/config.yml` under `statusLine:` (tracked — see -[Command Center repo](../core/index.md)); the file is file-watched, so edits -repaint a running session without restart (verify visually: niri screenshot, -see [niri capture recipe](../system/index.md)). +Ground truth from the installed bundle (`@oh-my-pi/pi-coding-agent/dist/cli.js`), +verified live on blankpad 2026-10-18 and re-audited line-by-line against the +minified source the same day (see [Audit log](#audit-log)). Status knobs live +in `agent/config.yml` under `statusLine:`; the two composer knobs +(`composer.shape`, `composer.tokenRate`) under `composer:`. The file is +file-watched — edits repaint a running session without restart (verify +visually: niri screenshot, see [niri capture recipe](../system/index.md)). +`/settings` (Appearance tab) previews these live with sample data. ## Preset vs custom — the trap -`statusLine.preset` ships whole configurations (`default`, `minimal`, -`compact`, `full`, `nerd`, `ascii`, `custom`). **`leftSegments` / -`rightSegments` / `segmentOptions` are only read when `preset: custom`** — -with any named preset they are silently ignored. The fleet config runs -`preset: custom`. +`statusLine.preset` ships whole configurations. **`leftSegments` / +`rightSegments` are ignored unless `preset: custom`** (`s ? user ?? preset +: preset` in the resolver). **`segmentOptions` is NOT gated** — user options +merge over the preset's own options under *every* preset. + +| preset | leftSegments | rightSegments | separator | +|---|---|---|---| +| `default` | pi vim model mode collab stream path git pr context_pct cost | session_name | powerline-thin | +| `minimal` | vim path git | session_name mode context_pct | slash | +| `compact` | vim model mode git pr | session_name cost context_pct | powerline-thin | +| `full` | pi vim hostname model mode path git pr subagents | session_name cache_hit token_in token_out token_rate cache_read cost context_pct time_spent time | powerline | +| `nerd` | pi vim hostname model mode path git pr session subagents | session_name token_in token_out cache_read cache_write token_rate cost context_pct context_total time_spent time | powerline | +| `ascii` | vim model mode path git pr | session_name token_total cost context_pct | ascii | +| `custom` | your `statusLine.leftSegments` | your `statusLine.rightSegments` | powerline-thin | + +The built-in default for `statusLine.leftSegments`/`rightSegments` themselves +is the `ascii`-era pair (`vim model mode path git pr` / `session_name +token_total cost context_pct`) — a config carrying those arrays with a named +preset is running the preset, not the arrays. The fleet runs `preset: custom`. ## Composer shape routes the segments -`composer.shape` decides *where* the two segment arrays render: +`composer.shape` decides *where* the two arrays render. Eight shapes ship in +the bundle; the plugin API can register more (`zG()` = built-ins + a live +registration map). Internally each shape carries `statusAttachment`, +`bottomBar`, `bottomBarGap`: -| shape | leftSegments | rightSegments | -|---|---|---| -| `band` (fleet) | merged single row above editor | same row, right side (title skipped — it rides the working row) | -| `claude` | bottom strip, left-aligned | top rule chip, right-aligned | -| `rule` | same as claude, gap above strip | same | -| `box` | box top border | box top border | -| `borderless` / `pi` / `field` / `rail` | single bottom bar | single bottom bar | +| shape | attach | bottom bar | leftSegments | rightSegments | +|---|---|---|---|---| +| `band` (fleet, default) | top-band | none | merged single row above editor, left | same row, right (`session_name` skipped — title rides the working row) | +| `box` | top-border | none | box top border | box top border | +| `claude` | top-rule-chip | left | bottom strip, left | top rule chip, right-aligned | +| `rule` | top-rule-chip | left + gap | like claude, gap above strip | like claude | +| `pi` | none | full | single bottom bar | single bottom bar | +| `borderless` | none | full | single bottom bar | single bottom bar | +| `field` / `rail` | none | full + gap (filled surface) | single bottom bar | single bottom bar | -The `⠿ Working…` row is hardcoded: shimmer text + `composer.tokenRate` readout -(+ session title in `band` only). Model/thinking-level can never join it -despite the settings description — that composer-bar behavior is Tern-only. +The chip/strip layouts paint their rules as **session-accent fillers, not +meters** — the context meter exists only in `box` and `band` +(see next section). The top-rule chip renders right segments only, the bottom +strip left segments only. + +The working row is composer chrome, not segment-addressable: session title + +shimmer, plus the tok/s readout when `composer.tokenRate: true` (default +false). The readout is estimated from streamed deltas, corrected by billed +output counts; the bundle also mentions a native-composer-bar placement in +filled styles. + +## The context meter + +`statusLine.contextLine` (enum `off` / `percentage` / `annotated` / +`embedded`, default `embedded`) tunes the rule between the segment groups. +The knob description says "box composer only" — **that is wrong**: the meter +renders in `box` **and** `band`; in every other shape the rule is a constant +session-accent filler regardless of this setting (live-verified claude with +`off` vs `embedded`: identical, and not context-proportional). + +In box/band: + +- `off` → plain accent rule (single color, full width). +- `embedded` → the inline labeled meter: `60% ——— × 200K`. Requires + `contextWindow > 0`, a `context_pct`/`context_total` segment present in + either array, and at least one non-context segment. The context segment(s) + are **hoisted out of the arrays** — they never render as text in this mode. +- `percentage` / `annotated` → unlabeled proportional meter painted into the + rule (live-verified in band: colored fill ∝ usage at the rule's right end); + `context_pct` stays a normal text segment. + +Fill length ∝ `min(100, contextPercent)`; >100% paints the raw percent and +shortens the meter. Meter/segment color thresholds scale with window size — +warning at ≥ min(50 %, 150K tokens), purple ≥ min(70 %, 270K), error ≥ +min(90 %, 500K); below that the theme's `statusLineContext` color. ## Segment universe (27) @@ -50,22 +103,33 @@ despite the settings description — that composer-bar behavior is Tern-only. `context_total`, `time_spent`, `time`, `session`, `hostname`, `cache_read`, `cache_write`, `cache_hit`, `session_name`, `usage`, `collab`, `stream`, `vim`. -Conditional segments render nothing until their trigger exists: `vim` needs -`tui.vimMode`, `mode` needs plan/yolo, `pr` needs an associated PR, `git` shows -staged/unstaged/untracked badges (branch text optional via -`segmentOptions.git.showBranch`), `status` needs an extension push. -`session` = first 8 chars of the session id (resume-by-id handle). +Zero/inactive segments render nothing — dead weight costs no width. -## The context meter - -In the `band` shape (fleet) the meter is the labeled inline line between the -segment groups (`60% ———— × 200K`). In the `claude` shape the red rule left of -the right-segment chip **is** the meter: its length tracks context usage. -`statusLine.contextLine` (`off` / `percentage` / `annotated` / `embedded`) -only changes rendering in `box`/`band` — in `claude` all non-`off` values -look identical. Docs' claim that contextLine is "box composer only" is -wrong for the meter itself; the labeled inline variant is the box/band-only -part. +| segment | renders | trigger / notes | +|---|---|---| +| `pi` | brand glyph + turn-elapsed | while streaming; focused-agent ghost id (warning color) when a subagent is focused | +| `status` | hook/extension statuses, dot-joined | extension pushes via `ctx.ui.setStatus()` (ordered by key); suppressed in footer when `statusLine.showHookStatus: false` | +| `model` | display `name` + thinking level | suffix hidden by `segmentOptions.model.showThinkingLevel: false`; `statusLine.compactThinkingLevel: true` (default) swaps in a compact glyph; fast-mode, advisor/tariff badges attach here | +| `mode` | `Plan` / `Prewalk` / `Goal` / `Vibe` / `Loop …` | only in those modes (paused variants add a pause glyph); there is **no yolo/auto-approval display** in this segment | +| `path` | cwd or `project/worktree` label | see [Path segment](#path-segment-and-stripworkprefix) | +| `git` | branch + dirty badges | `+N` staged, `*N` unstaged, `?N` untracked (`segmentOptions.git.showStaged/showUnstaged/showUntracked`, default true); `showBranch: false` hides branch text and keeps badges (git icon carries them); color flips on dirty | +| `pr` | `#` hyperlink | only once the session has an associated PR | +| `subagents` | count | hidden at 0; when subagents are actively running the composer paints its own live badge and this segment self-suppresses | +| `token_in` / `token_out` | cumulative session input/output tokens | hidden at 0; `cache_read` / `cache_write` likewise cumulative | +| `token_total` | `input + output + cache_write + orchestration_in + orchestration_out` | hidden at 0 | +| `token_rate` | `N.N tok/s` | hidden when not streaming (the working-row readout is a separate, `composer.tokenRate`-gated thing) | +| `cost` | session cost | includes subagent-tree + advisor cost; `↑`/`↓` peak/off-peak arrow for time-priced providers | +| `context_pct` | `NN.N%/200K` (or window alone when percent is unknown) | hoisted into the meter in `embedded` box/band; auto-compact speculation icon rides along | +| `context_total` | absolute context tokens | also hoisted by the embedded meter | +| `time_spent` | active session time | hidden under 1 s; this is *active* time, not wall clock | +| `time` | wall clock | `segmentOptions.time.format: "12h"/"24h"`, `showSeconds` | +| `session` | first 8 chars of session id (`new` before resume exists) | resume-by-id handle | +| `session_name` | session title, accent | in `band` it renders on the working row instead | +| `hostname` | short hostname | accent-tinted with session color | +| `usage` | rate-limit windows | 5h / daily / 7d / monthly bars + tier badge, when the provider reports them | +| `collab` | `collab:N` / `collab guest:N` | only in collab sessions | +| `stream` | `● LIVE ` / `● REC` | only while streaming/recording | +| `vim` | mode glyph/word | only while vim keybindings are active; selected-line count appended (` 3L`); `display` icon vs text comes from the vim runtime, not config | ## Path segment and `stripWorkPrefix` @@ -81,23 +145,55 @@ part. 2. **All sessions:** `true` uses the pretty display path (scratch sessions get the scratch-folder icon); `false` uses the raw absolute cwd. -`abbreviate` and `maxLength` (clip, default 40) apply afterwards in both -modes. The fleet runs `true` — logical label, worktree glyph (verified live -2026-10-18; an earlier trial of `false` for the full cwd was rejected by eye). +`abbreviate` (default **true**: home → `~`; `false` keeps the full path — +also affects tool labels/errors per upstream docs) and `maxLength` (clip, +default 40) apply afterwards in both modes. The fleet runs `true` — logical +label, worktree glyph (verified live 2026-10-18; an earlier trial of `false` +for the full cwd was rejected by eye). + +## Status knobs (registry-verified) + +`statusLine.preset` · `.leftSegments` · `.rightSegments` · `.segmentOptions` · +`.separator` (`powerline` `powerline-thin` `slash` `pipe` `block` `none` +`ascii`; default `powerline-thin`) · `.contextLine` · `.sessionAccent` +(default true; hashes the session name into the editor border *and* the +accent-tinted segments/meter color) · `.transparent` (terminal background, +no status bg fill) · `.showHookStatus` · `.compactThinkingLevel` (default +true). Plus `symbolPreset` at top level (`unicode` `nerd` `ascii` — segment +glyphs follow it). ## Fleet configuration (2026-10-18) -- Shape `band`: one merged status row. Left group: `session_name`, `vim`, - `mode`, `hostname`, `path`, `git` (no branch text — worktree branches are - autogenerated names), `pr`. Right group (array order = paint order, so the - last entry hugs the screen edge): `model`, `cost`, `context_pct`, - `time_spent` — `context_pct` hoists out of the run to paint the labeled - inline meter (`60% ——— × 200K`) as a flexible spacer between the groups. - `session_name` renders on the working row, not the status row. -- Deliberately cut: `token_rate` (lives on the working row), `time` (panel - clock), `cache_*` (noise), `context_total` (implied by the meter), - `subagents`, `session`, `token_in`/`token_out` (cumulative totals are - in `/session` anyway). -- Model display names slimmed in `models.yml` (`frank-archon`, no endpoint - suffix); `name:` is free-form display, `id:` is the wiring — renaming ids is - the cutover procedure, see [Pi Models](/pi/models.md). +- Shape `band`: one merged status row. Left group: `session_name`→working + row (skipped), `vim`, `mode`, `hostname`, `path`, `git` (no branch text — + worktree branches are autogenerated names), `pr`. Right group (array order + = paint order, so the last entry hugs the screen edge): `model`, `cost`, + `context_pct`, `time_spent` — `context_pct` hoists out of the run to paint + the labeled inline meter (`60% ——— × 200K`) between the groups under + `contextLine: embedded`. +- Deliberately cut: `token_rate` (working-row readout covers it), `time` + (panel clock), `cache_*` (noise), `context_total` (implied by the meter), + `subagents` (live badge supersedes it), `session`, `token_in`/`token_out` + (cumulative totals are in `/session` anyway). +- `models.yml`: frank-archon's display `name` slimmed to `"frank-archon"` + (endpoint suffix dropped); frank-dragoon/frank-zealot keep their endpoint + suffixes. `name:` is free-form display, `id:` is the wiring — renaming ids + is the cutover procedure, see [Pi Models](/pi/models.md). + +## Audit log + +2026-10-18 full-source re-audit corrected the first pass of this page: + +- ~~claude shape's top rule is the context meter~~ — **false**. The + meter code path runs only for `box`/`band`; claude/rule/pi/borderless/ + field/rail rules are constant session-accent fillers. (Earlier reading + mistook the accent rule for a meter.) +- ~~working-row composer-bar variant is "Tern-only"~~ — **false**; the + tok/s readout is the `composer.tokenRate` option (default false), title + placement is composer chrome. +- ~~`segmentOptions` gated to `preset: custom`~~ — **false**; options merge + under every preset, only the segment *arrays* are gated. +- ~~`mode` covers yolo~~ — **false**; states are Plan/Prewalk/Goal/Vibe/Loop. +- `contextLine` "(box composer only)" — the *bundle description* is wrong; + band honors it too (verified live: `off` plain rule, `percentage` rule + meter, `embedded` inline meter, screenshots + code).