mac-export · git:20260924.2784cb2 · 2026-09-24 · sha256 7a059fb8c136ecbb
mac-export git:20260924.2784cb2A
Immutable. This exact content never changes and is served at /api/v1/blob/7a059fb8c136ecbb.
--- name: mac-export description: >- Pull a NATIVE macOS data source (Contacts, Apple Notes, Reminders, Calendar) off THIS Mac into Anton's Obsidian vault as MD + JSON, plus a handoff README so the next Claude Code session knows what landed there. One skill, per-source adapters, idempotent refresh. Trigger on "/mac-export <источник>", "выкачай контакты/заметки/напоминания/календарь с мака", "выкачай всё с мака в обсидиан", "export contacts/notes/reminders/calendar from Mac", "что ещё можно достать с мака что недоступно с ПК", "pull <native mac source> into the vault". This is a native .app SQLite/AppleScript puller — DISTINCT from obsidian-ingest (archives an already-existing artifact/URL) and from gmail/telegram-reimport/whatsapp-sync (connector pulls of other sources). macOS-only (runs on the Mac that owns the data). Each source = a brick in the digital twin ([[main-goals]] цель №1). --- # /mac-export <источник> — тащим родные данные Мака в волт > 🧒 **When reporting to Anton:** end with a child-simple «Простыми словами» recap. Один паттерн для всех: родная база .app (SQLite / AppleScript) → `MD + JSON` в известный путь волта → короткий `README_FOR_CLAUDE.md` для следующей сессии. Меняется только адаптер под источник. Детерминированно, 0 токенов LLM (чистое извлечение). Работает на той машине, что владеет данными (этот Мак) — с ПК эти источники недоступны, в этом весь смысл. ## Когда сюда «выкачай контакты/заметки/напоминания/календарь с мака» · «что ещё можно достать с мака, чего нет на ПК» · любой родной источник macOS в волт. НЕ сюда: уже готовый файл/URL/артефакт → `/obsidian-ingest`; Gmail/Telegram/WhatsApp → их коннекторы. ## Источники и адаптеры | Источник | Родная база (копировать в tmp перед чтением!) | Выход в волте | Движок | Статус | |---|---|---|---|---| | **contacts** | `~/Library/Application Support/AddressBook/**/AddressBook-v22.abcddb` (+`-wal`,`-shm`); контакты = `ZABCDRECORD where Z_ENT=22` | ⚠️ КАНОН с 2026-08-20 = волт `07-People/Contacts/` (8 542, CRM-обогащены) + `_imports/apple-contacts/` (json/vcf/db, конвейер хаба); GDrive-копия `[машина флота]usa-Apr26/Contacts/` = legacy (GDrive-app выключен). Обновление карточек = merge (`merge_cards.py`), НЕ перезапись — иначе стираются crm-поля | `.../Contacts/_tools/extract_contacts.py` | ✅ ПРОВЕРЕН (12 495 контактов, 2026-06-11) [[contacts-export]] | | **notes** | `~/Library/Group Containers/group.com.apple.notes/NoteStore.sqlite` | `!_Claude_[машина флота]/Apple Notes Export <дата>/` (`notes_export.json`+`Notes/`+`attachments/`+`_INDEX.md`) | экспортёр рядом с выходом (см. `README_FOR_CLAUDE.md`) | ✅ ПРОВЕРЕН (649 заметок, 2026-06-11) | | **reminders** | `~/Library/Group Containers/group.com.apple.reminders/Container_v1/Stores/Data-*.sqlite` (ZREMCDREMINDER; списки ZREMCDBASELIST) | `!_Claude_[машина флота]/Reminders Export <дата>/` (`Reminders.md` чекбоксы + JSON) | `adapters/safari_calendar_reminders_export.py` | ✅ ПРОВЕРЕН (57 шт, 2026-08-20) | | **calendar** | `~/Library/Group Containers/group.com.apple.calendar/Calendar.sqlitedb` (⚠️ НЕ `~/Library/Calendars/**.ics` — там бэкапы 2018-2022!) | `!_Claude_[машина флота]/Calendar Export <дата>/` (`ics/` по календарю + JSON) | `adapters/safari_calendar_reminders_export.py` | ✅ ПРОВЕРЕН (27 476 событий, 15 .ics, 2026-08-20) | | **imessage** | `~/Library/Messages/chat.db` (+wal/shm; нужен Full Disk Access у Claude.app) | `!_Claude_[машина флота]/iMessage Export <дата>/` (MD по диалогу + `messages.json` + `attachments/`) | `adapters/imessage_export.py` (декодер attributedBody: `NSString`→`0x2b`→varint→UTF-8; имена из name_map контактов) | ✅ ПРОВЕРЕН (39 052 сообщ / 3 376 диалогов / 1 645 вложений, 2026-08-20) | | **safari** | `~/Library/Safari/Bookmarks.plist` + `History.db` + `CloudTabs.db` (FDA) | `!_Claude_[машина флота]/Safari Export <дата>/` (Bookmarks/ReadingList/History .md + JSON) | `adapters/safari_calendar_reminders_export.py` | ✅ ПРОВЕРЕН (3 301 закладка / 196 RL / 851 история, 2026-08-20) | > ⚠️ **Контакты — два адаптера, числа разные:** `_tools/extract_contacts.py` (Z_ENT=22, один источник, 12 495) vs `adapters/contacts_extract_allsources.py` (все 13 баз-источников + дедуп, 15 423, + name_map телефон/почта→имя для iMessage). Расхождение ОБЪЯСНЕНО (сессия contacts-dedupe 2026-08-20): 12 495 = фильтр «есть имя» (16 887 сырых → 14 502 named → дедуп), 15 423 = все записи включая безымянные email-only с другим дедупом. Оба числа честные, фильтры разные. ## Запуск ```bash # 1) КОПИЯ базы в tmp (иначе читаешь устаревший снимок — WAL не влит) cp "<db>" "<db>-wal" "<db>-shm" /tmp/mac-export/ 2>/dev/null # 2) прогнать адаптер источника (contacts проверен): python3 "/Users/<имя>/Library/CloudStorage/GoogleDrive-dzyatkovskiy.a@gmail.com/My Drive/!_Obsidian/[машина флота]usa-Apr26/Contacts/_tools/extract_contacts.py" # 3) для нового источника — склонировать структуру extract_contacts.py под его SQLite-схему ``` После прогона: положить/обновить `README_FOR_CLAUDE.md` (что за источник, сколько записей, схема frontmatter) → это и есть хэндофф следующей сессии. Идемпотентно: перезапуск перетирает выход (для contacts — чистит `People/`). ## Грабли - ⚠️ **AppleScript блокируется privacy (ошибка -1741)** для Contacts/Notes/Reminders → читать SQLite напрямую, не через AppleScript. - ⚠️ **Читать копию, не живую БД:** SQLite Apple держит хвост в `-wal`; без копирования `.sqlite`+`-wal`+`-shm` в tmp получишь устаревшие данные. - Фильтр контактов = «есть имя» (сырьё ~16 887 → 12 495 с именем); дубли по email/phone/name. - Новый источник → сперва глянуть его схему (`sqlite3 <db> .tables`), потом лепить адаптер по образцу `extract_contacts.py`. ## Канон Память [[contacts-export]] · правило [[always-archive-artifacts-to-vault]] (всё в волт + реиндекс + перелинковка) · цель [[main-goals]] (каждый источник — кирпич двойника). После нового экспорта — реиндекс RAG (`brain_embed_update.py`) как у других импортов.