Límite de 5 horas de Claude Code: revisa el cierre, guarda un checkpoint y continúa
Flujo práctico para el límite de cinco horas de Claude Code: inspeccionar el repositorio, guardar un estado recuperable y elegir con criterio entre esperar, usage credits o una API independiente.
Índice

Cuando Claude Code alcanza el límite de cinco horas en mitad de una tarea, su último mensaje no demuestra que el trabajo esté terminado. El nuevo graceful stop es un margen de cierre de tipo best effort: puede usar una pequeña asignación fija tomada del uso semanal para buscar un punto menos arriesgado, pero no promete un árbol de trabajo limpio, un commit, pruebas verdes ni una función acabada.
Sigue este orden:
- Lee el tipo exacto de límite y la hora de restablecimiento.
- Revisa cambios staged, unstaged y untracked.
- Ejecuta la validación mínima que aporte información.
- Crea un checkpoint de Git recuperable.
- Después decide si esperas, habilitas usage credits o continúas mediante una API.
Así conviertes un corte incierto en una entrega controlada y evitas pagar por seguir antes de saber en qué estado quedó el repositorio.
Graceful stop es un margen de seguridad, no una tarea finalizada
El anuncio de Claude Developers indica que, si el límite de cinco horas llega a mitad de una tarea, Claude Code intentará encontrar un punto de parada razonable y recibirá una pequeña asignación fija del uso semanal para cerrar lo que pueda. Las palabras importantes son intentará y lo que pueda.
Un usuario contó que obtuvo una parada más ordenada que los antiguos cortes en mitad de una edición. Es una experiencia útil, pero sigue siendo un caso individual, no una garantía de fiabilidad.
Distingue estos tres mecanismos:
| Mecanismo | Qué protege | Qué no garantiza |
|---|---|---|
| Graceful stop al llegar al límite | Da al agente unos instantes para detenerse de forma más coherente | Finalización, commit, árbol limpio, pruebas aprobadas |
| Checkpoint de Claude Code | Permite que /rewind restaure muchas ediciones directas de la sesión | Cambios hechos por Bash, la mayoría de cambios de subagents, ediciones externas, historial completo |
| Checkpoint de Git | Registra un estado revisable, ramificable y recuperable | Corrección si no lo revisas y pruebas |
El cierre puede dejar un resumen mejor o menos líneas a medias. La aceptación real sigue empezando en Git.
Identifica primero qué límite te ha detenido
No todos los bloqueos desaparecen en cinco horas. La documentación de límites de uso diferencia entre uso y longitud de contexto, y el consumo puede compartirse entre superficies de Claude asociadas a la misma cuenta.
Lee el aviso de forma literal:
- Approaching 5-hour limit: aún queda una ventana breve para dejar de ampliar la tarea y preparar el checkpoint.
- 5-hour limit reached — resets …: usa la hora indicada como referencia.
- Un límite semanal o específico de un modelo puede seguir activo cuando se restablezca la ventana de cinco horas.
- Un error de capacidad o del servicio es distinto del agotamiento de uso; pagar más no arregla una caída.
Si el cliente interactivo actual ofrece mantener la sesión abierta, esperar y continuar automáticamente después del reset, puede ser el camino más sencillo. Comprueba la indicación de tu versión y modo: salir puede cancelar la espera, y los modos background, print o con API key pueden comportarse de otra forma.
Inspecciona el repositorio antes de pedir más trabajo
Desde la raíz del repositorio, ejecuta comandos de solo lectura:
git status --short --branch
git diff --stat
git diff
git diff --cached
git ls-files --others --exclude-standard
/diff en Claude Code también puede ayudar, pero Git sigue siendo la fuente de verdad del working tree.
Antes de continuar, responde estas preguntas:
- ¿Qué archivos cambiaron?
- ¿Qué está staged, unstaged o untracked?
- ¿Hay una edición incompleta, como una llamada nueva sin el tipo, test o migración correspondiente?
- ¿Cambió inesperadamente un lockfile, una configuración, un archivo generado o una migración?
- ¿Cuál es el comando más pequeño que puede mostrar el fallo principal?
Ejecuta la comprobación real del proyecto:
# Ejemplos: usa el comando mínimo pertinente de tu repositorio
npm test -- path/to/affected.test.ts
pytest tests/test_affected.py -q
cargo test affected_module
git diff --check
Una parada segura no significa “Claude escribió un buen resumen”. Significa que puedes nombrar los archivos modificados, el trabajo pendiente, el resultado de la validación y el siguiente paso pequeño.
Si no entiendes el diff, no pidas “termina todo”. Guarda primero un checkpoint.
Crea un checkpoint recuperable con uno de estos métodos
Método 1: un commit WIP local y revisado
Úsalo cuando el estado actual sea suficientemente coherente y tu equipo permita commits temporales en una rama local.
git status --short --branch
git add -p
# Añade de forma explícita los archivos nuevos ya revisados.
git add -- path/to/reviewed-new-file
git diff --cached --check
git diff --cached
# Ejecuta aquí el test o lint mínimo relacionado.
git commit -m "WIP: checkpoint before Claude Code limit reset"
git rev-parse --short HEAD
No ejecutes git add -A a ciegas. Revisa .env, credenciales, fixtures privados, artefactos generados, binarios grandes y volcados de depuración. Un WIP local es un punto de recuperación, no permiso para hacer push a una rama protegida.
Guarda también una nota breve:
Objetivo: terminar la validación de caducidad del token
Checkpoint: a1b2c3d
Cambios: auth_service.py, tests/test_auth.py
Validación: el test dirigido falla; esperaba 401 y recibió 200
Siguiente paso: revisar la comparación de expiración antes de tocar callers
Método 2: patches y archivos untracked revisados fuera del repositorio
Usa esta opción si no quieres crear un commit. El script resuelve primero la ruta real de CLAUDE_CHECKPOINT_DIR; si queda dentro del repositorio, incluso a través de un enlace simbólico, se detiene antes de crear cualquier archivo del checkpoint.
El proceso tiene tres pasos: primero inspecciona, sin guardar, los candidatos staged, unstaged y untracked y sus diffs; después selecciona explícitamente los números de ruta de cada grupo, de modo que todo lo no elegido queda excluido; por último, no escribe nada hasta que introduces SAVE REVIEWED. Antes de seleccionar, revisa el diff completo o el archivo untracked y excluye claves, material privado y cualquier contenido que no deba conservarse. Si solo es segura una parte de un archivo, divide el cambio o usa el commit WIP anterior en vez de seleccionar el archivo entero.
El método externo se detiene si detecta un cambio de nombre de un archivo controlado; usa un commit WIP revisado. Si una ruta unstaged seleccionada también tiene cambios staged, revisa y guarda ambas versiones. Antes de restaurar, asigna a checkpoint el directorio absoluto indicado al guardar. Una base incorrecta, un checkout con cambios o cualquier paso fallido detiene la restauración.
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 registra las rutas elegidas y excluidas, not-saved.txt enumera cada omisión y scope.txt declara el alcance. Si se excluye cualquier candidato staged, unstaged o untracked, tanto la terminal como scope.txt marcan el resultado como PARTIAL; no es un punto de recuperación completo y solo restaura el alcance seleccionado. Los archivos ignored siguen fuera del alcance, y el checkpoint no demuestra que el código funcione.
Antes de restaurar, lee scope.txt y not-saved.txt. Restaura únicamente el alcance guardado en un checkout limpio situado en el commit base registrado:
(
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 el repositorio ya no está en ese commit, no fuerces los patches. Crea una rama o worktree limpio en la base guardada, restaura allí y fusiona de forma deliberada.
Usa los checkpoints de Claude Code, pero no en lugar de Git
La documentación oficial de checkpointing explica que Claude Code rastrea ediciones directas de archivos durante la sesión y permite revisarlas o restaurarlas mediante /rewind. Indica que conserva los 100 checkpoints más recientes de una sesión y que permanecen asociados a la conversation, por lo que pueden seguir disponibles al reanudarla.
Es útil para deshacer un turno malo del agente, pero no es una copia del repositorio. Entre las limitaciones documentadas están los cambios hechos mediante Bash, la mayoría de ediciones de subagents, modificaciones externas simultáneas y algunos casos con symlinks o hardlinks. Git aporta un commit ID duradero, ramas, patches revisables y recuperación independiente de Claude.
Usa las dos capas:
/rewindpara volver atrás dentro de la sesión;- commit de Git o bundle externo para un checkpoint duradero.
La referencia de CLI documenta:
claude -c
claude -r "<session>"
Tras reanudar, vuelve a ejecutar git status antes de autorizar cambios. Recuperar la conversation no prueba que el sistema de archivos coincida con el resumen anterior.
Decide entre esperar, usage credits o API después del checkpoint
| Situación | Primera opción | Motivo |
|---|---|---|
| El reset está cerca, el checkpoint es seguro y el plazo permite pausa | Esperar | No añade gasto medido ni cambia la autenticación |
| Necesitas la misma interfaz y conversation y aceptas gasto medido | Usage credits | Las cuentas elegibles pueden continuar tras agotar el uso incluido |
| Necesitas clave, saldo o presupuesto de proyecto separados | API | Separa facturación y autenticación de la suscripción |
| Los límites interrumpen varios días normales de trabajo | Revisar plan y proceso | Un único corte no justifica un upgrade permanente |
Espera cuando la pausa cueste menos que cambiar de ruta
Si el restablecimiento está próximo y el checkpoint está listo, esperar suele ser más seguro. Anota la hora exacta y deja el handoff. Mantén la sesión abierta solo si el cliente ofrece explícitamente esperar y reanudar.
Al volver:
git status --short --branch
git diff --stat
Después formula el siguiente paso. Un simple “continúa” obliga al agente a adivinar el estado.
Usa usage credits cuando la continuidad sea prioritaria
La documentación de usage credits señala que usuarios Pro y Max elegibles pueden activar uso adicional pay-as-you-go en Settings > Usage, añadir fondos y definir controles de gasto. El cobro es independiente de la suscripción y las ventanas normales de cinco horas siguen restableciéndose.
Antes de activarlo:
- establece un límite mensual y alertas;
- decide si aceptas auto-reload;
- confirma que la interfaz indica que continúa con usage credits;
- detente al completar el checkpoint urgente o la prueba de aceptación.
Mantiene la interfaz y el contexto, pero no es un excedente gratuito de la suscripción.
Usa una API cuando necesites autenticación o presupuesto separados
La API es otra ruta de autenticación y cobro. No hereda automáticamente el cupo de la suscripción, y cambiar una sola variable puede no sustituir un login guardado. En Claude Code, revisa /status, confirma el provider o gateway activo y verifica el request en el registro de uso del proveedor.
BetterToken es una API compatible con Anthropic y de pago por uso, no una ampliación de la suscripción de Claude. Puede servir para separar key y saldo, pero el checkpoint y el handoff siguen siendo necesarios con cualquier proveedor.
Compara precios API del mismo modelo, no el coste total de la tarea
Estos precios de texto estándar se verificaron el 2026-10-01. La unidad es USD por un millón de tokens. Los datos de Anthropic proceden de su tarifa API oficial; los de BetterToken, de su página de precios.
| ID exacto del modelo | Entrada Anthropic | Salida Anthropic | Entrada BetterToken | Salida 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 |
La tabla solo compara el precio estándar de entrada y salida del mismo model ID en esa fecha. No convierte en equivalentes estos tres mecanismos:
- el uso de suscripción es una asignación incluida con límites del plan;
- usage credits es continuación medida dentro de interfaces Claude elegibles;
- el uso de API se factura a otra cuenta por tokens y funciones aplicables.
El coste real depende de tokens de entrada y salida, caché, contexto largo o fast mode, reintentos, tool calls y reglas de la cuenta. Un precio de lista menor no demuestra que tu tarea completa vaya a costar menos.
Reanuda con un handoff de estado, no con “continúa”
Entrega a la siguiente sesión un resumen verificable:
Objetivo: qué debe cumplirse al terminar
Base: rama y commit/checkpoint ID
Cambios: staged, unstaged y untracked
Validación: comandos exactos y resultados
Fallo conocido: error o assertion precisa
No tocar: archivos sensibles o ajenos
Siguiente acción: un paso pequeño y comprobable
Pide primero que Claude Code inspeccione el diff actual y repita la acción prevista. Así detectarás una rama distinta, un resumen antiguo o un cierre incompleto antes de ampliar el daño.
Preguntas frecuentes
¿Graceful stop crea un commit automáticamente?
No. La declaración oficial promete intentar encontrar una parada más segura, no crear un commit de Git.
¿Garantiza que la tarea esté terminada?
No. Puede detenerse con trabajo pendiente o tras aplicar solo una parte de los cambios. Las pruebas y criterios de aceptación siguen mandando.
¿El cierre tiene un coste adicional?
La pequeña asignación fija anunciada procede del uso semanal. Usage credits y API son rutas medidas separadas; comprueba el modo de facturación de tu cuenta.
¿Puede /rewind sustituir a Git?
No. Ayuda con ediciones directas de la sesión, pero sus exclusiones documentadas no cubren todo el repositorio.
¿Y si el mensaje menciona un weekly limit?
El reset de cinco horas puede no eliminarlo. Guarda el checkpoint, sigue el tipo y la hora mostrados por el cliente y confirma qué contador te bloquea antes de comprar uso adicional.