Skip to content

Statusline

Daniel Nevoigt edited this page May 30, 2026 · 2 revisions

Statusline & Live Feedback

What bastra-recall shows while it works — the persistent statusline segment and the live phrases under a running tool call. Was bastra-recall während der Arbeit anzeigt — das persistente Statusline-Segment und die Live-Phrasen unter einem laufenden Tool-Call.


🇬🇧 English

bastra-recall surfaces its activity in two live channels inside Claude Code:

  1. the statusline segment — the persistent powerline at the very bottom.
  2. the progress line — the text under a running tool call (Calling bastra-recall …).

1. The statusline segment

Package @bastra-recall/statusline (owloops/claude-powerline vendored + a native bastra segment). It reads a per-session feed that the daemon's MCP forwarder writes to ~/.bastra/statusline/<claude-session-pid>.json, and renders one of three states:

State Looks like When
idle bastra · 182 memories no bastra tool call this turn
done (loads only) ✓ bastra · 2 calls · 12ms · Krame im Gedächtnis … tool calls finished, no recall
done (with recall) ✓ bastra · 3 calls · 14 hits · 142ms · Da, bitte. a recall ran this turn
  • calls — every bastra tool call this turn (recall + load_memory / save_memory / find_document / …).
  • hits — recalls only; omitted when 0.
  • ms — summed duration of all bastra calls this turn (e.g. two ~6 ms loads → ~12 ms; a recall ~120 ms).
  • the trailing phrase persists for ~10 s (TTL), then the banner drops back to the bare stats.

The feed is namespaced by the claude ancestor PID — Claude Code sends no session id to MCP servers (anthropics/claude-code#41836) — so concurrent sessions never clobber each other's counters. The turn boundary is detected via a turn_id the prompt-hook stamps, so recall_count stays correct even across parallel recalls.

Setup (bastra install claude-code wires this for you):

"statusLine": {
  "type": "command",
  "command": "node …/packages/statusline/dist/index.mjs --style=powerline",
  "refreshInterval": 1
}

refreshInterval is in seconds, minimum 1.

Configuring the segments

The "parts" of the statusline are segments, and they can only be changed through a config file (CLI flags / env vars only set theme, style and charset). The first file that exists wins:

  1. --config <path> flag, or the CLAUDE_POWERLINE_CONFIG env var (~ is expanded)
  2. <projectDir>/.claude-powerline.json
  3. <cwd>/.claude-powerline.json
  4. ~/.claude/claude-powerline.json ← the usual place for a global config
  5. ~/.config/claude-powerline/config.json

The file is deep-merged onto the built-in defaults, so you only list what you want to change. One exception: display.lines is an array — if you set it, it replaces the default lines wholesale, so list every segment you want on that line.

⚠️ display.style / theme / charset set in the file are overridden by the CLI flag in your statusLine.command (--style=…), which has the highest priority. The segments are unaffected — they come only from the file.

Default-on: directory, git, model, weekly, context, agent, bastra. Default-off: session, today, block, version, tmux, sessionId, metrics, thinking, cacheTimer, env.

Every segment takes enabled: true|false plus its own options:

Key Part Options (beyond enabled)
directory working dir style: basename | fish
git git status showSha, showWorkingTree, showOperation, showTag, showTimeSinceCommit, showStashCount, showUpstream, showRepoName
model active model
session session cost/tokens type: tokens | cost | both, costSource, showUnits
today today's cost type: cost | tokens | both | breakdown, showUnits
block 5h billing block type, burnType, displayStyle
weekly weekly usage displayStyle
context context usage showPercentageOnly, displayStyle, autocompactBuffer, percentageMode: remaining | used
metrics turn metrics showResponseTime, showLastResponseTime, showDuration, showMessageCount, showLinesAdded, showLinesRemoved
agent sub-agent showLabel
thinking thinking status showEnabled, showEffort
cacheTimer prompt-cache TTL displayMode: elapsed | remaining, ttlSeconds
bastra bastra-recall status
version / tmux / sessionId / env misc sessionId.showIdLabel, env.variable (required), env.prefix

Minimal example — drop the cost segments, show the git SHA, split across two lines:

{
  "display": {
    "lines": [
      { "segments": {
        "directory": { "enabled": true, "style": "basename" },
        "git": { "enabled": true, "showSha": true },
        "model": { "enabled": true },
        "context": { "enabled": true },
        "bastra": { "enabled": true }
      } },
      { "segments": {
        "weekly": { "enabled": true },
        "agent": { "enabled": true }
      } }
    ]
  }
}

Changes apply on the next render (a new prompt) — no rebuild needed. For the full set of themeable colors and display styles see the upstream engine, owloops/claude-powerline.

2. The progress line (Calling bastra-recall …)

During a tool call the forwarder sends MCP notifications/progress with a banter phrase; Claude Code renders it under the collapsed tool call, e.g. └ Krame im Gedächtnis … (100%).

  • recall streams one phrase per pipeline stage (query.parse → bm25.search → vector.search → …), so the line changes as the recall progresses — phrase-first, e.g. Stichwörter durchforsten … · 15ms.
  • non-streaming tools (load_memory, save_memory, …) emit one phrase per call; a series of them shows changing banter.
  • Requires Claude Code ≥ 2.1.153 — earlier versions did not render MCP progress in the collapsed tool view (anthropics/claude-code#51713).

Banter configuration

env var values effect
BASTRA_BANTER on (default) · terse · off terse/off → no phrases (statusline falls back to the raw stage name)
BASTRA_BANTER_LANG en (default) · de language of the phrases

Set these in the MCP server's env block in ~/.claude.json (the forwarder reads them). Phrases live in @bastra-recall/core (recall-banter.ts): per-stage pools for recall, plus per-tool pools for load_memory & co.

Notes & limits

  • The statusline refreshes at most ~1×/s plus on events, with a hardcoded ~300 ms debounce — enough for the done-banner, not for animating a sub-second recall. The live, changing phrases therefore appear in the progress line, not the statusline; the statusline's job is the persistent per-turn summary.
  • hits/ms are entangled only at render time: hits show only with a recall, ms whenever any tool ran — so a load_memory-only turn reads 2 calls · 12ms with no misleading 0 hits.

🇩🇪 Deutsch

bastra-recall zeigt seine Aktivität in zwei Live-Kanälen innerhalb von Claude Code:

  1. das Statusline-Segment — die persistente Powerline ganz unten.
  2. die Progress-Zeile — der Text unter einem laufenden Tool-Call (Calling bastra-recall …).

1. Das Statusline-Segment

Paket @bastra-recall/statusline (owloops/claude-powerline vendored + ein natives bastra-Segment). Es liest einen Per-Session-Feed, den der MCP-Forwarder des Daemons nach ~/.bastra/statusline/<claude-session-pid>.json schreibt, und rendert einen von drei Zuständen:

Zustand Sieht so aus Wann
idle bastra · 182 memories kein bastra-Tool-Call in diesem Turn
done (nur Loads) ✓ bastra · 2 calls · 12ms · Krame im Gedächtnis … Tool-Calls fertig, kein recall
done (mit recall) ✓ bastra · 3 calls · 14 hits · 142ms · Da, bitte. ein recall lief in diesem Turn
  • calls — jeder bastra-Tool-Call dieses Turns (recall + load_memory / save_memory / find_document / …).
  • hits — nur recalls; bei 0 weggelassen.
  • ms — Summe der Dauern aller bastra-Calls dieses Turns (z. B. zwei ~6 ms-Loads → ~12 ms; ein recall ~120 ms).
  • die abschließende Phrase bleibt ~10 s stehen (TTL), danach fällt der Banner auf die nackten Stats zurück.

Der Feed wird über die claude-Vorfahren-PID namespaced — Claude Code sendet keine Session-ID an MCP-Server (anthropics/claude-code#41836) — sodass parallele Sessions sich nicht gegenseitig die Zähler überschreiben. Die Turn-Grenze wird über eine turn_id erkannt, die der Prompt-Hook stempelt; so bleibt recall_count auch bei parallelen Recalls korrekt.

Einrichtung (bastra install claude-code erledigt das für dich):

"statusLine": {
  "type": "command",
  "command": "node …/packages/statusline/dist/index.mjs --style=powerline",
  "refreshInterval": 1
}

refreshInterval ist in Sekunden, Minimum 1.

Die Segmente konfigurieren

Die „Parts" der Statusline sind Segmente, und die lassen sich nur über eine Config-Datei anpassen (CLI-Flags / Env-Variablen setzen nur Theme, Style und Charset). Die erste existierende Datei gewinnt:

  1. --config <pfad>-Flag oder die Env-Variable CLAUDE_POWERLINE_CONFIG (~ wird expandiert)
  2. <projektDir>/.claude-powerline.json
  3. <cwd>/.claude-powerline.json
  4. ~/.claude/claude-powerline.json ← der übliche Ort für eine globale Config
  5. ~/.config/claude-powerline/config.json

Die Datei wird per Deep-Merge über die eingebauten Defaults gelegt — du gibst also nur an, was du ändern willst. Eine Ausnahme: display.lines ist ein Array — wenn du es setzt, ersetzt es die Default-Zeilen komplett; liste also jedes Segment auf, das auf dieser Zeile erscheinen soll.

⚠️ display.style / theme / charset aus der Datei werden vom CLI-Flag in deinem statusLine.command (--style=…) übersteuert, das die höchste Priorität hat. Die Segmente sind davon nicht betroffen — die kommen ausschließlich aus der Datei.

Standardmäßig an: directory, git, model, weekly, context, agent, bastra. Standardmäßig aus: session, today, block, version, tmux, sessionId, metrics, thinking, cacheTimer, env.

Jedes Segment nimmt enabled: true|false plus eigene Optionen:

Key Part Optionen (über enabled hinaus)
directory Arbeitsverzeichnis style: basename | fish
git Git-Status showSha, showWorkingTree, showOperation, showTag, showTimeSinceCommit, showStashCount, showUpstream, showRepoName
model aktives Modell
session Session-Kosten/Tokens type: tokens | cost | both, costSource, showUnits
today Tageskosten type: cost | tokens | both | breakdown, showUnits
block 5h-Abrechnungsblock type, burnType, displayStyle
weekly Wochenverbrauch displayStyle
context Kontext-Auslastung showPercentageOnly, displayStyle, autocompactBuffer, percentageMode: remaining | used
metrics Turn-Metriken showResponseTime, showLastResponseTime, showDuration, showMessageCount, showLinesAdded, showLinesRemoved
agent Sub-Agent showLabel
thinking Thinking-Status showEnabled, showEffort
cacheTimer Prompt-Cache-TTL displayMode: elapsed | remaining, ttlSeconds
bastra bastra-recall-Status
version / tmux / sessionId / env div. sessionId.showIdLabel, env.variable (Pflicht), env.prefix

Minimal-Beispiel — Kosten-Segmente raus, Git-SHA zeigen, auf zwei Zeilen aufgeteilt:

{
  "display": {
    "lines": [
      { "segments": {
        "directory": { "enabled": true, "style": "basename" },
        "git": { "enabled": true, "showSha": true },
        "model": { "enabled": true },
        "context": { "enabled": true },
        "bastra": { "enabled": true }
      } },
      { "segments": {
        "weekly": { "enabled": true },
        "agent": { "enabled": true }
      } }
    ]
  }
}

Änderungen greifen beim nächsten Render (neuer Prompt) — kein Rebuild nötig. Für die komplette Palette an Theme-Farben und Display-Styles siehe die Upstream-Engine, owloops/claude-powerline.

2. Die Progress-Zeile (Calling bastra-recall …)

Während eines Tool-Calls sendet der Forwarder MCP-notifications/progress mit einer Banter-Phrase; Claude Code rendert sie unter dem collapsed Tool-Call, z. B. └ Krame im Gedächtnis … (100%).

  • recall streamt eine Phrase pro Pipeline-Stage (query.parse → bm25.search → vector.search → …), die Zeile wechselt also mit dem Recall-Fortschritt — Phrase zuerst, z. B. Stichwörter durchforsten … · 15ms.
  • nicht-streamende Tools (load_memory, save_memory, …) feuern eine Phrase pro Call; eine Serie zeigt wechselnde Banter.
  • Benötigt Claude Code ≥ 2.1.153 — frühere Versionen rendern MCP-Progress nicht im collapsed Tool-View (anthropics/claude-code#51713).

Banter-Konfiguration

env-Variable Werte Wirkung
BASTRA_BANTER on (Default) · terse · off terse/off → keine Phrasen (Statusline fällt auf den rohen Stage-Namen zurück)
BASTRA_BANTER_LANG en (Default) · de Sprache der Phrasen

Im env-Block des MCP-Servers in ~/.claude.json setzen (der Forwarder liest sie). Die Phrasen liegen in @bastra-recall/core (recall-banter.ts): Pro-Stage-Pools für recall plus Pro-Tool-Pools für load_memory & Co.

Hinweise & Grenzen

  • Die Statusline rendert höchstens ~1×/s plus bei Events, mit einem hartcodierten ~300 ms-Debounce — genug für den Done-Banner, nicht für eine Animation eines Sub-Sekunden-Recalls. Die lebendigen, wechselnden Phrasen erscheinen deshalb in der Progress-Zeile, nicht in der Statusline; die Statusline liefert die persistente Pro-Turn-Zusammenfassung.
  • hits/ms sind nur beim Rendern entkoppelt: hits erscheinen nur mit einem recall, ms sobald irgendein Tool lief — ein reiner load_memory-Turn liest sich also 2 calls · 12ms ohne irreführende 0 hits.

🇬🇧 License & attribution

The statusline engine is owloops/claude-powerline, MIT-licensed, vendored into packages/statusline. The upstream license is kept verbatim at packages/statusline/LICENSE:

MIT License — Copyright (c) 2025 Owloops

bastra-recall's own additions (the native bastra segment, the per-session feed, the banter integration) are likewise MIT. Under the MIT terms, using and redistributing the statusline only requires keeping that LICENSE file and its copyright notice intact — which the package and every release tarball already do ("files": ["dist", "bin", "src", "LICENSE"] in package.json, and the engine is credited in the package description). No further obligation applies.

🇩🇪 Lizenz & Attribution

Die Statusline-Engine ist owloops/claude-powerline, MIT-lizenziert, nach packages/statusline vendored. Die Upstream-Lizenz liegt unverändert unter packages/statusline/LICENSE:

MIT License — Copyright (c) 2025 Owloops

Die eigenen Ergänzungen von bastra-recall (das native bastra-Segment, der Per-Session-Feed, die Banter-Integration) sind ebenfalls MIT. Nach den MIT-Bedingungen erfordert Nutzung und Weitergabe der Statusline lediglich, dass diese LICENSE-Datei samt Copyright-Hinweis erhalten bleibt — was Package und jedes Release-Tarball bereits tun ("files": ["dist", "bin", "src", "LICENSE"] in der package.json, und die Engine ist in der Package-description genannt). Keine weitere Pflicht.