Fix Fable usage anxiety by adding a daily target to your status bar
I’ve been underusing Fable for fear of hitting the weekly quota on day 5, and then facing some “this really needs Fable” tasks on day 6 or 7.
Soon I’ll just get another Max plan. Meantime, I’ve fixed this with a status-line upgrade. It shows a daily target: the % of my weekly quota I can spend, assuming an even seven-day burn.

Using 15% per day—and more if previous days undershot—now becomes a target. So I’m using Fable a bunch more.
The code:
~/.claude/settings.json:
"statusLine": {
"type": "command",
"command": "bash ~/.claude/scripts/statusline-command.sh"
}
~/.claude/scripts/statusline-command.sh:
#!/usr/bin/env bash
# Status line command for Claude Code
# Displays: model | cwd | 5h usage | 7d usage+pace | Fable usage+pace
input=$(cat)
# Model name
model=$(echo "$input" | jq -r '.model.display_name // empty')
# Working directory (strip /Users/ prefix and ph/Documents/ for brevity)
full_cwd=$(echo "$input" | jq -r '.workspace.current_dir')
cwd=$(echo "$full_cwd" | sed -e 's|^/Users/||' -e 's|ph/Documents/||' -e 's|www/_try/|_try/|')
# Pace helper: given %-used and window-reset epoch, print "pace N% <delta>"
# Weekly budget target: cumulative % of quota you'd have used by now at an
# even 1/7-per-day burn. Shared by the all-models and model-scoped windows
# (same 7-day window). Usage figures are coloured green/red against it.
target_pct() {
awk -v now="$(date +%s)" -v reset="$1" 'BEGIN {
elapsed = (now - (reset - 604800)) / 86400
if (elapsed < 0) elapsed = 0
if (elapsed > 7) elapsed = 7
printf "%.0f", elapsed * 100 / 7
}'
}
# colour_pct USED TARGET -> USED% coloured green (at/under target) or red (over)
colour_pct() {
awk -v used="$1" -v target="$2" 'BEGIN {
colour = (used > target + 0.5) ? 31 : 32
printf "\033[%dm%.0f%%\033[0m", colour, used
}'
}
# Usage limits (server-side, piped in via stdin JSON)
# 5-hour session window: show % used + reset time (HH:MM local)
five_pct=$(echo "$input" | jq -r '.rate_limits.five_hour.used_percentage // empty')
five_reset=$(echo "$input" | jq -r '.rate_limits.five_hour.resets_at // empty')
five_seg=""
if [ -n "$five_pct" ]; then
five_seg="5h $(printf '%.0f' "$five_pct")%"
if [ -n "$five_reset" ]; then
five_seg="$five_seg (r: $(date -r "$five_reset" '+%H:%M' 2>/dev/null))"
fi
fi
# 7-day window (all models): % used, coloured against the shared target.
# The target itself is printed once, on the last segment that has one.
week_pct=$(echo "$input" | jq -r '.rate_limits.seven_day.used_percentage // empty')
week_reset=$(echo "$input" | jq -r '.rate_limits.seven_day.resets_at // empty')
week_target=""
[ -n "$week_reset" ] && week_target=$(target_pct "$week_reset")
week_seg=""
if [ -n "$week_pct" ]; then
if [ -n "$week_target" ]; then
week_seg="7d $(colour_pct "$week_pct" "$week_target")"
else
week_seg="7d $(printf '%.0f' "$week_pct")%"
fi
fi
# Model-scoped weekly limit (e.g. Fable): not in the stdin JSON, so fetch from
# the OAuth usage endpoint (same data as /usage), cached for 5 minutes.
usage_cache="$HOME/.cache/claude-statusline/usage.json"
now_epoch=$(date +%s)
cache_mtime=$(stat -f %m "$usage_cache" 2>/dev/null || echo 0)
if [ $((now_epoch - cache_mtime)) -gt 300 ]; then
mkdir -p "${usage_cache%/*}"
tok=$(security find-generic-password -s "Claude Code-credentials" -w 2>/dev/null | jq -r '.claudeAiOauth.accessToken // empty')
fetched=0
if [ -n "$tok" ]; then
if curl -s --max-time 3 https://api.anthropic.com/api/oauth/usage \
-H "Authorization: Bearer $tok" -H "anthropic-beta: oauth-2025-04-20" \
-o "$usage_cache.tmp" 2>/dev/null \
&& jq -e '.limits' "$usage_cache.tmp" >/dev/null 2>&1; then
mv "$usage_cache.tmp" "$usage_cache"
fetched=1
fi
rm -f "$usage_cache.tmp"
fi
# On failure, bump mtime so the TTL still gates retries (keeps stale data).
[ "$fetched" = 0 ] && touch "$usage_cache" 2>/dev/null
fi
fable_seg=""
if [ -s "$usage_cache" ]; then
scoped=$(jq -r '[.limits[]? | select(.kind == "weekly_scoped" and .scope.model.display_name != null)][0] | if . == null then empty else "\(.scope.model.display_name)\t\(.percent)\t\(.resets_at)" end' "$usage_cache" 2>/dev/null)
if [ -n "$scoped" ]; then
scoped_name=$(printf '%s' "$scoped" | cut -f1)
scoped_pct=$(printf '%s' "$scoped" | cut -f2)
scoped_iso=$(printf '%s' "$scoped" | cut -f3)
scoped_reset=$(date -j -u -f "%Y-%m-%dT%H:%M:%S" "${scoped_iso%%.*}" +%s 2>/dev/null)
scoped_target="$week_target"
[ -z "$scoped_target" ] && [ -n "$scoped_reset" ] && scoped_target=$(target_pct "$scoped_reset")
if [ -n "$scoped_target" ]; then
fable_seg="$scoped_name $(colour_pct "$scoped_pct" "$scoped_target") (t: ${scoped_target}%)"
else
fable_seg="$scoped_name $(printf '%.0f' "$scoped_pct")%"
fi
fi
fi
# Combine: "7d X% Fable X% (t: X%) (r: Tue)"
weekly_seg=""
if [ -n "$week_seg" ] && [ -n "$fable_seg" ]; then
weekly_seg="$week_seg $fable_seg"
else
weekly_seg="$week_seg$fable_seg"
fi
# No scoped segment carried the target, so put it back on the 7d one.
if [ -n "$weekly_seg" ] && [ -n "$week_target" ] && [ -z "$scoped_target" ]; then
weekly_seg="$weekly_seg (t: ${week_target}%)"
fi
if [ -n "$weekly_seg" ] && [ -n "$week_reset" ]; then
reset_fmt='+%a'
seconds_until_reset=$((week_reset - now_epoch))
if [ "$seconds_until_reset" -ge 0 ] && [ "$seconds_until_reset" -lt 172800 ]; then
reset_fmt='+%a %H:%M'
fi
reset_at=$(date -r "$week_reset" "$reset_fmt" 2>/dev/null)
[ -n "$reset_at" ] && weekly_seg="$weekly_seg (r: $reset_at)"
fi
# Build status line
parts=()
[ -n "$model" ] && parts+=("$model")
parts+=("$cwd")
[ -n "$five_seg" ] && parts+=("$five_seg")
[ -n "$weekly_seg" ] && parts+=("$weekly_seg")
# Join with " | "
result=""
for part in "${parts[@]}"; do
[ -n "$result" ] && result="$result | "
result="$result$part"
done
printf "%s" "$result"
