---
name: claude-config-sync
description: "Автосинхронизация CLAUDE.md/скиллов/памяти (+ плагин chekan как skills-dir) между Mac, mac mini и телефоном (CodocehStol) — git-репо + launchd на Mac/mini, телефон сам тянет раз в час по публичному HTTPS (claude-sync.codoceh.ru), USB-релей — только запасной путь"
metadata:
  node_type: memory
  type: project
  modified: 2026-08-24T08:22:44.632Z
  originSessionId: 1f3a6f65-acf1-47fc-be99-74d26d2d0ce8
---

Заведено 2026-08-24, по образцу git-бэкапа Obsidian ([[obsidian_sync_overview]]). Mac — источник
истины (`~/.claude/CLAUDE.md`, `~/.claude/skills/`, `~/.claude/projects/-Users-cebers-----------/memory/`).

**Mac → mini, каждый час, чисто git:**
- Рабочий репо `~/Services/claude-config-sync` на Mac, bare-репо `~/Backups/claude-config.git` на mini.
- `~/Services/claude-config-sync/push.sh` — rsync актуальных файлов в репо (**скиллы через
  `rsync -aL`, не `-a`** — часть скиллов симлинки на `~/.agents/skills/...`, обычный `-a` копирует
  симлинк как есть, а он потом ведёт мимо), commit, push. launchd `com.cebers.claude-config-sync`
  на Mac (`~/Library/LaunchAgents/`), `StartInterval=3600`.
- `~/Services/claude-config-sync/pull.sh` на mini — git pull + rsync в `~/.claude/{CLAUDE.md,skills}`
  и `~/.claude/projects/-Users-cebers-mini-----------/memory/` (путь памяти на mini — с `-mini` в
  середине, это кодировка `/Users/cebers_mini/Разработки`, не перепутать с Mac-путём). launchd
  `com.cebers.claude-config-pull` на mini, тот же интервал.

**Телефон (CodocehStol) — САМ тянет по HTTPS раз в час, без USB и без Tailscale.**
Прямой путь телефон↔mini по Tailscale в принципе не работает (см. [[codoceh_fold_linux_desktop]] —
проверено decisive-тестом: даже голый HTTP на новом порту без всякого Tailscale Serve не долетел
до mini, запрос не появился в логе сервера; не проблема конкретного порта/протокола, а самого
канала для этой пары устройств, похоже на оператора, режущего UDP → Tailscale в DERP-релей →
недоставка данных). Обычный интернет у телефона при этом работает нормально (SSH до github.com
прошёл полностью) — решение обходит Tailscale целиком, используя публичный интернет:

- **На VPS-edge (195.133.147.176, тот же Caddy/rathole, что и codoceh.ru-сайты, см.
  [[codoceh_vps_edge]])** добавлен новый сервис по образцу `sync.codoceh.ru` (Obsidian):
  `rathole` `[services.claude-sync]` mini `127.0.0.1:20415` → VPS `127.0.0.1:14015`, Caddy-сайт
  `claude-sync.codoceh.ru { reverse_proxy 127.0.0.1:14015 }`. Бэкапы конфигов сделаны
  (`.bak.<timestamp>`) перед правкой, как принято для этого VPS.
- **На mini** — `pull.sh` (тот же hourly launchd) в конце пересобирает `public/<TOKEN>/payload.tgz`
  (архив `CLAUDE.md`+`skills`+`memory` уже разложенного репо). Статику раздаёт launchd
  `com.cebers.claude-sync-http` (`python3 -m http.server 20415 --bind 127.0.0.1`, RunAtLoad+KeepAlive).
  Токен — `~/Services/claude-config-sync/.sync_token` на mini (64 hex-символа), **не пароль, а
  просто нераспознаваемый путь** — без него `claude-sync.codoceh.ru/<путь>/payload.tgz` отдаёт 404.
- **На телефоне** — `/root/claude_sync_loop.sh` (сам скрипт залит один раз через `run-as curl`,
  правился через `adb shell run-as ru.codoceh.stol curl ... -o .claude/...` без открытия
  приложения): `while true; curl → tar → разложить в ~/.claude; sleep 3600`. Автостарт — идемпотентный
  блок в `/root/.bashrc`, **тот же паттерн, что уже был для `tailscaled`** (`pgrep -f
  claude_sync_loop.sh || bash ... & disown`) — стартует при любом открытии терминала, живёт пока жив
  процесс приложения, умирает вместе с полным килом приложения (как и tailscaled — не новая
  проблема, уже принятое ограничение этой среды).
- **USB-релей (`push_phone.sh` на Mac) оставлен как запасной путь**, не убран — работает даже если
  телефон давно не открывали (значит фоновый цикл внутри мог не стартовать), обновляет файлы через
  `adb shell run-as` напрямую, независимо от того, жив ли сам процесс «Стола». `push.sh` в конце
  зовёт его, тот тихо выходит (`adb get-state` падает), если телефона нет на USB.

**Проверить, что всё живо:**
```
launchctl list | grep claude-config          # на Mac и на mini отдельно
cat ~/Services/claude-config-sync/push.log ~/Services/claude-config-sync/push_phone.log
```

**Если добавится новая машина** — просто `git clone` bare-репо с mini, свой `pull.sh` по образцу
mini-варианта (главное — не перепутать путь памяти, он зависит от кодировки домашней директории
+ рабочей папки на конкретной машине, см. выше).

**Не синхронизируется и не планировалось:** сессии (`.jsonl` в `~/.claude/projects/`) — у каждой
машины свой независимый набор, готового механизма переноса/резюмирования сессии на другую машину
в Claude Code нет; syncить сырые транскрипты можно было бы read-only, но не запрошено.

**Плагины (2026-08-24) — синхронизируются НЕ через `claude plugin marketplace`, а через тот же
канал, что и скиллы.** Плагины из `~/.claude/plugins/` (маркетплейсы, `installed_plugins.json`,
кэш) в синк не входят вовсе — это отдельная система с абсолютными путями и своей регистрацией,
машина-специфичная. Конкретно всплыл chekan (см. [[chekan-dashboard-auto-open]], плагин с маркетплейсом `codoceh`, источник —
приватный репозиторий `github.com/CodoCeh/chekan`): ни у mini, ни у телефона нет SSH-ключа,
привязанного к GitHub, — `claude plugin marketplace add` для приватного репо не проходит
(`Permission denied` / `unable to get password`). Обходной путь оказался проще, чем чинить доступ
к GitHub: у `claude plugin` есть встроенный режим `skills-dir` — **любой каталог с формой плагина
(`.claude-plugin/plugin.json` и т.д.), положенный прямо в `~/.claude/skills/<имя>/`, грузится сам,
без всякого маркетплейса**, как `<имя>@skills-dir` (см. `claude plugin --help`, пункт про
`plugin init`). Проверено на mini: `claude plugin list` после этого показывает
`chekan@skills-dir · Status: ✔ loaded`.

`push.sh` (Mac) теперь после обычного `rsync` в `./skills/` дополнительно кладёт туда же
`./skills/chekan/` — не симлинком и не всем рабочим репозиторием `~/Разработки/chekan` целиком, а
чистым снимком `git archive HEAD` (только то, что реально в git, никаких `.venv`/`.pytest_cache`/
`__pycache__`) с ОТДЕЛЬНО вычищенным `.chekan/` (это рантайм-состояние прогонов НА ЭТОЙ машине,
незачем разносить его как часть плагина). Дальше это едет уже по существующим путям — mini через
git, телефон через `payload.tgz` — без единой правки `pull.sh`/`claude_sync_loop.sh`: они просто
льют весь `skills/` целиком, chekan/ доехал как любая другая папка.

**Это решение только для `chekan`, не универсальное правило «все плагины теперь синкаются».**
Если в `~/Разработки` появится другой локально разрабатываемый плагин с тем же паттерном
(маркетплейс типа `directory`, приватный репозиторий) — для него нужен ровно такой же отдельный
блок в `push.sh` (проверка `-d "$SRC/.git"`, `git archive HEAD | tar -x`, вычистить рантайм-папку).

**Плагины из ПУБЛИЧНЫХ маркетплейсов ставятся штатной командой, без всякого обхода — и уже
поставлены (2026-08-24) на mini и на телефоне:** `telegram@claude-plugins-official`
(маркетплейс `anthropics/claude-plugins-official` — публичный GitHub-репозиторий, клонируется
по HTTPS без ключа). На mini — `claude plugin marketplace update claude-plugins-official` (там
маркетплейс был добавлен раньше) + `claude plugin install telegram@claude-plugins-official -s
user -y`. На телефоне маркетплейса не было вовсе — сначала `claude plugin marketplace add
anthropics/claude-plugins-official`, потом та же установка; выполнено ЖИВЬЁМ через терминал
внутри «Стола» (`adb shell input text` командами, без Cyrillic — сработало без ловушки из
[[codoceh-stol-dev]]), `claude plugin list` на телефоне подтвердил `telegram@claude-plugins-official
· ✔ enabled` рядом с `chekan@skills-dir · ✔ loaded`. Это одноразовая установка (сохраняется в
`~/.claude/plugins/installed_plugins.json` самой машины), не часть часового цикла — новую машину
или сброс придётся повторить руками (или тем же терминалом внутри «Стола»).

Связано: [[obsidian_sync_overview]], [[codoceh_fold_linux_desktop]], [[mac_mini_upterm_access]], [[codoceh_vps_edge]].
