Диагностика: что команда делала
This page is in Russian.
Одно событие на запрос, два места, куда его можно направить. --trace показывает и ничего не
хранит, --record хранит и ничего не показывает. По умолчанию ничего не показывается, а
сохраняется только запуск, который кончился ошибкой (см. «Неудачный запуск сохраняется всегда»).
Показать
max chats list --trace→ session.init op 6 seq 1 432 B
← session.init op 6 seq 1 89ms 335 B 38 reg-country-code
→ session.login op 19 seq 2 871 B
← session.login op 19 seq 2 202ms 48.0 kB 25 chats 6 contacts
→ contacts.info op 32 seq 3 154 B 3 contacts
← contacts.info op 32 seq 3 91ms 6.5 kB 10 contacts→ — что спросили, ← — что пришло, • — ответ, который не уходил в сеть. Дальше по строке:
операция, опкод протокола, номер запроса в соединении, названные идентификаторы, длительность,
размер кадра и сколько чего вернулось.
Всё это идёт на stderr, поэтому рядом с --json ничего не ломается:
max chats list --json --trace > chats.json # данные в файл, диагностика на экранВ терминале — строки выше; в трубе — по одному объекту JSON на строку, то же самое правило, что и для данных:
max chats list --json --trace 2>&1 >/dev/null | jq -c 'select(.event == "response")'--trace сильнее --quiet: флаг, который дописан руками, срабатывает всегда.
Команды бота
У max <имя> bot … одна строка на HTTP-запрос к Bot API: операция, идентификаторы из адреса
(чат, сообщение, человек, комментарий), HTTP-код, время, размер ответа.
max shop bot messages list -100 --trace→ getMyInfo
← getMyInfo 200 143ms 211 B
→ getMessages chat -100
← getMessages 200 chat -100 187ms 6.2 kBОтказ показывает код ошибки и ключ MAX, например 404 not_found not.found, но не текст
ответа. Загрузка файла (--file, uploads put) — отдельная пара строк upload.image, upload.video и
так далее: размер, HTTP-код, время. Адреса загрузки и имени файла в ней нет: адрес сам работает как
пропуск.
Сохранить
max chats list --record
max runs list # что делалось, новое сверху
max runs show <id> # один запуск: чем кончился и куда ходил
max runs path <id> # каталог, для jq и grepКаталог запуска:
~/.local/share/max-cli/runs/2026-09-19/20260919T234428Z-chats-list-9df39e/
run.json что это было, когда, какой профиль, сколько длилось, чем кончилось
events.jsonl по объекту JSON на запрос, без единого управляющего символаКаталог — 0700, оба файла — 0600. run.json пишется дважды: как только запуск начался, со
статусом running, и в конце — с итогом. Каталог с событиями и без метаданных был бы особым
случаем, который max runs list носил бы вечно.
Итог записывается на любом пути — в том числе когда команда упала, не успев подключиться:
{ "runId": "…", "command": "chats list", "profile": "default", "status": "failed",
"requests": 0, "errorCode": "authentication_error", "durationMs": 12 }Чего в записи нет
Это главное, ради чего страница написана.
| Записывается | Не записывается никогда |
|---|---|
| операция, опкод, номер запроса | название чата |
идентификатор чата, номер отправки (send), идентификатор сообщения | имя человека |
| сколько байт ушло и пришло | текст сообщения |
| сколько миллисекунд занял ответ | номер телефона |
| сколько чатов, контактов, сообщений вернулось | токен |
код ошибки, и короткий ключ ошибки MAX вида login.token | текст ошибки, пришедший от MAX |
предупреждение — кодом, например reactions_unread | текст предупреждения |
| при падении — тип ошибки и строки кода, где оно случилось | текст ошибки при падении |
версия, среда (node или bun), система | путь к домашнему каталогу |
Ни в обрезанном виде, ни хэшем. Событие собирается из полей, названных по именам, а не
фильтрованием копии запроса: поле, которого никто не предвидел, в журнал попасть не может. У
session.login есть поле token — и ни одна ветка в коде до него не дотягивается.
Идентификаторы, наоборот, внутри сознательно: идентификатор чата — непрозрачное число, бесполезное без сессии, к которой он относится, и это единственное, что делает диагностику полезной, потому что любая настоящая жалоба — про один конкретный разговор.
Текст ошибки MAX не записывается по той же причине: отказ сервера может цитировать то, что мы
послали, а послали мы в том числе сообщение. Записывается только ключ — строчные латинские буквы,
цифры, точки и дефисы, как proto.payload. Если MAX ответил чем-то другим, не пишется ничего.
Что можно с этим делать
# сколько времени ушло на вход в последних запусках
for id in $(max runs list --json | jq -r '.items[].runId'); do
jq -r 'select(.operation=="session.login" and .event=="response") | "\(.durationMs)ms"' \
"$(max runs path "$id" --json | jq -r .path)/events.jsonl"
done
# какие запуски закончились плохо
max runs list --json | jq '.items[] | select(.status=="failed") | {runId, command, errorCode}'max runs show печатает то же самое, убрав служебные поля, которые Pino повторяет в каждой
строке: без этого таблица уезжает за правый край экрана раньше, чем доходит до длительностей.
Файл целиком, со служебными полями, отдаёт max runs path.
Сколько это живёт
30 дней, и удаление старого происходит только в тот момент, когда что-то записывается:
инструмент, который ничего не пишет, не имеет причин ходить по этому каталогу. Срок меняется
полем keepRunsForDays в настройках.
Удаляется днями целиком, по имени каталога, поэтому ничего не нужно открывать, чтобы решить.
Неудачный запуск сохраняется всегда
Если команда кончилась ошибкой, её запуск сохраняется и без --record — с пометкой
"keptBecauseFailed": true в run.json. Это касается любой команды и любой ошибки: неверного
флага, неизвестной команды, проверки до начала работы, команд, которые в MAX не ходят (models,
server, watch, upgrade). В записи — только слова команды, например messages list, без того,
что было написано после них. Удачный запуск без --record не оставляет ничего. Так
у отчёта о проблеме есть что приложить, а история того, что вы читали, по-прежнему не копится.
--no-record или "record": false в настройках отключают и это.
Когда записывать постоянно
{ "profiles": { "default": { "record": true } } }Тогда пишется каждый запуск, а --no-record отключает запись для одного вызова. Обратное — то,
что по умолчанию: удачный запуск не записывается, пока не попросили; неудачный сохраняется всегда,
без текстов, чтобы было что приложить к сообщению об ошибке. Мессенджер, который сам собирает
каталог с историей того, кого вы читали и когда, — это чужая жизнь в чужом логе.
Дальше
- security.md — что вообще попадает на диск
- troubleshooting.md — как этим пользоваться, когда что-то не работает