273 lines
92 KiB
Markdown
273 lines
92 KiB
Markdown
# 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`](https://git.ruzzy.dev/ruzzy/astra-bot/commit/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`](https://git.ruzzy.dev/ruzzy/astra-bot/commit/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 после завершения текущего ответа.
|
||
- ⚠️ 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/`)
|
||
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`](https://git.ruzzy.dev/ruzzy/astra-bot/commit/6276bf8). Бот собирает альбом по `media_group_id`/чату/отправителю, быстро пересланные картинки без ID — по чату/отправителю; после 1,5 секунды тишины передаёт все картинки, подписи и источники одним запросом Codex в порядке `message_id`. Служебные уведомления ожидания убраны 2026-10-11 ([коммит `c4e3cd1`](https://git.ruzzy.dev/ruzzy/astra-bot/commit/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`](https://git.ruzzy.dev/ruzzy/astra-bot/commit/88b88a5). Детская печать уточнена: единый PDF → «Печатай» / «Печатай на двух сторонах» → печать без системных кнопок. Доступ добавлен 2026-10-11: Telegram ID `6310034441` внесён в TG_ALLOWED_IDS (ранее только владелец `607015`), профиль закреплён за ID вместо username; [astra-bot `2d761d3`](https://git.ruzzy.dev/ruzzy/astra-bot/commit/2d761d3). Настройка применяется после перезапуска бота.
|
||
|
||
- Постоянная сессия и журнал Поли добавлены 2026-10-11, [astra-bot `8b3400a`](https://git.ruzzy.dev/ruzzy/astra-bot/commit/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`](https://git.ruzzy.dev/ruzzy/astra-bot/commit/95a2867). Содержание подбирается для 10 лет, материалы 16+/18+ исключаются; выбранные картинки проверяются перед отправкой. Это инструкции агента, не отдельный сетевой фильтр. Разрешение не распространяется на управление сервером и доступами.
|
||
|
||
- Голосовые Telegram добавлены 2026-10-11 (ранее отклонялись как неподдерживаемые): [astra-bot `e0fc9dc`](https://git.ruzzy.dev/ruzzy/astra-bot/commit/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`](https://git.ruzzy.dev/ruzzy/astra-bot/commit/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`](https://git.ruzzy.dev/ruzzy/astra-bot/commit/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`, потом установка.
|
||
|
||
## Рабочий помощник — скилл `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. Итог и обновление метрики успеха ещё ожидаются, алерт вручную не сбрасывался.
|
||
|
||
|
||
## 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`.
|
||
- **Выгрузка в заметки**: `mail export add АДРЕС ПАПКА` — письма адреса (вся почта) → заметки в `~astra/vault/ПАПКА/` (текст без изменений, вложения в `ПАПКА/attachments/<заметка>/`), проверка при каждом sync. Действует **nellka@inbox.ru → `Nelka/`** (193 письма 2014–2026, ~330 МБ вложений; Obsidian Sync принял, в т.ч. файлы > 5 МБ). Заметки попадают и в почасовой архив vault (`vault.git` → gitea).
|
||
|
||
- 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. Срок не задан; общие песни не включаются в ответы с домашкой ЭлЖура. Существующая сессия может не подхватить новые инструкции сразу.
|