Display Requirements¶
- Date: 2026-08-02
- Status: Approved (2026-08-02, ADR-0009)
- Supersedes: the model segment of the current
~/.claude/statusline.js
Objective¶
The statusline renders a single, bounded, deterministic line whose primary element is the resolved provider/model actually used by the last assistant response (per ADR-0005/0006/0007), degrading gracefully to the requested model when no resolved route exists yet. It never displays a value it cannot source.
General rules¶
- One line only. Output is a single string written to stdout; it never wraps.
- Deterministic: identical inputs produce identical output (no timestamps beyond the staleness decision, no randomness).
- Missing fields are omitted, never guessed (baseline behavior preserved).
- Any total failure renders an empty string (Claude Code then shows its own default).
Line structure (segment order)¶
🤖 <route> | <bar + %> | 🪟 <used/window> | ⇡in⇣out | 🌿 <branch>/🌳 <worktree-name> <state>
- Route segment (new — replaces the old model segment; defined below).
- Context bar (new): a 10-segment
▓░gauge plus the roundedused_percentage(<n>%); filled blocks and the%are health-colored by the same usage thresholds as before, empty blocks a dark grey. Omitted whenused_percentageis absent. - Fill meter (new): tokens-in-window over the window size (
78K/200K); the numerator is derived fromused_percentageso the bar,%, and meter always agree. Omitted whenused_percentageor the window is absent. - Token deltas (preserved):
⇡in⇣outfromcontext_window.current_usage; omitted when absent. - Git branch:
🌿 <branch>(or🌳 <worktree-name>inside a linked worktree) fromgit status --porcelain -bagainstcwd; omitted when not a repo. In a linked worktree the branch label is replaced by the worktree's own name (basename of its per-worktree gitdir), so the 🌳 marker identifies the isolated checkout. Muted green on feature branches and bright red on a protected default branch — the staticMAIN_BRANCHESlist (main/master) unioned with each configured remote's HEAD default. A clean default branch in the main tree omits the segment entirely (it is not a noteworthy state); it still renders for any dirty, in-progress, detached, or worktree state. A state emoji follows the branch, drawn fromgit status --porcelainplus per-worktree operation markers:
| State | Emoji | Detected by |
|---|---|---|
| Clean | ✅ |
no changes |
| Modified | ✏️ |
unstaged (index column Y) |
| Staged | 📦 |
staged (column X), no unstaged |
| Untracked | 🆕 |
?? entries only |
| Mixed | 🔄 |
staged and unstaged |
| Merge conflict | ⚔️ |
U in either column, or AA/DD |
| Rebasing | 🧩 |
rebase-merge / rebase-apply dir in the gitdir |
| Merging | 🤝 |
MERGE_HEAD present |
| Cherry-picking | 🍒 |
CHERRY_PICK_HEAD present |
| Reverting | ↩️ |
REVERT_HEAD present |
| Detached HEAD | 📍 |
branch header HEAD (no branch) |
Precedence (highest wins): conflict → rebasing → merging → cherry-picking → reverting → detached → mixed → staged → modified → untracked → clean.
Segments are joined with | (space-pipe-space). Color is a presentation-layer
tunable (lib/config.js STYLE), applied only at the render layer.
Route segment definition¶
| Condition | Render |
|---|---|
| Resolved route known (last assistant message has a model) | provider/model — e.g., opencode/big-pickle |
| Resolved route known, provider unknown (mapping miss) | model only — e.g., big-pickle |
| No resolved route yet (no assistant message in transcript) | requested label verbatim — e.g., auto/cheap |
| Resolved route older than the staleness threshold | append [stale] to the route — e.g., opencode/big-pickle [stale] |
Notes:
provider/modeluses the naming rules in03-provider-model-naming.md. Model strings are displayed verbatim, never parsed or rewritten.- When the route is stale, the last known value is still shown (with the marker) rather than cleared; this is the defined fallback in
Architecture.md. - The requested label (
model.display_name || model.id) is a fallback only; once the first assistant message exists, the resolved route replaces it.
Staleness¶
- Threshold: 5 minutes by default, a single configurable constant.
- Definition: the resolved route is stale when the wall-clock time minus the last assistant message's timestamp exceeds the threshold.
- Rationale: during active work, assistant messages arrive frequently and the route is fresh; 5 minutes avoids flagging normal reading pauses while still marking long idle periods where the next request would re-route. Because
auto/cheapre-resolves on every request (ADR-0007), the marker is a soft signal, not a guarantee of what the next request will use.
Truncation¶
- The route segment is bounded to 32 characters. When
provider/modelexceeds that, the model portion is truncated to fit while keeping the provider prefix, with a trailing…: opencode/very-long-model-identifier→opencode/very-long-model-identi…- When the provider is absent, the model alone is truncated at 32 chars.
- The decorative
🤖prefix is applied at the render layer and excluded from the truncation bound (it is a fixed label, not route content). - The remaining segments are never truncated; the full line's length is therefore bounded by the sum of the segments (Phase 5 validates behavior at different terminal widths).
Non-functional constraints (carried from Architecture.md)¶
- Read completes well within the documented 300 ms statusline debounce (transcript tail is sub-ms, verified).
- Read-only; no writes; no live traffic; no network.
- Never renders tokens, prompts, or request content (
05-security-privacy.md).