Files
obsidian-vault/personal/tech/macos-voom-cleanup.md
T

23 KiB
Raw Blame History

title, type, status, created, updated, tags, aliases, related
title type status created updated tags aliases related
macOS — Voom, Eagle и автоматическая очистка how-to active 2026-10-21 2026-10-21
macos
maintenance
voom
docker
eagle-dashboard
Автоматическая очистка Mac
Voom и Eagle
personal/tech/docker-mac-disk-issues
personal/tech/eagle-dashboard-launchd
personal/projects/virfield

macOS — Voom, Eagle и автоматическая очистка

Состояние проверено 21 октября 2026 по установленным скриптам, конфигурациям и включённым заданиям Eagle. Это описание действующих правил; разовые ручные удаления могли быть шире автоматической политики.

Сетап и расписание

Управление — Eagle Dashboard → Crons. Eagle управляет пользовательскими LaunchAgent macOS; отдельных дублирующих расписаний в Codex нет. Все четыре задания включены. RunAtLoad=false: загрузка задания сама по себе не запускает очистку.

Задание в Eagle Label Расписание
Очистка артефактов и симуляторов — каждые 2 часа local.voom.cleanup Каждые 7200 секунд
Docker — кэш и старые образы com.voom.docker-policy Каждые 7200 секунд
Бэкапы Balda и Virfield — хранить сутки com.voom.backup-retention Каждые 7200 секунд
Штатная очистка кэшей — воскресенье, 12:00 local.voom.weekly-caches Воскресенье, 12:00 по локальному времени Mac

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

Установленные файлы

Базовый каталог: /Users/admin/.local/share/voom-cleanup/ (~/.local/share/voom-cleanup). Python: /opt/homebrew/bin/python3. Voom: ~/.local/bin/voom.

Файл Назначение
cleanup.py Основной проход: временные файлы, Xcode/SwiftPM, симуляторы, merged worktree
tmp_cleanup.py Помощник для /private/tmp, вызывается основным проходом
docker_cleanup.py, docker_images.py BuildKit, наблюдение за ссылками образов и их ограниченная очистка
docker-policy.json Параметры Docker
docker-image-observations.json История наблюдаемых ссылок контейнеров; нужна для отсчёта 30 дней
backup_cleanup.py, backup-policy.json Суточное хранение явно перечисленных бэкапов
weekly-caches.py Штатные команды uv, npm и Homebrew

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

Что сейчас действительно включено

На момент проверки существуют все три файла разрешения:

  • enable-deletion — основной проход с --apply.
  • enable-docker-deletion — Docker с --apply.
  • enable-tmp-deletion — отдельное разрешение удаления из /private/tmp.

Очистка /private/tmp включена. Основной скрипт вызывает run_cleanup(apply and not args.scan_only). Прежний вызов run_cleanup(False) заменён. Одного изменения описания Eagle для включения недостаточно — проверены и код, и файл разрешения.

Бэкапы запускаются отдельным заданием с --apply, без дополнительного файла разрешения. Немедленный разовый запуск при установке этого задания не выполнялся; расписание включено. Успех конкретного прохода проверяется по отчёту, отдельно от факта включения задания.

Worktree и артефакты Xcode/SwiftPM

Worktree

Репозиторий: ~/DuckDuckGo/apple-browsers.git.

  • Voom удаляет вмерженные worktree без локальных изменений; merge через squash/rebase проверяется с GitHub.
  • main, ветки Git, заблокированные worktree и worktree с защищаемыми локальными изменениями сохраняются.
  • Используются --remove-merged-worktrees --github-merged-worktrees с явным исключением main.

Стандартный DerivedData

Каталог: ~/Library/Developer/Xcode/DerivedData.

Проектная папка подходит для удаления, если:

  1. Её WorkspacePath указывает на уже отсутствующий проект в домашнем каталоге; либо
  2. Во всём содержимом нет изменений 48 часов, и LastAccessedDate не указывает на недавнее обращение.

Требуются метаданные проекта или узнаваемые признаки Xcode output. Общие кэши без таких признаков сохраняются. Для возрастного правила учитывается максимум mtime и ctime всех элементов, включая каталоги; перед удалением условие перепроверяется.

Внутрипроектные папки

Поиск рекурсивный внутри:

  • ~/Developer
  • ~/DuckDuckGo
  • ~/.codex/worktrees
  • ~/Documents/Codex
  • ~/Documents/code
Имена каталогов Условие
.build 48 часов без изменений во всём дереве и признаки SwiftPM: workspace-state.json, build.db, debug.yaml или release.yaml
dd, deriveddata, DerivedData, .build-dd 48 часов без изменений во всём дереве и признаки Xcode output

Имена Xcode-папок сравниваются без учёта регистра. Признаки Xcode: например, Build/Intermediates.noindex/XCBuildData/build.db, либо info.plist с WorkspacePath вместе со стандартными каталогами результатов сборки. Одного имени папки недостаточно.

При обходе пропускаются ссылки, .git, node_modules, .venv, venv, target, .Trash, SourcePackages и сами корни артефактов. Внутри найденного корня возраст проверяется по всему содержимому.

Основной проход откладывает удаление при обнаружении процессов сборки xcodebuild, swift-build, swiftc, swift-frontend, clang, ld или при невозможности проверить процессы.

Симуляторы Xcode

  • Используется непустой lastUsedAt из device.plist.
  • Давность последнего использования — от 7 дней.
  • Последнее использованное устройство сохраняется; при одинаковой максимальной дате сохраняются все совпадения.
  • Запущенные устройства сохраняются. Непосредственно перед удалением повторно проверяются даты и состояние через simctl; удаляется только Shutdown.
  • Устройства без даты использования не удаляются. Возраст создания и lastBootedAt не подставляются вместо lastUsedAt.
  • Принудительной остановки и simctl delete all нет.

/private/tmp: 4 часа

Удаление включено в основном проходе раз в два часа.

  • Рассматриваются обычные файлы любых расширений, включая исходники, патчи, логи и результаты сборок.
  • Условие: не менее 4 часов с mtime каждого файла. ctime и возраст родительской папки не используются.
  • Старый файл может быть удалён рядом со свежим; свежий файл внутри старой папки сохраняется.
  • Открытые файлы сохраняются. Открытый каталог или рабочий каталог процесса защищает всё своё поддерево. Проверка — через lsof.
  • Ссылки, сокеты, специальные файлы, чужие владельцы и другие файловые системы пропускаются. Непустые каталоги целиком не удаляются; пустые каталоги скрипт также отдельно не убирает.
  • Перед удалением перепроверяются inode, размер, mtime, принадлежность, открытые пути; проход по каталогам выполняется без следования ссылкам.
  • При недоступности lsof удаление запрещено. При активной сборке удаление откладывается.

Бэкапы Balda и Virfield: сутки

Порог — 24 часа. Для снимка берётся самая новая дата создания (birthtime) или mtime во всём дереве. Это защищает свежие APFS-клоны, у которых сохранились старые даты содержимого. Недавнее изменение любого элемента откладывает удаление всего снимка.

Balda

Полностью проверяются отдельные снимки внутри:

  • ~/.local/share/balda-workspace/backups/
  • ~/Docker/balda-mm-mac/state/setup-backups/
  • ~/Docker/balda-mm-eagle/state/setup-backups/

Только в корнях ~/Docker/balda-mm-mac/ и ~/Docker/balda-mm-eagle/ дополнительно выбираются:

  • Каталоги/файлы backup-*, state-backup-*, state-failed-*.
  • Файлы с шаблонами *.before-*, *.backup, *.backup-*, *.bak, *.bak-*.

Рабочие state, текущие Compose/config-файлы и рабочая БД под эти шаблоны не попадают.

Virfield

  • backups/ и migration-backups/ внутри ~/.virfield-tart/ и ~/.virfield-v2/.
  • ~/.virfield-v2/upgrades/.
  • ~/.virfield-v2/retained-maintenance/.
  • В корнях ~/.virfield-tart/ и ~/.virfield-v2/ — только резервные файлы *.before-*, *.backup, *.backup-*, *.bak, *.bak-*.

Рабочие state.db, images, leases, nodes, текущие конфиги и обычные диски VM целями не являются.

Защита бэкапов

  • Используемый снимок или его содержимое сохраняются по проверке lsof; использование выделенного каталога бэкапов также защищает его содержимое.
  • Возраст, inode и открытые пути проверяются повторно перед удалением.
  • Корни со ссылками в пути, чужие владельцы, другие файловые системы, сокеты и специальные файлы пропускаются с записью в отчёт.
  • Ссылки внутри снимка не обходятся. Для удаления read-only каталогов снимка добавляются права только владельцу каталогов; файлы и внешние цели ссылок не изменяются.
  • Последний бэкап не закреплён навсегда: по этой политике все подходящие снимки старше суток могут быть удалены.

Docker

Цель жёстко закреплена: context colima, builder colima, socket /Users/admin/.colima/default/docker.sock. Перед работой проверяется соответствие контекста и работающего builder. Другие и неактивные builders не запускаются.

BuildKit cache

Тип Минимальное неиспользование
Обычный поддерживаемый build cache 14 дней от LastUsedAt
Cache mounts и распознанные слои установки зависимостей 30 дней от LastUsedAt

Зависимости распознаются по типу exec.cachemount и описаниям с apt/apk/dnf/yum, pip/uv, npm/pnpm/yarn, cargo, gem/bundler/composer, go mod.

Сохраняются InUse, Shared, internal/frontend, неизвестные типы и записи без корректной даты. Удаление ограничено точным списком cache-ID и фильтром возраста; BuildKit повторно проверяет использование. Broad --all не используется.

Образы: 30 дней без наблюдаемых ссылок

Область автоматической очистки:

  • execution-broker и execution-broker-*.
  • execution-prism-adapter.
  • balda и balda-*, включая старые обычные версии.
  • Образы без тегов и без digest-reference.

Условия и исключения:

  • Нет ссылок любых контейнеров, включая остановленные, не менее 30 дней по журналу наблюдений.
  • При появлении ссылки таймер сбрасывается; после исчезновения начинается новый отсчёт.
  • Сохраняются образы, найденные в доступных файлах конфигураций и переменных окружения работающих контейнеров.
  • Для обычных версий сохраняется одна самая новая сборка для каждого repository по Docker Created; одинаковые максимальные даты сохраняются все. Это дата сборки, а не сравнение номеров версий.
  • Явно тестовые/временные/резервные Balda-теги (test, temp, tmp, scratch, fixture, acceptance, prNN, backup, bak, rollback) могут истечь и без сохранения «последнего тестового» образа.
  • Для Broker дополнительно защищены теги/имена с rollback, base, accepted, approved, stable, latest, current, production, prod. Эти закрепления могут сохранять больше одной версии.
  • Для Balda постоянная защита всех исторических версий отключена; действуют ссылки, конфигурации, последняя обычная версия и срок 30 дней.
  • Перед каждым удалением повторно проверяются Docker inventory, конфигурации, ссылки, возраст наблюдений и теги. Удаление — по точному ID без --force, с --no-prune.

docker-image-observations.json отражает периодические наблюдения за ссылками контейнеров. Он не даёт полного last used: использование в FROM и короткоживущие контейнеры между проверками могут не попасть в историю. Нельзя подменять эти 30 дней возрастом создания образа. История начата 21 октября 2026; потеря журнала запускает отсчёт заново.

Известные ограничения Docker

  • Именованные образы вне списка выше сохраняются независимо от отсутствия контейнеров. Например: Mattermost, budget-*, workspace-smb, workspace-nfs-client, ssh-manager-isolation-fixture, go-cli*, базовые Go/Node/Python и прочие внешние образы.
  • Для Mattermost отсутствие ссылок контейнеров/конфигураций проверено; причина сохранения — ограничение списка разрешённых имён.
  • При нескольких тегах удаление по ID может закончиться конфликтом; скрипт сохраняет образ и пишет kept_conflict_or_error.
  • Полной очистки графа скрытых промежуточных образов нет: используется /system/df и --no-prune. Проявившийся безымянный родитель должен отдельно попасть под возрастное правило; ручная дочистка всей цепочки была шире автоматической политики.
  • Контейнеры, volumes и networks автоматически не удаляются. Удаление Broker/restore-контейнеров 21 октября было отдельным ручным действием.

Еженедельное обслуживание кэшей

По воскресеньям в 12:00 выполняются штатные команды:

/opt/homebrew/bin/uv cache prune
/opt/homebrew/bin/npm cache verify
/opt/homebrew/bin/brew cleanup

Возраст и выбор данных определяют сами инструменты. npm cache verify проверяет/обслуживает кэш; полного удаления всего npm-кэша правило не обещает. Автообновление Homebrew на время этого задания отключено.

Что ещё не входит в автоматические правила

  • WebKitBuild из Downloads и архив прошивки iPhone .ipsw: 21 октября удалены вручную, общих правил для них нет.
  • Android SDK исключён из согласованной очистки; отдельно его не трогать.
  • Claude VM bundles/Cowork VM не очищаются этим сетапом.
  • Все произвольные кэши приложений, все Docker images или все файлы Downloads не охватываются широким правилом.

Проверка, отчёты и управление

JSON-отчёты в ~/.local/share/voom-cleanup/:

Отчёт Что смотреть
last-report.json Xcode/SPM, симуляторы, worktree, сводка tmp
tmp-report.json Кандидаты tmp, deleted_files, deletion_deferred, ошибки
docker-report.json BuildKit, образы, причины сохранения, результаты удаления
backup-report.json Бэкапы, возраст, занятые пути, результаты и ошибки
weekly-caches-report.json Exit code и вывод каждой штатной команды

Основные логи: launchd.log, launchd.stderr.log; для еженедельного задания — weekly-caches.log, weekly-caches.stderr.log.

Включённое задание и поле apply сами по себе не подтверждают освобождение места: проверять время отчёта, results, ошибки и причины отложенного удаления. Основной скрипт при активной сборке может завершиться до обновления last-report.json; смотреть также лог и отдельный tmp-report.json.

Предпросмотр без удаления:

/opt/homebrew/bin/python3 ~/.local/share/voom-cleanup/cleanup.py --scan-only
/opt/homebrew/bin/python3 ~/.local/share/voom-cleanup/tmp_cleanup.py
/opt/homebrew/bin/python3 ~/.local/share/voom-cleanup/docker_cleanup.py
/opt/homebrew/bin/python3 ~/.local/share/voom-cleanup/backup_cleanup.py
/opt/homebrew/bin/python3 ~/.local/share/voom-cleanup/weekly-caches.py --check

--scan-only у основного скрипта показывает кандидатов артефактов/симуляторов/tmp, но пропускает Voom-проход worktree. Эти проверки могут обновлять отчёты; Docker также обновляет журнал наблюдений.

Для паузы задания использовать Eagle → Crons. Чтобы отключить только tmp, можно переименовать enable-tmp-deletion; остальные задачи основного прохода сохранят свои настройки. Для бэкапов отдельного файла разрешения нет — управлять их заданием в Eagle. Не создавать второе расписание поверх существующих labels.

Связанные заметки: personal/tech/eagle-dashboard-launchd, personal/tech/docker-mac-disk-issues, personal/tech/docker_colima_setup, personal/projects/virfield.