Files
knowledge-base/decisions/2026-06-30-cptr-on-mac.md

44 lines
7.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
date: 2026-06-30
type: decision
tags: [dttb, mac, ai, agent, open-webui, cptr, netbird, macos-tcc]
---
# cptr на Маке Олега — агент с доступом к РЕАЛЬНЫМ файлам, перенаправление chat.dttb.ru
## Контекст
Песочница cptr в [[2026-06-30-cptr-computer-agent|LXC 146]] делала задачи в изолированном контейнере и **не видела файлы Мака** (разные машины). Олег хотел «полезно по файлам» — агента, который работает с его реальными документами/рабочим столом. Выбор: «безопасно в вакууме» (песочница) vs «полезно, но агент получает доступ к реальной машине». Олег выбрал **второе, осознанно приняв риск** (публичный chat.dttb.ru сможет выполнять команды на Маке).
## Решение
Поставить cptr **на сам Mac** (`MacBookPro.lan`, юзер `ai`, LAN `10.0.0.180`, NetBird `100.70.242.212`, macOS 26.5.1) и **перенаправить** на него коннект cptr в chat.dttb.ru (idx4). Песочницу LXC 146 заглушить (`pct stop 146`).
## Что развёрнуто на Маке
- **Установка:** `uv tool install cptr` → бинарь `/Users/ai/.local/bin/cptr` (Docker на Маке нет, uv 0.11.7 есть). Данные `~/.cptr/app.db`.
- **Автозапуск:** LaunchAgent `~/Library/LaunchAgents/ru.dttb.cptr.plist` (`cptr run --host 0.0.0.0 --port 8000 --headless`, RunAtLoad+KeepAlive, лог `~/Library/Logs/cptr.log`, env `PYTHONUNBUFFERED=1` чтобы стартовый токен попадал в лог). Загрузка: `launchctl bootstrap gui/$(id -u) …plist`.
- **Admin** `dttb`/`App5870w`; **/v1-ключ** `sk-cptr-9RGc…WkQ` (им ходит Open WebUI).
- **Мозг** OmniRoute `cc/claude-opus-4-8`, api_key `lan-trust` — но **по NetBird** (см. грабли), base_url `http://100.70.92.138:20128/v1`.
- **Workspace** `/Users/ai` → модель `cptr/ai` (стартовый cwd; терминал агента не ограничен этой папкой — у него права юзера `ai` на весь Мак).
- **chat.dttb.ru:** idx4 перенаправлен с песочницы (10.0.0.166) → `http://10.0.0.180:8000/v1`, ключ Мака, `model_ids:["cptr/ai"]`, name «cptr (Mac)». Open WebUI (LXC 142, **без NetBird**) ходит до Мака по домашней LAN `10.0.0.180`.
## ⚠️ Главная грабля: macOS Local Network privacy (TCC) рубит LAN из launchd
**Симптом:** мозг не подключался — `verify` отдаёт `All connection attempts failed` к `10.0.0.179:20128`, **хотя** интерактивный `curl`/`python` с Мака до этого IP дают 200. Discriminating-тест: cptr до **публичного** `api.openai.com` соединяется (отдаёт «Invalid API key»), до **LAN** — «All connection attempts failed».
**Причина:** macOS 15+/26 **Local Network privacy** блокирует обращения **фонового launchd-процесса** к локальной сети (10.0.0.0/24 на en0). Промпта на грант для headless-демона нет → тихий отказ. Локальные `run_command` агента (ls, cat и т.п.) — НЕ сетевые, работают; режется только исходящая сеть cptr к LAN.
**Фикс (без грантов TCC):** ходить к OmniRoute по **NetBird (utun100)** вместо LAN. У хоста OmniRoute (LXC 132) NetBird-IP `100.70.92.138`, OmniRoute слушает 0.0.0.0:20128. Трафик к `100.70.x` идёт через utun (VPN), который **Local Network gate не трогает**`verify` = `Connected`. **Правило: на маке для launchd-сервиса, которому нужен LAN-ресурс, давай ему адрес ресурса по NetBird, а не 10.0.0.x.**
## Безопасность (риск принят Олегом)
- Агент исполняет тулы под юзером `ai` → доступ ко **всему Маку** этого юзера (файлы, терминал). Это и было целью.
- Гейт к `/v1`: Bearer-ключ (только у Open WebUI) + LAN-достижимость + admin-only Open WebUI. cptr-UI на 8000 — логин `dttb`/`App5870w`. Application Firewall на Маке **выключен**.
- cptr слушает `0.0.0.0:8000` → при роуминге на чужом Wi-Fi порт открыт в той сети (гейт — логин/ключ). Для дома ок; если важно — биндить на NetBird-IP или включить firewall.
- «Рулить откуда угодно» работает, пока **Mac в домашней сети** (Open WebUI без NetBird тянется только по 10.0.0.180). Для полного роуминга — добавить NetBird на LXC 142 (отложено).
- Мозг агента зависит от NetBird на Маке (100.70.92.138). NetBird ляжет → агент без мозга (`reference_mac_sudo` для рестарта).
## ⚠️ Грабля 2: cptr теряет контекст между ходами в Open WebUI
**Симптом:** в UI Олег ответил «Да» на предложение агента — cptr: «мы ещё ничего не обсуждали». Каждое новое сообщение приходило как пустая сессия.
**Причина:** cptr — агент с **серверной сессией**, склеивает ходы по заголовку **`X-OpenWebUI-Chat-Id`** (без него — каждый запрос = новая сессия, историю из тела он НЕ использует). Open WebUI по умолчанию этот заголовок **не шлёт** (`ENABLE_FORWARD_USER_INFO_HEADERS` не задан = false). Проверено напрямую: при стабильном `X-OpenWebUI-Chat-Id` cptr помнит (ход2 без истории в теле → верный ответ); без него — забывает.
**Фикс:** на Open WebUI (LXC 142) выставлен `ENABLE_FORWARD_USER_INFO_HEADERS=true` (форвардит `X-OpenWebUI-User-*` + `X-OpenWebUI-Chat-Id`). Это env, не persistent-config → контейнер пересоздан: `docker inspect open-webui` → дамп всех env в `/root/owui.env`, добавлен флаг, `docker run … --env-file /root/owui.env` (том `open-webui` тот же, логины/токены живы; старый контейнер держал как `open-webui-old` для отката, затем удалил). E2E через Open WebUI с одним `chat_id`: ход1 «ок» → ход2 (без истории) «73» = контекст держится.
## Проверено (e2e)
chat.dttb.ru → `cptr/ai` → агент на Маке → `hostname; sw_vers; ls ~/Desktop|wc -l` = `MacBookPro.lan` / `macOS` / `16`. Список `~/Desktop` совпал с реальным. Прямой вызов cptr `/v1` и через Open WebUI — оба ок.
См. [[2026-06-30-cptr-computer-agent]] (песочница-предшественник), [[../projects/dttb/proxmox-inventory]], [[../projects/dttb/credentials]].