Skip to content

Phase 4 Implementation Plan — Approval Record

  • Date: 2026-08-02
  • Status: Approved (2026-08-02, by repository owner, no ADR — this is implementation of approved architecture, not a new architectural decision)
  • Based on: the approved Phase 3 design (Statusline/Design/01–06, 07-design-handoff.md) and the approved architecture (Architecture.md, ADR-0005–0009)

Scope

Implement the approved statusline design as a zero-dependency modular Node.js application with a contract test suite covering all16 acceptance cases from Statusline/Design/06-test-cases-acceptance.md. SQLite enrichment at read time is explicitly out of scope (off by default per ADR-0009).

Change requests incorporated

The following change requests were made during the approval review and are incorporated into the implementation:

  1. Single named constant for tail window. All implementation constants (transcript tail window, staleness threshold, truncation max, read timeouts) are defined as named constants in a single lib/config.js module — no hardcoded values scattered across files.

  2. Modular implementation. The CLI entry point (statusline.js) is small. Parsing, transcript handling, mapping, staleness, route composition, and formatting are implemented as separate lib/ modules, each independently testable.

  3. Mapping is a read-only runtime dependency. The statusline reads ~/.claude/statusline-model-provider.json at runtime. It never regenerates or modifies this file. Generation is an explicit user-initiated action via Scripts/update-model-provider-mapping.js.

  4. Failure invariant: degrade toward requested model. Every failure path degrades toward the requested-model display (model.display_name || model.id from the payload). No error, exception, undefined, or null appears in output. A catch-all in the CLI entry enforces this invariant.

  5. No ADR-0010. This plan is recorded in Findings/ only. No Decisions.md change — this is implementation of an already-approved architecture, not a new architectural decision.

Deliverables

File Purpose
Statusline/statusline.js CLI entry point (small; reads stdin, wires modules, writes single output line)
Statusline/lib/config.js Named constants: TRANSCRIPT_TAIL_WINDOW_BYTES, STALENESS_THRESHOLD_MS, ROUTE_MAX_CHARS, read timeouts, mapping file path
Statusline/lib/timeout.js withTimeout(promise, ms) — Promise.race hard timeout
Statusline/lib/parse-stdin.js parseStdin(raw) — JSON parse with null-on-failure
Statusline/lib/transcript.js readTranscriptTail(path, windowBytes) + findLastAssistantModel(tailText) — bounded read + backward line walk
Statusline/lib/mapping.js loadMapping(path, timeoutMs) + resolveProvider(model, mapping) — read-only; never writes
Statusline/lib/staleness.js isStale(timestamp, nowMs, thresholdMs) — ISO timestamp comparison
Statusline/lib/route.js requestedLabel(payload), truncateRoute(provider, model, maxChars), composeRoute(...)
Statusline/lib/format.js formatBranch(cwd), formatContext(ctx) — preserved baseline
Statusline/test/statusline.test.js Contract tests for all16 cases + invariants
Statusline/test/fixtures/transcripts/*.jsonl Transcript fixtures for each case
Scripts/update-model-provider-mapping.js Maintenance: aggregate call_logs, write mapping atomically
Statusline/README.md Usage and configuration docs

Deployment

  • Backup current ~/.claude/statusline.js~/.claude/statusline.js.pre-phase4.<timestamp>
  • Install statusline.js + lib/ to ~/.claude/statusline/ (self-contained; works without the repo)
  • No settings.json change required (the wrapper at ~/.claude/statusline.js keeps the command path unchanged)
  • Generate initial mapping via Scripts/update-model-provider-mapping.js