Эксплуатация
Ядро — один процесс плюс каталог данных. Держать его сервисом удобно, но не обязательно: десктопная сборка запускает ядро сама, без 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, сверяет версию, проверяет подпись и запускает установщик. Каталог версии неизменяем: новый релиз кладёт рядом свой.
- артефакт без файла подписи в манифест не попадает; без ключа подписи сборка релиза не начинается, а приложение без совпадающей подписи обновление не примет;
- файлы выкладываются 0644, каталоги 0755: раздающий сервис работает не под твоим пользователем, и
umask 077даёт 403 вместо ошибки.
Откат ядра — вернуть 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.