[2026-09-29] eagle: personal/plans/balda-callee-prism-plan.md

This commit is contained in:
Alexey Martemyanov committed 2026-09-29 01:33:18 +06:00
1 parent afabb21c25
commit 1c2d734ace
1 file changed
+131 -32
+131 -32
View File
@@ -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 <resource> --message <prompt>`
▼
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`.
---