Three lines in One Dark: model, thinking effort and a context bar up top; cost, quota, session clock and token throughput in the middle; weather, free memory and a rotating kaomoji below.
Updated 2026-09-07
0 copies
Preview
Clean repo
Model: Opus 4.8 | Thinking: high | Context: [▰▰▱▱▱▱▱▱▱▱] 45k/200k (22%) | cwd: ~/app | ⎇ main | (+0,-0)
Cost: $0.41 | Block: 2hr 6m | Weekly: 7.0% | Session: 10m | In: 916.7 t/s | Out: 29.2 t/s | Cached: 2k | Session: [▰▱▱▱▱] 26.0%
Mem: 0.8G/1.0G | (*゚∀゚*) | Session ID: b8e1c0d2-4a6f-4e2a-9c1b-3f5d7a9e2c10
New session
Model: Opus 4.8 | Thinking: high | Context: [▱▱▱▱▱▱▱▱▱▱] 0/200k (0%) | cwd: ~/app | ⎇ main | (+0,-0)
Cost: $0.00 | Session: 10m | In: 0.0 t/s | Out: 0.0 t/s
Mem: 0.8G/1.0G | q(❂‿❂)p | Session ID: b8e1c0d2-4a6f-4e2a-9c1b-3f5d7a9e2c10
Dirty branch
Model: Sonnet 4.6 | Thinking: medium | Context: [▰▰▰▰▱▱▱▱▱▱] 97k/200k (48%) | cwd: ~/app | ⎇ feat/auth | (+1,-0)
Cost: $0.41 | Block: 1hr 11m | Weekly: 18.0% | Session: 10m | In: 2000.0 t/s | Out: 29.2 t/s | Cached: 2k | Session: [▰▰▱▱▱] 40.0%
Mem: 0.8G/1.0G | ꒰˘̩̩̩⌣˘̩̩̩๑꒱♡ | Session ID: b8e1c0d2-4a6f-4e2a-9c1b-3f5d7a9e2c10
Near-full
Model: Opus 4.8 | Thinking: max | Context: [▰▰▰▰▰▰▰▰▰▱] 183k/200k (91%) | cwd: ~/app | ⎇ main | (+0,-0)
Cost: $4.12 | Block: 17m | Weekly: 61.0% | Session: 10m | In: 3791.7 t/s | Out: 29.2 t/s | Cached: 2k | Session: [▰▰▰▰▱] 88.0%
Mem: 0.8G/1.0G | ヽ(͡◕ ͜ʖ ͡◕)ノ | Session ID: b8e1c0d2-4a6f-4e2a-9c1b-3f5d7a9e2c10
1M context
Model: Fable 5 | Thinking: xhigh | Context: [▰▰▰▰▰▰▱▱▱▱] 641k/1.0M (64%) | cwd: ~/app | ⎇ main | (+0,-0)
Cost: $0.41 | Block: 3hr 29m | Weekly: 80.0% | Session: 10m | In: 13333.3 t/s | Out: 29.2 t/s | Cached: 2k | Session: [▰▱▱▱▱] 33.0%
Mem: 0.8G/1.0G | ヽ(⌐■_■)ノ♪ | Session ID: b8e1c0d2-4a6f-4e2a-9c1b-3f5d7a9e2c10
Post-compact
Model: Haiku 4.5 | Context: [▱▱▱▱▱▱▱▱▱▱] 0/200k (0%) | cwd: ~/app | ⎇ main | (+0,-0)
Cost: $0.41 | Block: 4hr 1m | Session: 10m | In: 0.0 t/s | Out: 0.0 t/s | Session: [▰▰▱▱▱] 52.0%
Mem: 0.8G/1.0G | ᕦ(ò_óˇ)ᕤ | Session ID: b8e1c0d2-4a6f-4e2a-9c1b-3f5d7a9e2c10
Worktree
Model: Opus 4.8 | Thinking: low | Context: [▰▰▰▱▱▱▱▱▱▱] 75k/200k (37%) | cwd: ~/./feature | ⎇ worktree-feature | (+0,-0)
Cost: $0.41 | Block: 2hr 49m | Weekly: 20.0% | Session: 10m | In: 1541.7 t/s | Out: 29.2 t/s | Cached: 2k | Session: [▰▰▱▱▱] 44.0%
Mem: 0.8G/1.0G | (ノ◕ヮ◕)ノ*:・゚✧ | Session ID: b8e1c0d2-4a6f-4e2a-9c1b-3f5d7a9e2c10
Non-git
Model: Opus 4.8 | Thinking: high | Context: [▰▰▱▱▱▱▱▱▱▱] 45k/200k (22%) | cwd: ~/scratch
Cost: $0.41 | Session: 10m | In: 916.7 t/s | Out: 29.2 t/s | Cached: 2k
Mem: 0.8G/1.0G | ¯\_(ツ)_/¯ | refactor-pass | Session ID: b8e1c0d2-4a6f-4e2a-9c1b-3f5d7a9e2c10
Source
#!/usr/bin/env bash
# One Dark Triptych — a three-line Claude Code status line.
#
# Model: Opus 5 | Thinking: high | Context: [▰▰▱▱▱▱▱▱▱▱] 123k/1.0M (12%) | cwd: ~/P/h/my-repo | ⎇ dev | (+12,-3)
# Cost: $2.73 | Block: 3hr 42m | Weekly: 1.0% | Session: 12m | In: 0.5 t/s | Out: 119.7 t/s | Cached: 5.4M | Session: [▰▱▱▱▱] 10.0%
# 🌧 25°C feels 26°C 💨4.0m/s | Mem: 5.8G/16.0G | (*¯︶¯*) | Session ID: 93f52d0c-…
#
# Requires: jq. Optional: git, curl.
#
# Weather is opt-in. Without a key the widget is omitted and nothing touches the network:
# export OPENWEATHER_API_KEY=... # free key from openweathermap.org
# export OPENWEATHER_CITY="Berlin,DE" # defaults to London,GB
set -uo pipefail
input=$(cat)
command -v jq >/dev/null 2>&1 || { printf 'status line needs jq on PATH\n'; exit 0; }
# ── One Dark palette ────────────────────────────────────────────────────────
BLUE=$'\033[38;2;97;175;239m'
RED=$'\033[38;2;224;108;117m'
GREEN=$'\033[38;2;152;195;121m'
GREY=$'\033[38;2;171;178;191m'
PURPLE=$'\033[38;2;198;120;221m'
YELLOW=$'\033[38;2;229;192;123m'
ORANGE=$'\033[38;2;209;154;102m'
CYAN=$'\033[38;2;86;182;194m'
DIM=$'\033[38;2;92;99;112m'
RESET=$'\033[0m'
SEP="${DIM} | ${RESET}"
# ── Helpers ────────────────────────────────────────────────────────────────
int() { printf '%.0f' "${1:-0}" 2>/dev/null || printf '0'; }
# 1234 -> 1.2k, 5400000 -> 5.4M
human() {
awk -v n="${1:-0}" 'BEGIN {
if (n >= 1000000) printf "%.1fM", n / 1000000
else if (n >= 1000) printf "%.0fk", n / 1000
else printf "%d", n
}'
}
# 10 -> ▰▱▱▱▱▱▱▱▱▱
bar() {
awk -v p="${1:-0}" -v w="${2:-10}" 'BEGIN {
if (p < 0) p = 0; if (p > 100) p = 100
f = int(p * w / 100)
for (i = 0; i < w; i++) printf (i < f ? "▰" : "▱")
}'
}
# 3720 -> "1hr 2m", 720 -> "12m"
dur() {
awk -v s="${1:-0}" 'BEGIN {
h = int(s / 3600); m = int((s % 3600) / 60)
if (h > 0) printf "%dhr %dm", h, m
else if (m > 0) printf "%dm", m
else printf "%ds", s
}'
}
# ── Pull every field in one jq pass ────────────────────────────────────────
# One value per line rather than @tsv: tab counts as whitespace to `read`, so a
# tab-separated row silently collapses empty fields and shifts every later value.
F=()
while IFS= read -r line; do F+=("$line"); done < <(
printf '%s' "$input" | jq -r '[
.model.display_name // "?",
.effort.level // "",
(.thinking.enabled // false | tostring),
(.context_window.used_percentage // 0),
((.context_window.total_input_tokens // 0) + (.context_window.total_output_tokens // 0)),
(.context_window.context_window_size // 200000),
.workspace.current_dir // .cwd // "",
(.cost.total_cost_usd // 0),
(.cost.total_duration_ms // 0),
(.cost.total_api_duration_ms // 0),
(.context_window.total_input_tokens // 0),
(.context_window.total_output_tokens // 0),
(.context_window.current_usage.cache_read_input_tokens // 0),
.session_id // "",
.session_name // "",
(.rate_limits.five_hour.used_percentage // ""),
(.rate_limits.five_hour.resets_at // ""),
(.rate_limits.seven_day.used_percentage // "")
] | .[] | tostring'
)
MODEL="${F[0]:-?}" EFFORT="${F[1]:-}" THINKING="${F[2]:-false}"
PCT="${F[3]:-0}" TOK_TOTAL="${F[4]:-0}" CTX_SIZE="${F[5]:-200000}"
CWD="${F[6]:-}" COST="${F[7]:-0}" DUR_MS="${F[8]:-0}"
API_MS="${F[9]:-0}" TOK_IN="${F[10]:-0}" TOK_OUT="${F[11]:-0}"
CACHED="${F[12]:-0}" SID="${F[13]:-}" SNAME="${F[14]:-}"
H5_PCT="${F[15]:-}" H5_RESET="${F[16]:-}" D7_PCT="${F[17]:-}"
# ── Line 1: model, thinking, context, location ─────────────────────────────
L1="${BLUE}Model: ${MODEL}${RESET}"
if [[ -n "$EFFORT" ]]; then
L1+="${SEP}${RED}Thinking: ${EFFORT}${RESET}"
elif [[ "$THINKING" == "true" ]]; then
L1+="${SEP}${RED}Thinking: on${RESET}"
fi
PCT_I=$(int "$PCT")
if (( PCT_I >= 90 )); then CTX_COLOR="$RED"
elif (( PCT_I >= 70 )); then CTX_COLOR="$YELLOW"
else CTX_COLOR="$GREEN"
fi
L1+="${SEP}${CTX_COLOR}Context: [$(bar "$PCT_I" 10)] $(human "$TOK_TOTAL")/$(human "$CTX_SIZE") (${PCT_I}%)${RESET}"
# Fish-style path: ~ for home, every parent squashed to one character.
if [[ -n "$CWD" ]]; then
SHORT="${CWD/#$HOME/\~}"
IFS='/' read -r -a PARTS <<<"$SHORT"
LAST=$(( ${#PARTS[@]} - 1 ))
FISH=""
for i in "${!PARTS[@]}"; do
P="${PARTS[$i]}"
[[ -z "$P" ]] && continue
if (( i == LAST )); then FISH+="/${P}"
elif [[ "$P" == "~" ]]; then FISH+="~"
else FISH+="/${P:0:1}"
fi
done
[[ "$SHORT" == /* ]] || FISH="${FISH#/}"
L1+="${SEP}${GREY}cwd: ${FISH}${RESET}"
fi
if command -v git >/dev/null 2>&1 && git -C "${CWD:-.}" rev-parse --git-dir >/dev/null 2>&1; then
BRANCH=$(git -C "$CWD" branch --show-current 2>/dev/null)
[[ -z "$BRANCH" ]] && BRANCH=$(git -C "$CWD" rev-parse --short HEAD 2>/dev/null)
[[ -n "$BRANCH" ]] && L1+="${SEP}${PURPLE}⎇ ${BRANCH}${RESET}"
read -r ADDED REMOVED <<<"$(
git -C "$CWD" diff --numstat HEAD 2>/dev/null |
awk '$1 ~ /^[0-9]+$/ { a += $1 } $2 ~ /^[0-9]+$/ { r += $2 } END { print a+0, r+0 }'
)"
L1+="${SEP}${YELLOW}(+${ADDED:-0},-${REMOVED:-0})${RESET}"
fi
# ── Line 2: spend, quota, throughput ───────────────────────────────────────
L2="${GREEN}Cost: $(printf '$%.2f' "${COST:-0}")${RESET}"
if [[ -n "$H5_RESET" ]]; then
LEFT=$(( $(int "$H5_RESET") - $(date +%s) ))
# A five-hour window never has more than five hours left; anything larger is a
# stale or bogus timestamp, so drop it rather than render "2281018hr".
(( LEFT > 0 && LEFT <= 18000 )) && L2+="${SEP}${ORANGE}Block: $(dur "$LEFT")${RESET}"
fi
[[ -n "$D7_PCT" ]] && L2+="${SEP}${BLUE}Weekly: $(awk -v p="$D7_PCT" 'BEGIN { printf "%.1f", p }')%${RESET}"
L2+="${SEP}${CYAN}Session: $(dur $(( $(int "$DUR_MS") / 1000 )))${RESET}"
# Throughput, averaged over time actually spent inside API calls.
API_MS_I=$(int "$API_MS")
if (( API_MS_I > 0 )); then
L2+="${SEP}${CYAN}In: $(awk -v t="$TOK_IN" -v ms="$API_MS_I" 'BEGIN { printf "%.1f", t / (ms / 1000) }') t/s${RESET}"
L2+="${SEP}${BLUE}Out: $(awk -v t="$TOK_OUT" -v ms="$API_MS_I" 'BEGIN { printf "%.1f", t / (ms / 1000) }') t/s${RESET}"
fi
CACHED_I=$(int "$CACHED")
(( CACHED_I > 0 )) && L2+="${SEP}${DIM}Cached: $(human "$CACHED_I")${RESET}"
if [[ -n "$H5_PCT" ]]; then
L2+="${SEP}${PURPLE}Session: [$(bar "$(int "$H5_PCT")" 5)] $(awk -v p="$H5_PCT" 'BEGIN { printf "%.1f", p }')%${RESET}"
fi
# ── Line 3: ambience ───────────────────────────────────────────────────────
L3=""
# Weather, cached for ten minutes so the API sees at most six calls an hour.
if [[ -n "${OPENWEATHER_API_KEY:-}" ]] && command -v curl >/dev/null 2>&1; then
CITY="${OPENWEATHER_CITY:-London,GB}"
CACHE="${TMPDIR:-/tmp}/statusline_wx_$(printf '%s' "$CITY" | tr -c 'a-zA-Z0-9' '_')"
WX=""
if [[ -f "$CACHE" ]]; then
MTIME=$(stat -f %m "$CACHE" 2>/dev/null || stat -c %Y "$CACHE" 2>/dev/null || echo 0)
(( $(date +%s) - MTIME < 600 )) && WX=$(cat "$CACHE")
fi
if [[ -z "$WX" ]]; then
RESP=$(curl -fsS --max-time 3 \
"https://api.openweathermap.org/data/2.5/weather?q=${CITY}&appid=${OPENWEATHER_API_KEY}&units=metric" 2>/dev/null)
if [[ -n "$RESP" ]] && [[ "$(jq -r '.cod | tostring' <<<"$RESP" 2>/dev/null)" == "200" ]]; then
read -r TEMP FEELS WIND CODE <<<"$(
jq -r '[(.main.temp | round), (.main.feels_like | round), .wind.speed, .weather[0].id] | @tsv' <<<"$RESP"
)"
if (( CODE >= 200 && CODE < 300 )); then ICON="⛈"
elif (( CODE >= 300 && CODE < 500 )); then ICON="🌦"
elif (( CODE >= 500 && CODE < 600 )); then ICON="🌧"
elif (( CODE >= 600 && CODE < 700 )); then ICON="❄"
elif (( CODE >= 700 && CODE < 800 )); then ICON="🌫"
elif (( CODE == 800 )); then ICON="☀"
else ICON="☁"
fi
WX="${ICON} ${TEMP}°C feels ${FEELS}°C 💨$(awk -v w="$WIND" 'BEGIN { printf "%.1f", w }')m/s"
printf '%s' "$WX" >"$CACHE" 2>/dev/null
elif [[ -f "$CACHE" ]]; then
WX=$(cat "$CACHE")
fi
fi
[[ -n "$WX" ]] && L3+="${CYAN}${WX}${RESET}"
fi
# Free / total memory, read the native way on each platform.
read -r MEM_FREE MEM_TOTAL <<<"$(
if [[ -r /proc/meminfo ]]; then
awk '/^MemAvailable:/ { f = $2 } /^MemTotal:/ { t = $2 } END { print f / 1048576, t / 1048576 }' /proc/meminfo
elif command -v vm_stat >/dev/null 2>&1; then
TOTAL_B=$(sysctl -n hw.memsize 2>/dev/null || echo 0)
vm_stat | awk -v tb="$TOTAL_B" '
/page size of/ { match($0, /[0-9]+/); ps = substr($0, RSTART, RLENGTH) }
/Pages free/ || /Pages inactive/ { gsub(/\./, "", $NF); pages += $NF }
END { if (ps > 0) print pages * ps / 1073741824, tb / 1073741824 }'
fi
)"
if [[ -n "${MEM_TOTAL:-}" ]] && awk -v t="$MEM_TOTAL" 'BEGIN { exit !(t > 0) }'; then
[[ -n "$L3" ]] && L3+="$SEP"
L3+="${RED}Mem: $(awk -v f="$MEM_FREE" 'BEGIN { printf "%.1fG", f }')/$(awk -v t="$MEM_TOTAL" 'BEGIN { printf "%.1fG", t }')${RESET}"
fi
# A kaomoji that advances every second, so the bar always looks alive.
VIBES=(
'ヽ(⌐■_■)ノ♪' 'ᕦ(ò_óˇ)ᕤ' '(ノ◕ヮ◕)ノ*:・゚✧' '¯\_(ツ)_/¯' 'ʕ•ᴥ•ʔ'
'(╯°□°)╯︵ ┻━┻' '┬─┬ノ(º_ºノ)' '(☞゚ヮ゚)☞' 'ʕっ•ᴥ•ʔっ' '(•_•) ( •_•)>⌐■-■'
'ヾ(•ω•)o' '(づ。◕‿‿◕。)づ' '( ˘ω˘ )zzZ' '٩(◕‿◕。)۶' 'o(≧▽≦)o'
'(ò_ó)' 'щ(ಠ益ಠщ)' '∠( ᐛ 」∠)_' '(´。• ω •。)' 'ᕙ(⇀‸↼‶)ᕗ'
'(˵ ͡° ͜ʖ ͡°˵)' '╰(*°▽°*)╯' '(ง •_•)ง' '¿ⓧ_ⓧミ' '(*¯︶¯*)'
'ヽ(*・ω・)ノ' '(੭ˊ꒳ˋ)੭✧' 'ʕ·͡ˑ·ཻʔ' '(灬º‿º灬)♡' '( ͡~ ͜ʖ ͡°)'
'\(٥⁀▽⁀ )/' '(¬‿¬)' '(*^▽^)/' 'ヽ(´▽`)/' '( •_•)>⌐▪-▪'
'凸(¬‿¬)凸' '(ノ^_^)ノ' '~(>_<~)' '(ó﹏ò。)' '৲(͡ ˡ ͜ʖ ͡ˡ)৳'
'ʕ •ₒ• ʔ' '(っ˘ڡ˘ς)' '( ͡° ͜ʖ ͡°)╭∩╮' 'ᕦ(ò‸ó)ᕥ' '(*゚∀゚*)'
'(◕‿◕✿)' 'q(❂‿❂)p' '꒰˘̩̩̩⌣˘̩̩̩๑꒱♡' 'ヽ(͡◕ ͜ʖ ͡◕)ノ' '( ˶ˆᗜˆ˵ )'
)
FRAME=$(( (10#$(date +%M) * 60 + 10#$(date +%S)) % ${#VIBES[@]} ))
[[ -n "$L3" ]] && L3+="$SEP"
L3+="${GREY}${VIBES[$FRAME]}${RESET}"
[[ -n "$SNAME" ]] && L3+="${SEP}${PURPLE}${SNAME}${RESET}"
[[ -n "$SID" ]] && L3+="${SEP}${CYAN}Session ID: ${SID}${RESET}"
printf '%s\n%s\n%s\n' "$L1" "$L2" "$L3"
What it shows
- Model display name, labeled Model:
- Thinking effort when stdin includes effort.level
- Context window as a 10-cell bar, used and total tokens, and a percent
- Working directory shortened fish-style, with home as ~
- Git branch and (+added,-removed) counts when the directory is a repo
- Session cost in dollars
- Time left in the five-hour window, labeled Block, when a reset timestamp is present and at most five hours away
- Weekly quota as a percent
- Session duration
- Input and output token rates in t/s, averaged over API time
- Cached token count when cache-read tokens are above zero
- Five-hour usage as a 5-cell bar, also labeled Session
- Free and total memory
- A kaomoji that advances with the clock
- Session name, when Claude Code sends one
- The full session ID
- Opt-in weather (icon, C, feels-like, wind) from OpenWeatherMap when OPENWEATHER_API_KEY is set
Requirements
- bash
- jq on PATH; without it the status line prints a one-line error and exits 0
- git, optional, for branch and diff counts
- curl plus OPENWEATHER_API_KEY to show weather; OPENWEATHER_CITY defaults to London,GB
- Declared network host api.openweathermap.org, used only when the weather key is set
- A 24-bit color terminal for the One Dark RGB palette
- Writes a ten-minute weather cache under TMPDIR or /tmp
Behavior notes
- Always three lines: identity and context, spend and quota, then memory, a kaomoji, and the session ID
- A brand-new session still prints a zeroed context bar and $0.00, and drops Block, Weekly, Cached, and the five-hour Session bar because rate_limits are missing
- After compact, Thinking disappears (no effort field) and Weekly is omitted; the five-hour Block and Session bar remain
- Outside a git repo the branch and (+/-) counts vanish; a named session such as refactor-pass shows up on line 3
- Context color is green below 70%, yellow from 70, red from 90; the 91% preview went red and 64% stayed green
- Dirty feat/auth showed (+1,-0); clean main showed (+0,-0)
- The kaomoji is different in every preview because it is keyed off minute and second
- Weather never appeared in the sandbox previews; there is no OpenWeather key in that environment
- The worktree preview printed cwd: ~/./feature and branch worktree-feature
More status lines
Dreambase Panel
171 copies
╭─ CONTEXT ────────────────────────────────────────────╮
│ ████▊░░░░░░░░░░░░░░░░░ 22% of 200K · GOOD │
├─ STATS ──────────────────────────────────────────────┤
│ ↓ 44.0K ↑ 1.4K │ $0.41 │ ⏱ 10m 12s │ +128/-34 │
├─ REPO ───────────────────────────────────────────────┤
│ ◆ Opus 4.8 · main · 16:21 │
╰──────────────────────────────────────────────────────╯
Single-line usage
106 copies
app · main · Opus-4.8 · effort high · ctx 22% · 5h 26% ↻2h6m · 7d 7% ↻2d0hPace Dot Meters
72 copies
Opus 4.8 [high] ~/app main
16:20:55 | ⛁ ██░░░░░░░░ 22% | 5h ●◔○○○ 26% ↻2h7m | 7d ◔○○○○○○ 7% ↻2d1h │ $0.41 ⏱ 10m
Catppuccin Frappé
46 copies
Opus 4.8 │ main │ app │ ▓▓░░░░░░░░ 44k/200k │ $0.41
Activity Feed
43 copies
Opus 4.8 high ✦ │ ctx 22% │ app (main) │ PR #1287 ● │ $0.41 · 10m +128 -34
Session ● ● ● ● ● ● ● ● ○ ○ ○ 74% left Resets in 2h 6m
Weekly ● ● ● ● ● ● ● ● ● ● ○ 93% left Resets in 2d 0h
Fable ● ● ● ● ● ● ● ● ● ○ ○ 85% left Resets in 2d 0h
◐ Read:index.ts ✓ Read×1 ✓ Bash×1 ✓ Edit×1 ✓ Grep×1
◐ code-reviewer Review the change for regressions
Dreambase Flat
39 copies
████▊░░░░░░░░░░░░░░░░░ 22% of 200K · GOOD │ ↓ 44.0K ↑ 1.4K │ $0.41 │ ⏱ 10m 12s │ +128/-34 │ ◆ Opus 4.8 · main · 16:22