Skill v1.0.0
currentAutomated scan100/100version: "1.0.0" name: subscription description: Состояние подписок Claude — окна лимитов (5 часов, неделя, помодельные), темп расхода, прогноз упора и местный расход в долларах. Применять, когда хозяин спрашивает «сколько осталось», «как подписка», «на чём мы», «не упрёмся ли», а также в утреннем ритуале и перед тяжёлой работой.
subscription — сколько осталось от подписки
Что даёт
· Хозяин видит остаток раньше, чем упрётся в стену посреди работы. · Ответ числом и с временем сброса, а не «вроде хватает». · Одна и та же картина у всех агентов флота — считается одинаково.
Когда
Спросили про лимиты, остаток, расход или «почему всё встало». Утренний ритуал. Перед большой работой, если неделя уже за 80%.
Не по своей инициативе в течение дня: эндпоинт режет частые запросы, и лишний опрос делает хуже всем.
Как
python3 ~/.claude/skills/subscription/subscription.py # отчёт python3 ~/.claude/skills/subscription/subscription.py --telegram # готовый блок в чат python3 ~/.claude/skills/subscription/subscription.py --card # PNG-дэшборд (путь) или пусто python3 ~/.claude/skills/subscription/subscription.py --json # машине python3 ~/.claude/skills/subscription/subscription.py --local # без сети, только расход python3 ~/.claude/skills/subscription/subscription.py --force # спросить сервер вне очереди
В Telegram отправлять `--telegram`. Отчёт держится на выравнивании, а обычный текст в Telegram не моноширинный — колонки разъедутся. Ключ заворачивает вывод в блок кода: format: "markdownv2", внутри блока экранировать ничего не нужно.
--force — только по прямой просьбе. Без причины не дёргать.
Команды в чате (mila-companion, 10.09.2026)
Хозяин пишет боту команду — агент отвечает сразу, без вопросов:
| Команда | Что делает | ||
|---|---|---|---|
/usage (или слово «подписки», «usage») | своя подписка: текстовый блок --telegram (слово владельца 10.09: в Telegram и терминале — текст в стиле claude code, картинки не слать); /usage card — картинка по просьбе | ||
/usage all | все подписки из accounts.json и агенты на них — текстовый блок + строка совета «кого переключить»; /usage all card — картинкой | ||
/usage watch on / off | включить/выключить часовой сторож (`subscription_watch.py --on | --off`) | |
/usage json | сырой --json файлом (для старшей и разборов) |
Порядок хода: python3 ~/.claude/skills/subscription/subscription.py --telegram → блок markdownv2 одним сообщением; card в команде → --card → reply(files=[png]), пусто → тот же текст. Одна строка вывода под картинкой обязательна: «неделя 46 %, сильная модель 7 % — до среды тяжёлое на Sonnet», без пересказа цифр с картинки.
Картинка (rich media)
subscription_card.py рисует card.html в фирменных цветах и печатает PNG через Chrome. В контейнере Chrome нет — тогда берётся общий PNG старшей: в accounts.json поле "card": {"path": "/home/companion/state/subscription-card.png", "max_age_min": 75}; старшая кладёт его раз в час вместе с отчётом. Устарел или нет — текстовый блок, без извинений. Статус агента на картинке: 🟢 работает · 🟡 данным N ч · 🔴 стоит (5-часовой бак < 3 %).
Сторож (раз в час)
subscription_watch.py по cron/launchd: история снимков, темп по своей истории (не раньше чем через 2 ч точек), сигнал хозяину один раз на повод, повтор через 3 ч: неделя/сильная модель ≤ 20 % или «кончится раньше сброса»; 5-часовой бак ≤ 30 %. Доставка: Компаньон — --tg-token-env TELEGRAM_BOT_TOKEN --chat <id хозяина>; Мила Админ — --outbox ~/.claude/channels/telegram/outbox --chat <id>. Картинка прикладывается, если собралась. --off / --on — состояние в $SUBSCRIPTION_STATE/subscription-watch.off.
Утренний отчёт
В утренний ритуал (WAKE.md) — одна строка из --telegram блока или картинка --card после дел дня; не первой строкой, не отдельным сообщением, если нет сигнала.
Как читать отчёт
бак · осталось 5 часов ███████████░ 99% ровно неделя ████░░░░░░░░ 36% ровно нед · Fable █░░░░░░░░░░░ 2% пусто
сброс 5 часов сегодня 18:50 — через 2 ч 45 мин неделя сб 12.09 08:00 — через 2 дн 15 ч
Время сброса — точное, с днём недели, и всегда с обратным отсчётом (просьба хозяина 09.09: «дата, время и сколько осталось в днях-часах»). Окна с общим сроком — неделя и помодельные — сводятся в одну строку: ключ группировки по минуте, потому что у них метки расходятся на микросекунды.
Показываем остаток, а не расход — так просил хозяин 09.09: «мне понятней видеть бак». Полоса и число — сколько осталось до сброса. Проценты — доля окна, не деньги.
Правая колонка сравнивает скорость расхода с ходом времени в окне:
ровно — тратим примерно по ходу окна, остатка хватит до сброса. тает быстро — расход обгоняет время больше чем на 15 пунктов, кончится раньше срока. с запасом — идём медленнее окна. пусто — осталось 5% и меньше, окно можно считать закрытым до сброса.
Строка «при этом темпе … кончится …» появляется только при заметном перерасходе и пока в баке что-то есть — иначе это шум.
Расход в долларах — пересчёт по прайсу API, а не счёт. Подписка так не тарифицируется. Так и говорить: «мера, не счёт». Числом меряем нагрузку, а не выставляем сумму.
Несколько подписок
accounts.json рядом со скриптом. Одна запись — одна подписка:
{"accounts": [ {"name": "Основная", "credentials": "~/.claude/.credentials.json"}, {"name": "Вторая", "credentials": "~/work/tools/accounts/second.credentials.json"} ]}
Вместо файла можно {"name": "…", "env": "ИМЯ_ПЕРЕМЕННОЙ"}.
Чужой контейнер недостижим по устройству. Файл входа виден только тот, что смонтирован в свой дом. Токен от claude setup-token не подойдёт: он только для вывода, окон лимитов не отдаёт (нет области user:profile).
Поэтому чужая подписка берётся готовым отчётом, а не входом:
{"name": "Мила Админ", "report": "/home/companion/state/subscription-ashotashirov.json"}
Файл — вывод этого же скрипта с --json, его кладёт тот агент, у кого этот вход живёт. К нам приезжают только проценты и время сброса; чужой вход остаётся у чужого агента. Так с 09.09 подключена вторая подписка владельца (<email> — рабочий вход старшей на Маке, обновление раз в полчаса).
Возраст отчёта проверяется всегда. Старше часа — в отчёте «отчёт устарел, снят N часов назад»; нет файла — «не подключена — отчёт не приходил». Чужие цифры без отметки о времени не показывать.
На Маке вход Claude Code лежит не в файле, а в связке ключей — там читается через security find-generic-password -s 'Claude Code-credentials' -w (доработка старшей от 09.09; в контейнерах Linux не нужна).
Устройство — чтобы чинить, а не гадать
Токен — ~/.claude/.credentials.json, объект claudeAiOauth. Каталог переопределяется переменной CLAUDE_CONFIG_DIR.
Окна — GET https://api.anthropic.com/api/oauth/usage, заголовки Authorization: Bearer … и anthropic-beta: oauth-2025-04-20. Без beta-заголовка приходит 401. Имя и план — соседний /api/oauth/profile.
Ответ: five_hour и seven_day с utilization (0–100) и resets_at. Помодельные недельные окна лежат в массиве limits, записи kind: "weekly_scoped" с scope.model.display_name и percent; старые ключи seven_day_<модель> возвращают null.
Местный расход — state/usage-daily.json, его считает хук.
Механизм разобран по исходникам OpenUsage (MIT, github.com/robinebers/openusage, Sources/OpenUsage/Providers/Claude/). Реализация своя.
Чего делать нельзя
Не обновлять токен самому. Claude Code перевыпускает его сам; запись ротированного токена ломает живую сессию. Просроченный — просто сказать.
Не показывать токен. Ни в чат, ни в лог, ни в кэш. В кэше лежат только проценты и время сброса — проверено грепом.
Не долбить `--force`. 429 прилетает легко, держится часами, Retry-After бывает не всегда. В скрипте кэш на 15 минут и выдержка с удвоением до часа — это защита, а не помеха.
Не называть доллары счётом клиенту. Это внутренняя мера нагрузки.
Что ломается со временем
anthropic-beta: oauth-2025-04-20 — дата в заголовке однажды сменится, и окна молча перестанут читаться. Если в отчёте вдруг «вход просрочен» на живом входе — смотреть сюда первым делом.