Files

120 KiB
Raw Permalink Blame History

rpi — домашняя Raspberry Pi 4 (rpi.local, 192.168.10.25)

Поднята 2026-10-11. Домашний сервер за NAT: первая задача — бэкап личного OneDrive на внешний HDD; с того же дня ещё и медиацентр (Jellyfin + *arr, Docker). Мониторится с fr1 через pushgateway (скрейпить её снаружи нельзя — она за домашним роутером).

Железо и ОС

  • Raspberry Pi 4, SD 64 ГБ (mmcblk0), питание штатное — vcgencmd get_throttled = 0x0.
  • Raspberry Pi OS Lite 64-bit Trixie (Debian 13), образ 2026-10-06-raspios-trixie-arm64-lite.
  • Headless-настройка — cloud-init, а не старые ssh/userconf.txt: в Trixie Pi Imager пишет user-data/network-config на bootfs. Наш user-data создал пользователя, ключ, hostname, таймзону MSK.
  • Сеть: Ethernet 1 Гбит/с, DHCP. MAC dc:a6:32:db:b0:f9, роутер 192.168.10.254 (Huawei HG8245X6-10, Cyta). Адрес 192.168.10.25 закреплён за MAC статической DHCP-привязкой на роутере (2026-10-11; была без резерва).

Доступ

  • С Mac: ssh rpi (алиас → rpi.local, user rus, ключ ~/.ssh/id_ed25519). Резолвится через mDNS (avahi в образе по умолчанию).
  • Только по ключу: passwordauthentication no, у rus пароль заблокирован, sudo NOPASSWD (иначе sudo был бы недоступен вовсе).

Диски

Устройство Модель Роль
sda WD My Passport 4 ТБ (WD40NDZW, s/n WD-WX82D6228YCD) ext4 backup → /mnt/backup
— WD Elements 1 ТБ (WD10SDRW) в USB роутера, не малины: NTFS/MBR, метка ROUTER → router: / /mnt/router (см. «Вторая копия»)
  • fstab по UUID с nofail,x-systemd.device-timeout=30s (stacks/rpi-backup/fstab.line): без диска малина грузится, бэкап просто пропускается (mountpoint -q).
  • ⚠️ Два 2.5" HDD от USB Pi 4 не тянут. Проверено 2026-10-11: при раскрутке обоих — over-current на всех USB3-портах; под нагрузкой 4-ТБ диск отваливался (USB disconnect) и залипал в Unit Not Ready. Один диск стабилен (20 ГБ чтения 103 МБ/с, mkfs ~60 ГБ записи без сбросов). Второй диск — только через USB3-хаб с собственным питанием.
  • Залипший после отвала диск лечится power-cycle всех USB (Pi 4 переключает питание портов только разом): sudo uhubctl -l 2 -a off; sudo uhubctl -l 1-1 -a off; sleep 8; …-a on.
  • SMART на момент ввода: 9 897 ч, 0 переназначенных/ожидающих, Start_Stop 21 946, Load_Cycle 42 530.

Бэкап OneDrive (код — stacks/rpi-backup/)

  • rclone (официальный .deb, v1.75.2 — в Debian 1.60, старый), remote onedrive: = личный OneDrive (drive_type personal). Токен — в ~rus/.config/rclone/rclone.conf (600), только на малине. Получен через rclone authorize onedrive на Mac.
  • onedrive-backup (таймер каждые 4 ч, 00/4:30): rclone sync в /mnt/backup/onedrive/current, всё удалённое/перезаписанное в облаке — в archive/<ts>/ навсегда (пользователь хочет иметь всё, что когда-либо было в OneDrive). Хэши архива — manifests/archive-<ts>.qxh, лог каждого прогона — logs/sync-<ts>.log (INFO: поштучно что скачано/убрано в архив).
  • Целостность: rclone сверяет QuickXorHash каждого скачанного файла с OneDrive; onedrive-verify (вс 05:00) перечитывает весь HDD: rclone check current↔облако + rclone checksum archive↔манифесты. Отчёт — logs/verify-<ts>*.
  • Оба юнита под общим flock /run/lock/onedrive-backup.lock — не идут параллельно и не убивают друг друга.
  • ⚠️ Файл, загруженный и удалённый в облаке между прогонами (<4 ч), в бэкап не попадёт.
  • ⚠️ Personal Vault исключён — rclone через API туда не ходит.
  • ⚠️ Архив без ротации: растёт вечно. Скрипт выходит с кодом 2 при заполнении >90 % (→ алерт BackupFailed), плюс HostDisk* если когда-то поставим node-exporter.
  • Первая полная выгрузка (368 ГБ) запущена 2026-10-11 ~13:13, ~27 МБ/с (упор в домашний канал).

Вторая копия — 1 ТБ диск в роутере (с 2026-10-11)

  • Диск воткнут в роутер Huawei (192.168.10.254), а не в малину — не ест питание USB малины (два HDD от неё не тянут, см. «Диски»). Доступ — SFTP роутера на порту 8022, пользователь root, remote router: в ~rus/.config/rclone/rclone.conf (пароль только там), host key — ~rus/.ssh/known_hosts_router.

  • ⚠️ Роутер не считает хэши (shell_type = none, md5sum_command = none) — rclone сравнивает по размеру+mtime, целостность проверяется перечиткой.

  • mnt-router.service — rclone mount router: /mnt/router (user rus, --vfs-cache-mode writes, кэш в /mnt/backup/.rclone-cache). Для просмотра/ручной работы; бэкап пишет напрямую в remote, не через FUSE (коды ошибок, без кэша).

  • Скорость (замер 2026-10-11, параллельно с выгрузкой OneDrive): запись ~8 МБ/с, чтение ~11 МБ/с — первичная копия ~370 ГБ ≈ 13 ч. Диск 932 ГБ.

  • router-backup (stacks/rpi-backup/, таймер 06:00, flock): в router:rpi-backup/ — onedrive/{archive,manifests,logs} только copy (там ничего не удаляется), затем зеркало onedrive/current с --max-delete 1000, затем зеркало зашифрованных servers/ с --max-delete 50. Порядок важен: удалённое из current к этому моменту уже скопировано в archive. Логи — /mnt/backup/router-logs/.

  • ⚠️ --max-delete — предохранитель: если локально «пропадёт» много файлов (сбой диска/монтирования), копия на роутере не зачистится, а прогон упадёт с ошибкой → алерт BackupFailed.

  • По воскресеньям verify: сверка размеров деревьев + перечитать с роутера последний daily каждого сервера и сравнить sha256.

  • Ежемесячно (1-го, 08:00) router-sample: случайные файлы OneDrive из current/ и archive/ старше суток, ~2 ГБ / до 300 шт., перечитываются с роутера и сверяются sha256 с HDD — ловит тихую порчу, которую сверка размеров не видит. Отсутствующий на роутере файл = ошибка. Итог — backup_*{job="backup_router_sample"} → BackupFailed, BackupStale (>35 дней). Проверено 2026-10-11: 20 из 20 скопированных файлов совпали.

  • Мониторинг: router_mount_up и заполнение /mnt/router (в smart-metrics, df под timeout 20), итог прогона — backup_*{job="backup_router"}; алерты RouterDiskMountDown (30 мин), BackupDiskFull (>90 %, любой диск бэкапа), BackupStale (>30 ч); ряд «Вторая копия» на дашборде rpi-disk.

  • ⚠️ 1 ТБ меньше основного диска: сейчас влезает (~370 ГБ OneDrive + ~100 ГБ серверов), но архив версий растёт вечно — следить за BackupDiskFull.

  • Почему NTFS (2026-10-11): прошивка Cyta видит FAT32 и NTFS, exFAT — нет (диск в списке USB не появлялся); FAT32 отпал из-за лимита 4 ГБ на файл. Файл 4,4 ГБ через SFTP записан и прочитан. На Mac NTFS штатно не создать — делали mkntfs из ntfs-3g, собранного без FUSE (--disable-ntfs-3g), на блочное /dev/diskNs1 (на rdisk mkntfs отказывается).

  • ⚠️ FTP роутера (порт 21) включён в его конфиге, но из LAN filtered: доступ к FTP со стороны LAN открывается только на странице ONT Access Control, а у пользователя cytauser её нет (нужен суперадмин Cyta). Поэтому SFTP: включён 2026-10-11 через веб-API роутера — сервер 8022, LAN=1, WAN=0, аккаунт root с корнем /mnt/usb/usb-1058-363434_1. Пароли SFTP и веб-интерфейса — только у пользователя и в rclone.conf.

  • ⚠️ Потолок ~10 МБ/с — CPU роутера (dropbear): aes128/256-ctr вдвое медленнее chacha20 (нет аппаратного AES), параллельные потоки почти не помогают. Быстрее только диск на малине через хаб с питанием (~100 МБ/с).

Бэкап серверов fr1/ru1 (с 2026-10-11, код — stacks/server-backup/)

  • Малина — внешняя площадка для VPS: servers-backup.timer (02:15) забирает по SSH выгрузки, которые сервер сам шифрует открытым ключом age (tar | zstd | age). Закрытого ключа на малине нет — ни она, ни Astra, ни взломщик архивы не прочитают. Ключ у владельца: Mac ~/.config/age/servers-backup.key.
  • Хранилище /mnt/backup/servers/<host>/{daily,weekly,monthly} (root 700): 14 / 8 / 12, monthly — хардлинк первого daily месяца. fr1 daily ~2.1 ГБ (5.5 мин), ru1 ~17 МБ, fr1 weekly (вс) — тома ботов и imgbot.
  • Ключ /etc/server-backup/id_ed25519 (root 600): на серверах ограничен forced command — только запустить выгрузку. Host keys закреплены в /etc/server-backup/known_hosts.
  • Целостность: sha256 шифротекста считает сервер, малина сверяет при приёме и по воскресеньям (servers-backup verify). Итог — метрики backup_*{job="backup_servers"}, алерт BackupStale >26 ч, панель на дашборде rpi-disk.
  • Пробное восстановление 2026-10-11 на Mac: оба архива расшифрованы, на месте CA OpenVPN (easy-rsa/pki/private/ca.key), ключи AWG, конфиги прокси, репо gitea, снимок gitea.db.

Мониторинг → fr1

  • smartd (stacks/rpi-backup/smartd.conf): DEVICESCAN -d removable, -n standby,q (не будить диск), короткий самотест сб 03:00, длинный 1-го числа 05:00. ⚠️ -d sat с DEVICESCAN не работает («Not a SAT device») — тип моста пусть определяет сам.
  • smart-metrics (таймер 15 мин): smartctl -n standby → метрики smart_* → job smart. Спящий диск не будится: отдаются значения из кэша /var/lib/smart-metrics/ + smart_disk_standby=1.
  • backup-metrics <job> — ExecStopPost=+ у юнитов бэкапа: backup_last_exit_code, backup_last_run_timestamp, backup_last_success_timestamp (время успеха хранится локально в /var/lib/backup-metrics/, т.к. PUT заменяет группу целиком).
  • Доставка: metrics-push <job> = ssh с ключом /etc/metrics-push/id_ed25519 (root, 600) на rus@161.97.93.252; host key fr1 закреплён в /etc/metrics-push/known_hosts. На fr1 ключ ограничен forced command (servers/fr1.md → Мониторинг).
  • smart-metrics заодно отдаёт backup_disk_size_bytes/backup_disk_avail_bytes для /mnt/backup (statfs, диск не будит).
  • Дашборд: https://mon.ruzzy.dev/d/rpi-disk (SMART, износ за сутки, свежесть бэкапов, заполнение).
  • ⚠️ BackupStale видит только существующие серии — задача, ни разу не отчитавшаяся, им не ловится. Для этого BackupNeverReported на absent() (с 2026-10-11): OneDrive 12 ч, серверы 26 ч, роутер 30 ч, проверка OneDrive 8 дней; и PushMetricsStale на отсутствие SMART-метрик 1 ч. Доставка в Telegram проверена тестовым алертом 2026-10-11.
  • monwatch — сторож самого мониторинга (с 2026-10-11, stacks/rpi-backup/bin/monwatch, таймер раз в час): весь мониторинг живёт на fr1, и если упадёт fr1 или цепочка доставки — алертов не будет вообще. Малина спрашивает fr1 health (тот же ключ метрик, режим только чтение): живы ли Prometheus/Alertmanager/pushgateway, видит ли Prometheus пуши малины моложе часа, не растут ли alertmanager_notifications_failed_total{integration="telegram"}. При проблеме (после повторной проверки через 2 мин) пишет в Telegram напрямую, минуя fr1 — ботом @rasp_contol_bot (токен из /etc/astra-bot.env) в чат 607015; повтор раз в 6 ч, ✅ при восстановлении. Состояние — /var/lib/monwatch/. Путь тревоги проверен имитацией 2026-10-11 (MONWATCH_MAX_PUSH_AGE=1).
  • ⚠️ Сообщения сторожа приходят в чат с ботом Astra — это бот сам пишет, Codex их не видит и не обрабатывает.
  • Алерты — группа rpi в stacks/monitoring/prometheus/rules/alerts.yml.

Домашняя печать (с 2026-10-11)

  • Brother DCP-L2620DW обнаружен через mDNS: 192.168.10.24, BRW2C9C58C1EEA7.local, IPP порт 631 /ipp/print; чёрно-белый, A4, двусторонняя печать. Ранее службы печати на rpi не было.

  • Установлены cups, cups-client, cups-filters, cups-ipp-utils (CUPS 2.4.10); включён cups.service. Очередь по умолчанию home-brother, драйвер everywhere, URI ipp://BRW2C9C58C1EEA7.local:631/ipp/print. По умолчанию A4, одна сторона; printer-is-shared=false, CUPS слушает только 127.0.0.1:631 и [::1]:631. Доступ из Telegram — команда агента, без отдельного открытого веб-интерфейса.

  • Код настройки и команда — stacks/rpi-print/; home-print установлен в /usr/local/bin/ (root, 755). home-print status — состояние/очередь; home-print [--duplex] <PDF/PNG/JPEG> — одна копия, A4 с подгонкой. Печать только по прямой просьбе пользователя; приём задания в очередь не означает, что бумага уже вышла.

  • Навык home-print упрощён для ребёнка 2026-10-11; источник — astra-bot 11d0a85, codex/skills/home-print/, установлен в ~astra/.codex/skills/home-print/. Вместо PNG каждой страницы и повторного подтверждения отправляет один PDF, затем по прямой просьбе «распечатай» печатает одну копию A4 с одной стороны без дополнительных вопросов. Текст извлекается из скриншотов, картинки сохраняются в оттенках серого, все страницы проверяются локально. Если PDF не доставлен, печать не запускается; повторная отправка задания при ошибке не автоматическая. Для этого сценария установлены узкие постоянные разрешения ~astra/.codex/rules/home-print.rules (источник codex/rules/ в astra-bot): только /usr/local/bin/home-print и PDF-режим штатного отправщика. Общая политика подтверждений сохранена. Проверка: 31 тест, валидация скилла и правил; произвольный Python правилами не разрешается. Инструкции установлены в ~/.codex/AGENTS.md; новые разговоры получают их автоматически.

  • Кнопки и промежуточные ответы печати убраны в самом боте 2026-10-11, astra-bot 6b1317d. Ранее постоянных правил скилла было недостаточно: запросы approval и все agentMessage уходили в Telegram. Бот теперь автоматически отвечает accept только на штатную PDF-отправку разрешённому чату и home-print для print.pdf в каталогах /tmp/astra-print-*; shell-операторы и произвольные команды исключены. В задачах печати сохраняет последний ответ и отправляет его после завершения, PDF доставляется отдельным вложением. Проверено 34 тестами, установлен bot.py; прежний код — /opt/astra-bot/bot.py.bak-20261011-child-print. Перезапуск через restart-check.py после завершения текущего ответа.

  • Печать для Поли — только после кнопки владельца (решение владельца 2026-10-13; установлено Astra 2026-10-13; ⚠️ ОТМЕНЕНО уточнением владельца в тот же день — см. следующий пункт; действует на хосте, пока не установлен astra-bot d916407), astra-bot 83aed7a. Причина: владелец хочет видеть и подтверждать всё, что печатает ребёнок; прежний сценарий «Поля пишет “Печатай”» отменяется. Поля просит распечатать → агент собирает PDF и сразу (без её «Печатай») вызывает /usr/local/bin/home-print-request CHAT /tmp/astra-print-<id>/…/print.pdf → бот забирает копию в ~astra/.local/share/astra-bot/print-requests/<id>/ (каталог 700, PDF 600, sha256, число страниц) и шлёт владельцу (607015) этот PDF с кнопками «Подтвердить» / «Отменить» → после «Подтвердить» бот сам запускает home-print на сохранённой копии. Поле — только простые сообщения («отправила папе», «папа разрешил» / «пока не разрешил»). Почему одной правки бота было мало: home-print был разрешён правилом allow в ~astra/.codex/rules/home-print.rules и выполнялся мимо бота для всех чатов; теперь правило prompt — прямая печать приходит боту, взрослым (владелец, Оля) он одобряет её сам без кнопки (взрослый сценарий PDF → «Печатай» сохранён), в детском чате отклоняет home-print/lp/lpr. В песочнице Codex CUPS недоступен (проверено codex sandbox: lpstat → scheduler is not running, sudo не работает), поэтому мимо бота печать не проходит. Защиты: кнопку принимает только владелец в своём личном чате и только от сообщения с этим PDF; заявка выходит из pending один раз, статус printing пишется на диск до запуска принтера — повторное нажатие, сбой lp и перезапуск бота второй копии не дают (после сбоя нужен новый запрос); изменённая копия PDF не печатается; путь только /tmp/astra-print-*/…/print.pdf без ссылок, ≤ 20 МБ, 1–50 стр.; не больше 5 ожидающих запросов, срок 24 ч, закрытые заявки хранятся 7 дней. Заодно: запросы подтверждения команд из чата Поли теперь уходят владельцу («👧 Запрос из чата Поли»), а не ей — раньше она могла нажать «Разрешить» под любой командой, включая sudo. Проверено 90 тестами (не-владелец, повтор, отмена, подмена PDF, сбой принтера, взрослый сценарий), правила — codex execpolicy check; реальной печати и сообщений в Telegram не было. Установка (делает Astra): bot.py и новый print_requests.py → /opt/astra-bot/, home-print-request → /usr/local/bin/ (root, 755), home-print.rules, skills/home-print/SKILL.md, AGENTS.md → ~astra/.codex/, перезапуск astra-bot (правила читаются при старте codex app-server). ⚠️ Ограничения: подтверждает только владелец (Оля — нет); «напечатано» = принято в очередь CUPS, бумагу бот не видит; пока владелец не ответил на системный запрос из чата Поли, её задача ждёт; защита рассчитана на послушного агента и просьбы ребёнка, а не на агента, намеренно ищущего выход из песочницы (у astra sudo NOPASSWD, base.rules выполняют git вне песочницы).

  • Материал не по возрасту — с разрешения владельца; печать Поли снова обычная (уточнение владельца 2026-10-13; код готов, ⚠️ ещё НЕ установлен), astra-bot d916407. Заменяет предыдущий пункт: владелец хотел подтверждать не всю печать ребёнка, а работу с конкретным материалом, который агент счёл неподходящим по возрасту (пример: Поля просит полностью «Дары Терека», ей отвечали «распечатай у папы» — неверно). Сценарий: агент до подготовки полного текста вызывает /usr/local/bin/material-approval-request --title … --reason … --request … CHAT → бот (спул ~astra/.local/share/astra-bot/material-approvals/, каталог 700, записи 600) шлёт владельцу (607015) название, причину, просьбу Поли и кнопки «Подтвердить» / «Отменить»; Поле агент говорит «Я спрошу папу». После «Подтвердить» бот сам начинает ход в постоянном разговоре Поли — доверенное сообщение [astra-bot: решение владельца] с названием и исходной просьбой — и задача продолжается как обычно: полный PDF Поле → «Печатай» / «Печатай на двух сторонах» → home-print, без владельца. После «Отменить» бот пишет Поле, что папа пока не разрешил. Обычная печать Поли идёт сразу обычным сценарием: правило home-print.rules осталось prompt, бот одобряет в её чате сам только /usr/local/bin/home-print [--duplex] /tmp/astra-print-*/…/print.pdf (взрослым — как раньше), прочие команды из её чата по-прежнему уходят кнопкой владельцу. Защиты: запрос только из детского чата; название 2–120, причина 5–300, просьба 3–600 символов без управляющих; кнопку принимает только владелец в своём личном чате от сообщения с этим запросом (одноразовый код); заявка выходит из pending один раз; кнопки «до конца разговора» нет — разрешение на один материал и одну просьбу, команд не одобряет; метку доверенного сообщения бот вырезает из сообщений Поли, агент сверяет разрешение командой material-approval-request status ID; тот же материал в ожидании повторно владельцу не уходит, после отказа — сутки отклоняется; не больше 5 в ожидании, срок ответа 24 ч; approved переживает перезапуск бота. Разрешение владельца не открывает запрещённое законом/правилами (прежде всего сексуальный контент с несовершеннолетними) и взрослые развлекательные материалы — это записано в AGENTS, скилле и тексте доверенного сообщения. home-print-request оставлен необязательным режимом «покажи владельцу PDF перед печатью». Проверено 125 тестами (не-владелец, повтор, отмена, подделка кнопки и метки, возобновление после «Подтвердить», в т.ч. после перезапуска и при идущей задаче, обычная детская печать без владельца), правила — codex execpolicy check; установки, перезапуска, печати и сообщений в Telegram не было. Установка (делает Astra): bot.py, print_requests.py, новый material_approvals.py → /opt/astra-bot/ (root, 644); codex/skills/home-print/scripts/material-approval-request → /usr/local/bin/ (root, 755); home-print.rules, skills/home-print/SKILL.md, AGENTS.md → ~astra/.codex/ (astra); перезапуск astra-bot (правила читаются при старте codex app-server); каталог material-approvals/ бот создаёт сам. ⚠️ Ограничения: возрастная оценка — суждение агента, не фильтр (что-то пропустит, о чём-то спросит зря); подтверждает только владелец (Оля — нет); пока он не ответил, Поля ждёт, через сутки запрос устаревает без сообщения ей; «тот же материал» сравнивается по названию; при сбое точно между запуском хода и записью resumed разрешение может прийти агенту дважды (печать от этого не запускается); постоянный разговор Поли помнит прежнее правило — новые инструкции приходят с каждым её сообщением, но старая привычка может проявиться; защита рассчитана на послушного агента, а не на агента, ищущего выход из песочницы.

  • ⚠️ DOCX напрямую не печатается — сначала преобразовать в PDF. Hostname выбран вместо DHCP-IP, чтобы пережить смену адреса; требуется mDNS и включённый принтер. printer-error-policy=abort-job исключает неожиданную автоматическую печать старых заданий после ошибки; ошибочный прогон нужно отправить заново.

  • Проверено: запрос атрибутов IPP (ipptool) PASS, принтер idle/enabled, A4/Gray/duplex доступны. Портрет успешно преобразован фильтрами CUPS PNG → PDF → PWG Raster (A4, 300 dpi), без ошибок. Тестовая страница A4 отправлена 2026-10-11 в 15:20 MSK: home-brother-1, CUPS сообщил job-completed-successfully, принтер вернулся в idle, очередь пуста; качество на бумаге проверяет пользователь.

  • Для перевёрстки извлечённого текста в PDF установлен python3-reportlab 4.3.1 (2026-10-11; ранее средств создания PDF с кириллицей не было), с зависимостями Pillow/Cairo. Шрифт DejaVu Sans внедряется в PDF; PNG-предпросмотр строится из итогового серого PDF. Проверено на комплекте Лермонтова: 3 страницы A4, текст со скриншотов и исходный портрет.

Медиацентр (с 2026-10-11, код — stacks/rpi-media/)

  • 2026-10-18 по просьбе владельца добавлен «Невероятный Бёрт Уандерстоун» (2013, TMDB 124459, Radarr id=3), вручную выбрана RuTracker-раздача BDRip 1080p MVO + Original Eng RUS, 11,4 ГБ. Установлен notify-movie-ready.timer (раз в 2 мин, ранее уведомления для этого фильма не было): после импорта и появления в Jellyfin отправляет владельцу 607015 ссылку на фильм. Язык выбран по описанию раздачи до скачивания; повторная проверка дорожек после загрузки убрана по просьбе владельца 2026-10-18. Скрипт и юниты — stacks/rpi-media/; отметка доставки /var/lib/media-ready/burt-wonderstone.sent, после неё повторно не шлёт. Секреты читает из существующих env, в логах только тип ошибки, чтобы не раскрыть Telegram URL с токеном. ⚠️ Ссылка доступна в домашней сети; таймер не означает, что загрузка уже завершилась. Docker CE 29.9 + Compose v5.6 из репо download.docker.com (в Debian старее). /etc/docker/daemon.json: json-file 10m×3 — чтобы логи контейнеров не точили SD. rus в группе docker (= root-эквивалент; у него и так sudo NOPASSWD). Стек — /opt/media/docker-compose.yml, конфиги — /opt/media/config/<сервис> (SD, ~20 МБ), образы ~7.8 ГБ на SD.
Сервис Порт Зачем Версия на 2026-10-11
Jellyfin 8096 (host-сеть) медиасервер; клиенты LG webOS, Infuse/Swiftfin на iOS 12.2
Seerr 5055 каталог «хочу посмотреть» → Radarr/Sonarr v3.5.0
qBittorrent 8080, торренты 6881 tcp/udp загрузка 5.2.4
Radarr / Sonarr 7878 / 8989 фильмы / сериалы: поиск, загрузка, импорт 6.4.4 / 4.0.20
Prowlarr 9696 индексаторы, раздаёт их в Radarr/Sonarr 2.6.5
FlareSolverr 8191 обход Cloudflare для индексаторов с тегом flaresolverr v3.5.2
Bazarr 6767 субтитры, профиль ru+en v1.6.2
Homepage 3000 стартовая страница: все сервисы с описанием по-русски, живой статус, CPU/температура/диск v2.5.0
  • Данные — /mnt/backup/media (4-ТБ диск, решение пользователя): torrents/{movies,tv,other}, library/{movies,tv}, .cache/jellyfin (кэш и транскоды Jellyfin — не на SD). qBittorrent и *arr монтируют один и тот же корень как /data — иначе импорт из torrents/ в library/ превращается из хардлинка в копию и раздача занимает место дважды. copyUsingHardlinks включён. В бэкапы (router-backup, onedrive-*) media/ не входит.
  • ⚠️ Медиа делят диск с бэкапами. onedrive-backup падает с кодом 2 при заполнении >90 % (~370 ГБ свободно) → BackupFailed. В Radarr/Sonarr стоит minimumFreeSpaceWhenImporting = 500 ГБ: ниже этого импорт останавливается. qBittorrent своего порога не имеет — ручная заливка торрентов мимо *arr может забить диск.
  • Jellyfin в network_mode: host — иначе LG/iOS не находят сервер автообнаружением (UDP 7359 и DLNA-мультикаст не проходят через бридж). Аппаратного транскодинга на Pi 4 нет (V4L2 убран в Jellyfin 10.9), EncodingThreadCount=3: расчёт на Direct Play. ⚠️ Транскод 4K/HEVC Pi не тянет — клиенту нужен нативный кодек (Infuse играет почти всё сам).
  • Метаданные и интерфейс — ru, предпочтительные аудио/субтитры у пользователя — rus, режим субтитров Smart. Библиотеки «Фильмы» (/data/library/movies) и «Сериалы» (/data/library/tv), в Jellyfin только чтение.
  • Индексаторы (публичные, без аккаунтов): NoNaMe Club, The Pirate Bay, YTS — синхронизированы в Radarr/Sonarr; Rutor и EZTV есть в Prowlarr, но в *arr не доехали (Rutor не проходит тест по категориям, EZTV на момент настройки лежал); 1337x не добавился (таймаут даже через FlareSolverr). RuTracker (добавлен 2026-10-11, аккаунт пользователя; логин/пароль — только в БД Prowlarr): через FlareSolverr, опции «убрать кириллицу», «добавить RUS», «первые теги в конец» — чтобы *arr сопоставляли английские названия и видели русскую дорожку; приоритет 10 (выше публичных, 25). Синхронизирован в Radarr и Sonarr. Kinozal и прочие приватные — руками.
  • ⚠️ RuTracker закрывает login.php/tracker.php челленджем Cloudflare (по IPv4; IPv6 у малины нет маршрута). FlareSolverr на Pi решает его 80–180 с — у прокси в Prowlarr requestTimeout=180 (было 60, с ним добавление падало по таймауту). После решения Prowlarr держит cookie и поиск идёт ~4 с; когда cookie протухнет, первый поиск снова будет минутами, и *arr могут на время пометить индексатор недоступным.
  • Языки дорожек (2026-10-11, provision.py langs): custom formats «Русская дорожка» (язык Russian или RUS|MVO|DVO|Dub|Дубляж в названии) = 100 и «Оригинальная»/«Английская дорожка» = 50 во всех профилях Radarr/Sonarr; minFormatScore=0 (ничего не отклоняется), cutoffFormatScore=150 + upgradeAllowed — *arr сами перекачают, когда появится раздача с русской дорожкой. Язык профилей Radarr — Any (было Original: раздачи только с дубляжом отклонялись). Повод — первый фильм (The Fix, 2026) скачался с YTS только на английском; русского дубляжа у свежих релизов ещё нет неделями, есть только Sub-раздачи.
  • Bazarr: провайдеры без аккаунтов (embeddedsubtitles, podnapisi, yifysubtitles); для русских субтитров лучший — OpenSubtitles.com, нужен аккаунт. ⚠️ Бесплатные провайдеры для свежих фильмов русских субтитров не находят (The Fix — пусто); тогда субтитры вытаскивали из Sub-раздачи RuTor: mkv в torrents/other, ffmpeg -map 0:s:m:language:rus -c copy → <имя>.ru.srt рядом с фильмом (сверить длительность/fps — иначе рассинхрон), лишнюю раздачу удалить.
  • Авторизация: везде пользователь rus, один пароль — /opt/media/.admin-password (rus 600). *arr — формы, пароль всегда (режим «без пароля из LAN» в новых *arr требует AllowedHosts). Между собой сервисы ходят по API-ключам из config/<app>/config.xml.
  • Пароли сняты для домашней сети 2026-10-11 (решение владельца): Radarr/Sonarr/Prowlarr — AuthenticationRequired=DisabledForLocalAddresses (из LAN/частных сетей без входа, снаружи пароль бы остался; API по-прежнему по ключу — UI берёт его из /initialize.json); qBittorrent — bypass_auth_subnet_whitelist 192.168.10.0/24 + 172.16.0.0/12 и bypass_local_auth (учётка rus для *arr не тронута); Bazarr — auth.type: null. Бэкапы конфигов — config/<app>/*.bak-20261011-auth. Jellyfin: пустой пароль у админа запрещён самим Jellyfin 12 («Admin user passwords must not be empty») — поэтому заведён пользователь «Дом» без пароля и без прав админа (все библиотеки, без удаления), он один на экране входа; rus (админ) — с паролем, для настроек. Seerr по-прежнему входит через учётку Jellyfin. ⚠️ Теперь любое устройство в домашней сети (гости в Wi‑Fi, умный дом) управляет загрузками и библиотекой. ⚠️ provision.py на чистой установке снова включит пароли — при переустановке повторить.
  • Точка входа для пользователя — http://192.168.10.25:3000 (Homepage, конфиги stacks/rpi-media/homepage/ → /opt/media/homepage/). Ключи виджетов — /opt/media/homepage.env (rus 600, HOMEPAGE_VAR_*, генерит provision.py homepage). ⚠️ Там же пароль qBittorrent: после смены общего пароля перегенерировать env и docker compose up -d homepage, иначе виджет qBittorrent отвалится. HOMEPAGE_ALLOWED_HOSTS обязателен — без него 400 на любой Host, кроме localhost.
  • ⚠️ Встроенный виджет jellyfin Homepage 2.5 с Jellyfin 12 не работает: ходит на /emby/…?api_key= — пути нет (404), ключ в query отключён (EnableLegacyAuthorization=false, включать не стали). Вместо него customapi на /Items/Counts с заголовком Authorization: MediaBrowser Token=….
  • Radarr/Sonarr → Jellyfin (Connect «Jellyfin», тип MediaBrowser, ключ Jellyfin homepage; provision.py connect на чистой установке заводит ключ arr-connect): библиотека обновляется сразу после импорта. Без этого новый фильм висел невидимым до скана по расписанию — realtime-монитор хардлинк не заметил (проверено 2026-10-11 на первом фильме).
  • Первичная связка — stacks/rpi-media/provision.py (идемпотентный, пароль и ключи читает на месте): python3 /opt/media/provision.py [qbit jellyfin arr prowlarr bazarr seerr connect homepage].
  • ⚠️ Каталог config/<сервис>, которого нет до up, docker создаёт от root — Jellyfin/Seerr (uid 1000) падают с Permission denied. Новые каталоги создавать заранее или chown -R rus:rus /opt/media/config.
  • ⚠️ fallenbagel/jellyseerr заброшен (последний образ 2025-08) и не логинится в Jellyfin 12 — заменён на ghcr.io/seerr-team/seerr.
  • Торренты идут напрямую с домашнего IP (решение пользователя 2026-10-11; вариант через AWG fr1 отложен). Порт 6881 на роутере не проброшен — входящих соединений нет, раздача и скорость хуже.
  • Astra управляет медиацентром (с 2026-10-11) — скилл media в ruzzy/astra-bot, команда /usr/local/bin/media (поиск/добавление/выбор раздачи по языку/очередь/удаление; изменения — только --yes и кнопкой). Ключи — /etc/media.env (root:astra 640). ⚠️ Там же копия пароля qBittorrent — при смене общего пароля обновлять вместе с homepage.env. В инструкциях Astra /mnt/backup/media — исключение из «ничего в /mnt/backup не удалять», но только через media. Поле — только чтение.
  • Образы на :latest, автообновления нет: cd /opt/media && docker compose pull && docker compose up -d.

Агент Astra (с 2026-10-11)

Агент на базе Codex (OpenAI), работает на самой малине, управление — из Telegram-бота @rasp_contol_bot. Код бота — отдельный репо ruzzy/astra-bot (там же схема работы).

  • Пользователь astra (группы sudo, adm, systemd-journal, users), пароль заблокирован, sudo NOPASSWD (/etc/sudoers.d/90-astra) — по решению пользователя. SSH-вход под ним — ключом ~/.ssh/id_ed25519 с Mac (алиас ssh rpi-astra).

  • ⚠️ sudo = агент видит всё: токен OneDrive (~rus/.config/rclone/rclone.conf), пуш-ключ метрик (/etc/metrics-push/), deploy-ключ с записью в infra, токен бота. Утечка контекста агента = утечка этих секретов.

  • Codex CLI 0.162.1 — полный пакет в /opt/codex, симлинк /usr/local/bin/codex. ⚠️ Голый бинарник из релиза (codex-aarch64-…tar.gz) не годится: remote-control/app-server требуют пакет (codex-package-aarch64-unknown-linux-musl.tar.gz), иначе «this CLI has no complete local package». Логин — подпиской ChatGPT (codex login --device-auth, аккаунт ruzzyrullezz@gmail.com, Plus), токен ~astra/.codex/auth.json (600). Ключ API не используется.

  • Агенту разрешено пушить в main ruzzy/infra напрямую (решение пользователя 2026-10-11, перекрывает правило из CLAUDE.md только для него): любые изменения сервера он обязан внести в servers/rpi.md/stacks/ и запушить в том же прогоне, конфликты — pull --rebase без --force, неразрешимые — отдать пользователю. Источник инструкций — codex/AGENTS.md в ruzzy/astra-bot.

  • Конфиг ~astra/.codex/config.toml: approval_policy=on-request, sandbox_mode=workspace-write; инструкции агенту — ~astra/.codex/AGENTS.md (паспорт, правила infra, что не трогать).

  • astra-bot (astra-bot.service, user astra): /opt/astra-bot/bot.py ⇄ codex app-server (JSON-RPC stdio) ⇄ Telegram long polling. Подтверждения команд/правок — кнопками в чате. Конфиг /etc/astra-bot.env (root 600): TG_TOKEN, TG_ALLOWED_IDS=607015,6310034441,129703290 (владелец; Поля — детский профиль; 129703290 — полный доступ как у владельца с 2026-10-12, astra-bot 546b0be). Уведомления малины (ЭлЖур, роутер) — всем ID из TG_NOTIFY_IDS в том же файле (сейчас 607015,129703290 — второй добавлен по его просьбе 2026-10-12; перезапуск не нужен, astra-bot 130b8f8). Алерты мониторинга — Alertmanager fr1 → @ultimate_log_bot, отдельно. Для 129703290 vault владельца закрыт (правило в инструкциях Astra, не права ФС — Astra root); его заметки — отдельный vault /home/astra/vaults/129703290/, создаётся по его просьбе (astra-bot 6218260). 2026-10-12 исправлен ~astra/.profile (пустой if для ~/.local/bin ломал login-shell; бэкап .profile.bak-20261012). Тред Codex на чат — ~astra/.local/state/astra-bot.json. Бот лежит в /opt под root, а не в ~/infra, чтобы агент не правил свой код без sudo.

  • Приём вложений исправлен 2026-10-11 (раньше бот читал только text, фото и подписи молча пропадали): код — ruzzy/astra-bot. Фото и JPEG/PNG/WebP-документы до 20 МиБ скачиваются через Telegram getFile в ~astra/.local/share/astra-bot/incoming/ (файлы 600, UUID), передаются Codex как localImage; подпись и источник пересылки — текстом. Пересланные /stop и другие команды читаются как цитата. Во время работы сообщения ставятся в очередь процесса, реальная доставка картинки с подписью и источником подтверждена пользователем 2026-10-11.

  • Пачки изображений добавлены 2026-10-11 (раньше каждый элемент альбома запускал отдельную задачу и отдельное уведомление очереди): установлен коммит 6276bf8. Бот собирает альбом по media_group_id/чату/отправителю, быстро пересланные картинки без ID — по чату/отправителю; после 1,5 секунды тишины передаёт все картинки, подписи и источники одним запросом Codex в порядке message_id. Служебные уведомления ожидания убраны 2026-10-11 (коммит c4e3cd1): прежняя проверка пустой очереди повторяла их между пачками; очередь сохранена и работает молча. Проверка включает повторное заполнение опустевшей очереди. Предыдущий код — /opt/astra-bot/bot.py.bak-20261011-silent-queue. 23 теста прошли; изменение загружается при перезапуске через restart-check.py. ⚠️ Пауза больше 1,5 секунды разделяет серию на пачки; буфер и очередь не переживают перезапуск. Предыдущий код — /opt/astra-bot/bot.py.bak-20261011-batches.

  • Код бота с доработкой Astra перенесён в ruzzy/astra-bot (f9f6c39; текущая установленная версия — c4e3cd1); временная копия stacks/astra-bot/ удалена 2026-10-11. Клон — ~astra/astra-bot. Резервная копия прежнего кода — /opt/astra-bot/bot.py.bak-20261011-incoming.

  • ⚠️ Почему не штатный Codex Remote из ChatGPT: телефон к безголовому Linux не сопрягается — официально хостом может быть только macOS/Windows; codex remote-control pair выдаёт код, но и QR, и ручной ввод дают «Pair Failed», до демона попытка даже не доходит (проверено с debug-логом 2026-10-11). Рабочая альтернатива — ChatGPT Desktop на Mac → SSH-хост rpi-astra, но тогда Mac должен быть включён.

  • /boot/firmware/cmdline.txt: добавлен cfg80211.ieee80211_regdom=RU (бэкап .bak-20261011) — только чтобы /etc/profile.d/wifi-check.sh не печатал в stdout login-shell предупреждение про rfkill: оно ломало бы stdio-протоколы (Codex app-server по SSH). Wi-Fi не используется.

  • Доступ к Gitea — пользователь astra (с 2026-10-11, вместо двух deploy-ключей): один SSH-ключ ~astra/.ssh/gitea, коллаборатор с записью в ruzzy/infra (~astra/infra) и ruzzy/astra-bot (~astra/astra-bot), может создавать свои репо в astra/… (API-токен ~astra/.config/gitea/token, 600, scopes write:repository,write:user, в Gitea — astra-rpi). Почему пользователь, а не deploy-ключи: deploy-ключом нельзя создавать репо, а права коллаборатора видны и меняются в настройках репо. Создавать репо от имени ruzzy нельзя — он пользователь, не организация. git identity Astra (rpi) <astra@rpi.ruzzy.dev>, host key Gitea (RSA) закреплён. Автопулла нет.

  • Профиль Поли (@Polli4ka303), 10 лет, сохранён в инструкциях 2026-10-11: простые короткие ответы без технических терминов; источник astra-bot 88b88a5. Детская печать уточнена: единый PDF → «Печатай» / «Печатай на двух сторонах» → печать без системных кнопок. Доступ добавлен 2026-10-11: Telegram ID 6310034441 внесён в TG_ALLOWED_IDS (ранее только владелец 607015), профиль закреплён за ID вместо username; astra-bot 2d761d3. Настройка применяется после перезапуска бота.

  • Постоянная сессия и журнал Поли добавлены 2026-10-11, astra-bot 8b3400a. После авторизации её чат сохраняется в state.child_chats, тред возобновляется после перезапуска; служебные slash-команды не сбрасывают разговор и не показывают справку администратора. Бот передаёт возраст и текущий chat_id в контекст, отправляет только итоговый ответ. Входящие сообщения, метаданные/пути вложений и текстовые ответы пишутся в ~/.local/share/astra-bot/conversations/<chat_id>.jsonl (файл 600, каталог 700); PDF, отправленный отдельным скриптом, в этот журнал не записывается. Имя пользователя выбирает профиль только после проверки TG_ALLOWED_IDS и не предоставляет доступ. Проверка: 37 тестов; резервный код /opt/astra-bot/bot.py.bak-20261011-child-session. ⚠️ При невозможности resume бот создаёт новый тред; локальный журнал остаётся, автоматического импорта журнала в контекст нет.

Роутер Huawei HG8245X6 — скилл router (с 2026-10-11)

  • Роутер — OptiXstar HG8245X6-10, оптический терминал Cyta (GPON), ПО V5R022C10S110, 192.168.10.254. Интернет — PPPoE 1_INTERNET_R_VID_42 (публичный IP динамический, на 2026-10-11 — 46.199.208.45); ещё WAN TR069, VOIP, IPTV. За LAN3 — mesh-точки M15/E15 (Wi-Fi-клиенты за ними видны как lan3), на LAN4 — малина.

  • Управление — Codex-скилл Astra router, код в ruzzy/astra-bot (codex/skills/router/), команда /usr/local/bin/router. Креды веб-интерфейса — /etc/router.env (root:astra 640), в git нет. Умеет: статус/WAN, клиенты (IPv4 из аренд DHCP, сигнал Wi-Fi), трафик по интерфейсам, DHCP static add/del, проброс портов add/del (через WAN INTERNET), Wi-Fi — только чтение. Изменения — только --yes и кнопкой (codex/rules/router.rules разрешает лишь чтение).

  • ⚠️ 3 неудачных входа подряд блокируют вход в роутер (errloginlockNum = '3'). login.cgi разбирает поля позиционно — порядок как у браузера (UserName, PassWord, Language, x.X_HW_Token), иначе вход «неудачный». login не ретраится. Веб-сервер однопоточный и рвёт соединения при частых запросах — чтение ретраится с паузой; выход (logout.cgi) всегда отвечает обрывом, это норма. После каждой операции — выход, чтобы не забивать лимит сессий и не выбивать человека из веб-интерфейса.

  • ⚠️ Трафик по устройствам прошивка не считает (поля TrafficRecvRate/SendRate всегда 0) — только по интерфейсам: wan (сумма GEM Ethernet), iptv, lan1..4, wifi-2.4, wifi-5.

  • ⚠️ Запись Wi-Fi не сделана сознательно: SSID 2.4/5 ГГц связаны (WifiCover/band steering), запрос — десятки полей; ошибка отключит весь дом. Делать отдельно, в согласованное окно.

  • router-watch.timer (5 мин, root): снимок /var/lib/router-watch/state.json (читает astra без сети), seen.json (все MAC с первым появлением; база — 22 устройства на 2026-10-11 15:57), known.json (имена от пользователя), events.log. Новый MAC → Telegram ботом @rasp_contol_bot с флагами (случайный MAC, ночь, без имени, ≥3 новых за час). Метрики router_* → pushgateway (job router) → алерты группы home-network: RouterWatchStale (>20 мин), RouterDownloadSpike/RouterUploadSpike (WAN: 15-мин скорость >4× средней за неделю и >5 МБ/с ↓ / >1 МБ/с ↑, 30 мин). Дашборд https://mon.ruzzy.dev/d/home-net.

  • DLNA и FTP на USB-диске роутера выключены 2026-10-11 (по решению владельца; включали в тот же день с Mac .17 при настройке диска): DLNA (X_HW_DmsService, ShareAllPath, порт 56002) без пароля отдавал всей домашней сети содержимое диска — а там копия OneDrive; FTP (21, root) не нужен. SFTP :8022 (LAN only, WAN выкл) оставлен — через него router-backup. Управление — router usb status|dlna|ftp.

  • Проверено на живом роутере 2026-10-11: чтение всех разделов; dhcp add/del (тестовая привязка 02:00:00:00:00:01 → .250 создана и удалена), portmap add/del (TCP 59999 → rpi создан и удалён).

  • Статическая привязка DHCP 192.168.10.25 ↔ dc:a6:32:db:b0:f9 (малина) на роутере уже есть — единственная. Привязка 192.168.10.101 ↔ 8e:a9:3a:4e:69:ba удалена 2026-10-11: устройства с таким MAC нет ни в сети, ни в истории роутера (вероятно, старый телефон со сменившимся случайным MAC).

  • Свободная беседа, интернет-поиск, объяснение школьного материала, поиск и генерация картинок для Поли разрешены 2026-10-11; правила установлены в ~/.codex/AGENTS.md, источник astra-bot 95a2867. Содержание подбирается для 10 лет, материалы 16+/18+ исключаются; выбранные картинки проверяются перед отправкой. Это инструкции агента, не отдельный сетевой фильтр. Разрешение не распространяется на управление сервером и доступами.

  • Голосовые Telegram добавлены 2026-10-11 (ранее отклонялись как неподдерживаемые): astra-bot e0fc9dc, исходники установки и распознавания voice/. Установлен ffmpeg 7.1.5 с зависимостями; python3-venv уже был. Vosk 0.3.45 в /opt/astra-voice/venv, русская модель vosk-model-small-ru-0.22 и helper /opt/astra-voice/transcribe.py, всего 115 МБ. OGG/Opus скачивается через Telegram (600), распознаётся локально без стороннего API, до 5 минут / 20 МиБ, таймаут 180 с; одна запись обрабатывается, до трёх в работе/ожидании, основной цикл бота свободен. Расшифровка идёт в существующий чат, пересылки остаются цитатами; для Поли пишется в журнал. ⚠️ Модель небольшая: шум, имена и сложная речь дают ошибки; пустой результат вызывает просьбу записать заново. Исходные записи автоматически не удаляются. Проверка: 43 теста и настоящий OGG с тишиной (модель запускается, пустая расшифровка); качество живой русской речи ещё предстоит проверить голосовым пользователя. Предыдущий бот — /opt/astra-bot/bot.py.bak-20261011-voice; обновление установлено, перезапуск через restart-check.py после текущего ответа.

  • Распознавание голосовых заменено 2026-10-11 на whisper.cpp v1.7.6 + многоязычную base (141 МиБ), astra-bot c5c488f, установка — voice/setup-whisper.sh в репозитории бота. Причина: Vosk услышал «кастовой голосовой» в записи «тестовое голосовое» и поддерживал только русский; Whisper на той же записи получил «тестовый голосовое» (ошибка окончания остаётся). Русский, английский и греческий выбираются автоматически, перевода нет, обработка локальная. Бинарник /opt/astra-voice/whisper-cli, модель /opt/astra-voice/ggml-base.bin, helper запускается системным Python; установлен CMake 3.31.6 для сборки. Два потока CPU, таймаут бота увеличен с 180 до 900 с. ⚠️ На Pi обработка медленнее, короткие и смешанные фразы могут ошибаться; качество греческой речи ещё не проверено реальной записью. Проверки: 43 теста бота, пользовательский OGG, английский образец JFK распознан правильно, тишина даёт пустой текст. Прежний Vosk сохранён, helper — transcribe.py.vosk-bak-20261011, предыдущий бот — /opt/astra-bot/bot.py.bak-20261011-whisper. Перезапуск через restart-check.py после ответа.

  • Индикатор работы добавлен 2026-10-11: astra-bot 20a8ffc. Раньше typing отправлялся один раз и пропадал через несколько секунд; теперь при распознавании голосовых и выполнении задачи отдельное тихое сообщение с машинкой 🚗 редактируется каждые 4 с, typing обновляется. Один индикатор на чат, перекрывающиеся задачи учитываются; после окончания сообщение удаляется. Проверки: 46 тестов, включая перекрытие задач, редактирование/удаление и неудачную отправку. Резервная копия /opt/astra-bot/bot.py.bak-20261011-waiting-car; установка выполнена, перезапуск через restart-check.py после ответа.

Разговорный навык Маруси — отменён и удалён (2026-10-11)

  • Подготовленную за день интеграцию (разговорный сервис Astra для колонки Маруся через вебхук VK → nginx fr1 → SSH-туннель → rpi) владелец отменил в тот же вечер. Навык в VK так и не регистрировался.

  • Удалено с rpi: astra-marusia.service, astra-marusia-tunnel.service, /opt/astra-marusia, /etc/astra-marusia.env (секрет пути вебхука), /var/lib/astra-marusia (отдельный CODEX_HOME), ключ туннеля ~astra/.ssh/marusia_tunnel{,.pub} и known_hosts_marusia. На fr1 — vhost, сертификат, sshd-правило, пользователь marusia-tunnel (см. servers/fr1.md).

  • Код удалён и из репозиториев (2026-10-11): marusia/, test_marusia.py в ruzzy/astra-bot, stacks/astra-marusia/ в ruzzy/infra — остаётся в истории git. Если вернёмся к идее — восстановить оттуда; ключ туннеля и пользователь на fr1 — заново.

  • Реестр устройств уточнён 2026-10-11 по сообщению владельца: Xiaomi-Pad-7, ce:14:42:fd:a2:d5, при обнаружении 192.168.10.45 — «Планшет подруги Полины (Xiaomi Pad 7)». Записано через router known add; MAC частный, при его смене потребуется новая отметка.

Obsidian-vault (с 2026-10-11)

  • Vault владельца «MyVault» (Obsidian Sync, тариф Standard: 1 vault, 1 ГБ, файл ≤ 6 МБ, история 31 день, продление помесячное) — на rpi в /home/astra/vault (~60 МБ, 332 файла).
  • Клиент — официальный obsidian-headless 0.0.14 (/usr/bin/ob, npm, Node.js 24 LTS из репо NodeSource — в Debian 13 только Node 20, а клиенту нужен ≥ 22). Вход ob login делал владелец (учётка ruzzyrullezz@gmail.com), привязка ob sync-setup — vault id 469340a4…, устройство rpi-astra, без E2E-пароля.
  • obsidian-sync.service (user astra, ob sync --path /home/astra/vault --continuous, Restart=always). Режим bidirectional (решение владельца: Astra правит заметки по его просьбе); конфиги .obsidian не синхронизируются; типы файлов — все (unsupported включён).
  • ⚠️ Mac владельца не выгружает в Sync «прочие типы» (.mmd — 7 диаграмм Работа/Perps/flows/): их нет ни в облаке, ни на rpi/iPhone. Лечится на Mac: Настройки → Синхронизация → Другие типы файлов. Суточный архив пока записал их удаление (в истории они есть, коммит 014b2a9).
  • Архив в git — vault-archive.timer (каждый час с 2026-10-11, коммит только при изменениях; было раз в сутки 03:45) → /usr/local/bin/vault-archive (stacks/rpi-backup/): односторонний commit+push в ruzzy/MyVault (продолжает историю git-эпохи; Astra — коллаборатор с записью). Git-каталог отдельно — ~astra/vault.git с core.worktree=/home/astra/vault, в vault нет .git. Скрытые файлы не стейджатся (Sync их не приносит — иначе были бы ложные удаления). Первый снимок 2026-10-11 — 014b2a9 (изменения с 2026-09-23). Итог → backup_*{job="backup_vault"}, алерты BackupStale (>3 ч) и BackupNeverReported (3 ч).
  • Astra — скилл obsidian (ruzzy/astra-bot, codex/skills/obsidian/): читать свободно, писать только по прямой просьбе, новое — в Неотсортированное/, правка — с показом изменений, в стиле владельца (вики-ссылки, без тегов/frontmatter, заметка-папка, картинки в static/images/); служебные файлы агента в vault — никогда. Запись в vault вне песочницы Codex → каждая правка через кнопку подтверждения. Проверено 2026-10-11: ответ по заметке «Читаем и слушаем».
  • ⚠️ Бот claude-channels на fr1 доступа к vault больше не имеет (см. servers/fr1.md).

Камера Xiaomi в домашней сети (2026-10-11)

  • chuangmi.camera.046c04 (линейка Xiaomi Smart Camera, вероятно C300), 192.168.10.129, MAC 78:df:72:54:ef:bf, за mesh; в router-watch подписана как известная.
  • Заводская прошивка: открытых TCP-портов нет (ни RTSP, ни ONVIF, ни веба), только UDP 54321 (miIO); видео и настройки — через облако Xiaomi / Mi Home.
  • Интеграцию с rpi владелец снял: просмотр, движение и запись уже даёт Mi Home. Если вернёмся (снимок для Astra/в Telegram, доступ без аккаунта Xiaomi, архив на rpi без облака) — начинать с go2rtc (источник xiaomi, нужен вход в аккаунт Xiaomi; проверить поддержку модели). Выгрузка роликов в облако управляется «Обнаружением движения» (MIoT siid 5).

Субагент Claude Code (с 2026-10-11)

  • Пользователь claude (uid 1002; группы sudo, adm, systemd-journal, users, astra), пароль заблокирован, sudo NOPASSWD (/etc/sudoers.d/91-claude) — по решению владельца, как у Astra. ⚠️ Это второй агент с root на rpi.
  • Почему отдельный пользователь, а не под astra: свои клоны и $HOME (иначе Codex и Claude Code правили бы одну рабочую копию ~/infra и ломали друг другу git), отдельная авторизация подписки, видно, кто что сделал.
  • Claude Code 2.1.296 — нативный установщик под claude (~claude/.local/bin/claude, автообновление). Вход — личная подписка Claude владельца (ruz…@gmail.com, stripe_subscription), ~claude/.credentials.json (600). Подписка общая с Claude Code владельца на Mac (лимиты).
  • Gitea-пользователь claude (id 6, пароль случайный, вход ключом ~claude/.ssh/gitea), коллаборатор с записью в ruzzy/infra и ruzzy/astra-bot; клоны ~claude/infra, ~claude/astra-bot, коммиты «Claude (rpi)». Прямой push в main разрешён, как Astra.
  • Доступ к ресурсам Astra — через группу astra: /home/astra открыт группе (750, было 700) ради vault и снимков; секреты Astra (~astra/.codex/auth.json, ключи ~astra/.ssh/*) — 600, claude их не читает (проверено). /etc/router.env — root:astra 640.
  • Вход с Mac: ssh rpi-claude (ключ владельца в ~claude/.ssh/authorized_keys).
  • Мост ask-claude (/usr/local/bin/ask-claude, исходник — ruzzy/astra-bot codex/skills/claude-code/scripts/): Astra запускает claude -p … --output-format json --dangerously-skip-permissions через sudo -u claude; --bg — фоном, до 3 одновременно, тайм-аут 60 мин; status / result / wait. Журнал — /var/lib/ask-claude/runs/<ID>/ (claude:astra 2770). ⚠️ Подсчёт идущих задач — по /proc/<pid>, не kill -0 (процесс чужого пользователя → EPERM).
  • Инструкция субагента — ~claude/.claude/CLAUDE.md (исходник codex/claude/CLAUDE.md): правила хоста/infra/vault, не работать в клонах Astra, отчёт в конце. Скилл Astra — claude-code (делегирует по просьбе и сама при распараллеливании; каждый запуск — через кнопку подтверждения).
  • Проверено 2026-10-11: две фоновые задачи параллельно (место на дисках, таймеры) — обе код 0, 4 и 8 с.

Сетевая папка для Mac — Samba, только чтение (с 2026-10-11)

  • Зачем: смотреть бэкап OneDrive (фото «Пленки» и пр.) с Mac в Finder: «Подключиться к серверу» → smb://rpi.local (или smb://192.168.10.25).
  • Шары: onedrive → /mnt/backup/onedrive/current (зеркало OneDrive), onedrive-archive → /mnt/backup/onedrive/archive (удалённое/перезаписанное). Обе read only = yes — бэкап с Mac не стереть.
  • Доступ: только rus, пароль Samba отдельный от системного (sudo smbpasswd -a rus, задаёт владелец); гостей нет (map to guest = never, restrict anonymous = 2). Слушает только 192.168.10.25:445 и loopback (bind interfaces only), hosts allow 192.168.10.0/24; SMB ≥ 2.1; NetBIOS (nmbd) выключен, Mac находит по mDNS (multicast dns register). macOS-совместимость — vfs objects = catia fruit streams_xattr.
  • Конфиг — stacks/rpi-share/smb.conf → /etc/samba/smb.conf (исходный Debian — smb.conf.orig).
  • ⚠️ Где фото: живая фотопленка телефона идёт в OneDrive Изображения/Пленка/<год>/<месяц> (4393 файла, 39 ГБ на 2026-10-11); Ruslan/Фотокамера — разовая выгрузка 2022 г. (121 снимок 2017–2018), Olya/Фотокамера (5921, последний — 2025-11).

Электронный дневник ЭлЖур (с 2026-10-12)

  • Школа Morfosis, https://morfosis.eljur.ru, ученица 4В-К (u.2701). Родительская учётка — /etc/eljur.env (root:astra 640), в git нет.
  • Скилл Astra eljur (ruzzy/astra-bot, codex/skills/eljur/), команда /usr/local/bin/eljur: hw [день], week [день] (расписание + ДЗ), grades [предмет] (все оценки по предмету с датами и весом), avg, table, final [--year] (итоговые за триместры и годовая, /journal-student-resultmarks-action), watch; у grades/avg/table — -t I|II|III или --from/--to (промежуток — со всех триместров). Чтение — без подтверждения (codex/rules/eljur.rules, плюс бот сам подтверждает eljur hw/week/grades/table/avg/final); в ЭлЖуре ничего не меняется. Поле всё это тоже доступно (владелец 2026-10-12).
  • API для родителя у ЭлЖура нет — разбор страниц: вход POST /ajaxauthorize (multipart: username, password, return_uri) → JWT-кука jwt_v_2, кэш сессии /var/lib/eljur/cookies (root:astra 2770/660). Дневник — /journal-app/u.2701/week.N; ⚠️ знак обратный: week.-1 — следующая неделя, week.1 — прошлая. Оценки — /journal-student-grades-action/u.2701 (ячейки name=предмет, id — уникален только внутри предмета, не путать с data-lid, mark_date, weight 1–3, cell-data).
  • Таблицы — eljur table [-t I|II|III] [--from Д --to Д]: компактная (~32 знака) таблица 5/4/3/2/Н/средний по предметам в блоке …. Бот Astra с 2026-10-12 рендерит такие блоки моноширинно (HTML <pre> + parse_mode, при отказе Telegram — обычный текст; astra-bot a9c43e2, бэкап прежнего /opt/astra-bot/bot.py.bak-20261012-tables). Markdown-таблицы | a | b | Telegram не рисует — бот сам переводит их в выровненный <pre> (777804c); жирный/курсив/ссылки/списки тоже конвертируются в HTML (a0c8952).
  • ⚠️ Триместры: границы — из JSON страницы (sp_start/sp_end, полночь по Кипру в UTC): I 01.09–27.11, II 01.12–26.02 (2026/27). Страница триместра /sp.II%20триместр отдаёт и оценки вне периода (II до начала показывает сентябрьские) — фильтруем по границам.
  • ⚠️ Колонка «Средняя» на сайте пустая в HTML (её досчитывает JS) — средний балл считаем сами: взвешенный, «Н» не учитывается, «Общий» — среднее по предметам. На 2026-10-12: общий 4.88.
  • Уведомления о новых оценках — eljur-watch.timer (каждые 30 мин, 07–22) → eljur watch (root, токен бота) → Telegram ботом @rasp_contol_bot в чат 607015. Состояние — /var/lib/eljur/grades.json; первый запуск 2026-10-12 запомнил 105 оценок без уведомления; в тот же день ключ оценки исправлен (раньше склеивал оценки одного предмета через data-lid) и состояние пересоздано (старое — grades.json.bak-20261012).

Подтверждения Astra — критерии (с 2026-10-13, astra-bot fdeae21)

  • Владелец: «напрягает на каждый чих». Разбор сессий Codex за 5 дней: ~75 кнопок на git (в песочнице .git всегда read-only), ~50 на правки ~/astra-bot (вне workspace), ~20 на systemctl/journalctl.
  • Теперь без кнопки: ~/.codex/rules/base.rules — git в своих репо (status…pull/commit/push; push --force/-f/--mirror/--delete — forbidden), systemctl status/show/list-*, journalctl, sudo ls/du/smartctl -A, docker ps/logs; config.toml [sandbox_workspace_write] writable_roots = ["/home/astra/astra-bot", "/home/astra/vault"] (vault — решение владельца: откат через историю Sync и vault.git).
  • По-прежнему кнопкой: системные изменения (sudo install/cp/rm, systemctl restart/enable, apt, /etc, /opt, /usr/local), удаление вне /tmp, действия скиллов с последствиями. ⚠️ network_access = false сознательно: агент читает почту/чаты — внедрённая инструкция не должна без кнопки вывести данные наружу; sudo cat/tail не разрешены (секреты).
  • Прежние config.toml/AGENTS.md — ~astra/.codex/*.bak-20261013-approvals. Проверено codex execpolicy check и codex sandbox (запись в оба каталога есть, сети нет).
  • ⚠️ Грабли: ставя AGENTS.md из своего клона, можно затереть свежий коммит Astra (так 2026-10-13 чуть не потерялась её заметка про песню Поли) — сначала git pull, потом установка.

Личные дела — скилл life (с 2026-10-13, astra-bot ad051b2)

  • Тот же код, что work: /usr/local/bin/life → симлинк на work, режим по имени команды. Раздел — папка владельца Дела насущные/ (уже была, личные дела): темы Дела насущные/Темы/Имя.md (Контекст/Планы/Проблемы/Журнал), TODOшки.md, Входящие.md, Дневник/. Заведены темы «Гвардейская», «Миграционка» (ссылаются на одноимённые справочные заметки владельца).
  • Таймеры root: life-digest.timer — каждый день 09:00 Asia/Nicosia (просрочено, сегодня, личный календарь из gcal agenda без рабочей занятости, открытые проблемы), молчит, если нечего сказать; life-remind.timer — каждую минуту, ⏰ (состояние /var/lib/astra-work/life/). Только владелец; Оле закрыто.

Рабочий помощник — скилл work (с 2026-10-12)

  • Рабочие задачи/записи владельца — в его vault, папка Работа/ (отдельный vault не заводили: Sync Standard = 1 удалённый vault): задачи Работа/TODOшки.md (его прежний список; формат Tasks - [ ] … 📅 ГГГГ-ММ-ДД ⏰ ГГГГ-ММ-ДД ЧЧ:ММ, выполненные ✅), Входящие.md, Дневник/ГГГГ-ММ-ДД.md, Встречи/ГГГГ-ММ-ДД Тема.md (папки — с заметкой-папкой).
  • Проекты (с 2026-10-12, astra-bot dae16bc): заметка на проект Работа/Проекты/Имя.md — разделы Контекст / Планы / Проблемы (чекбоксы, найденные баги и риски) / Журнал; задачи проектов попадают в work list и утреннюю сводку (+ счётчик открытых проблем). Дневник ссылается на проект полным путём ([[Работа/Проекты/Perps|Perps]] — у владельца уже есть одноимённые справочные заметки).
  • /usr/local/bin/work (код — ruzzy/astra-bot 1173d33, codex/skills/work/); только владелец (--by 607015, иначе отказ), без кнопок (work.rules) — пишет только в перечисленные места.
  • Таймеры root: work-digest.timer — будни 09:00 Asia/Nicosia (задачи просрочено/сегодня + рабочая занятость из gcal agenda + счётчик входящих); work-remind.timer — каждую минуту, задачи с ⏰ (досылает до 30 мин опоздания; дедуп /var/lib/astra-work/reminded.json).
  • Решение владельца: на личной инфре — только его рабочие пометки, без паролей/токенов/данных клиентов/выгрузок прода; рабочие системы (почта, Slack, GitLab, grafana walletteam) не подключаются. Оле — закрыто.

Открытые хвосты (на 2026-10-11)

  • USB3-хаб с питанием — теперь только ради скорости: WD Elements 1 ТБ работает второй копией в роутере (~10 МБ/с); на малине через хаб было бы ~100 МБ/с (обновлено 2026-10-11, было «копия одна»).

  • Нет node-exporter (CPU/RAM/диск самой малины в Prometheus не видны) — пуш через pushgateway для node-метрик неудобен; решить, нужен ли.

  • Первый прогон бэкапа стартовал до появления ExecStopPost — его итог может не дойти в метрики; backup_last_success_timestamp появится с первого прогона по таймеру. До этого BackupStale молчит (серии нет).

  • ⏳ codex-remote.service (демон codex remote-control с RUST_LOG=debug) всё ещё включён и работает, хотя сопряжение не взлетело — убрать или оставить ждать поддержки Linux от OpenAI (решение за пользователем).

  • Токен бота передавался через чат с ассистентом — при желании перевыпустить в @BotFather (/revoke) и вписать в /etc/astra-bot.env.

  • ⚠️ Закрытый ключ age бэкапа серверов — одна копия, на Mac. Положить вторую вне малины и вне Mac (менеджер паролей/распечатка), иначе потеря Mac = бэкапы fr1/ru1 бесполезны.

  • Разово скопировать на малину ~rus/backups (5.4 ГБ) и ~tgclaude/backups (4.2 ГБ) с fr1 — тогда их можно убрать с fr1.

  • Пробное восстановление бэкапа серверов — раз в квартал (следующее ~январь 2027), см. stacks/server-backup/README.md.

  • Через неделю снять SMART и посчитать реальный прирост Start_Stop/Load_Cycle — прогноз ресурса пока оценочный.

  • ⏳ Определить хранение входящих фото: сейчас автоматически не удаляются ради ссылок в старых тредах; очередь сообщений только в памяти и теряется при перезапуске.

  • Медиацентр: проброс 6881 tcp/udp на роутере (раздача/скорость); пароль SFTP роутера слабый (только LAN) — сменить; Kinozal и OpenSubtitles — аккаунты пользователя; решить про автообновление образов.

  • Ложный алерт PushMetricsStale для backup_servers разобран 2026-10-11: live Result=success, завершение 15:14:12, ExecStopPost завершён 15:14:15, локальный backup_servers.success есть; SMART и router-watch успешно пушат, health fr1 видит свежие метрики. Ошибка в правиле fr1: общий порог 3 ч применялся к дневному бэкапу. В infra подготовлено ограничение PushMetricsStale на job=smart; BackupStale/BackupNeverReported сохранены. Применение/reload выполняет агент fr1; сами бэкапы не перезапускались.

  • 2026-10-11 по просьбе владельца включено Telegram-уведомление Sonarr после импорта серий Chernobyl (HBO, 2019, TVDB 360893) в чат владельца 607015. Ранее уведомления о загрузках не были настроены. Connect Telegram: Chernobyl owner, только onDownload, ограничение тегом notify-owner-chernobyl; другие сериалы не затрагиваются. Повторяемая настройка — stacks/rpi-media/scripts/notify-chernobyl.py, запуск root; токен берётся из /etc/astra-bot.env, хранится также в локальной БД Sonarr, в git отсутствует. ⚠️ Уведомление означает импорт отдельной серии, не подтверждает английские субтитры или готовность всего сезона; подходящая раздача при настройке пока не найдена. Настройка проверена чтением API, фактическая доставка будет проверена при импорте.

  • 2026-10-11 Chernobyl импортирован Sonarr (5/5), но Jellyfin показывал 0 сериалов: автообнаружение/Connect не обновили каталог. POST /Library/Refresh через существующий API-ключ обновил каталог, проверено media status: 1 сериал, 5 серий. Refresh конкретного ItemId библиотеки с Recursive=true новых серий не обнаружил; для этой ситуации нужен полный скан. Причина сбоя Connect пока не установлена; конфиги и файлы медиатеки не менялись.

  • 2026-10-12 по прямой просьбе владельца OneDrive-бэкап и еженедельная проверка исключают объекты с метаданными malware-detected=true через --metadata-exclude; --onedrive-av-override=false явно запрещает обход серверного антивируса независимо от конфигурации. Ранее восемь заблокированных файлов приводили к ошибке всех прогонов и нулевой метке последнего успеха. Фильтр динамический, не список восьми путей; проверен на Olya/laptop/калитники - платформы.rar: без фильтра файл виден, с фильтром отсутствует; метаданные подтверждают true. Скрипты установлены в /usr/local/bin/, прежние сохранены с .bak-20261012-malware. Файлы в current/archive и в облаке не удалялись, текущие процессы не прерывались; следующий запуск по таймеру использует фильтр. ⚠️ Успех означает полноту бэкапа только среди файлов без отметки OneDrive; ранее сохранённые копии не очищаются, новые реальные ошибки не подавляются. Успешный полный прогон после изменения пока не подтверждён.

  • 2026-10-12 08:16 MSK по прямой просьбе владельца вручную запущен onedrive-backup.service после установки фильтра malware-detected. Перед запуском служба была failed (предыдущий результат 04:57), конкурирующего прогона не было; запуск принят, состояние activating/start. Итог и обновление метрики успеха ещё ожидаются, алерт вручную не сбрасывался.

  • Место на 1-ТБ диске роутера (2026-10-18: 409 из 932 ГБ, 44 %): растут архивы серверов (⚠️ на роутере ежемесячные — полные копии: hardlink'и малины SFTP не переносит) и вечный архив версий OneDrive; прогноз ~600 ГБ (65 %) через год. Действий не нужно — сработает BackupDiskFull (>90 %, метрика /mnt/router в Prometheus проверена 2026-10-18). Варианты, когда понадобится: не копировать на роутер ежемесячные архивы (−~100 ГБ), срок хранения архива версий на роутере, диск больше.

Google: календарь и почта владельца (с 2026-10-12)

  • Скилл Astra google (ruzzy/astra-bot, codex/skills/google/): gcal (повестка, свободные окна, создать/перенести/изменить/удалить событие), gmail (только чтение: список/поиск, непрочитанные, письмо, вложения → /tmp/astra-gmail/), google-auth (вход/статус). На rpi: /usr/local/bin/{gcal,gmail,google-auth}, модуль /usr/local/lib/astra-google/google_api.py (только stdlib). Без подтверждения — codex/rules/google.rules.
  • Аккаунт ruslan.gilfanov@gmail.com; OAuth-клиент Desktop в Google Cloud проекте astra (Calendar API + Gmail API), приложение опубликовано (In production, не проверено Google — для личного использования). Branding: домашняя https://www.ruzzy.dev/astra/index.html, политика https://www.ruzzy.dev/astra/privacy.html (fr1, stacks/www-ruzzy/), authorized domain ruzzy.dev, без логотипа (логотип требует верификации).
  • Права токена: calendar + gmail.modify (с 2026-10-12 вместо gmail.readonly — ради «прочитано»; по правилам владельца других изменений почты нет, gmail mark-read — только по прямой просьбе, с кнопкой). Секреты — /etc/astra-google/ (root:astra 2770; client.json 640, token.json 640 — refresh-токен), в git нет. Вход (PKCE, redirect http://localhost): google-auth url → «Разрешить» → адрес http://localhost/?code=… из браузера → google-auth code 'АДРЕС'. Отозвать — myaccount.google.com/permissions.
  • Календари: личный (запись), «Семейная группа» (запись — только по явной просьбе), праздники Кипра (ru.cy#holiday, чтение; США убраны 2026-10-12), рабочий rgilfanov@walletteam.org — только занятость (freeBusyReader через freeBusy): админ walletteam запрещает внешний доступ к подробностям; обход (секретный iCal, копирование) — не делать. gcal пишет только в календари с ролью owner/writer.
  • Правила записи (владелец 2026-10-12): менять календарь по запросу могут владелец и Оля (129703290); gcal пишет только в основной личный и только в свободное время (add/move отказывают при пересечении с любым событием, включая рабочую занятость). Каждое изменение — с --by <TG_ID>; журнал /var/lib/astra-google/changes.log; изменения Оли → оповещение владельцу через очередь /var/lib/astra-google/outbox/ (astra не видит токен бота; отправляет таймер root). Состояние — /var/lib/astra-google/ (root:astra 2770).
  • Напоминания владельцу (только 607015): gcal-remind.timer (каждую минуту, root) — «⏰ Через 5 мин» для всех событий личного и семейного календарей (рабочая занятость и праздники — нет), дедуп reminded.json; gcal-digest.timer (10:00 Asia/Nicosia) — важные события завтра (врач/стоматолог/анализы/парикмахерская/поездки/рейсы/отели — по словам, или флаг --important в extendedProperties.private.important). Юниты — codex/skills/google/systemd/ в astra-bot. Проверено 2026-10-12: тестовое событие от Оли → оповещение в 10:02 и напоминание за 5 мин в 10:03.
  • Доступ: владелец — всё; Оля (129703290) — календарь (чтение, запись в личный в свободное время), почта закрыта; Поле — ни календарь, ни почту (правила в codex/AGENTS.md).

Почта: индекс, классы, выгрузка в заметки (с 2026-10-12)

  • Скилл mail (codex/skills/mail/), /usr/local/bin/mail: индекс «Входящих» и «Спама» в /var/lib/astra-mail/mail.db (SQLite + FTS5, astra 2770/660) — поиск по отправителю/теме/тексту/вложениям, классы важное / обычное / рассылка / спам с причиной (правила владельца → Gmail «Спам» → адресаты «Отправленных» и смысловые признаки → List-Unsubscribe/категории Gmail → обычное). В Gmail ничего не меняет.

  • mail-sync.timer (astra, раз в 5 мин после окончания прошлого запуска): history.list по historyId; если история устарела — полная пересинхронизация. ⚠️ Квота Gmail проекта astra — ~100 писем messages.get(full) в минуту (замерено: 403 «Units per minute per user» после ~105 запросов) → скорость ≤ 1,5 запроса/с; первичная индексация ~12,4 тыс. писем ≈ 2+ часа (запущена 2026-10-12).

  • Первичная индексация завершена 2026-10-12 (~16:30): 12 447 писем, 259 контактов. Грабли: ~500 писем, скачанных в прерванном прогоне до «отметить всё прочитанным», остались в индексе непрочитанными (полная синхронизация не перекачивает уже имеющиеся) → добавлена сверка mail sync --unread (и в конце полной), astra-bot b501d6d. Классы после настройки: важное 1822 / обычное 4700 / рассылка 5865 / спам 60; автоматические адреса (no-reply, notifier, hello@, info@…) не считаются «людьми», Gmail-«важное» для них → обычное.

  • С 2026-10-12 (astra-bot db247c9) в индексе и «Отправленные» — класс «отправленное» (855 писем), в полнотекстовом поиске адресаты (миграция fts — пересоздание и rebuild при первом запуске), фильтр --to. Докачка +872 письма ≈ 10 мин; бэкап базы до миграции — mail.db.bak-20261012-sent, прежний скрипт — /usr/local/bin/mail.bak-20261012-sent. Итого 13 319 писем.

  • Ожидаемые письма (с 2026-10-13, astra-bot 3995320): mail watch add АДРЕС|@домен [--once] [--note] — новое письмо (в т.ч. в спаме) при инкрементальной синхронизации → файл в /var/lib/astra-google/outbox/ → gcal remind (root, раз в минуту) шлёт владельцу; задержка ≤ ~6 мин. При полной пересинхронизации не оповещает (чтобы не завалить старым). Действует: nellka@inbox.ru (постоянно). Прежний скрипт — /usr/local/bin/mail.bak-20261013-watch.

  • Метки классов в Gmail (с 2026-10-13, astra-bot 68030df): ❗ Важное / 📰 Рассылки / 🚫 Мусор (с b92046e без родителя Astra/ — переименованы labels.patch, письма сохранили метки; ⚠️ «Важное», «Спам», «Important» Gmail отвергает — 400 Invalid label name, заняты системными) — mail ставит их сам (batchModify по 1000) после синхронизации и смены правил; письма не переносятся. Что стоит — колонка msg.glabel; ⚠️ свои изменения меток отфильтрованы в history.list (id меток в meta.glabel_ids), иначе каждая разметка → перекачка писем по квоте (13 тыс. ≈ 2 ч). Первая разметка — 7 762 письма; правила владельца: LinkedIn/BoC campaigns/Apple developer/JetBrains/Pinterest/Paysend → рассылка (рекрутерские ответы LinkedIn — обычное), news.crypto.com и sberbank info → спам. Бэкап базы — mail.db.bak-20261013-labels, скрипта — /usr/local/bin/mail.bak-20261013-labels. Правило владельца: nikita.shumigin@gmail.com (приглашения на уроки греческого) → обычное.

  • Выгрузка в заметки: mail export add АДРЕС ПАПКА — письма адреса (вся почта) → заметки в ~astra/vault/ПАПКА/ (текст без изменений, вложения в ПАПКА/attachments/<заметка>/), проверка при каждом sync. Действует nellka@inbox.ru → Nelka/ (193 письма 2014–2026, ~330 МБ вложений; Obsidian Sync принял, в т.ч. файлы > 5 МБ). Заметки попадают и в почасовой архив vault (vault.git → gitea).

  • Второй ящик ruzzyrullezz@gmail.com (с 2026-10-16, astra-bot 86c7f4d; под регистрации и спам, но бывает полезное): тот же OAuth-клиент проекта astra, отдельный токен /etc/astra-google/token-ruzzyrullezz@gmail.com.json (astra:astra 640, только gmail.modify, без календаря) и индекс /var/lib/astra-mail/mail-ruzzyrullezz@gmail.com.db. --account ЯЩИК (адрес или начало: ruzzy, ruslan) — в любом месте команды mail/gmail/google-auth, чтобы правила Astra по префиксу продолжали работать. mail search/list/read/stats/sync — по всем подключённым ящикам (в выдаче [ruzzy]), rule/watch/export/labels/reclassify — по умолчанию основной. Метки классов ставятся и во втором ящике. mail sync проходит ящики по очереди, каждый — под своей блокировкой mail-<…>.sync.lock (занят — пропуск), ошибка одного не останавливает другой. ⚠️ Вход google-auth url --account ruzzy делает владелец; auth_finish проверяет emailAddress профиля — вход не в тот аккаунт токен не сохраняет. Первичная индексация (6 118 писем) — отдельным systemd-run --unit mail-sync-ruzzy2 2026-10-16 18:17, чтобы таймер не держал основной ящик час. Прежние скрипты — *.bak-20261016-accounts рядом с установленными.

  • 2026-10-12 по просьбе владельца напоминания за 5 минут включены и для рабочей занятости (ранее только личный/семейный). Установлен astra-bot cc6a4f8, код и юнит — в codex/skills/google/; таймер каждую минуту без перезапуска бота. Работа читается только freeBusy, сообщение «Занят (работа)», подробности не запрашиваются; праздники исключены, утренний дайджест не изменён. ⚠️ FreeBusy объединяет соседние/пересекающиеся встречи в один интервал: напоминание к началу интервала, не каждой скрытой встрече. Запрос за полные дни сохраняет исходное начало и не напоминает о уже идущей встрече; дедуп включает календарь и начало. Проверены будущий рабочий интервал, пропуск идущего, отсутствие повторной отправки, 52 теста бота прошли. Предыдущий gcal сохранён /usr/local/bin/gcal.bak-20261012-work.

  • 2026-10-12 по просьбе владельца в постоянный профиль Поли добавлена заметка о необходимости выучить песню к Новому году (ссылка сохранена в инструкциях); ранее заметки не было. astra-bot 9009e9f, codex/AGENTS.md установлен в ~/.codex/AGENTS.md. Срок и автоматические уведомления не назначались. ⚠️ Инструкции подхватываются новым разговором, существующая постоянная сессия ребёнка может сохранять прежний контекст.

  • 2026-10-12 по просьбе владельца скилл eljur изменён: общий запрос домашки показывает 14 календарных дней начиная с завтра, затем остальные даты по порядку; ранее период по умолчанию не был задан. Явные даты/диапазоны сохраняются. Данные запрашиваются для всех пересекающихся недель, пустые записи не выдаются за отсутствие будущего ДЗ. SKILL.md сохранён в astra-bot и установлен в ~/.codex/skills/eljur/; CLI и школьные данные не изменялись.

  • 2026-10-12 уточнён формат ДЗ по просьбе владельца: скилл eljur полностью пропускает выходные, даты и предметы без заданий (ранее перечислял пустые дни). Диапазон по умолчанию остаётся 14 дней с завтра; если весь диапазон пуст, одна короткая фраза. Изменение в astra-bot codex/skills/eljur/SKILL.md, установлено в ~/.codex/skills/eljur/; школьные данные не менялись.

  • 2026-10-12 по просьбе владельца общие задания/напоминания из профиля (например, песня без срока) исключены из ответов о домашке; ранее могли добавляться отдельным пунктом. Скилл eljur теперь показывает только датированные задания дневника, общие задания — по отдельному явному запросу. astra-bot 55ab697, SKILL.md проверен валидатором и установлен в ~/.codex/skills/eljur/.

  • 2026-10-13 в постоянный профиль Поли по просьбе владельца добавлена вторая песня для изучения, предыдущая сохранена. astra-bot 33fb800, codex/AGENTS.md установлен в ~/.codex/AGENTS.md. Срок не задан; общие песни не включаются в ответы с домашкой ЭлЖура. Существующая сессия может не подхватить новые инструкции сразу.

  • 2026-10-13 Astra установила astra-bot 83aed7a: bot.py и print_requests.py в /opt/astra-bot, home-print-request в /usr/local/bin, правило prompt, скилл и AGENTS в ~/.codex. 90 тестов повторно прошли; installed-файлы сверены cmp. Старый бот сохранён .bak-20261013-print-request. Перезапуск и проверка готовности отложены на 60 секунд через astra-print-restart-check (с адаптированным текстом уведомления); реальный сценарий детского запроса и кнопок пока не проверялся, печать не запускалась.

  • 2026-10-13 Claude (rpi) по уточнению владельца подготовил astra-bot d916407 (⚠️ pending install, ставит Astra): вместо подтверждения всей детской печати — запрос владельцу на конкретный материал не по возрасту (material-approval-request, material_approvals.py), обычная печать Поли восстановлена. На хосте пока действует 83aed7a (вся печать Поли через кнопку владельца). Подробности и план установки — «Домашняя печать». Ничего не устанавливалось и не перезапускалось.

  • 2026-10-13 Astra установила d916407: bot.py, print_requests.py, material_approvals.py сверены с /opt/astra-bot; helper material-approval-request установлен в /usr/local/bin, скилл/правила/AGENTS обновлены. 125 тестов повторно прошли. Прежний бот сохранён .bak-20261013-material-approval. Перезапуск с проверкой готовности запланирован через astra-material-restart-check на 60 секунд после установки; после готовности отправляется один запрос владельцу на полный текст «Даров Терека» по исходной просьбе Поли. Сам материал пока не готовился и не печатался; живой проход callback/возобновления ожидает решения владельца.

  • 2026-10-13 исправлена исходящая отправка вложений: раньше обычный agentMessage передавался только текстом, локальные ссылки на файлы/картинки не доставлялись. Установлен astra-bot 40fcc98: bot.py + attachments.py в /opt/astra-bot, инструкция в ~/.codex/AGENTS.md. Явные локальные Markdown-ссылки на результаты из /tmp и каталогов incoming/outgoing превращаются в документы, PNG/JPEG до 10 МиБ — в фото; лимит файлов 49 МиБ, пути вне каталогов/симлинки отклоняются, кодовые блоки и веб-ссылки не загружаются. Ошибка доставки сообщается, неоднозначные сетевые ошибки без автоповтора, фото после явного HTTP 400 отправляется документом. Дедуп в пределах хода. Команды approval теперь в блоках кода. 132 теста прошли, файлы сверены cmp; прежний bot.py сохранён .bak-20261013-attachments. Перезапуск/проверка готовности и реальная отправка образцов PDF/фото запланированы через astra-attachments-restart-check на 60 секунд после установки. ⚠️ Бот сам не извлекает вложения из произвольного вывода инструментов: агент должен явно дать ссылку на файл результата. Входящие PDF/другие документы этим изменением не затрагиваются; живую доставку ещё предстоит подтвердить.

  • 2026-10-14 владелец опознал Onyx Boox: IP при обнаружении 192.168.10.146, MAC 00:0a:0a:fd:89:17, hostname android-dhcp-11. Ранее неизвестное устройство; через router known add записано имя «Onyx Boox Руслана» в known.json. Это только отметка реестра, DHCP и сеть не менялись.

  • 2026-10-15 исправлено распознавание локальных вложений с пробелами вокруг Markdown-пути: прежняя ссылка [PDF]( /tmp/...) не вызывала отправку. astra-bot dd79caf, attachments.py установлен в /opt/astra-bot, прежний сохранён .bak-before-spaces; 133 теста прошли (включая пробелы и угловые скобки). PDF morphemes-20261015 заново доставлен владельцу штатным send-preview, Telegram подтвердил успех. Перезапуск с проверкой готовности запланирован через astra-attachment-space-restart на 60 секунд; остальные ограничения путей сохранены.

Telegram: выгрузка второго аккаунта владельца (с 2026-10-17)

  • Проект tg_export (Telethon) перенесён с Mac: код, юниты и установка — stacks/rpi-tg-export/. На малине — второй аккаунт владельца, докачка только текста раз в сутки (tg-export.timer, 04:30, run --no-media --archived), выгрузка в /mnt/backup/tg/ (tgexport:astra 2750/640 — Astra читает). Старая выгрузка первого аккаунта (~14 ГБ) — на Mac, не переносилась (решение владельца).
  • Отдельный системный пользователь tgexport (без шелла): сессия /var/lib/tg-export/tg.session (600) = полный доступ к аккаунту — Astra её не видит; ключи приложения /etc/tg-export/env (root:tgexport 640, те же api_id/api_hash, что на Mac). Вход — владелец: ssh -t rpi sudo -u tgexport tg-export login.
  • Мониторинг — backup-metrics backup_tg_export → BackupFailed/BackupStale (>30 ч). ⚠️ Первый прогон может идти дольше суток из-за FloodWait.
  • Поиск и сводка (с 2026-10-18): докачка каждый час (было раз в сутки 04:30) + индекс /mnt/backup/tg/index.db (FTS5 + эмбеддинги potion-multilingual-128M, fastembed в venv, модели /opt/tg-export/models); tg search для Astra, темы tg topic, сводка tg-report.timer 08:00 Asia/Nicosia через Codex → очередь outbox. Навык и правила — astra-bot 11dd4fc. Вечерний рекап группы целиком — tg-digest.timer 23:50 Asia/Nicosia (tg digest, сейчас @cyfasttrack). Служба tg-embed (astra) держит модель эмбеддингов в памяти для быстрых запросов (~6 с вместо ~40). Первая полная выгрузка 2026-10-18 19:49: 12 чатов, 303 тыс. сообщений с 2024-10-18, индекс 85 580 кусков, 1,2 ГБ на HDD. Подробно — README стека. Вход во второй аккаунт (@mikpokrovsky) — 2026-10-18; выгружаются только 6 выбранных владельцем чатов (--only, см. README стека). ⚠️ 2026-10-18 18:45–18:51 по ошибке шла выгрузка всех групп и каналов (успела только группа Python, 35 500 сообщений) — остановлена, данные удалены по решению владельца. ⚠️ Таймер выгрузки выключен до вступления владельца в @cyprusdiy, @cymedic и Cyprus Car – Chat; сводка включена, без тем и индекса молчит.
  • Доступ: тексты — только для владельца; Оле и Поле закрыто (правило в codex/AGENTS.md и скилл tg, astra-bot 27bf8e6), как почта.

Читалка books → Obsidian (с 2026-10-18)

  • Заметки и рекапы из books.ruzzy.dev (диалоги с ИИ — только через кнопку «В заметки», целиком не выгружаются) → vault Книги/ (файл на книгу) раз в 10 мин: books-sync.timer (astra) тянет GET /api/export с токеном export:obsidian-rpi (/etc/books-sync/token, root:astra 640; на fr1 только хэш). Export-токены читалка пускает только на /api/export. Подробно — stacks/rpi-books-sync/.

  • Односторонняя: выше ## Мои мысли перезаписывается, раздел владельца сохраняется. Первая синхронизация 2026-10-18 00:38 — «Efficient Go», «Observability Engineering».

  • 2026-10-19 установлен astra-bot 8401f4d: проверки очереди и завершения домашней печати через lpstat больше не требуют кнопок, включая чат Поли (раньше запрос уходил владельцу). Разрешены только локальный lpstat и ограниченные аргументы домашней очереди; удалённый сервер, shell-выражения и другие команды не разрешены. Все 142 теста прошли, включая исходную команду в bash-обёртке и отклонение подмены/дополнительных действий. Старый bot.py сохранён .bak-20261019-printer-status; перезапуск с проверкой готовности отложен на 60 секунд через astra-printer-status-restart, результат готовности приходит владельцу.