Skip to content

Instantly share code, notes, and snippets.

@patyearone
Last active February 13, 2026 01:56
Show Gist options
  • Select an option

  • Save patyearone/7c753ef536a49839c400efaf640e17de to your computer and use it in GitHub Desktop.

Select an option

Save patyearone/7c753ef536a49839c400efaf640e17de to your computer and use it in GitHub Desktop.
Claude Code Status Line: Usage Limits, Pacing Targets, and Context Window - Complete guide with all the gotchas

Claude Code Status Line: Usage Limits, Pacing Targets, and Context Window

A complete guide to building a Claude Code status line that shows your 5-hour and weekly usage limits with color-coded progress bars, pacing markers, reset times, and context window usage.

What you get:

yearone-3 main* │ Opus 4.6 │ 07:00 PM │ ctx ▓▓░░░░░░░░ 20% │ 5hr (11pm) ▓▓▓│░░░░░░ 37% │ wk (thu, 10am) ▓▓░│░░░░░░ 26%
  • Color-coded bars: green (<50%), yellow (50-80%), bright red (>80%)
  • Hot pink pacing marker showing where you should be for even usage across the window
  • Reset times so you know when your limits refill

Prerequisites

  • macOS (uses security keychain CLI and BSD date)
  • jq installed (brew install jq)
  • Claude Code with an active subscription (Max, Pro, etc.)

The Hard Part: Getting a Valid OAuth Token

The status line calls an undocumented Anthropic API (/api/oauth/usage) that requires an OAuth token with user:profile scope. Here's where it gets tricky.

How Claude Code stores credentials

Claude Code stores OAuth credentials in the macOS Keychain under the service name Claude Code-credentials. The entry contains JSON with a claudeAiOauth object that includes accessToken, refreshToken, expiresAt, and scopes.

Gotcha 1: The keychain token expires and CC doesn't refresh it

Claude Code refreshes its token in-memory but does not write the refreshed token back to the keychain. So the keychain entry can go stale (ours was expired for 7+ months while CC worked fine).

Fix: Delete the stale keychain entry and force CC to re-authenticate:

# Delete the stale entry
security delete-generic-password -s "Claude Code-credentials"

# Then fully quit ALL Claude Code instances and restart.
# CC will open a browser for OAuth login and write fresh credentials.

Gotcha 2: /login is NOT what you want

The /login slash command inside Claude Code is for MCP server authentication, not CC's own OAuth. Running it will overwrite the keychain entry with MCP OAuth data (just an mcpOAuth key) and wipe out your claudeAiOauth credentials.

If you accidentally did this, delete the keychain entry again and restart CC as above.

Gotcha 3: claude setup-token has the wrong scopes

claude setup-token generates a long-lived token, but it only has user:inference scope. The usage API requires user:profile scope. This token will return:

{"error": {"message": "OAuth token does not meet scope requirement user:profile"}}

Don't use setup-token for this purpose.

Gotcha 4: Refresh tokens are single-use

If you try to manually refresh the token using the OAuth endpoint, be aware that the refresh token is single-use. If you call the refresh endpoint and don't save the new access token, the refresh token is consumed and you'll need to delete the keychain entry and re-authenticate.

For reference, the refresh endpoint is:

POST https://api.anthropic.com/v1/oauth/token
Content-Type: application/json
{"grant_type": "refresh_token", "refresh_token": "...", "client_id": "9d1c250a-e61b-44d9-88ed-5944d1962f5e"}

Gotcha 5: Timezone handling on resets_at

The API returns timestamps in UTC (2026-02-07T23:59:59.771624+00:00). On macOS, when parsing with date -jf, you must use the -u flag to tell date the input is UTC, otherwise the pacing target calculation will be wrong:

# WRONG - interprets UTC time as local time
date -jf "%Y-%m-%dT%H:%M:%S" "2026-02-07T23:59:59" +%s

# CORRECT - treats input as UTC
date -juf "%Y-%m-%dT%H:%M:%S" "2026-02-07T23:59:59" +%s

Gotcha 6: printf chokes on ANSI escape codes in variables

If you build a string with ANSI color codes (\033[32m) and pass it to printf, the \ characters get interpreted as format specifiers and you'll get:

printf: `\': invalid format character

Use echo -e instead of printf for the final output line.

The Usage API

Endpoint: GET https://api.anthropic.com/api/oauth/usage

Headers:

Authorization: Bearer <oauth_access_token>
anthropic-beta: oauth-2025-04-20
Content-Type: application/json

Response:

{
  "five_hour": {
    "utilization": 37.0,
    "resets_at": "2026-02-08T04:59:59.000000+00:00"
  },
  "seven_day": {
    "utilization": 26.0,
    "resets_at": "2026-02-12T14:59:59.771647+00:00"
  },
  "seven_day_opus": null,
  "seven_day_sonnet": {
    "utilization": 1.0,
    "resets_at": "2026-02-13T20:59:59.771655+00:00"
  },
  "extra_usage": {
    "is_enabled": false,
    "monthly_limit": null,
    "used_credits": null,
    "utilization": null
  }
}
  • utilization is a percentage (0-100)
  • resets_at is when the window ends (UTC)
  • five_hour is a rolling 5-hour window
  • seven_day is a rolling 7-day window

Setup

Step 1: Create the status line script

Save this as ~/.claude/statusline-command.sh:

#!/bin/bash

# Read Claude Code context from stdin
input=$(cat)

# Extract information from Claude Code context
model_name=$(echo "$input" | jq -r '.model.display_name // "Claude"')
current_dir=$(echo "$input" | jq -r '.workspace.current_dir // ""')
output_style=$(echo "$input" | jq -r '.output_style.name // "default"')
context_pct=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)

# Get current working directory basename for display
if [ -n "$current_dir" ]; then
    dir_name=$(basename "$current_dir")
else
    dir_name=$(basename "$(pwd)")
fi

# Get git branch with dirty indicator
git_info=""
if git rev-parse --git-dir > /dev/null 2>&1; then
    branch=$(git branch --show-current 2>/dev/null || git rev-parse --short HEAD 2>/dev/null)
    if [ -n "$branch" ]; then
        if ! git diff --quiet || ! git diff --cached --quiet || [ -n "$(git ls-files --others --exclude-standard)" ]; then
            git_info=" ${branch}*"
        else
            git_info=" ${branch}"
        fi
    fi
fi

current_time=$(date '+%I:%M %p')

# --- Progress bar with optional pacing marker ---
# Usage: make_bar <pct> [target_pct] [ansi_color_code]
# The target marker shows where you'd be with perfectly even usage across the window.
# If your filled blocks are past the marker, you're ahead of pace (burning fast).
# If behind, you're pacing well.
make_bar() {
    local pct=$1 target=${2:-} color=${3:-} width=10
    local filled=$((pct * width / 100))
    [ "$filled" -gt "$width" ] && filled=$width
    local target_pos=-1
    if [ -n "$target" ] && [ "$target" -ge 0 ] 2>/dev/null && [ "$target" -le 100 ]; then
        target_pos=$((target * width / 100))
        [ "$target_pos" -gt "$width" ] && target_pos=$width
    fi
    local bar=""
    for ((i=0; i<width; i++)); do
        if [ "$i" -eq "$target_pos" ]; then
            # Hot pink pacing marker, then restore the bar color
            bar="${bar}\033[38;5;199m│\033[0m${color}"
        elif [ "$i" -lt "$filled" ]; then
            bar="${bar}"
        else
            bar="${bar}"
        fi
    done
    printf "%s" "$bar"
}

# Color thresholds: green < 50%, yellow 50-80%, bright red > 80%
color_for_pct() {
    local pct=$1
    if [ "$pct" -ge 80 ]; then
        printf "\033[91m"   # bright red
    elif [ "$pct" -ge 50 ]; then
        printf "\033[33m"   # yellow
    else
        printf "\033[32m"   # green
    fi
}

CTX_COLOR=$(color_for_pct "$context_pct")
CTX_BAR=$(make_bar "$context_pct" "" "$CTX_COLOR")

# --- Usage limits from Anthropic API ---
USAGE_CACHE="/tmp/claude-statusline-usage.json"
USAGE_CACHE_AGE=60  # seconds between API calls

fetch_usage() {
    local creds token response
    creds=$(security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null) || return 1
    token=$(echo "$creds" | jq -r '.claudeAiOauth.accessToken') || return 1
    [ -z "$token" ] || [ "$token" = "null" ] && return 1
    response=$(curl -s --max-time 3 "https://api.anthropic.com/api/oauth/usage" \
        -H "Authorization: Bearer $token" \
        -H "anthropic-beta: oauth-2025-04-20" \
        -H "Content-Type: application/json" 2>/dev/null) || return 1
    if echo "$response" | jq -e '.error' >/dev/null 2>&1; then
        return 1
    fi
    echo "$response" > "$USAGE_CACHE"
}

# Only call API if cache is stale or missing
if [ ! -f "$USAGE_CACHE" ] || [ $(($(date +%s) - $(stat -f%m "$USAGE_CACHE" 2>/dev/null || echo 0))) -gt $USAGE_CACHE_AGE ]; then
    fetch_usage 2>/dev/null
fi

# Parse cached data and calculate pacing targets
usage_5h=""
usage_7d=""
target_5h=""
target_7d=""
resets_5h_label=""
resets_7d_label=""

if [ -f "$USAGE_CACHE" ]; then
    usage_5h=$(jq -r '.five_hour.utilization // empty' "$USAGE_CACHE" 2>/dev/null | cut -d. -f1)
    usage_7d=$(jq -r '.seven_day.utilization // empty' "$USAGE_CACHE" 2>/dev/null | cut -d. -f1)

    NOW_EPOCH=$(date +%s)

    # 5-hour pacing target
    resets_5h=$(jq -r '.five_hour.resets_at // empty' "$USAGE_CACHE" 2>/dev/null)
    if [ -n "$resets_5h" ]; then
        # IMPORTANT: -u flag treats input as UTC (resets_at is always UTC)
        reset_epoch=$(date -juf "%Y-%m-%dT%H:%M:%S" "$(echo "$resets_5h" | cut -d. -f1 | sed 's/+.*//')" +%s 2>/dev/null || date -d "$resets_5h" +%s 2>/dev/null)
        if [ -n "$reset_epoch" ]; then
            window_secs=$((5 * 3600))
            start_epoch=$((reset_epoch - window_secs))
            elapsed=$((NOW_EPOCH - start_epoch))
            [ "$elapsed" -lt 0 ] && elapsed=0
            [ "$elapsed" -gt "$window_secs" ] && elapsed=$window_secs
            target_5h=$((elapsed * 100 / window_secs))
            resets_5h_label=$(date -r "$reset_epoch" '+%-l%p' | tr '[:upper:]' '[:lower:]' | tr -d ' ')
        fi
    fi

    # 7-day pacing target
    resets_7d=$(jq -r '.seven_day.resets_at // empty' "$USAGE_CACHE" 2>/dev/null)
    if [ -n "$resets_7d" ]; then
        reset_epoch=$(date -juf "%Y-%m-%dT%H:%M:%S" "$(echo "$resets_7d" | cut -d. -f1 | sed 's/+.*//')" +%s 2>/dev/null || date -d "$resets_7d" +%s 2>/dev/null)
        if [ -n "$reset_epoch" ]; then
            window_secs=$((7 * 86400))
            start_epoch=$((reset_epoch - window_secs))
            elapsed=$((NOW_EPOCH - start_epoch))
            [ "$elapsed" -lt 0 ] && elapsed=0
            [ "$elapsed" -gt "$window_secs" ] && elapsed=$window_secs
            target_7d=$((elapsed * 100 / window_secs))
            resets_7d_label=$(date -r "$reset_epoch" '+%a, %-l%p' | tr '[:upper:]' '[:lower:]' | sed 's/ //2')
        fi
    fi
fi

# Assemble usage segments
usage_parts=""
if [ -n "$usage_5h" ]; then
    U5_COLOR=$(color_for_pct "$usage_5h")
    U5_BAR=$(make_bar "$usage_5h" "$target_5h" "$U5_COLOR")
    reset_label=""
    [ -n "$resets_5h_label" ] && reset_label=" (${resets_5h_label})"
    usage_parts="${U5_COLOR}5hr${reset_label} ${U5_BAR} ${usage_5h}%\033[0m"
fi
if [ -n "$usage_7d" ]; then
    U7_COLOR=$(color_for_pct "$usage_7d")
    U7_BAR=$(make_bar "$usage_7d" "$target_7d" "$U7_COLOR")
    reset_7d_label_str=""
    [ -n "$resets_7d_label" ] && reset_7d_label_str=" (${resets_7d_label})"
    [ -n "$usage_parts" ] && usage_parts="${usage_parts}\033[2m │ \033[0m"
    usage_parts="${usage_parts}${U7_COLOR}wk${reset_7d_label_str} ${U7_BAR} ${usage_7d}%\033[0m"
fi

# Single line output using echo -e (NOT printf — printf chokes on ANSI codes in variables)
line="\033[2m\033[96m${dir_name}\033[0m\033[2m${git_info}${model_name}${current_time}${CTX_COLOR}ctx ${CTX_BAR} ${context_pct}%\033[0m"
if [ -n "$usage_parts" ]; then
    line="${line}\033[2m │ \033[0m${usage_parts}"
fi
echo -e "$line"

Step 2: Make it executable

chmod +x ~/.claude/statusline-command.sh

Step 3: Configure Claude Code

Add this to ~/.claude/settings.json:

{
  "statusLine": {
    "type": "command",
    "command": "bash ~/.claude/statusline-command.sh"
  }
}

Step 4: Ensure your keychain has a valid token

# Check if you have a valid token
security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null | jq '.claudeAiOauth.scopes'

You need ["user:inference", "user:profile"]. If the entry is missing, expired, or has wrong scopes:

# Delete stale entry
security delete-generic-password -s "Claude Code-credentials"

# Quit ALL Claude Code instances, then restart.
# CC opens a browser for OAuth — this creates a fresh keychain entry with correct scopes.

Step 5: Verify

# Test the script manually
echo '{"model":{"display_name":"Test"},"workspace":{"current_dir":"/tmp"},"context_window":{"used_percentage":42}}' \
  | bash ~/.claude/statusline-command.sh

Customization

Colors

The script uses ANSI 256-color codes. Change these to taste:

Element Current Code
Directory Light cyan \033[96m
Pacing marker Hot pink \033[38;5;199m
Good (<50%) Green \033[32m
Warning (50-80%) Yellow \033[33m
Danger (>80%) Bright red \033[91m

Dark red (\033[31m) is nearly invisible on dark terminal backgrounds. Use bright red (\033[91m) instead.

Bar width

Change width=10 in make_bar() to make bars wider or narrower.

Cache interval

Change USAGE_CACHE_AGE=60 to control how often the API is called (in seconds).

Available status line JSON fields

Claude Code pipes these fields to your script via stdin:

Field Description
model.display_name Current model name
model.id Model identifier
context_window.used_percentage Context window usage
context_window.total_input_tokens Cumulative input tokens
context_window.total_output_tokens Cumulative output tokens
cost.total_cost_usd Session cost
cost.total_duration_ms Total session time
cost.total_lines_added Lines added
cost.total_lines_removed Lines removed
workspace.current_dir Current directory
output_style.name Output style
vim.mode Vim mode (if enabled)

Linux adaptation

The script uses macOS-specific commands. For Linux:

  • Replace security find-generic-password ... with however you store credentials (e.g., secret-tool, a file, or an env var)
  • Replace date -juf with date -ud for UTC parsing
  • Replace stat -f%m with stat -c%Y for file modification time
  • Replace date -r $epoch with date -d @$epoch for epoch-to-human conversion

Troubleshooting

Quick diagnostic

Run this to check everything at once:

echo "=== 1. jq installed? ==="
which jq && jq --version || echo "MISSING: brew install jq"

echo -e "\n=== 2. Keychain entry exists? ==="
CREDS=$(security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null)
if [ -z "$CREDS" ]; then
    echo "MISSING: No keychain entry. Quit all CC instances and restart to trigger OAuth login."
else
    echo "Found keychain entry"
fi

echo -e "\n=== 3. Has claudeAiOauth? ==="
echo "$CREDS" | jq -e '.claudeAiOauth' >/dev/null 2>&1 \
    && echo "YES" \
    || echo "NO — keychain only has: $(echo "$CREDS" | jq -r 'keys | join(", ")'). Delete entry and restart CC."

echo -e "\n=== 4. Token scopes ==="
echo "$CREDS" | jq -r '.claudeAiOauth.scopes // ["none"] | join(", ")' 2>/dev/null
echo "(need: user:inference, user:profile)"

echo -e "\n=== 5. Token expired? ==="
EXPIRES=$(echo "$CREDS" | jq -r '.claudeAiOauth.expiresAt // 0' 2>/dev/null)
NOW_MS=$(($(date +%s) * 1000))
if [ "$EXPIRES" -gt "$NOW_MS" ] 2>/dev/null; then
    echo "VALID — expires $(date -r $((EXPIRES / 1000)))"
else
    echo "EXPIRED — delete keychain entry and restart CC"
fi

echo -e "\n=== 6. API test ==="
TOKEN=$(echo "$CREDS" | jq -r '.claudeAiOauth.accessToken // empty' 2>/dev/null)
if [ -n "$TOKEN" ]; then
    RESP=$(curl -s --max-time 5 "https://api.anthropic.com/api/oauth/usage" \
        -H "Authorization: Bearer $TOKEN" \
        -H "anthropic-beta: oauth-2025-04-20" \
        -H "Content-Type: application/json")
    if echo "$RESP" | jq -e '.five_hour' >/dev/null 2>&1; then
        echo "SUCCESS"
        echo "$RESP" | jq '{five_hour: .five_hour.utilization, seven_day: .seven_day.utilization}'
    else
        echo "FAILED: $(echo "$RESP" | jq -r '.error.message // "unknown error"')"
    fi
else
    echo "SKIPPED — no token"
fi

echo -e "\n=== 7. Script test ==="
echo '{"model":{"display_name":"Test"},"workspace":{"current_dir":"/tmp"},"context_window":{"used_percentage":42}}' \
    | bash ~/.claude/statusline-command.sh 2>&1 && echo -e "\n(exit: 0)" || echo -e "\n(exit: $?)"

Common issues

Problem Cause Fix
No status line at all Script crashes with non-zero exit Run the diagnostic above — step 7 shows the error
No usage data (only ctx shows) Keychain token expired or missing Run diagnostic steps 2-6, then delete entry + restart CC
Usage shows 0% with bar at far left Stale cache from a previous window rm /tmp/claude-statusline-usage.json to force a fresh fetch
Pacing marker at far left (wrong) UTC timezone not handled in date parsing Ensure -u flag: date -juf not date -jf
printf: invalid format character ANSI escape codes in printf variable Use echo -e for final output, not printf
Token scope error (user:profile) Used claude setup-token That token only has user:inference. Delete keychain entry, restart CC for browser OAuth
Keychain has only mcpOAuth key Ran /login inside CC /login is for MCP servers, not CC auth. Delete entry, restart CC
Status line wraps to next line Output too wide for terminal Shorten labels (wk not weekly), drop user@host, drop seconds from time
jq: command not found jq not installed brew install jq
Keychain access popup/prompt macOS asking permission Click "Always Allow" — the script reads keychain on every cache refresh
Usage data is stale / not updating Cache file not refreshing Check ls -la /tmp/claude-statusline-usage.json — if mod time is old, token is probably expired
Script works manually but not in CC disableAllHooks: true in settings Remove that setting from ~/.claude/settings.json
Git branch slow in large repos git diff and git ls-files scanning Cache git info to a file with a 5-second TTL

The nuclear option

If nothing works, start completely fresh:

# 1. Delete keychain entry
security delete-generic-password -s "Claude Code-credentials" 2>/dev/null

# 2. Delete stale cache
rm -f /tmp/claude-statusline-usage.json

# 3. Quit ALL Claude Code instances (all terminals)
# Cmd+Q or `killall claude` if desperate

# 4. Restart Claude Code
# It will open a browser for OAuth login
# This creates a fresh keychain entry with user:inference + user:profile scopes

# 5. Verify
security find-generic-password -s "Claude Code-credentials" -w | jq '.claudeAiOauth.scopes'
# Should output: ["user:inference", "user:profile"]

Credits

  • Usage API endpoint discovered via codelynx.dev
  • OAuth client ID and refresh flow reverse-engineered from the Claude Code binary
  • Context window calculation inspired by Richard-Weiss/ffadccca6238
#!/bin/bash
# Read Claude Code context from stdin
input=$(cat)
# Extract information from Claude Code context
model_name=$(echo "$input" | jq -r '.model.display_name // "Claude"')
current_dir=$(echo "$input" | jq -r '.workspace.current_dir // ""')
output_style=$(echo "$input" | jq -r '.output_style.name // "default"')
context_pct=$(echo "$input" | jq -r '.context_window.used_percentage // 0' | cut -d. -f1)
# Get username and hostname
user=$(whoami)
host=$(hostname -s)
# Get current working directory basename for display
if [ -n "$current_dir" ]; then
dir_name=$(basename "$current_dir")
else
dir_name=$(basename "$(pwd)")
fi
# Get git status if we're in a git repo
git_info=""
if git rev-parse --git-dir > /dev/null 2>&1; then
branch=$(git branch --show-current 2>/dev/null || git rev-parse --short HEAD 2>/dev/null)
if [ -n "$branch" ]; then
if ! git diff --quiet || ! git diff --cached --quiet || [ -n "$(git ls-files --others --exclude-standard)" ]; then
git_info=" ${branch}*"
else
git_info=" ${branch}"
fi
fi
fi
# Get current time in 12-hour format (no seconds)
current_time=$(date '+%I:%M %p')
# Bar with optional target marker (│) showing where even pacing would be
# Usage: make_bar <pct> [target_pct] [color_code]
make_bar() {
local pct=$1 target=${2:-} color=${3:-} width=10
local filled=$((pct * width / 100))
[ "$filled" -gt "$width" ] && filled=$width
local target_pos=-1
if [ -n "$target" ] && [ "$target" -ge 0 ] 2>/dev/null && [ "$target" -le 100 ]; then
target_pos=$((target * width / 100))
[ "$target_pos" -gt "$width" ] && target_pos=$width
fi
local bar=""
for ((i=0; i<width; i++)); do
if [ "$i" -eq "$target_pos" ]; then
bar="${bar}\033[38;5;199m│\033[0m${color}"
elif [ "$i" -lt "$filled" ]; then
bar="${bar}"
else
bar="${bar}"
fi
done
printf "%s" "$bar"
}
color_for_pct() {
local pct=$1
if [ "$pct" -ge 80 ]; then
printf "\033[91m" # bright red
elif [ "$pct" -ge 50 ]; then
printf "\033[33m" # yellow
else
printf "\033[32m" # green
fi
}
CTX_COLOR=$(color_for_pct "$context_pct")
CTX_BAR=$(make_bar "$context_pct" "" "$CTX_COLOR")
# --- Usage limits (5-hour and 7-day) from Anthropic API ---
USAGE_CACHE="/tmp/claude-statusline-usage.json"
USAGE_CACHE_AGE=60 # refresh every 60 seconds
fetch_usage() {
local creds token response
creds=$(security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null) || return 1
token=$(echo "$creds" | jq -r '.claudeAiOauth.accessToken') || return 1
[ -z "$token" ] || [ "$token" = "null" ] && return 1
response=$(curl -s --max-time 3 "https://api.anthropic.com/api/oauth/usage" \
-H "Authorization: Bearer $token" \
-H "anthropic-beta: oauth-2025-04-20" \
-H "Content-Type: application/json" 2>/dev/null) || return 1
# Check for errors
if echo "$response" | jq -e '.error' >/dev/null 2>&1; then
return 1
fi
echo "$response" > "$USAGE_CACHE"
}
# Refresh cache if stale or missing
if [ ! -f "$USAGE_CACHE" ] || [ $(($(date +%s) - $(stat -f%m "$USAGE_CACHE" 2>/dev/null || echo 0))) -gt $USAGE_CACHE_AGE ]; then
fetch_usage 2>/dev/null
fi
# Read cached usage data and calculate pacing targets
usage_5h=""
usage_7d=""
target_5h=""
target_7d=""
if [ -f "$USAGE_CACHE" ]; then
usage_5h=$(jq -r '.five_hour.utilization // empty' "$USAGE_CACHE" 2>/dev/null | cut -d. -f1)
usage_7d=$(jq -r '.seven_day.utilization // empty' "$USAGE_CACHE" 2>/dev/null | cut -d. -f1)
# Calculate pacing targets: how far through each window are we?
NOW_EPOCH=$(date +%s)
# 5-hour window target
resets_5h=$(jq -r '.five_hour.resets_at // empty' "$USAGE_CACHE" 2>/dev/null)
if [ -n "$resets_5h" ]; then
reset_epoch=$(date -juf "%Y-%m-%dT%H:%M:%S" "$(echo "$resets_5h" | cut -d. -f1 | sed 's/+.*//')" +%s 2>/dev/null || date -d "$resets_5h" +%s 2>/dev/null)
if [ -n "$reset_epoch" ]; then
window_secs=$((5 * 3600))
start_epoch=$((reset_epoch - window_secs))
elapsed=$((NOW_EPOCH - start_epoch))
[ "$elapsed" -lt 0 ] && elapsed=0
[ "$elapsed" -gt "$window_secs" ] && elapsed=$window_secs
target_5h=$((elapsed * 100 / window_secs))
resets_5h_label=$(date -r "$reset_epoch" '+%-l%p' | tr '[:upper:]' '[:lower:]' | tr -d ' ')
fi
fi
# 7-day window target
resets_7d=$(jq -r '.seven_day.resets_at // empty' "$USAGE_CACHE" 2>/dev/null)
if [ -n "$resets_7d" ]; then
reset_epoch=$(date -juf "%Y-%m-%dT%H:%M:%S" "$(echo "$resets_7d" | cut -d. -f1 | sed 's/+.*//')" +%s 2>/dev/null || date -d "$resets_7d" +%s 2>/dev/null)
if [ -n "$reset_epoch" ]; then
window_secs=$((7 * 86400))
start_epoch=$((reset_epoch - window_secs))
elapsed=$((NOW_EPOCH - start_epoch))
[ "$elapsed" -lt 0 ] && elapsed=0
[ "$elapsed" -gt "$window_secs" ] && elapsed=$window_secs
target_7d=$((elapsed * 100 / window_secs))
resets_7d_label=$(date -r "$reset_epoch" '+%a, %-l%p' | tr '[:upper:]' '[:lower:]' | sed 's/ //2')
fi
fi
fi
# Build usage parts
usage_parts=""
if [ -n "$usage_5h" ]; then
U5_COLOR=$(color_for_pct "$usage_5h")
U5_BAR=$(make_bar "$usage_5h" "$target_5h" "$U5_COLOR")
reset_label=""
[ -n "$resets_5h_label" ] && reset_label=" (${resets_5h_label})"
usage_parts="${U5_COLOR}5hr${reset_label} ${U5_BAR} ${usage_5h}%\033[0m"
fi
if [ -n "$usage_7d" ]; then
U7_COLOR=$(color_for_pct "$usage_7d")
U7_BAR=$(make_bar "$usage_7d" "$target_7d" "$U7_COLOR")
reset_7d_label_str=""
[ -n "$resets_7d_label" ] && reset_7d_label_str=" (${resets_7d_label})"
[ -n "$usage_parts" ] && usage_parts="${usage_parts}\033[2m │ \033[0m"
usage_parts="${usage_parts}${U7_COLOR}wk${reset_7d_label_str} ${U7_BAR} ${usage_7d}%\033[0m"
fi
# Single line output
line="\033[2m\033[96m${dir_name}\033[0m\033[2m${git_info}${model_name}${current_time}${CTX_COLOR}ctx ${CTX_BAR} ${context_pct}%\033[0m"
if [ -n "$usage_parts" ]; then
line="${line}\033[2m │ \033[0m${usage_parts}"
fi
echo -e "$line"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment