Написал свой мод для отслеживания лимитов в Claude Code

Claude упёрся в лимит, сброс через час, а мне уходить на три — сидеть и ждать или потерять часы работы? Сделал мод, который продолжает сам после сброса. А потом выяснилось, что Claude Code уже умеет это сам. Как устроен мод, грабли и вывод.

Содержание
  1. Что умеет мод
  2. Как это устроено
  3. Нюансы, на которые я наткнулся
  4. Проверка вживую и неожиданный поворот
  5. Почему я всё равно им пользуюсь
  6. Как установить
  7. Как поделиться своим модом
  8. Что дальше

Даю Claude Code большую задачу, и где-то на середине он упирается в лимит сессии. До сброса — час. А мне как раз пора в спортзал, и вернусь я часа через три.

И тут выбор без хорошего варианта:

  • Ждать. Сидеть час у компьютера, чтобы после сброса напечатать одно слово «продолжай», — и только потом уйти.
  • Уйти. Тогда лимит восстановится через час, но Claude об этом не узнает: задача будет стоять, пока я не вернусь. Два часа, за которые она спокойно могла доделаться, просто пропадут. А если вечером закрутят другие дела, задача не сдвинется и до завтра.

Лимит сбрасывается сам — а вот продолжить работу без человека Claude не может. Ему нужен кто-то, кто нажмёт «продолжай» в нужную минуту.

Когда в Claude Code появились моды — способ менять сам интерфейс и поведение агента, — я сразу понял, что сделаю первым: наблюдателя за лимитами. Он показывает, сколько осталось, и после сброса сам говорит Claude продолжать. А чтобы это точно сработало, пока меня нет, — не даёт Mac уснуть.

Так появился limit-watch. А чем всё закончилось — в конце статьи.

Что умеет мод

Над полем ввода появляется полоса:

Полоса limit-watch под нативным предупреждением Claude: лимиты 5ч и неделя со временем до сброса, продолжение включено, кнопка Zzz
Полоса limit-watch под нативным предупреждением Claude: лимиты 5ч и неделя со временем до сброса, продолжение включено, кнопка Zzz
  • Лимиты на виду. Пятичасовой и недельный — сколько потрачено и через сколько сброс. До 50% цифры серые, от 50% — жёлтые, от 80% — красные.
  • Продолжить после сброса. Нажимаешь кнопку — рядом загорается зелёная точка. Если работа оборвётся на лимите, мод дождётся сброса, подождёт ещё минуту и отправит в чат сообщение с моим последним запросом и последним ответом Claude. Claude продолжает с того же места.
  • Zzz — не засыпать. На macOS одна кнопка не даёт Mac уйти в сон, пока открыт чат. Иначе ночью ноутбук уснёт, и продолжать будет некому.
  • 9 языков. Язык берётся из системы: русский, английский, испанский, немецкий, французский, португальский, китайский, японский, украинский.

Как это устроено

Мод — это плагин из трёх файлов: манифест, hooks/hooks.json и модуль на TypeScript. В модуле одна функция register, которая подписывается на события Claude Code:

hooks/register.tsxTypeScript
export const register: Register = (on, options) => {  on('session.measure', async ($, e, next) => {    await applyUsage($, e.rateLimits) // свежие проценты и время сброса    return next(e)  })   on('turn.complete', async ($, e, next) => {    const result = await next(e)    if (e.reason === 'error') await markInterrupted($) // ход оборвался — есть что продолжать    return result  })   on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {    // рисуем полосу над полем ввода  })}

Дальше цепочка простая:

  1. session.measure — движок сам присылает лимиты после каждого ответа: проценты и время сброса каждого окна.
  2. turn.complete с reason: 'error' — ход оборвался. Только тогда мод считает, что есть что продолжать.
  3. Если окно на 100% и ход оборвался — мод ставит таймер на время сброса плюс минуту.
  4. Когда таймер срабатывает — $.prompt.submit отправляет сообщение о продолжении. В него мод вставляет цитаты из истории через $.session.messages().
  5. Кнопка Zzz запускает системную команду caffeinate -i через $.process.spawn и останавливает её повторным нажатием.

У модов есть тесты: claude plugin test гоняет их на настоящем движке с подставными часами. Например, «лимит исчерпан → прошёл час и минута → ушло ровно одно сообщение» проверяется за доли секунды, без ожидания реального сброса. Сейчас в моде 29 тестов.

Нюансы, на которые я наткнулся

Моды — свежая функция, документация ещё догоняет, поэтому многое пришлось выяснять опытным путём.

Две версии Claude Code на одном Mac

Десктопное приложение работало на 2.1.295, а claude в терминале был старым — 2.1.226, который про моды ещё не знал. claude plugin validate выдавал бессмысленную ошибку, пока я не понял, что проверяю не той версией.

Стилизовать почти нельзя

Первая версия выглядела так — и это было больно:

Первая версия полосы: значения переносятся на вторую строку
Первая версия полосы: значения переносятся на вторую строку

А вот рядом нативная плашка Claude и моя полоса:

Сверху — нативная плашка Claude, снизу — ранняя версия мода с символами вместо иконок
Сверху — нативная плашка Claude, снизу — ранняя версия мода с символами вместо иконок

Нативная плашка — обычный HTML и CSS приложения. Моду такого не дают: у него Box, Text и Button, размеры в символьных ячейках, как в терминале. Нет размера шрифта, нет скруглений, нет цвета кнопки. Символы вроде ▰▱ и 📅 браузер берёт из запасных шрифтов — отсюда наклонные «шкалы» и цветные эмодзи.

Иконки, которые молча не рисовались

Для картинок есть элемент Svg. Я добавил иконки — их не было. Ни ошибки, ни предупреждения. Оказалось, у всех иконок стоял пустой alt="", и с пустой подписью приложение просто выбрасывает картинку. С подписью иконки появились:

Иконки Lucide появились после того, как у Svg появился alt
Иконки Lucide появились после того, как у Svg появился alt

Своя кнопка против скруглённых углов

Хотелось сделать включённую кнопку полупрозрачно-зелёной. У нативной кнопки цвет не задать, поэтому я нарисовал свою через Client — мини-модуль, в котором можно заливать фон и ловить клики:

Своя кнопка с полупрозрачной зелёной заливкой, но с прямыми углами
Своя кнопка с полупрозрачной зелёной заливкой, но с прямыми углами

Цвет получился, а углы — прямые. Скругление удалось только рамкой round, но она сделала кнопку вдвое выше и сломала строку:

Скруглённая рамка сделала кнопку выше, лимиты переехали в две строки
Скруглённая рамка сделала кнопку выше, лимиты переехали в две строки

В итоге вернулся к нативной кнопке: включённая — белая, а состояние показывает зелёная точка слева. Маленький урок: в модах красиво получается не тогда, когда рисуешь своё, а когда опираешься на то, что уже есть в приложении.

Ширина в ячейках, а шрифт пропорциональный

Полоса умеет ужиматься: если окно узкое — например, справа открыта панель, — остаются только иконки и проценты. Первая версия адаптива прятала время даже на широком окне. Я записал в файл, какую ширину видит мод: десктоп сообщал 94 ячейки. Только рисует он пропорциональным шрифтом, где символ занимает примерно три четверти ячейки, а я считал по ячейке на символ. Пришлось ввести поправочный коэффициент, и подбирал я его по скриншотам: сначала 0,75 — полоса всё равно съезжала, когда справа открыта панель, — потом с запасом 0,85.

Узкое окно в ранней версии: подписи обрезались многоточием
Узкое окно в ранней версии: подписи обрезались многоточием

Код проверяет сам движок

Движок читает код мода перед запуском. Функция, которой передаётся $, обязана быть объявлена на верхнем уровне файла — иначе мод не загрузится. В документации это неочевидно, всплыло только на проверке.

Команда /limits уже занята

Сначала команда мода называлась /limits. В десктопе работало, а в терминале /limits открывала страницу подписки: там есть встроенная команда с таким именем. Переименовал в /limit-watch.

Сон Mac и двойное сообщение

Таймер на три часа во время сна Mac может «стоять», и продолжение уехало бы на часы позже. Поэтому мод раз в 30 секунд сверяется с реальными часами. Но тогда после пробуждения срабатывают оба механизма разом — и уходило бы два сообщения. Тест это поймал, когда я специально запустил два продолжения одновременно. Спасает флаг «уже отправляю», который ставится до первого await.

Что нашло ревью перед публикацией

Перед публикацией я прогнал два ревью кода, и они нашли то, что легко пропустить:

  • Продолжение без обрыва. Сначала мод смотрел только на «окно на 100%». Но 100% бывает и тогда, когда ответ успешно закончился ровно на границе. Через пару часов мод написал бы «продолжай», и Claude начал бы что-то доделывать, тратя лимит. Теперь продолжение ставится, только если ход действительно оборвался.
  • Вечные попытки. Если сервер не сообщает время сброса, мод пробует каждые 15 минут. Без ограничения это длилось бы вечно — теперь после трёх неудач подряд мод выключается.

Проверка вживую и неожиданный поворот

Тесты — это хорошо, но мне хотелось увидеть всё по-настоящему. Я включил «Продолжить после сброса», продолжил работать и дождался, когда лимит сессии действительно закончится.

Лимит закончился — и прямо в чате Claude Code появилась его собственная карточка с галочкой «Автоматически продолжать после сброса лимитов» и временем возобновления. Без всяких модов:

Встроенная карточка Claude Code «Достигнут лимит сессии»: автоматическое возобновление в 23:31 и галочка «Автоматически продолжать после сброса лимитов»
Встроенная карточка Claude Code «Достигнут лимит сессии»: автоматическое возобновление в 23:31 и галочка «Автоматически продолжать после сброса лимитов»

Я увидел эту галочку впервые, хотя в десктопном приложении она, судя по журналу изменений, появилась ещё в августе. То есть ровно то, что я делал весь вечер, Anthropic уже сделали — просто я об этом не знал.

Мод, кстати, тоже отработал: после сброса он прислал своё сообщение — с моим последним запросом и пометкой, на чём Claude остановился. Но главную задачу, ради которой я всё затевал, Claude Code в десктопе решает сам.

Но у встроенной функции есть две интересные детали.

Первая: она продолжает работу только после пятичасового лимита. Когда кончается недельный, карточка выглядит иначе — галочки нет, вместо неё предложение включить платные кредиты использования:

Встроенная карточка «Достигнут недельный лимит»: только кнопки «Повторить попытку» и «Открыть настройки использования», без автопродолжения
Встроенная карточка «Достигнут недельный лимит»: только кнопки «Повторить попытку» и «Открыть настройки использования», без автопродолжения

Вторая: галочка есть только в десктопном приложении. В терминале её нет — а я часто работаю именно в терминале. Там мой мод по-прежнему единственный способ продолжить работу после сброса без меня. И недельный лимит он тоже умеет ждать — только сначала спрашивает, если до сброса больше 6 часов.

Вот так полоса выглядит в терминале — те же лимиты и кнопки, только текстом, без иконок:

limit-watch в терминальной версии Claude Code: лимиты, «Продолжить после сброса», Zzz и «Скрыть» над полем ввода
limit-watch в терминальной версии Claude Code: лимиты, «Продолжить после сброса», Zzz и «Скрыть» над полем ввода

Почему я всё равно им пользуюсь

Мод от этого не стал бесполезным — по крайней мере для меня. Мне всегда хотелось видеть текущие лимиты прямо во время работы, а не узнавать о них, когда уже поздно. Полоса над полем ввода показывает их постоянно: сколько ушло за пять часов и за неделю и когда сброс. По ней удобно решать, браться ли за большую задачу сейчас или подождать.

Есть и пара вещей, которых во встроенной функции нет:

  • продолжение после сброса работает и в терминале — а там встроенной галочки нет вовсе;
  • учитывается недельный лимит: если до сброса больше 6 часов, мод спрашивает, ждать ли;
  • кнопка Zzz не даёт Mac уснуть, пока ждём сброса.

Так что limit-watch остаётся у меня — как приборная панель лимитов.

Как установить

Нужен Claude Code 2.1.295 или новее. Одна команда в терминале:

Терминал
claude plugin install limit-watch --marketplace setcodes/claude-code-mods

Откройте новую сессию — в терминале или во вкладке Code десктопа — и полоса появится над полем ввода. Чтобы проверить продолжение, не дожидаясь настоящего лимита, наберите в чате /limit-watch test 1m: через минуту мод отправит настоящее сообщение о продолжении.

Как поделиться своим модом

Если вы сделали свой мод, поделиться им можно за несколько минут. Я так и выложил limit-watch.

  1. Создайте на GitHub публичный репозиторий. Удобно сразу под несколько модов — у меня это setcodes/claude-code-mods.
  2. Положите каждый мод в свою папку, а в корень — файл .claude-plugin/marketplace.json со списком модов. С ним репозиторий становится маркетплейсом:
.claude-plugin/marketplace.jsonJSON
{  "name": "claude-code-mods",  "owner": { "name": "Egor Maximov" },  "plugins": [{ "name": "limit-watch", "source": "./limit-watch" }]}
  1. Заполните в plugin.json описание, автора, homepage и version, добавьте README с командой установки.
  2. Проверьте всё строгой проверкой и тестами:
Терминал
claude plugin validate --strict limit-watchclaude plugin test limit-watch
  1. Запушьте — мод опубликован, без всяких форм и модерации. Дайте людям команду: claude plugin install <мод> --marketplace <логин>/<репозиторий>.
  2. При каждом релизе повышайте version. Иначе claude plugin update ответит, что всё уже последней версии, и обновление до людей не дойдёт.

Шире всего — каталог плагинов Anthropic: оттуда плагин попадает к людям на claude.ai, в Cowork и в Claude Code. Подаётся через портал разработчика, нужен платный план claude.ai, и каждую версию проверяют перед публикацией.

Что дальше

Пока я разбирался с лимитами, нашёл в Claude Code скрытую команду /limit-reset — сброс лимита, похожий на тот, что недавно появился в Codex у ChatGPT. Была идея добавить на полосу кнопку «Сбросить лимит сейчас». Но теперь я знаю, с чего начну: сначала проверю, не сделали ли это уже в Claude Code.

Мод открытый, код и тесты — в репозитории. Если найдёте ошибку в переводе или идею для следующего мода — пишите.