Лимит Claude Code на 5 часов: проверьте graceful stop, сохраните checkpoint и продолжайте
Практический план на случай пятчасового лимита Claude Code: проверить репозиторий, зафиксировать восстанавливаемое состояние и осознанно выбрать ожидание, usage credits или отдельный API.
Содержание

Если Claude Code упёрся в пятчасовой лимит посреди задачи, не считайте последнюю реплику доказательством готовности. Новый graceful stop — это best-effort буфер: инструмент может получить небольшой фиксированный запас из недельного лимита и попытаться остановиться в более безопасной точке. Но он не обещает чистый working tree, commit, зелёные тесты или полностью законченный feature.
Действуйте в таком порядке:
- Прочитайте точный тип лимита и время восстановления.
- Проверьте staged, unstaged и untracked изменения.
- Запустите минимальную полезную проверку.
- Создайте восстанавливаемый Git-checkpoint.
- Только после этого решайте: ждать, включать usage credits или переходить на API.
Так неопределённая остановка превращается в управляемую передачу состояния. И вы не начинаете платить за продолжение, пока не знаете, что именно осталось в репозитории.
Graceful stop — это запас на остановку, а не завершённая задача
В объявлении Claude Developers сказано, что при достижении пятчасового лимита посреди задачи Claude Code попытается найти подходящую точку остановки и получит небольшой фиксированный запас из недельного usage. Ключевое здесь — попытается, а не «обязательно завершит».
Один пользователь сообщил, что остановка оказалась аккуратнее прежнего обрыва посреди правки. Это полезный единичный опыт, но не статистика и не гарантия одинакового результата для всех проектов.
Не смешивайте три разных механизма:
| Механизм | Что он защищает | Чего не гарантирует |
|---|---|---|
| Graceful stop при лимите | Даёт агенту немного времени остановиться связнее | Завершение, commit, чистый working tree, успешные тесты |
| Checkpoint Claude Code | Позволяет /rewind откатить многие прямые правки файлов в сессии | Изменения через Bash, большинство правок subagent, внешние изменения, полную историю репозитория |
| Git-checkpoint | Фиксирует состояние, которое можно проверить, ветвить и восстановить | Корректность без ревью и тестов |
Graceful stop может оставить понятное резюме или меньше незавершённых строк. Но приёмка всё равно начинается с Git.
Сначала выясните, какой именно лимит остановил работу
Не любая остановка исчезнет через пять часов. Документация Anthropic об usage limits отделяет лимиты использования от ограничения длины контекста; расход также может суммироваться между интерфейсами Claude, относящимися к одной учётной записи.
Читайте сообщение буквально:
- Approaching 5-hour limit — у вас ещё есть короткое окно, чтобы прекратить расширять задачу и подготовить checkpoint.
- 5-hour limit reached — resets … — ориентируйтесь на указанное время восстановления.
- Недельный или model-specific limit может остаться и после сброса пятчасового окна.
- Capacity error или сбой сервиса — это не исчерпанный usage; дополнительная оплата не исправит аварию.
Если текущий интерактивный клиент предлагает сохранить сессию открытой, дождаться reset и продолжить автоматически, это может быть самым простым маршрутом. Но проверяйте подсказку именно своей версии и режима: выход из сессии может прекратить ожидание, а background, print и API-key режимы ведут себя иначе.
До нового запроса Claude проверьте репозиторий
Перейдите в корень репозитория и выполните команды, которые ничего не меняют:
git status --short --branch
git diff --stat
git diff
git diff --cached
git ls-files --others --exclude-standard
Команда /diff в Claude Code тоже помогает посмотреть незакоммиченные изменения, но источником истины для working tree остаётся Git.
До продолжения ответьте на пять вопросов:
- Какие файлы изменены?
- Что находится в staged, unstaged и untracked?
- Есть ли правка «наполовину»: новый вызов без обновления типа, теста или миграции?
- Не изменились ли неожиданно lockfile, конфигурация, generated-файл или схема БД?
- Какая самая короткая команда сейчас обнаружит основную поломку?
Запустите настоящую проверку проекта, а не универсальную команду из статьи:
# Примеры: выберите минимальную релевантную команду своего репозитория
npm test -- path/to/affected.test.ts
pytest tests/test_affected.py -q
cargo test affected_module
git diff --check
Безопасная остановка — это не красивое резюме от Claude. Это состояние, в котором вы можете назвать изменённые файлы, оставшуюся работу, результат теста и следующий небольшой шаг.
Если diff непонятен, не просите «закончить всё». Сначала сохраните checkpoint.
Создайте восстанавливаемый checkpoint одним из двух способов
Способ 1: проверенный локальный WIP commit
Этот вариант подходит, когда текущее состояние достаточно связное, а временный commit допустим в локальной ветке.
git status --short --branch
git add -p
# Проверенные новые файлы добавляйте явно: git add -p не включает автоматически все untracked-файлы.
git add -- path/to/reviewed-new-file
git diff --cached --check
git diff --cached
# Здесь запустите минимальный релевантный test или lint.
git commit -m "WIP: checkpoint before Claude Code limit reset"
git rev-parse --short HEAD
Не запускайте git add -A вслепую. Проверьте .env, ключи, приватные fixtures, сгенерированные артефакты, большие бинарные файлы и debug dumps. Локальный WIP commit — точка восстановления, а не разрешение отправлять код в protected branch.
Сохраните рядом короткую передачу состояния:
Цель: закончить проверку срока действия токена
Checkpoint: a1b2c3d
Изменено: auth_service.py, tests/test_auth.py
Проверка: targeted test падает; ожидался 401, получен 200
Следующий шаг: проверить сравнение времени до изменения callers
Способ 2: patches и проверенные untracked-файлы вне репозитория
Если commit нежелателен, используйте этот внешний checkpoint. Скрипт сначала разрешает реальный путь CLAUDE_CHECKPOINT_DIR; если каталог находится внутри репозитория, в том числе через символическую ссылку, выполнение завершится до создания файлов checkpoint.
Процесс разделён на три шага: сначала без записи просмотрите staged-, unstaged- и untracked-кандидаты и их diff; затем для каждой группы явно выберите номера путей, а всё невыбранное будет явно исключено; только после ввода SAVE REVIEWED данные записываются. До выбора полностью проверьте соответствующий diff или untracked-файл и исключите ключи, приватные данные и всё, что сохранять не следует. Если безопасна лишь часть изменений в файле, сначала разделите изменения или используйте WIP commit выше, а не выбирайте файл целиком.
Внешний способ останавливается при обнаружении переименования отслеживаемого файла: используйте проверенный WIP-коммит. Если выбранный unstaged-путь зависит от staged-изменений, проверьте и сохраните обе версии. Перед восстановлением укажите в checkpoint абсолютный путь, который вывел шаг сохранения. Несовпадение базового коммита, грязное рабочее дерево или ошибка любого шага останавливают восстановление.
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 фиксирует выбранные и исключённые пути, not-saved.txt перечисляет всё несохранённое, а scope.txt описывает охват. Если исключён хотя бы один staged-, unstaged- или untracked-кандидат, терминал и scope.txt помечают результат как PARTIAL; это не полный checkpoint для восстановления, и вернуть можно только выбранный объём. Ignored-файлы по-прежнему вне охвата, а сам checkpoint не подтверждает работоспособность кода.
Перед восстановлением прочитайте scope.txt и not-saved.txt. В чистом checkout на записанном base commit восстанавливайте только сохранённый объём:
(
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
)
Если репозиторий уже ушёл вперёд, не накладывайте patches силой. Создайте чистую ветку или worktree на сохранённом commit, восстановите изменения там и объедините осознанно.
Checkpoints Claude Code полезны, но Git они не заменяют
Согласно официальной документации checkpointing, Claude Code отслеживает прямые изменения файлов в сессии и позволяет просматривать или восстанавливать их через /rewind. Документация указывает на хранение последних 100 checkpoints сессии и их связь с conversation, поэтому они могут оставаться доступными после resume.
Это удобно для отмены неудачного шага агента, но не является резервной копией репозитория. В документированных ограничениях — файлы, изменённые через Bash, большинство правок subagent, параллельные внешние изменения и некоторые случаи symlink/hardlink. Git добавляет устойчивый commit ID, ветки, reviewable patches и восстановление, не зависящее от сессии Claude.
Используйте оба слоя:
/rewind— для быстрого отката внутри сессии;- Git commit или внешний patch bundle — для долговечного checkpoint репозитория.
В CLI reference указаны команды продолжения:
claude -c
claude -r "<session>"
После resume снова выполните git status. Восстановленная conversation не доказывает, что файловая система осталась в прежнем состоянии.
Выберите ожидание, usage credits или API только после checkpoint
| Ситуация | Первый выбор | Почему |
|---|---|---|
| Reset близко, состояние сохранено, дедлайн допускает паузу | Ждать | Нет дополнительной тарификации и смены авторизации |
| Нужны тот же интерфейс и conversation, а metered spend приемлем | Usage credits | Подходящие платные аккаунты могут продолжить в Claude и Claude Code после включённого usage |
| Нужны отдельный ключ, баланс провайдера или бюджет проекта | API | Биллинг и авторизация отделяются от подписки |
| Лимиты мешают несколько обычных рабочих дней подряд | Пересмотреть тариф и процесс | Одна остановка — слабое основание для постоянного upgrade |
Ждите, когда пауза дешевле переключения
Если reset скоро, а checkpoint готов, ожидание обычно безопаснее. Запишите точное время, оставьте handoff и держите сессию открытой только когда клиент явно предлагает wait-and-resume.
После возврата выполните:
git status --short --branch
git diff --stat
Затем сформулируйте следующий шаг. Команда «продолжай» без контекста заставляет агент догадываться.
Используйте usage credits, когда важнее сохранить тот же контекст
Документация usage credits объясняет, что подходящие пользователи Pro и Max могут включить дополнительное pay-as-you-go использование в Settings > Usage, пополнить баланс и настроить контроль расходов. Оплата идёт отдельно от подписки, а обычные пятчасовые окна всё равно сбрасываются.
Перед включением:
- задайте месячный cap и alerts;
- решите, допустим ли auto-reload;
- убедитесь, что интерфейс прямо сообщает о продолжении через usage credits;
- остановитесь после срочного checkpoint или acceptance test.
Это удобное продолжение в том же интерфейсе, но не бесплатный запас подписки.
Переходите на API, когда нужен отдельный бюджет или ключ
API — отдельный путь авторизации и счёта. Он не наследует лимит подписки автоматически. Одной переменной окружения может быть недостаточно, если сохранён subscription login. В Claude Code сначала проверьте /status, затем подтвердите ожидаемый provider или gateway и найдите запрос в usage log поставщика.
BetterToken — Anthropic-compatible API с оплатой по мере использования, а не продолжение подписки Claude. Он может подойти для отдельного key и balance, но не меняет главного: Git-checkpoint и точный handoff нужны при любом API-провайдере.
Сравнивайте API-цены одной модели, но не называйте их стоимостью задачи
Ниже приведены стандартные цены текстовых токенов, проверенные 2026-10-01. Единица — USD за 1 млн токенов. Данные Anthropic взяты с официальной страницы API pricing, BetterToken — с его страницы цен.
| Точный model ID | Anthropic input | Anthropic output | BetterToken input | BetterToken output |
|---|---|---|---|---|
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 |
Таблица показывает только стандартную цену input/output для одинакового model ID на эту дату. Она не делает три механизма взаимозаменяемыми:
- subscription usage — включённая квота с ограничениями тарифа;
- usage credits — metered continuation в подходящих интерфейсах Claude;
- API usage — отдельный аккаунт провайдера с оплатой токенов и функций.
Фактическая стоимость задачи зависит от input/output tokens, cache reads/writes, long context или fast mode, повторов, tool calls и правил аккаунта. Более низкая каталожная цена не доказывает, что конкретная задача обойдётся дешевле.
Возобновляйте работу с проверяемым handoff, а не словом «продолжай»
Перед новой сессией подготовьте короткое состояние:
Цель: что должно быть верно после завершения
Base: ветка и commit/checkpoint ID
Изменения: staged, unstaged, untracked
Проверка: точные команды и результаты
Известная ошибка: сообщение или failing assertion
Не трогать: чувствительные и посторонние файлы
Следующий шаг: одно небольшое проверяемое действие
Попросите Claude Code сначала проверить текущий diff и повторить следующий шаг, а уже потом редактировать. Так устаревшее резюме, другая ветка или неполный graceful stop обнаружатся до новых правок.
Частые вопросы
Graceful stop автоматически создаёт commit?
Нет. Официальное сообщение обещает попытку остановиться безопаснее, а не Git commit. Проверка и сохранение репозитория остаются на вас.
Он гарантирует завершение задачи?
Нет. Агент может остановиться с описанием остатка или выполнить только часть правок. Готовность определяют тесты и acceptance criteria.
Wrap-up оплачивается отдельно?
Небольшой фиксированный запас из объявления берётся из недельного usage. Usage credits и API — отдельные metered маршруты. Смотрите режим биллинга в своём аккаунте.
Может ли /rewind заменить Git?
Нет. Он полезен для прямых правок внутри сессии, но документированные исключения не покрывают все изменения репозитория.
Что делать при weekly limit?
Сброс пятчасового окна может не снять недельное ограничение. Сохраните checkpoint, ориентируйтесь на тип лимита и время в клиенте, а затем решайте вопрос с дополнительным usage.