diff --git a/personal/plans/balda-callee-prism-plan.md b/personal/plans/balda-callee-prism-plan.md index 94f6babe..79723da3 100755 --- a/personal/plans/balda-callee-prism-plan.md +++ b/personal/plans/balda-callee-prism-plan.md @@ -7,49 +7,148 @@ ## 1. Целевая архитектура +**Принцип: стек — единое целое по признаку «работает с файлами на Mac».** Всё, что трогает +код, сборку, тесты, хосты, обязано быть рядом. Всё, что только принимает сообщения — может +жить отдельно. + ``` -Mattermost (Alex) - │ «добавь CSV-экспорт в отчёт» - ▼ -Балда-оркестратор (Kraken, DeepSeek, balda-mm:0.1.13) - │ приём сообщения, чтение Obsidian, контекст, ответ в чат - │ MCP-инструмент executor_run - ▼ -MCP-сервер balda-executor-mcp (Kraken, :8890, сеть mattermost_mm-net) - │ HTTP + X-Bridge-Secret - ▼ -Мост agents-bridge (Mac, :8790, launchd com.agents.bridge) - │ запускает `callee agent run --message ` - ▼ -callee CLI (контейнер balda-executor, Mac) - │ компилирует граф → валидирует ЦЕЛИКОМ до запуска - │ общий state-объект через прогон → ОДИН артефакт в stdout - ├→ Role / DynamicRole → ACP-процесс → DeepSeek (generic_acp) - ├→ Script → локальные детерминированные проверки - └→ Human → точка одобрения - ▼ -Beads (`bd`) — durable-состояние Story/Epic, переживает сессии - ▼ -артефакт → Балда → Mattermost +┌─ Mac ─────────────────────────────────────────────┐ +│ Балда (оркестрация, планирование, крон) │ +│ callee (движок воркфлоу) │ +│ движки: codex / claude / dsh-acp │ +│ bd (Beads) — состояние задач │ +│ тулчейн: ~/Developer, xcodebuild, lume, docker │ +└───────────────────────────────────────────────────┘ + ▲ + │ Mattermost API — ИСХОДЯЩЕЕ соединение с Mac + │ +┌─ Kraken ──────────────────────────────────────────┐ +│ MM-сервер + postgres ← только это │ +└───────────────────────────────────────────────────┘ ``` -### Разделение ролей +### Что это убирает -| Слой | Владелец | +| Узел | Почему больше не нужен | |---|---| -| Граф воркфлоу, валидация, state | **callee** | -| Durable-состояние + одобрение | **coding agent** | -| Исполнение модели | ACP-процесс | +| `balda-executor-mcp` (:8890) | его работа — пропихнуть вызов к мосту. Балда на Mac → пропускать нечего | +| мост `agents-bridge` (:8790) | был границей хостов. Границы нет — нет моста | +| Cloudflare Tunnel для этого потока | нужен только для внешнего доступа к MM | +| MCP-сервер `obsidian-mcp` на Kraken | Obsidian рядом с Балдой | + +📌 **Соединение — исходящее с Mac к MM.** Никаких входящих портов, туннеля внутрь Mac, +«Mac спит → мост недоступен». При недоступности MM — переподключение. + +### Что остаётся на Kraken + +Только **MM-сервер + postgres**. Доступность 24/7, один сетевой вход, ничего тяжёлого. +Kraken разгружается: уходят Балда, MCP-сервер, obsidian-mcp (при load 8.03 на 4 ядрах это +заметно). ### Разделение расходов | Роль | Где | Провайдер | |---|---|---| -| Оркестратор верхнего уровня | Kraken | DeepSeek `deepseek-chat` | -| Исполнитель-роли callee | Mac, контейнер | DeepSeek | +| Оркестратор | Mac | DeepSeek `deepseek-chat` | +| Исполнитель-роли callee | Mac | DeepSeek | -📌 «DeepSeek с обоих концов» = обе стороны на DeepSeek. Подписочный Codex подключается -позже заменой `State.provider` в `DynamicRole` — без правки графа. +📌 «DeepSeek с обоих концов» = обе стороны на DeepSeek. Codex/Claude подключаются позже +заменой провайдера в `DynamicRole` — без правки графа. + +--- + +## 1.1 Балда на Mac: контейнер и границы доступа + +### Где живёт + +**В Docker-контейнере.** Причины те же, что были на Kraken: изоляция, воспроизводимость, +образ уже собран (`balda-mm:0.1.13`), откат одним тегом. + +### Проблема: контейнер изолирован, а нужен тулчейн + +В контейнере нет и не должно быть по умолчанию: + +| Чего нет | Почему это правильно | +|---|---| +| `~/.ssh` | ключи дают доступ ко всем хостам сразу | +| `docker.sock` | **эквивалент root на хосте** | +| пароли, `.env` с токенами | Балде они не нужны | +| `~/.aws`, `~/.config/gh`, прочие креды | то же | + +Но нужны: `xcodebuild`, `lume`, `docker build`, опционально `ssh`. + +### Решение: три класса доступа + +| Класс | Что | Как | Права | +|---|---|---|---| +| **1. Прямой** | файлы проектов, git | bind-mount `~/Developer` (только нужные проекты, не весь `~`) | чтение-запись в проекте | +| **2. Через шлюз** | `docker build`, `lume` | **не давать `docker.sock` и бинарь** — вместо этого узкий сокет/скрипт-обёртка на хосте с белым списком команд | только разрешённые операции | +| **3. Через ssh** | доступ к хосту, TrueNAS, Kraken | `ssh` с ключом **ограниченным** `command=` в `authorized_keys` | одноразовые команды, без шелла | + +🔴 **`docker.sock` в контейнер не монтировать никогда.** Это тождественно выдаче root на +хосте: через сокет можно запустить контейнер с `-v /:/host` и получить всё. Если нужны +сборки — либо `docker build` через ограниченную обёртку на хосте, либо **вынести сборку в +отдельный Script-узел, исполняемый на хосте**, а не в контейнере. + +### Xcode и lume: где физически + +| Задача | Где исполняется | Почему | +|---|---|---| +| `xcodebuild` | **не в Linux-контейнере** — в lume VM с macOS | контейнер Linux, Xcode только на macOS | +| `lume` | **на хосте Mac** | бинарь на хосте, в контейнере недоступен | +| `docker build` | **на хосте Mac** | `docker.sock` в контейнер не даём | + +📌 **Это означает: часть ролей исполняется НЕ в контейнере Балды.** Значит нужен явный +механизм «роль → хост-исполнитель». Вариант — callee запускается не только в контейнере, +но и на хосте (для ролей, требующих Xcode/lume/docker); маршрутизация роли по хосту +описывается в графе. + +### Границы: что Балда НЕ должна получить + +| Ресурс | Статус | +|---|---| +| пароли, токены в открытом виде | ❌ только через env-файл с ограниченным набором (DeepSeek-ключ) | +| `~/.ssh` целиком | ❌ только конкретные ключи | +| `docker.sock` | ❌ никогда | +| весь `~` | ❌ только выбранные проекты | +| root на хосте | ❌ | +| host-шелл | ❌ только белый список команд | + +--- + +## 1.2 Правила работы: Hermes-конфигурация в Балде + +В Hermes у Alex накоплены: правила ведения документации (Obsidian — источник истины), +правила работы (план → апрув → работа, бэкапы, запрет удаления), формат ответов +(артефакт первой строкой, единица счёта, ADHD-friendly), правила приёмки (от учётки +заказчика, а не подставной). + +**Эти правила — не код, а контент.** Значит их надо переносить как контент, а не +зашивать в Балду. + +| Слой Hermes | Аналог в Балде | Как переносится | +|---|---|---| +| System prompt / SOUL | `balda.global_instruction` | текст в конфиг | +| Память (`memory`) | session memory Балды + Obsidian | Obsidian MCP | +| Скиллы (процедуры) | **callee-ресурсы** (`Role`/`Sequential`) | правила работы как воркфлоу | +| Правила документирования | `global_instruction` + Role, обновляющий Obsidian | текст | +| Формат ответов | `deliveryfmt` / `questionfmt` | рендеринг, не промпт | +| Правила приёмки | `Script` + `Human` в графе | исполняемый граф | + +🔴 **Ключевое различие:** в Hermes правила лежат в промпте и памяти — это **мягкое** +принуждение (модель может нарушить). В callee часть правил становится **жёсткой**: +валидация графа, `Human`-гейт, `Script`-проверка. Например «план → апрув → работа» +превращается в узел `Human` между фазами, а не в просьбу в промпте. + +**Что это значит на практике:** правила, которые важны как инвариант (апрув, бэкап, +приёмка) — переносятся в граф как узлы. Правила, которые про стиль (формат ответа, +тон) — остаются в `global_instruction`. + +### Obsidian + +Балда ходит в Obsidian по MCP. На Mac поднимается `obsidian-mcp` рядом (по образцу +Kraken — контейнер `mcp-proxy --port 3101 -- mcpvault /vault`, `type: sse`), том +`~/obsidian:/vault`. ---