
Status line Claude Code : afficher sa consommation API en temps réel
Le problème : combien de quota reste-t-il vraiment ?
Claude Code n'offre aucune visibilité sur la consommation. On lance une session, on discute trente minutes, et « Limite d'utilisation atteinte » tombe sans prévenir.
L'objectif : une vue temps réel — modèle actuel, contexte utilisé, limites 5h et 7j, temps avant reset — dans une status line en bas du terminal.
Architecture
Claude Code a une feature statusLine qui exécute une commande shell custom. Cette commande reçoit du JSON en stdin (session, contexte, modèle), peut appeler l'API Anthropic pour la vraie consommation, et retourne du texte ANSI coloré.
Dans ~/.claude/settings.json :
{
"statusLine": {
"type": "command",
"command": "~/.claude/statusline.sh",
"padding": 0
}
}
type: "command" exécute un script shell (pas du texte statique), command pointe le script (à rendre exécutable avec chmod +x), et padding: 0 supprime l'espace supplémentaire.
Le script
#!/bin/bash
# Status line script pour Claude Code
# Affiche : modèle + contexte + API usage en temps réel
# Reçoit les données en JSON sur stdin
CACHE_FILE="$HOME/.claude/usage_cache.json"
CACHE_TTL=600 # 10 minutes (l'API a un rate limit strict)
# Couleurs ANSI
INDIGO="\033[38;5;54m"
CYAN="\033[38;5;51m"
VIOLET="\033[38;5;141m"
MAGENTA="\033[38;5;201m"
RESET="\033[0m"
BOLD="\033[1m"
# Lire les données JSON depuis stdin
input=$(cat)
model=$(echo "$input" | jq -r '.model.display_name // "Unknown"')
context_pct=$(echo "$input" | jq -r '.context_window.used_percentage // 0')
work_dir=$(echo "$input" | jq -r '.workspace.current_dir // "~"' | xargs basename)
# Fonction : retourner la couleur selon le pourcentage
get_color() {
local pct=$1
if (( $(echo "$pct < 50" | bc -l) )); then
echo -e "$CYAN"
elif (( $(echo "$pct < 80" | bc -l) )); then
echo -e "$VIOLET"
else
echo -e "$MAGENTA"
fi
}
# Fonction : afficher une barre de progression (5 blocs, 20% par bloc)
progress_bar() {
local pct=$1
local blocks=5
local filled=$(( pct / 20 ))
[[ $filled -gt $blocks ]] && filled=$blocks
local bar=""
for (( i=0; i<filled; i++ )); do
bar+="▰"
done
for (( i=filled; i<blocks; i++ )); do
bar+="▱"
done
echo "$bar"
}
# Fonction : formatter l'heure
format_time() {
local seconds=$1
local hours=$(( seconds / 3600 ))
local minutes=$(( (seconds % 3600) / 60 ))
echo "${hours}h${minutes}m"
}
# Fonction : récupérer l'usage API
get_api_usage() {
# Vérifier le cache (basé sur le timestamp dans le JSON)
if [[ -f "$CACHE_FILE" ]]; then
local cache_time=$(jq -r '.timestamp // 0' "$CACHE_FILE" 2>/dev/null)
local cache_age=$(( $(date +%s) - cache_time ))
if [[ $cache_age -lt $CACHE_TTL ]]; then
cat "$CACHE_FILE"
return 0
fi
fi
# Token OAuth généré par Claude Code à la connexion
local token=$(jq -r '.claudeAiOauth.accessToken // empty' "$HOME/.claude/.credentials.json" 2>/dev/null)
if [[ -z "$token" ]]; then
echo '{"five_hour": 0, "seven_day": 0, "reset_time": ""}'
return 1
fi
# Vérifier le code HTTP pour détecter les erreurs (429, 401, etc.)
local http_response=$(curl -s -w "\n%{http_code}" --max-time 5 \
-H "Authorization: Bearer $token" \
-H "anthropic-beta: oauth-2025-04-20" \
"https://api.anthropic.com/api/oauth/usage" 2>/dev/null)
local http_code=$(echo "$http_response" | tail -1)
local response=$(echo "$http_response" | sed '$d')
if [[ "$http_code" != "200" ]] || [[ -z "$response" ]]; then
# Erreur API (rate limit, etc.) : réutiliser l'ancien cache
if [[ -f "$CACHE_FILE" ]]; then
# Prolonger le TTL pour éviter de re-tenter trop vite
local old_data=$(cat "$CACHE_FILE")
echo "$old_data" | jq --arg ts "$(date +%s)" '.timestamp = ($ts | tonumber)' > "$CACHE_FILE"
cat "$CACHE_FILE"
else
echo '{"five_hour": 0, "seven_day": 0, "reset_time": ""}'
fi
return 1
fi
local five_h=$(echo "$response" | jq -r '.five_hour.utilization // 0')
local seven_d=$(echo "$response" | jq -r '.seven_day.utilization // 0')
local reset_ts=$(echo "$response" | jq -r '.five_hour.resets_at // ""')
local result='{"five_hour": '"$five_h"', "seven_day": '"$seven_d"', "reset_time": "'"$reset_ts"'", "timestamp": '"$(date +%s)"'}'
echo "$result" > "$CACHE_FILE"
echo "$result"
}
# Récupérer l'usage
usage=$(get_api_usage)
five_h=$(echo "$usage" | jq -r '.five_hour // 0')
seven_d=$(echo "$usage" | jq -r '.seven_day // 0')
reset_time=$(echo "$usage" | jq -r '.reset_time // ""')
# Calculer le temps avant reset
time_until_reset=""
if [[ -n "$reset_time" && "$reset_time" != "null" ]]; then
reset_epoch=$(date -d "$reset_time" +%s 2>/dev/null || echo 0)
now_epoch=$(date +%s)
diff=$(( reset_epoch - now_epoch ))
if [[ $diff -gt 0 ]]; then
time_until_reset=$(format_time $diff)
fi
fi
# Construire la status line
status=""
status+="${BOLD}${INDIGO}◆${RESET} ${model} │ "
ctx_color=$(get_color "$context_pct")
ctx_bar=$(progress_bar "$context_pct")
status+="${ctx_color}Ctx: ${ctx_bar} ${context_pct}%${RESET} │ "
if [[ -n "$time_until_reset" ]]; then
status+="${INDIGO}⏱ ${time_until_reset}${RESET} │ "
fi
five_color=$(get_color "$five_h")
five_bar=$(progress_bar "$five_h")
status+="${five_color}5h: ${five_bar} ${five_h}%${RESET} │ "
seven_color=$(get_color "$seven_d")
seven_bar=$(progress_bar "$seven_d")
status+="${seven_color}7d: ${seven_bar} ${seven_d}%${RESET} │ "
status+="${INDIGO}⌂ ${work_dir}${RESET}"
echo -e "$status"
Les quatre points qui comptent
Le token d'authentification est stocké dans ~/.claude/.credentials.json sous la clé claudeAiOauth.accessToken, généré par Claude Code à la connexion. L'appel exige le header anthropic-beta: oauth-2025-04-20 (toujours d'actualité avec Claude Code 2.1.x).
Les vraies limites viennent de trois champs : five_hour.utilization (pourcentage sur 5h), seven_day.utilization (pourcentage sur 7j), et five_hour.resets_at (timestamp ISO du reset).
Le caching limite l'API à un appel toutes les 10 minutes (CACHE_TTL=600). L'endpoint /api/oauth/usage a un rate limit strict : avec un TTL trop court, on se fait rate-limiter en boucle. Point crucial : en cas d'erreur API, on réutilise l'ancien cache au lieu de l'écraser avec des zéros. Sans ça, un seul rate limit suffit à afficher 0 % jusqu'au prochain appel réussi.
Le codage couleur par seuil : cyan sous 50 % (tranquille), violet entre 50 et 80 % (ça se resserre), magenta au-dessus (alerte). Chaque barre fait 5 blocs, soit 20 % par bloc :
▰▰▱▱▱ = 40%
▰▰▰▱▱ = 60%
▰▰▰▰▰ = 100%
Exemple de sortie
◆ Claude Opus 4.6 │ Ctx: ▰▰▱▱▱ 35% │ ⏱ 3h42m │ 5h: ▰▰▰▱▱ 52% │ 7d: ▰▱▱▱▱ 18% │ ⌂ fransys-blog
Modèle full Opus, 35 % de la fenêtre de contexte utilisée, reset dans 3h42m, 52 % de la limite 5h et 18 % de la limite 7j consommés, dans le répertoire fransys-blog. Beaucoup de marge.
Dépannage
La status line n'apparaît pas : vérifier que le script est exécutable (chmod +x ~/.claude/statusline.sh) et le tester à la main :
echo '{"model": {"display_name": "test"}, "context_window": {"used_percentage": 50}}' | ~/.claude/statusline.sh
Les valeurs API sont à 0 : vérifier le token avec jq '.claudeAiOauth.accessToken' ~/.claude/.credentials.json, réauthentifier avec claude auth login s'il est vide, puis tester l'API :
TOKEN=$(jq -r '.claudeAiOauth.accessToken' ~/.claude/.credentials.json)
curl -s -w "\nHTTP:%{http_code}" \
-H "Authorization: Bearer $TOKEN" \
-H "anthropic-beta: oauth-2025-04-20" \
"https://api.anthropic.com/api/oauth/usage"
Le piège du rate limit (0 % permanent) est le problème le plus courant. Le mécanisme :
- L'API retourne HTTP 429
curlretourne quand même exit code 0 (la connexion a réussi)jqparse la réponse d'erreur,.five_hour.utilizationn'existe pas → fallback à0- Le
0est mis en cache → affiché pendant tout le TTL - Cache expire → on re-tente → encore rate-limited → boucle infinie de 0 %
La solution : vérifier le code HTTP (curl -w "%{http_code}"), ne jamais cacher les erreurs, et garder un TTL d'au moins 600 s.
Les couleurs sont fausses : le terminal n'a peut-être pas 256 couleurs (echo $TERM doit dire xterm-256color ou mieux). Sur un vieux terminal, remplacer les codes 38;5;XX par les classiques (31 rouge, 32 vert). Pour visualiser la palette :
for i in {0..255}; do echo -e "\033[38;5;${i}m█\033[0m"; done
Extensions
Logger la consommation dans un hook Stop pour garder un historique :
echo "$(date) - 5h: $(echo "$usage" | jq '.five_hour')% | 7d: $(echo "$usage" | jq '.seven_day')%" >> ~/.claude/usage.log
Ou déclencher une alerte système sur seuil :
if [[ $five_h -gt 85 ]]; then
notify-send "Claude Code" "5h usage at ${five_h}% - slow down!"
fi
Le script n'est pas parfait — il gagnerait à être écrit dans un langage plus rapide que bash — mais il donne exactement ce qui manquait : savoir où on en est, combien de temps avant reset, et pouvoir décider en connaissance de cause entre 10 000 thinking tokens et une réflexion simple.
Articles similaires