snens

Эксплуатация

Ядро — один процесс плюс каталог данных. Держать его сервисом удобно, но не обязательно: десктопная сборка запускает ядро сама, без systemd.

systemd user-юнит

deploy/snens.service — пример, а не обязательное условие:

[Unit]
Description=snens production HTTP/SSE surface
After=default.target

[Service]
Type=simple
WorkingDirectory=%h/.local/share/snens
ExecStart=%h/.local/bin/snens serve --config %h/.config/snens/config.toml --listen 127.0.0.1:<порт>
Restart=on-failure
RestartSec=2s
KillSignal=SIGTERM
TimeoutStopSec=120s
UMask=0077

[Install]
WantedBy=default.target

%h вместо абсолютных путей — чтобы файл переезжал между машинами без правок; UMask=0077 важен: токен и журналы сессий создаются приватными; порт — любой свободный loopback-порт, его же видят клиенты.

cp deploy/snens.service ~/.config/systemd/user/
systemctl --user daemon-reload && systemctl --user enable --now snens.service

Отдельный юнит для веб-клиента — snens-web.service: бинарь snens-web отдаёт собранный клиент и проксирует /api в ядро, подставляя Bearer из файла токена. В поставке десктопа клиент отдаёт само ядро из web/.

Рестарт обрывает работу

Рестарт ядра рубит текущую сессию: активный ход обрывается с done=error, состояние сессии становится interrupted. Сессию можно продолжить, но потерянный ход придётся повторить — поэтому обновление ядра не делают посреди разговора.

Проверять изменения на отдельном стенде: отдельный инстанс — это не второй бинарник, а свои каталоги и порт.

snens serve --config ~/.config/snens-dev/config.toml \
            --data-dir ~/.local/share/snens-dev \
            --listen 127.0.0.1:<другой-порт>

Перенос на рабочий сервис — scripts/prod-restart.sh: собирает релиз, ставит его неизменяемым каталогом (~/.local/lib/snens/releases/<sha>/snens), атомарно переключает launcher ~/.local/bin/snens и перезапускает юнит. --dry-run показывает шаги, --no-restart ставит и переключает без перезапуска.

Рестарт без скрипта поднимет старый бинарь: юнит запускает launcher, а не сборку из рабочего дерева. Скрипт печатает текущую цель launcher до изменений — это точка отката.

Обновление и откат десктопа

Одно обновление на всё приложение: установщик везёт ядро, тулы, плагин памяти и клиент. tauri-plugin-updater на старте читает манифест latest.json, сверяет версию, проверяет подпись и запускает установщик. Каталог версии неизменяем: новый релиз кладёт рядом свой.

Откат ядра — вернуть launcher на прошлый каталог релиза и перезапустить юнит; откат десктопа — поставить установщик прошлой версии, её каталог на сервере остался. Каталог данных установка и удаление не трогают.

Где лежат сессии и как чистить

<каталог-данных>/sessions/<id>.jsonl        журнал: реплики, вызовы, расход, Done
<каталог-данных>/sessions/<id>.out/cwd      рабочий каталог сессии
<каталог-данных>/sessions/<id>.out/*.txt    дампы длинных выводов и LIVE_CONTEXT.json
<каталог-данных>/sessions/<id>.out/attach/  вложения вызова
snens sessions                   # список
snens show --session <ID>        # транскрипт
snens log --session <ID>         # журнал как есть
snens sweep --dry-run            # что было бы убрано
snens sweep                      # уборка старше 30 дней
snens sweep --older-than 7
snens sweep --attachments        # включить в уборку вложения

snens sweep не трогает журналы и убирает нужное только закрытым сессиям: дампы, на которые не ссылается живой лог, зеркало контекста, вложения (только с --attachments — это данные человека). Порог по возрасту — вторая страховка: свежий файл не удаляется, даже если ссылок на него не нашлось.

Что бэкапить

config.toml — да: он копируется в git и бэкап. .env рядом с ним и api.token — нет: это действующие секреты. Каталог данных бэкапить не обязательно: журналы сессий полезны, но не критичны. prod-restart.sh, выкладка релизов и правки /etc — операторские действия; агенту доступно только разрешённое брокером snens-priv.