Catppuccin Frappé

Catppuccin Frappé–themed status line with model, git branch and dirty flag, folder, a block context bar, and session cost. Source: github.com/danjdewhurst/cc-status-line

Before you install

  • This version was reviewed before it was listed on Jun 29, 2026
  • Doesn't ask to connect to the internet
  • Needs jq and git. The palette uses 24-bit color, so your terminal needs true color support.
  • With no context percentage, as right after /compact, the cost slot reads $0.00 even when cost is higher.
  • Set CURRENCY_CODE to anything but USD and it fetches rates from api.frankfurter.app, cached for 24 hours.
Not showing after you paste? Fix it

Preview

Clean repo
Opus 4.8 │ main │ app │ ▓▓░░░░░░░░ 44k/200k │ $0.41
New session
Opus 4.8 │ main │ app │ ░░░░░░░░░░ 0k/200k │ $0.00
Dirty branch
Sonnet 4.6 │ feat/auth● │ app │ ▓▓▓▓░░░░░░ 96k/200k │ $0.41
Near-full
Opus 4.8 │ main │ app │ ▓▓▓▓▓▓▓▓▓░ 182k/200k │ $4.12
1M context
Fable 5 │ main │ app │ ▓▓▓▓▓▓░░░░ 640k/1000k │ $0.41
Post-compact
Haiku 4.5 │ main │ app │ ░░░░░░░░░░ 0k/200k │ $0.00
Worktree
Opus 4.8 │ worktree-feature │ feature │ ▓▓▓░░░░░░░ 74k/200k │ $0.41
Non-git
Opus 4.8 │ scratch │ ▓▓░░░░░░░░ 44k/200k │ $0.41

In Claude Desktop

Catppuccin Frappé in Claude Desktop

Recorded with statusline-anywhere.

What it does

A Catppuccin Frappé themed line with the model, git branch and a dirty dot, the folder, a 10-block context bar with tokens used, and the session cost.

Written in
Bash
Network access
None requested
Works in
Terminal

How it works

  1. Reads model, folder, window size, context percentage and cost in one jq call.
  2. Gets the branch from git, cut to 20 characters, plus ● for uncommitted changes.
  3. Fills one block per 10% of context and turns the bar from blue to red above 60%.
  4. Ends with the version from claude --version if that command is installed.

Source

#!/bin/bash

# Status line - model, git branch, cwd, context usage, cost
# Catppuccin Frappe theme

# Configuration
CURRENCY='$'              # Currency symbol (e.g., '$', '€', '£', '¥')
CURRENCY_CODE='USD'       # ISO 4217 code for API lookup (e.g., 'USD', 'GBP', 'EUR', 'JPY')
EXCHANGE_RATE=1           # Fallback rate if API unavailable

# Cache settings
CACHE_DIR="${HOME}/.cache/cc-status-line"
CACHE_FILE="${CACHE_DIR}/exchange-rate.json"
CACHE_MAX_AGE=86400       # 24 hours in seconds

# Get exchange rate (from cache or API)
get_exchange_rate() {
    # Use fallback if no currency code set or set to USD
    [ -z "$CURRENCY_CODE" ] || [ "$CURRENCY_CODE" = "USD" ] && echo "1" && return

    # Check if cache exists and is fresh
    if [ -f "$CACHE_FILE" ]; then
        cache_age=$(( $(date +%s) - $(stat -c %Y "$CACHE_FILE" 2>/dev/null || stat -f %m "$CACHE_FILE" 2>/dev/null || echo 0) ))
        if [ "$cache_age" -lt "$CACHE_MAX_AGE" ]; then
            cached_rate=$(jq -r --arg code "$CURRENCY_CODE" '.rates[$code] // empty' "$CACHE_FILE" 2>/dev/null)
            [ -n "$cached_rate" ] && echo "$cached_rate" && return
        fi
    fi

    # Fetch fresh rate (in background to avoid blocking)
    mkdir -p "$CACHE_DIR"
    rate=$(curl -sf --max-time 2 "https://api.frankfurter.app/latest?from=USD&to=${CURRENCY_CODE}" 2>/dev/null)
    if [ -n "$rate" ]; then
        echo "$rate" > "$CACHE_FILE"
        jq -r --arg code "$CURRENCY_CODE" '.rates[$code] // empty' <<< "$rate" 2>/dev/null && return
    fi

    # Fallback to configured rate
    echo "$EXCHANGE_RATE"
}

data=$(cat)

# Single jq call - extract all values at once (tab-separated)
IFS=$'\t' read -r model cwd max_ctx used_pct cost_usd <<< "$(echo "$data" | jq -r '[
    (.model.display_name // .model.id // "unknown"),
    (.workspace.current_dir // ""),
    (.context_window.context_window_size // 200000),
    (.context_window.used_percentage // ""),
    (.cost.total_cost_usd // 0)
] | @tsv')"

# Get Claude Code version
cc_version=$(claude --version 2>/dev/null | awk '{print $1}')

# Folder name from path
folder="${cwd##*/}"
[ -z "$folder" ] && folder="?"

# Git: branch + dirty status (fast combined check)
branch=""
dirty=""
if git rev-parse --git-dir > /dev/null 2>&1; then
    branch=$(git branch --show-current 2>/dev/null)
    [ -z "$branch" ] && branch=$(git rev-parse --short HEAD 2>/dev/null)

    # Truncate long branches (max 20 chars)
    if [ "${#branch}" -gt 20 ]; then
        branch="${branch:0:19}…"
    fi

    # Check for uncommitted changes (fast: just check if output exists)
    if [ -n "$(git status --porcelain 2>/dev/null | head -1)" ]; then
        dirty="●"
    fi
fi

# Catppuccin Frappe colors (24-bit true color)
BLUE='\033[38;2;140;170;238m'      # Blue - context bar (low)
RED='\033[38;2;231;130;132m'       # Red - context bar (high)
TEAL='\033[38;2;129;200;190m'      # Teal - folder
MAUVE='\033[38;2;202;158;230m'     # Mauve - git branch
LAVENDER='\033[38;2;186;187;241m'  # Lavender - model
PEACH='\033[38;2;239;159;118m'     # Peach - dirty indicator
GREEN='\033[38;2;166;209;137m'     # Green - cost
OVERLAY='\033[38;2;115;121;148m'   # Overlay 0 - separators
SUBTEXT='\033[38;2;165;173;206m'   # Subtext 0 - secondary text
RESET='\033[0m'

# Format context bar
if [ -z "$used_pct" ] || [ "$used_pct" = "null" ]; then
    context_info="${OVERLAY}░░░░░░░░░░${RESET}"
else
    pct=$(printf "%.0f" "$used_pct" 2>/dev/null || echo "$used_pct")
    [ "$pct" -gt 100 ] 2>/dev/null && pct=100

    # Calculate tokens in k
    used_k=$(( max_ctx * pct / 100 / 1000 ))
    max_k=$(( max_ctx / 1000 ))

    # Build block bar (10 segments)
    filled=$(( pct / 10 ))

    # Blue by default, red when > 60%
    [ "$pct" -gt 60 ] && COLOR="$RED" || COLOR="$BLUE"

    bar=""
    for i in 0 1 2 3 4 5 6 7 8 9; do
        if [ "$i" -lt "$filled" ]; then
            bar="${bar}${COLOR}▓${RESET}"
        else
            bar="${bar}${OVERLAY}░${RESET}"
        fi
    done

    context_info="${bar} ${SUBTEXT}${used_k}k/${max_k}k${RESET}"
fi

# Format cost (convert from USD using exchange rate)
if [ -n "$cost_usd" ] && [ "$cost_usd" != "0" ] && [ "$cost_usd" != "null" ]; then
    rate=$(get_exchange_rate)
    cost_converted=$(echo "$cost_usd * $rate" | bc -l 2>/dev/null || echo "$cost_usd")
    cost_fmt=$(printf "%.2f" "$cost_converted" 2>/dev/null || echo "0.00")
    cost_display="${GREEN}${CURRENCY}${cost_fmt}${RESET}"
else
    cost_display="${OVERLAY}${CURRENCY}0.00${RESET}"
fi

# Build output
output="${LAVENDER}${model}${RESET}"

if [ -n "$branch" ]; then
    output="${output} ${OVERLAY}│${RESET} ${MAUVE}${branch}${RESET}"
    [ -n "$dirty" ] && output="${output}${PEACH}${dirty}${RESET}"
fi

output="${output} ${OVERLAY}│${RESET} ${TEAL}${folder}${RESET}"
output="${output} ${OVERLAY}│${RESET} ${context_info}"
output="${output} ${OVERLAY}│${RESET} ${cost_display}"

# Append version segment
if [ -n "$cc_version" ]; then
    output="${output} ${OVERLAY}│${RESET} ${SUBTEXT}v${cc_version}${RESET}"
fi

printf '%b\n' "$output"

Badge for your README

Own this listing? Add it to your README. The badge shows the install count as it grows.

Reviewed on statuslin.es
[![Reviewed on statuslin.es](https://staging.statuslin.es/badge/c/catppuccin-frapp-7670ff73.svg)](https://staging.statuslin.es/c/catppuccin-frapp-7670ff73?utm_source=readme-badge)

Or show the preview card:

Preview on statuslin.es
[![Preview on statuslin.es](https://staging.statuslin.es/og/c/catppuccin-frapp-7670ff73.png)](https://staging.statuslin.es/c/catppuccin-frapp-7670ff73?utm_source=readme-badge)

More status lines

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
Opus 4.8 │ ✍️ 78% │ app (main) │ +128/-34 Cost $0.4100 Tokens in 44.0k │ cache write 5000 │ cache read 2000 │ out 1.4k
Opus 4.8 │ ✍️ 22% │ app (main) │ ● high current ●●○○○○○○○○ 26% ⟳ 3:35pm weekly ○○○○○○○○○○ 7% ⟳ oct 20, 2:28pm

Related mods

⎿ cache-tax: keepwarm on for 6h00m, a ping 50m after each idle stretch keeps the cache read, not re-written ⎿ cache-tax: claude-opus-5-5 state warm, 1h00m left context 44,000 tokens cold cost $0.35 to re-write it (warm turn $0.01) keepwarm on, 6h00m left · ping in 50m break-even up to 40 pings at the read rate cost one cold write, about 33h20m of idle at one ping per 50m guard ask first (/cache-tax guard warn to only show the price) session 0 cold writes paid, $0.00 [>] cache-tax · warm · keepwarm 6h00m left · ping in 50m [-]

A Claude Code mod that keeps the one-hour prompt cache warm during breaks and asks before a cold send, showing its estimated rewrite cost. Warming uses model requests and costs tokens. Requires Claude Code 2.1.287+.

Deck in Claude Desktop

A cockpit for Claude Code: plan bars and subagent strips, context, usage limits with reset countdowns and burn rates, spend, the model route and a pet. Six bar styles, three collapsed looks. CLI and Desktop.

Flightdeck in Claude Desktop

Flightdeck: a live agent dashboard for Claude Code. Main model vitals, an on-call architect, every permission check, subagent cards and swimlanes, a turn receipt and a session log, all from real session events