23 KiB
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 — 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.
Проектная папка подходит для удаления, если:
- Её
WorkspacePathуказывает на уже отсутствующий проект в домашнем каталоге; либо - Во всём содержимом нет изменений 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.