Перейти к основному содержимому

JSON-events схема

CLI переключается в JSON-lines режим автоматически когда запущен внутри AI-агента (Cursor, Claude Code) или с не-TTY stdout. Также можно включить явно: флаг --json или env LAYERO_JSON=1.

В этом режиме CLI:

  • Не задаёт вопросов — все интерактивные подтверждения пропускаются (для --prod всё равно нужен --yes)
  • На stdout печатает по одной строке {"event":"...", ...} за действие
  • Ошибки приходят со стабильным code и next_action
  • Каждое событие также содержит поле ts (ISO-8601 timestamp)

События

Каждая строка — самостоятельный JSON-объект. Парсите по event полю.

auth_required

CLI начал device-flow логин. Покажите URL пользователю как кликабельную ссылку.

полетиппримечание
urlstringнапример https://app.layero.ru/cli?code=ABCD-1234
user_codestringнапример ABCD-1234 — также видно на странице подтверждения

CLI продолжит поллить каждые 2 секунды. Когда пользователь подтвердит — последует authorized. Истечение — error{code: "auth_expired" | "auth_timeout"}.

authorized

Логин успешен.

полетип
userstring — username, email или user id

detected

Авто-детект фреймворка отработал.

полетип
frameworkstring — next/vite/astro/sveltekit/nuxt/gatsby/cra/docusaurus/static
build_cmdstring
output_dirstring
confidentboolean — false для static-fallback

project_created

Первый деплой в этой папке. Создан новый проект.

полетип
project_idstring
slugstring
organizationstring — slug организации

project_linked

Деплой в существующий проект (cwd привязан через .layero/project.json).

полетип
project_idstring
slugstring

packing

CLI упаковал директорию в tar.gz.

полетип
filesnumber
bytesnumber
sha256string

uploading

Заливка архива в S3 началась. Без дополнительных полей.

uploaded

Заливка успешна.

полетип
archive_keystring

prebuilt

Деплой идёт с готовой сборкой (--prebuilt <dir>) — установка зависимостей и сборка на стороне платформы пропускаются.

полетип
dirstring — папка с артефактом

runtime_type_applied

Проект определён как runtime-приложение, и тип проставлен автоматически.

полетип
project_typessr_next · node_web · python_web · streamlit · gradio · flask

runtime_type_apply_failed

Тип определился, но проставить его не удалось. Деплой продолжается с прежним типом проекта.

полетип
errorstring

setup_applied

Применили настройки проекта (framework_hint / build_cmd / output_dir) на первом деплое. Без полей.

repeated_failure_guard

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

Дальше CLI либо спросит подтверждение (интерактивный терминал), либо завершится с кодом repeated_failure. Продолжить автоматически нельзя — это ровно тот цикл, который правило разрывает.

полетип
streaknumber — сколько отказов с этой ошибкой насчитано
thresholdnumber — порог, на котором срабатывает стоп
scope"project" | "owner" — где насчитано: в этом проекте или суммой по всем вашим проектам
failure_stagestring, опционально — стадия сборки
errorstring, опционально — текст ошибки

scope: "owner" отвечает на вопрос, который возникает первым: «я собирал здесь три раза, откуда десять?». Одна и та же ошибка считается и по всем проектам владельца сразу — перенос приложения в новый проект правило не обходит, потому что причина не в проекте.

deploy_started

Бэкенд принял задачу.

полетип
deploy_idstring

stage

Сменилась стадия сборки.

полетип
nameclone/install/build/upload/activate

build_log

Строка лога сборки. Форвардить пользователю стоит только если содержит ошибку — в успешных билдах их много и они шумные.

полетип
linestring
streamstdout/stderr

ready

Финальное событие. Деплой жив. Покажите url пользователю и завершите выполнение.

полетиппримечание
urlstringЖивой публичный адрес сайта — НЕ дашборд. Для обычного layero deploy CLI-проекта это production-адрес проекта (CLI-загрузки авто-промоутятся в apex). Для деплоя в конкретную ветку (--branch) — preview-адрес ветки. Адрес живой сразу; открывайте и показывайте пользователю именно его.
dashboard_urlstring?Страница управления проектом в дашборде (https://app.layero.ru/projects/<id>). Это НЕ сайт — не выдавайте её как ссылку на готовый сайт.
preview_urlstring?Legacy, больше не приходит. Отдельный per-deploy preview-хост в зоне *.preview.layero.ru. Существовал, чтобы дать ссылку, пока apex прогревался на CDN. Отдельной preview-зоны у layero.app нет, а на layero.ru пользовательских сайтов не осталось — поле не заполняется ни для одного проекта.
edge_readybool?Отвечает ли адрес на момент завершения деплоя. Раньше поле означало «apex прогрелся на CDN» и у новых хостов навсегда оставалось false; теперь берётся из реальной пробы. Как гейт всё равно не нужно: адрес живой сразу.
edge_eta_secondsnumber?Legacy, больше не приходит. Оценка остатка прогрева CDN. Распространять нечего — CDN перед пользовательскими сайтами нет.
deploy_idstring

Апекс переведён на указанный деплой. Приходит от layero promote и от layero deploy --promote.

полетип
urlstring — публичный адрес
deploy_idstring

error

полетип
codestring — см. таблицу ниже
next_actionstring — конкретная команда / URL для разрешения
messagestring — человекочитаемое описание

Коды ошибок

Список сверен с исходниками CLI: это все коды, которые он действительно выдаёт. Не изобретайте обработку кодов, которых здесь нет.

codeКогда происходитЧто делать (next_action)
auth_requiredНет токена ни в ~/.layero/config.json, ни в LAYERO_TOKENlayero login, либо задать LAYERO_TOKEN
auth_expiredВход больше не действует: либо user_code истёк (15 мин TTL) и пользователь не подтвердил, либо сохранённый токен протух (TTL 7 дней) или сессия отозвана — API ответил 401Запустить layero login ещё раз
auth_timeoutCLI поллил 15 минут, юзер так и не подтвердилЗапустить layero login ещё раз
plan_limitЛимит тарифа: API ответил 402 (например, проектов на free-тарифе больше, чем разрешено)Сменить тариф на app.layero.ru/billing или удалить ненужное
username_requiredУ аккаунта не выбрано имя (оно же адрес личной организации) — API отвечает 412. В интерактивном терминале login и deploy спрашивают имя сами, в агентском режиме спрашивать некогоlayero username <имя>
username_rejectedИмя занято, зарезервировано или не проходит по форматуВыбрать другое: строчные латинские буквы, цифры и дефис, 2–32 символа
oauth_unavailableПровайдер входа недоступенЭто на нашей стороне — попробовать позже
project_unknownКоманда вызвана вне каталога проекта и без --projectЗапустить из каталога проекта или передать --project <id|slug>
project_not_found--project указывает на несуществующий проектlayero projects list
cli_deploys_disabledАдмин выключил CLI-деплои в проектеВключить в Project Settings → CLI deploys, либо деплоить в другой проект
invalid_type--type с неизвестным значениемУбрать флаг (авто-детект) или передать валидный пресет — список в сообщении
invalid_choiceИнтерактивный prompt получил невалидный выбор в non-TTYПередать значение явным флагом
prebuilt_no_dirКаталог из --prebuilt не найденУказать явно: --prebuilt ./dist
prebuilt_no_indexВ каталоге --prebuilt нет index.htmlУказать папку со собранным index.html
deploy_not_startedСборка не стартовалаПовторить layero deploy; если повторяется — смотреть проект в дашборде
deploy_failedБилд не дошёл до readyОткрыть логи по ссылке из next_action
repeated_failureПодряд идущие сборки падают с одной и той же ошибкой, и платформа отказалась выкатывать следующую вслепую. Текст ошибки — в message и в событии repeated_failure_guardПрочитать ошибку и устранить причину. Повтор без изменений даст тот же результат. Если причина уже устранена — layero deploy --confirm-repeated-failure
repeated_failure_declinedТо же, но в интерактивном терминале на вопрос «Всё равно выкатить?» ответили «нет»Исправить ошибку и запустить layero deploy заново
no_deploy / no_deploysУ проекта ещё нет деплоевСначала layero deploy
rollback_unsupportedУ деплоя нет раздаваемого артефакта: runtime-проект либо вычищенная по ретенции статикаПересобрать нужный коммит через layero deploy
env_not_foundПеременной нетlayero env list
nothing_to_setlayero env set вызван без пары KEY=valuelayero env set KEY=value
bad_formatАргумент не разобранФормат — в сообщении
domain_not_foundДомена нет у проектаlayero domains list
domain_rejectedПлатформа отклонила доменПричина — в сообщении
forbiddenОперации не хватает scope у токена CI (layero_ci_*)Выпустить токен с нужным scope
org_unknownУ аккаунта несколько организаций, а команда не знает, в какой работатьПередать --org <slug>; список — layero orgs list
database_unknownВ организации нет базы с таким именем, слагом или idlayero db list; завести — layero db create <имя>
sql_missinglayero db sql вызван без запросаПередать запрос: -c "select 1"
branch_without_envДля ветки ещё нет окруженияСначала задеплоить эту ветку
analytics_not_connectedАналитика не подключенаlayero analytics connect
no_runsНет прогонов замера скоростиlayero perf check
internalНепредвиденная ошибка CLI (сеть, неожиданное исключение)Перезапустить с --debug
Код деплоя собирается из статуса

Код неуспешного деплоя формируется как deploy_<status> по статусу сборки, а статусов у деплоя четыре: ready, building, failed, cancelled. Значит на практике встречаются ровно deploy_failed и deploy_cancelled — кодов deploy_error и deploy_timed_out не существует, не закладывайтесь на них.

Cold-start template для агента

Минимальный поведенческий блок (положите в системный промпт):

If user asks to deploy via Layero:
1. Run: npx layero@latest deploy --json
2. Parse each stdout line as JSON, route on .event:
- "auth_required" → render .url as clickable link, keep waiting
- "ready" → show .url (the live site) to user. It is reachable right
away — do NOT gate on .edge_ready. Then stop.
- "error" → follow .next_action verbatim
3. Never run `git init`. Never run `npm install -g layero`.

Полный пример — Деплой из AI-агентов.