Limite de 5 heures de Claude Code : vérifier l’arrêt, créer un checkpoint et reprendre
Une procédure pratique face à la limite de cinq heures de Claude Code : inspecter le dépôt, préserver un état récupérable et choisir entre attente, usage credits ou API indépendante.
Sommaire

Lorsque Claude Code atteint sa limite de cinq heures au milieu d’une tâche, son dernier message ne prouve pas que le travail est terminé. Le nouveau graceful stop est un arrêt best effort : l’outil peut utiliser une petite allocation fixe prélevée sur l’usage hebdomadaire pour chercher un point d’arrêt plus sûr, mais il ne promet ni working tree propre, ni commit, ni tests réussis, ni fonctionnalité achevée.
Procédez dans cet ordre :
- Lisez le type exact de limite et l’heure de réinitialisation.
- Contrôlez les changements staged, unstaged et untracked.
- Lancez la plus petite validation réellement utile.
- Créez un checkpoint Git récupérable.
- Décidez ensuite d’attendre, d’activer les usage credits ou de poursuivre via une API.
Cette séquence transforme une interruption incertaine en transmission maîtrisée. Elle évite aussi de payer pour continuer avant de connaître l’état réel du dépôt.
Le graceful stop est une marge de sécurité, pas une tâche terminée
L’annonce de Claude Developers indique que Claude Code essaiera de trouver un point d’arrêt raisonnable si la limite de cinq heures survient en cours de tâche, avec une petite allocation fixe tirée de l’usage hebdomadaire. Les mots importants sont essaiera et ce qu’il peut terminer.
Un utilisateur a rapporté un arrêt plus propre que les anciennes coupures au milieu d’une modification. Ce témoignage montre que la fonction peut aider, mais il ne constitue ni une statistique ni une garantie.
Distinguez trois mécanismes :
| Mécanisme | Ce qu’il protège | Ce qu’il ne garantit pas |
|---|---|---|
| Graceful stop à la limite | Donne un peu de temps à l’agent pour s’arrêter plus proprement | Fin de la tâche, commit, arbre propre, tests réussis |
| Checkpoint Claude Code | Permet à /rewind de restaurer de nombreuses éditions directes de la session | Changements via Bash, plupart des éditions de subagents, modifications externes, historique complet |
| Checkpoint Git | Enregistre un état révisable, branchable et restaurable | Exactitude sans revue ni tests |
Le graceful stop peut produire un meilleur résumé ou laisser moins de lignes incomplètes. L’acceptation réelle commence toujours par Git.
Identifiez d’abord la limite qui vous a bloqué
Toutes les interruptions ne disparaissent pas après cinq heures. La documentation Anthropic sur les limites d’usage distingue usage limits et longueur de contexte ; l’usage peut aussi être partagé entre plusieurs interfaces Claude rattachées au même compte.
Lisez le message littéralement :
- Approaching 5-hour limit : il reste une courte fenêtre pour arrêter d’élargir la tâche et préparer le checkpoint.
- 5-hour limit reached — resets … : prenez l’heure affichée comme référence.
- Une limite hebdomadaire ou propre à un modèle peut rester active après le reset de la fenêtre de cinq heures.
- Une erreur de capacité ou de service n’est pas un épuisement d’usage ; payer davantage ne répare pas une panne.
Si le client interactif actuel propose de garder la session ouverte, d’attendre puis de reprendre automatiquement, cela peut être le chemin le plus simple. Vérifiez toutefois l’invite de votre version et de votre mode : quitter peut annuler l’attente, et les modes background, print ou API key peuvent différer.
Inspectez le dépôt avant de demander davantage de modifications
Depuis la racine du dépôt, exécutez ces commandes sans effet sur les fichiers :
git status --short --branch
git diff --stat
git diff
git diff --cached
git ls-files --others --exclude-standard
La commande /diff de Claude Code peut aussi aider, mais Git reste la source de vérité du working tree.
Avant de poursuivre, répondez à cinq questions :
- Quels fichiers ont changé ?
- Qu’est-ce qui est staged, unstaged ou untracked ?
- Une modification est-elle restée à moitié faite, par exemple un nouvel appel sans mise à jour du type, du test ou de la migration ?
- Un lockfile, un fichier généré, une configuration ou une migration a-t-il changé sans raison ?
- Quelle est la plus petite commande susceptible de révéler le problème principal ?
Lancez la vraie validation du projet :
# Exemples : utilisez la plus petite commande pertinente pour votre dépôt
npm test -- path/to/affected.test.ts
pytest tests/test_affected.py -q
cargo test affected_module
git diff --check
Un arrêt sûr ne signifie pas « Claude a écrit un bon résumé ». Il signifie que vous pouvez nommer les fichiers modifiés, le travail restant, le résultat de la validation et la prochaine petite action.
Si le diff reste incompréhensible, ne demandez pas de « tout finir ». Créez d’abord le checkpoint.
Créez un checkpoint récupérable de l’une de ces deux façons
Méthode 1 : un commit WIP local et révisé
Utilisez-la lorsque l’état courant est suffisamment cohérent et que des commits temporaires sont permis sur une branche locale.
git status --short --branch
git add -p
# Ajoutez explicitement les nouveaux fichiers déjà contrôlés.
git add -- path/to/reviewed-new-file
git diff --cached --check
git diff --cached
# Lancez ici le test ou lint minimal correspondant.
git commit -m "WIP: checkpoint before Claude Code limit reset"
git rev-parse --short HEAD
N’exécutez pas git add -A sans regarder. Vérifiez les .env, identifiants, fixtures privées, artefacts générés, gros binaires et dumps de débogage. Un WIP local est un point de restauration, pas une autorisation de push vers une branche protégée.
Ajoutez une note courte :
Objectif : terminer la validation d’expiration du token
Checkpoint : a1b2c3d
Fichiers : auth_service.py, tests/test_auth.py
Validation : le test ciblé échoue ; 401 attendu, 200 reçu
Étape suivante : vérifier la comparaison d’expiration avant de modifier les callers
Méthode 2 : patches et fichiers untracked contrôlés hors du dépôt
Utilisez cette méthode si vous ne souhaitez pas créer de commit. Le script résout d’abord le chemin réel de CLAUDE_CHECKPOINT_DIR ; s’il se trouve dans le dépôt, y compris via un lien symbolique, il s’arrête avant de créer le moindre fichier de checkpoint.
Le processus comporte trois étapes : inspecter sans rien sauvegarder les candidats staged, unstaged et untracked ainsi que leurs diffs ; sélectionner explicitement les numéros de chemin à conserver dans chaque groupe, tout élément non choisi étant exclu ; puis saisir SAVE REVIEWED avant toute écriture. Avant de sélectionner un chemin, examinez son diff complet ou le fichier untracked et écartez les clés, données privées et tout contenu qui ne doit pas être conservé. Si seule une partie d’un fichier peut être sauvegardée sans risque, séparez la modification ou utilisez le commit WIP ci-dessus au lieu de sélectionner le fichier entier.
La méthode externe s’arrête si elle détecte le renommage d’un fichier suivi ; utilisez alors un commit WIP vérifié. Si un chemin unstaged sélectionné comporte aussi des modifications staged, vérifiez et sauvegardez les deux versions. Avant la restauration, définissez checkpoint sur le répertoire absolu affiché lors de la sauvegarde. Une base différente, un checkout modifié ou l’échec d’une étape arrête la restauration.
repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"
# Step 1: inspect everything. These commands do not save files.
git status --short --branch
git diff --cached
git diff
git ls-files --others --exclude-standard
# Steps 2-3: choose reviewed paths explicitly, then save only that scope.
python3 /dev/fd/3 3<<'PY'
from datetime import datetime, timezone
from pathlib import Path
import json, os, shlex, subprocess, tarfile
def git(*args):
return subprocess.run(["git", *args], check=True, stdout=subprocess.PIPE).stdout
def path_list(*args):
return list(dict.fromkeys(Path(os.fsdecode(x)) for x in git(*args).split(b"\0") if x))
def choose(label, items):
print(f"\n{label} candidates:")
if not items:
print(" (none)")
return []
for i, path in enumerate(items, 1):
print(f" {i:>3} {shlex.quote(os.fspath(path))}")
answer = input(
"Select reviewed numbers to save "
"(1,3-5; 'all'; blank saves none): "
).strip().lower()
if not answer:
return []
if answer == "all":
return items[:]
chosen = set()
try:
for token in answer.split(","):
bounds = [int(x) for x in token.strip().split("-", 1)]
chosen.update(range(min(bounds), max(bounds) + 1))
except ValueError as exc:
raise SystemExit("Invalid selection; nothing was saved.") from exc
if not chosen or min(chosen) < 1 or max(chosen) > len(items):
raise SystemExit("Selection is outside the displayed range; nothing was saved.")
return [path for i, path in enumerate(items, 1) if i in chosen]
def patch(cached, items):
if not items:
return b""
args = ["diff"] + (["--cached"] if cached else [])
return git(*args, "--binary", "--", *(os.fspath(path) for path in items))
repo = Path(git("rev-parse", "--show-toplevel").decode().rstrip("\n")).resolve()
root = Path(os.environ.get(
"CLAUDE_CHECKPOINT_DIR", os.fspath(Path.home() / "claude-checkpoints")
)).expanduser().resolve(strict=False)
if root == repo or repo in root.parents:
raise SystemExit("CLAUDE_CHECKPOINT_DIR must resolve outside the repository.")
root.mkdir(parents=True, exist_ok=True)
root = root.resolve()
if root == repo or repo in root.parents:
raise SystemExit("CLAUDE_CHECKPOINT_DIR must resolve outside the repository.")
# A path-only selection cannot represent both sides of a detected rename.
if (git("diff", "--cached", "--find-renames", "--diff-filter=R", "--name-only", "-z")
or git("diff", "--find-renames", "--diff-filter=R", "--name-only", "-z")):
raise SystemExit("Renames require a reviewed WIP commit; nothing was saved.")
candidates = {
"staged": path_list("diff", "--cached", "--name-only", "-z"),
"unstaged": path_list("diff", "--name-only", "-z"),
"untracked": path_list("ls-files", "--others", "--exclude-standard", "-z"),
}
if not any(candidates.values()):
raise SystemExit("No staged, unstaged, or untracked changes were found.")
selected = {name: choose(name, items) for name, items in candidates.items()}
if not any(selected.values()):
raise SystemExit("No reviewed changes were selected; nothing was saved.")
missing_baseline = set(selected["unstaged"]) & (
set(candidates["staged"]) - set(selected["staged"])
)
if missing_baseline:
raise SystemExit(
"Selected unstaged paths also have staged changes. Select both reviewed "
"versions or use a WIP commit; nothing was saved."
)
not_saved = {
name: [path for path in candidates[name] if path not in selected[name]]
for name in candidates
}
print("\nSelected for saving:")
for name, items in selected.items():
print(f" {name}: " + (", ".join(shlex.quote(os.fspath(p)) for p in items) or "(none)"))
print("Excluded and NOT saved:")
for name, items in not_saved.items():
print(f" {name}: " + (", ".join(shlex.quote(os.fspath(p)) for p in items) or "(none)"))
if input("Type SAVE REVIEWED to save exactly this scope: ").strip() != "SAVE REVIEWED":
raise SystemExit("Confirmation did not match; nothing was saved.")
current = {
"staged": path_list("diff", "--cached", "--name-only", "-z"),
"unstaged": path_list("diff", "--name-only", "-z"),
"untracked": path_list("ls-files", "--others", "--exclude-standard", "-z"),
}
if current != candidates:
raise SystemExit("The candidate list changed during review; rerun from step 1.")
stamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
checkpoint = (root / f"{repo.name}-claude-{stamp}").resolve(strict=False)
if checkpoint == repo or repo in checkpoint.parents:
raise SystemExit("Checkpoint path unexpectedly resolves inside the repository.")
checkpoint.mkdir(exist_ok=False)
(checkpoint / "base-commit.txt").write_bytes(git("rev-parse", "HEAD"))
(checkpoint / "status.txt").write_bytes(git("status", "--short", "--branch"))
(checkpoint / "staged.patch").write_bytes(patch(True, selected["staged"]))
(checkpoint / "unstaged.patch").write_bytes(patch(False, selected["unstaged"]))
(checkpoint / "untracked.list0").write_bytes(b"".join(
os.fsencode(os.fspath(path)) + b"\0" for path in selected["untracked"]
))
manifest = {
"selected": {name: [os.fspath(p) for p in items] for name, items in selected.items()},
"not_saved": {name: [os.fspath(p) for p in items] for name, items in not_saved.items()},
}
(checkpoint / "selection.json").write_text(
json.dumps(manifest, ensure_ascii=True, indent=2) + "\n", encoding="utf-8"
)
omitted = [
f"{name}\t{json.dumps(os.fspath(path), ensure_ascii=True)}"
for name, items in not_saved.items() for path in items
]
(checkpoint / "not-saved.txt").write_text(
"\n".join(omitted) + ("\n" if omitted else "(none)\n"), encoding="utf-8"
)
if selected["untracked"]:
with tarfile.open(checkpoint / "untracked.tar.gz", "w:gz", dereference=False) as archive:
for path in selected["untracked"]:
archive.add(repo / path, arcname=path.as_posix(), recursive=False)
partial = bool(omitted)
(checkpoint / "scope.txt").write_text(
"PARTIAL: see not-saved.txt; this is not a complete recovery point.\n"
if partial else
"REVIEWED SCOPE: every listed candidate was saved; ignored files remain outside scope.\n",
encoding="utf-8",
)
print(("PARTIAL checkpoint" if partial else "Reviewed checkpoint") + f" saved to {checkpoint}")
if partial:
print("Some listed changes were not saved; read not-saved.txt before recovery.")
PY
selection.json consigne les chemins retenus et exclus, not-saved.txt énumère chaque omission et scope.txt précise le périmètre. Si un seul candidat staged, unstaged ou untracked est exclu, le terminal et scope.txt marquent le résultat PARTIAL ; ce n’est pas un point de récupération complet et seule la sélection pourra être restaurée. Les fichiers ignored restent hors périmètre, et le checkpoint ne prouve pas que le code fonctionne.
Avant la restauration, lisez scope.txt et not-saved.txt. Dans un checkout propre placé sur le commit de base enregistré, ne restaurez que le périmètre sauvegardé :
(
set -eu
checkpoint="/absolute/path/printed-by-the-save-step" # Replace with the actual checkpoint directory.
test -d "$checkpoint"
repo_root="$(git rev-parse --show-toplevel)"
cd "$repo_root"
for required in base-commit.txt scope.txt not-saved.txt staged.patch unstaged.patch untracked.list0; do
test -f "$checkpoint/$required"
done
cat "$checkpoint/scope.txt" "$checkpoint/not-saved.txt"
test "$(git rev-parse HEAD)" = "$(cat "$checkpoint/base-commit.txt")"
test -z "$(git status --porcelain --untracked-files=all)"
if [ -s "$checkpoint/staged.patch" ]; then
git apply --index "$checkpoint/staged.patch"
fi
if [ -s "$checkpoint/unstaged.patch" ]; then
git apply "$checkpoint/unstaged.patch"
fi
if [ -s "$checkpoint/untracked.list0" ]; then
tar -xzkf "$checkpoint/untracked.tar.gz"
fi
git status --short
)
Si le dépôt n’est plus sur cette base, ne forcez pas les patches. Créez une branche ou un worktree propre au commit enregistré, restaurez-y l’état, puis fusionnez volontairement.
Utilisez les checkpoints Claude Code, mais pas à la place de Git
La documentation officielle du checkpointing explique que Claude Code suit les modifications directes de fichiers pendant la session et permet de les examiner ou de les restaurer avec /rewind. Elle décrit la conservation des 100 checkpoints les plus récents d’une session et leur association à la conversation, ce qui peut les rendre disponibles après une reprise.
C’est utile pour annuler un mauvais tour de l’agent, mais ce n’est pas une sauvegarde du dépôt. Les limites documentées incluent les changements produits par Bash, la plupart des éditions de subagents, les modifications externes concurrentes et certains cas de symlink ou hardlink. Git fournit en plus un commit ID durable, des branches, des patches révisables et une restauration indépendante de Claude.
Utilisez les deux couches :
/rewindpour revenir rapidement en arrière dans la session ;- commit Git ou bundle externe pour un checkpoint durable.
La référence CLI documente :
claude -c
claude -r "<session>"
Après la reprise, relancez git status avant d’autoriser des modifications. Restaurer la conversation ne prouve pas que le système de fichiers correspond encore à l’ancien résumé.
Choisissez attente, usage credits ou API seulement après le checkpoint
| Situation | Premier choix | Pourquoi |
|---|---|---|
| Reset proche, checkpoint sûr, délai compatible avec une pause | Attendre | Aucun coût mesuré supplémentaire ni changement d’authentification |
| Même interface et conversation indispensables, dépense mesurée acceptable | Usage credits | Les comptes éligibles peuvent continuer après l’usage inclus |
| Clé, solde fournisseur ou budget projet séparé nécessaire | API | Facturation et authentification séparées de l’abonnement |
| Les limites perturbent plusieurs journées normales | Revoir le plan et le processus | Une seule interruption ne justifie pas un upgrade permanent |
Attendez lorsque la pause coûte moins que le changement de route
Si le reset est proche et le checkpoint prêt, attendre est souvent plus sûr. Notez l’heure exacte et laissez le handoff. Ne gardez la session ouverte que si le client propose explicitement l’attente et la reprise.
Au retour :
git status --short --branch
git diff --stat
Décrivez ensuite l’étape suivante. Un simple « continue » oblige l’agent à deviner l’état.
Utilisez les usage credits lorsque la continuité compte le plus
La documentation des usage credits indique que les utilisateurs Pro et Max éligibles peuvent activer un usage supplémentaire pay-as-you-go dans Settings > Usage, ajouter des fonds et définir des contrôles. La facturation est séparée de l’abonnement et les fenêtres normales de cinq heures continuent à se réinitialiser.
Avant l’activation :
- fixez un plafond mensuel et des alertes ;
- décidez si l’auto-reload est acceptable ;
- vérifiez que l’interface annonce une poursuite avec usage credits ;
- arrêtez après le checkpoint urgent ou le test d’acceptation.
Cette option conserve l’interface et le contexte, mais ce n’est pas un surplus gratuit de l’abonnement.
Utilisez une API lorsqu’il faut séparer authentification ou budget
Une API est une autre route d’authentification et de facturation. Elle n’hérite pas automatiquement du quota d’abonnement, et une seule variable d’environnement peut ne pas remplacer une connexion enregistrée. Dans Claude Code, contrôlez /status, confirmez le provider ou gateway actif, puis vérifiez la requête dans le journal du fournisseur.
BetterToken est une API compatible Anthropic facturée à l’usage, pas une extension de l’abonnement Claude. Elle peut répondre au besoin d’une clé et d’un solde séparés, mais checkpoint et handoff restent indispensables quel que soit le fournisseur.
Comparez les prix API du même modèle, pas le coût total de la tâche
Les tarifs texte standard ci-dessous ont été vérifiés le 2026-10-01. L’unité est USD par million de tokens. Les données Anthropic proviennent de sa tarification API officielle, celles de BetterToken de sa page de prix.
| ID exact du modèle | Entrée Anthropic | Sortie Anthropic | Entrée BetterToken | Sortie BetterToken |
|---|---|---|---|---|
claude-opus-5-5 | $4.00 | $20.00 | $2.72 | $13.60 |
claude-sonnet-5 | $2.00 | $10.00 | $1.36 | $6.80 |
claude-haiku-4-5-20251001 | $1.00 | $5.00 | $0.68 | $3.40 |
Ce tableau compare seulement le prix standard input/output du même model ID à cette date. Il ne rend pas équivalents :
- l’usage d’abonnement, allocation incluse soumise aux limites du plan ;
- les usage credits, continuation mesurée dans certaines interfaces Claude ;
- l’usage API, facturé sur un autre compte selon tokens et fonctions.
Le coût réel dépend des tokens d’entrée et de sortie, du cache, du contexte long ou fast mode, des retries, tool calls et règles du compte. Un tarif catalogue inférieur ne prouve pas que votre tâche complète coûtera moins cher.
Reprenez avec un handoff vérifiable, pas seulement « continue »
Préparez un état compact :
Objectif : ce qui doit être vrai à la fin
Base : branche et commit/checkpoint ID
Changements : staged, unstaged et untracked
Validation : commandes exactes et résultats
Échec connu : erreur ou assertion précise
Ne pas toucher : fichiers sensibles ou hors périmètre
Action suivante : une étape petite et testable
Demandez d’abord à Claude Code d’inspecter le diff courant et de répéter l’action prévue. Vous détecterez ainsi une autre branche, un ancien résumé ou un arrêt incomplet avant de créer de nouvelles modifications.
Questions fréquentes
Le graceful stop crée-t-il automatiquement un commit ?
Non. L’annonce officielle promet d’essayer de trouver un arrêt plus sûr, pas de créer un commit Git.
Garantit-il que la tâche est terminée ?
Non. L’agent peut s’arrêter avec du travail restant ou après une partie des modifications. Tests et critères d’acceptation restent décisifs.
Le wrap-up coûte-t-il plus cher ?
La petite allocation fixe annoncée provient de l’usage hebdomadaire. Usage credits et API sont des routes mesurées distinctes ; vérifiez le mode affiché par votre compte.
/rewind peut-il remplacer Git ?
Non. Il aide pour les éditions directes de la session, mais ses exclusions documentées ne couvrent pas tous les changements du dépôt.
Et si le message mentionne une weekly limit ?
Le reset de cinq heures peut ne pas la lever. Sauvegardez le checkpoint, suivez le type et l’heure affichés, puis confirmez le compteur bloquant avant d’acheter de l’usage supplémentaire.