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

CLI-клиент

Notifly-CLI — это маленькая консольная утилита notifly для отправки сообщений в ваш канал прямо из терминала, cron-задач и shell-скриптов. Она хранит токен и адрес сервера в конфиге, умеет читать сообщение из stdin и отслеживать изменение вывода произвольной команды (watch).

Утилита не обязательна для отправки уведомлений — то же самое можно сделать через curl (см. REST API). CLI просто избавляет от повторения токена и URL в каждой команде.

Готовых сборок CLI для скачивания пока нет: утилита собирается из исходников — каталога cli/ репозитория Notifly (по вопросам доступа к исходникам пишите на support@notifly.ru). Нужен Go 1.27+ и рядом — каталог sdk/go того же репозитория: CLI использует Go SDK из рабочего дерева.

Окно терминала
cd cli
go build -o notifly cli.go
./notifly version

make build соберёт сразу набор бинарников в подкаталог build/ — под Linux (amd64, 386, arm64, armv7), macOS (amd64, arm64) и Windows (amd64, 386); файлы называются по-старому, gotify-cli-<ОС>-<архитектура> — наследство форка.

При желании положите бинарник в каталог из $PATH:

Окно терминала
sudo mv notifly /usr/local/bin/notifly
notifly init # мастер настройки (запишет конфиг)
notifly version # показать версию (алиас: v)
notifly config # показать текущий конфиг
notifly push # отправить сообщение (алиас: p)
notifly watch # следить за выводом команды и слать изменения
notifly create-app # создать канал (нужен API-токен)
notifly list # последние сообщения (алиас: ls; нужен API-токен)
notifly ask # задать вопрос и, если нужно, дождаться ответа
notifly help # помощь по командам (алиас: h)

Помощь по конкретной команде: notifly help push, notifly help watch.

Самый простой способ начать — мастер init. Он спросит адрес сервера, токен и приоритет по умолчанию, проверит соединение и запишет конфиг.

Окно терминала
$ notifly init
Notifly URL: https://api.notifly.ru
Notifly v2.7.4@2025-09-25-16:27:04
Configure an application token
1. Enter an application-token
2. Create an application token (with user/pass)
Enter 1 or 2: 2
Sign in (credentials are used now and not saved; only the issued tokens are)
Email: me@example.com
Password:
Signing in -> Success!
Application name: deploy-bot
Application description (can be empty): CI notifications
Creating -> Success!
Default Priority [0-10]: 6
API token for the account-level commands (create-app, list)
1. Enter an API token (issued on the "API tokens" page of the admin UI)
2. Issue a new API token (with user/pass)
Press Enter to skip — pushing works without one.
Enter 1, 2 or nothing: 2
API token name [notifly-cli (myhost)]:
Issuing API token -> Success!
Issued API token "notifly-cli (myhost)" (M…d8Fs); manage it on the "API tokens" page of the admin UI.
Written config to: /home/user/.config/notifly/cli.json

На шаге App-токена два варианта:

  • 1 — ввести готовый App-токен. Возьмите его из админки; утилита тут же проверит его, отправив тестовое сообщение в канал.
  • 2 — создать App-токен по логину/паролю. Вы вводите email и пароль, CLI входит в аккаунт как временное устройство notifly-cli setup (имя машины), создаёт канал с указанными именем и описанием и сохраняет его токен. Если в аккаунте включена 2FA, мастер спросит код из приложения-аутентификатора или recovery-код; при подключённом методе «Notifly mobile» можно подтвердить вход в приложении и просто нажать Enter. Логин и пароль не сохраняются — только итоговый токен.

Приоритет по умолчанию должен быть числом от 0 до 10.

Последний шаг — API-токен для команд create-app и list. Enter пропускает его: отправка работает и без API-токена.

  • 1 — вставить готовый API-токен со страницы API-токены в админке; мастер проверит его одним запросом на чтение.
  • 2 — выпустить новый API-токен по логину/паролю. Тот же вход, что и для App-токена: если вы уже входили на предыдущем шаге, пароль второй раз не спрашивается. Токен выпускается с правом write, без ограничения по каналам и без срока действия, с именем notifly-cli (имя машины); сузить скоуп или поставить срок можно потом на странице API-токены.

Временное устройство мастер удаляет перед записью конфига: ни слот в лимите устройств, ни токен устройства после него не остаются. Как любой вход по паролю, он шлёт владельцу письмо «новый вход», а на заполненном лимите устройств на время усыпляет самое старое из них (оно проснётся при следующем обращении). Если мастер прерван до конца, устройство notifly-cli setup (…) останется на странице Устройства — удалите его вручную.

Файл конфига мастер создаёт с правами 0600: в нём лежат живые токены.

init предложит выбрать путь, а остальные команды ищут конфиг в этих местах (первый найденный — побеждает):

  1. ./cli.json (рядом с текущим каталогом);
  2. $XDG_CONFIG_HOME/notifly/cli.json (обычно ~/.config/notifly/cli.json);
  3. ~/.notifly/cli.json;
  4. /etc/notifly/cli.json (кроме Windows).

Следом, если ничего не нашлось, просматриваются те же пути с gotify вместо notifly — наследство форка, чтобы старый конфиг продолжал работать.

Конфиг — это обычный JSON. Можно создать его руками, не запуская мастер:

{
"token": "AbC3dEf5gHi7jKl9mNo1pQr",
"url": "https://api.notifly.ru",
"defaultPriority": 6,
"apiToken": "Mx7Kp2Lq9Wz4Rt6Yb1Nd8Fs"
}
ПолеОписаниеПример
tokenApp-токен (API-токен и токен устройства для отправки не подойдут)AbC3dEf5gHi7jKl9mNo1pQr
urlАдрес API Notiflyhttps://api.notifly.ru
defaultPriorityПриоритет по умолчанию (0, если не задан)6
apiToken(необязательно) API-токен для команд create-app и listMx7Kp2Lq9Wz4Rt6Yb1Nd8Fs

Кроме отправки CLI умеет две операции над аккаунтом — завести канал и прочитать последние сообщения. Им нужен не app-токен, а API-токен (M…): его выпускают в админке на странице API-токены или прямо в мастере notifly init по логину/паролю, а CLI берёт его из поля apiToken, флага --apiToken или переменной окружения NOTIFLY_API_TOKEN.

Окно терминала
$ export NOTIFLY_API_TOKEN=Mx7Kp2Lq9Wz4Rt6Yb1Nd8Fs
$ notifly create-app -n "deploy-bot" -d "Уведомления CI"
Channel created
ID: 42
Name: deploy-bot
App-Token: AbC3dEf5gHi7jKl9mNo1pQr
$ notifly list -n 10

create-app печатает app-токен нового канала — его и кладут в token, чтобы дальше слать в этот канал через notifly push. Канал, созданный API-токеном с ограниченным скоупом, автоматически попадает в его скоуп.

notifly init предлагает API-токен на отдельном шаге — вставить готовый или выпустить новый по логину/паролю (см. Настройка); пропустите его клавишей Enter, если аккаунтные команды не нужны.

Посмотреть, какой конфиг используется сейчас:

Окно терминала
$ notifly config
Used Config: /home/user/.config/notifly/cli.json
URL: https://api.notifly.ru
Default Priority: 6
Token: AbC3dEf5gHi7jKl9mNo1pQr
API Token: set (M…d8Fs)

notifly ask задаёт вопрос через канал — уведомление приходит с кнопками ответа, а CLI может дождаться нажатия. Это готовый approval-гейт для скрипта развёртывания: подробнее о самой механике — на странице Вопросы (Ask). Нужен app-токен канала, тот же, что у push.

Окно терминала
$ notifly ask -o yes,no --wait "Выкатывать в прод?"
question created, id: 8260183728527568 — waiting for the answer (Ctrl+C to stop)...
answer: yes

Флаги идут до текста вопроса: всё, что стоит после него, считается частью вопроса.

ФлагНазначениеПо умолчанию
-o, --optionsВарианты ответа через запятую; без них ответ свободным текстом—
--timeoutЧерез сколько секунд вопрос истечётбез срока
--default-answerОтвет, засчитываемый по истечении (нужен --timeout)—
-t, --titleЗаголовок уведомленияимя канала
-w, --waitЖдать ответа, а не печатать только idвыкл.
--pollИнтервал фолбэка при ожидании, в секундах3
-q, --quietПечатать только сам ответ — удобно для $(...)выкл.
--token, --urlПереопределить app-токен и адрес (env: NOTIFLY_TOKEN)из конфига

С --wait ответ приходит push-ом по WebSocket, поэтому команда завершается в тот же момент, когда человек нажал кнопку. Если сокет недоступен, CLI переходит на опрос раз в --poll секунд. Ctrl+C прекращает ожидание, сам вопрос остаётся неотвеченным.

Коды выхода делают команду пригодной для if: 0 — ответ получен, 1 — вопрос истёк, отменён или ожидание прервано.

Окно терминала
if answer=$(notifly ask -q -o yes,no --wait "Выкатывать в прод?") && [ "$answer" = yes ]; then
./deploy.sh
fi

Текст сообщения передаётся аргументом или через stdin:

Окно терминала
notifly push my message
notifly push "моё сообщение"
echo "моё сообщение" | notifly push
notifly push < somefile

Заголовок и приоритет:

Окно терминала
notifly push -t "Деплой" -p 10 "Прод выкатился"

Флаги команды push:

ФлагНазначениеПо умолчанию
-p, --priorityПриоритет сообщенияиз defaultPriority
-t, --titleЗаголовок (если пусто — берётся имя приложения)имя приложения
--tokenПереопределить App-токен (env: NOTIFLY_TOKEN, GOTIFY_TOKEN)из конфига
--urlПереопределить адрес сервераиз конфига
-q, --quietНичего не печатать при успехевыкл.
--contentTypeContent-type сообщения, например text/markdown (см. msgextras)—
--clickUrlURL, открываемый по тапу на уведомление (см. msgextras)—
--bigImageUrlURL картинки, показываемой в уведомлении (см. msgextras)—
--disable-unescape-backslashНе раскрывать \n и \t (оставить как обычный текст)раскрывает

Если -p не указан, берётся defaultPriority из конфига; если нет и его, приоритет не передаётся вовсе и сервер берёт умолчание канала.

Не обязательно держать конфиг — можно передать токен и адрес прямо в команде или через переменную окружения NOTIFLY_TOKEN (старое имя GOTIFY_TOKEN тоже принимается):

Окно терминала
notifly push --url https://api.notifly.ru --token AbC3dEf5gHi7jKl9mNo1pQr "без конфига"
NOTIFLY_TOKEN=AbC3dEf5gHi7jKl9mNo1pQr notifly push --url https://api.notifly.ru "из env"

По умолчанию notifly раскрывает \n и \t в реальные перенос строки и табуляцию. Это удобно для многострочных сообщений из одной строки аргумента:

Окно терминала
notifly push -t "Отчёт" "Строка 1\nСтрока 2\tс табом"

Чтобы оставить \n и \t как буквальный текст — добавьте --disable-unescape-backslash.

Markdown включается через --contentType:

Окно терминала
notifly push --contentType text/markdown -t "Релиз" "**v2.0** готов — [changelog](https://notifly.ru)"
Окно терминала
notifly push -t "Сборка упала" \
--clickUrl https://ci.example.com/build/42 \
--bigImageUrl https://ci.example.com/build/42/graph.png \
"Джоба #42 завершилась с ошибкой"

Подробнее про эти поля — на странице Доп. поля сообщений.

watch периодически выполняет заданную команду и, как только её вывод изменился по сравнению с прошлым запуском, отправляет новый вывод в канал. Удобно для самодельного мониторинга «на коленке» без отдельного сервиса.

Окно терминала
notifly watch "curl -s https://api.example.com/status | jq '.state'"

По умолчанию команда запускается каждые 2 секунды через sh -c. Заголовком, если он не задан, становится сама команда.

Флаги команды watch:

ФлагНазначениеПо умолчанию
-n, --intervalИнтервал опроса в секундах (дробное допустимо)2
-p, --priorityПриоритетиз defaultPriority
-x, --execЧем исполнять командуsh -c
-t, --titleЗаголовок (если пусто — текст команды)команда
--tokenПереопределить App-токен (env: NOTIFLY_TOKEN)из конфига
--urlПереопределить адрес сервераиз конфига
-o, --outputПодробность тела сообщения: short, default, longdefault

Режимы --output:

  • short — только новый вывод, без обёрток;
  • default — новый вывод в блоке == BEGIN NEW OUTPUT == … == END NEW OUTPUT ==;
  • long — и старый, и новый вывод (полный diff в блоках OLD/NEW).

Пример: следить каждые 30 секунд за числом контейнеров и слать длинный diff:

Окно терминала
notifly watch -n 30 -o long -t "docker ps" "docker ps -q | wc -l"

Если сервер за самоподписанным сертификатом, есть переменные окружения:

Окно терминала
# полностью отключить проверку TLS (небезопасно)
export NOTIFLY_SKIP_VERIFY_TLS=True
# или указать собственный корневой CA / закреплённый сертификат
export SSL_CERT_FILE=/path/to/cert.pem

Любую отправку из CLI можно повторить обычным curl — это тот же REST API:

Окно терминала
curl -X POST "https://api.notifly.ru/message" \
-H "X-Notifly-Key: AbC3dEf5gHi7jKl9mNo1pQr" \
-H "Content-Type: application/json" \
-d '{"title": "Деплой", "priority": 10, "message": "Прод выкатился"}'

CLI работает поверх того же публичного API, что и всё остальное. Авторизация — заголовком X-Notifly-Key с App-токеном (A…).

МетодПутьНазначениеТокен
POST/messageОтправить сообщение в каналApp-токен
GET/versionВерсия сервера (используется мастером init)—

Тело POST /message (JSON): message (обязателен), title, priority (0–10), extras (например client::display.contentType, client::notification.click.url, client::notification.bigImageUrl). Подробности — на страницах Отправка сообщений и Доп. поля сообщений.