[2026-09-29] eagle: personal/plans/balda-callee-prism-plan.md
This commit is contained in:
1 parent
1c2d734ace
commit
0f67b3791b
1 file changed
+226
-42
@@ -116,6 +116,167 @@ Kraken разгружается: уходят Балда, MCP-сервер, obsi
|
||||
|
||||
---
|
||||
|
||||
## 1.1a Формула прав
|
||||
|
||||
**`права = права процесса × смонтированное × разрешённое в графе`**
|
||||
|
||||
| Уровень | Кто задаёт | Пример |
|
||||
|---|---|---|
|
||||
| Чем запущен процесс | вы, при старте | контейнер / хост-юзер / отдельный системный юзер |
|
||||
| Что смонтировано | compose | `~/agents:/agents` — и ничего больше |
|
||||
| Что разрешено в графе | автор воркфлоу | какие роли и скрипты вообще есть в каталоге |
|
||||
|
||||
🔴 **`permissions.mode: allow_all` у роли — это про права модели ВНУТРИ ACP-сессии**
|
||||
(править файлы, запускать команды). Оно **не** расширяет, что процесс видит в файловой
|
||||
системе. Это два разных ограничения, не путать.
|
||||
|
||||
### Где callee — там и движки, и Script'ы
|
||||
|
||||
🔴 **ACP-провайдер — дочерний процесс callee.** Движок на хосте + callee в контейнере
|
||||
технически невозможны: это один процесс-тред.
|
||||
|
||||
| Исполнитель | Что исполняет | Права |
|
||||
|---|---|---|
|
||||
| callee | сам граф: циклы, роли, state | права процесса, которыми запущен |
|
||||
| движок (codex/claude/dsh) | модель: думает, правит файлы | наследует + своя песочница |
|
||||
| Script | shell: сборки, тесты, ssh | наследует права процесса |
|
||||
|
||||
**Следствие:** «callee на хосте» = **всё исполнение на хосте целиком**. Промежуточного
|
||||
варианта нет.
|
||||
|
||||
### Динамических маунтов не существует
|
||||
|
||||
На macOS Docker маунты задаются **при создании контейнера**; live `mount --bind` контейнер
|
||||
не видит; симлинк на внешний путь битый. **Вопрос «как модель запросит доступ к папке»
|
||||
не имеет решения через маунты.**
|
||||
|
||||
| Подход | Как | Оценка |
|
||||
|---|---|---|
|
||||
| A. Смонтировать всё заранее | `~/Developer:ro` | запись нельзя |
|
||||
| B. Пересоздание контейнера | правка compose + `up -d` (~3 с) | нужен механизм вне контейнера |
|
||||
| C. Хост-агент ставит права сам | callee на хосте | полный доступ, ноль изоляции |
|
||||
| **D. Проект = рабочая копия** ✅ | модель работает в `~/agents/<проект>`, результат уходит в `~/Developer` через git | доступ задаётся наличием репозитория, а не маунтом |
|
||||
|
||||
**Решение: D.** Модель всегда работает в `~/agents/<проект>` (уже смонтировано), результат
|
||||
попадает в проект через `git`. Право выдаётся точечно.
|
||||
|
||||
### Доступ не запрашивается — он выбирается маршрутом
|
||||
|
||||
Модель **не просит** прав: она не может эскалировать. Если у роли нет доступа, задача
|
||||
**падает**, а не спрашивает. Доступ задаёт автор графа.
|
||||
|
||||
```
|
||||
Роутер в графе
|
||||
├─ задача требует ~/agents → роль в контейнере
|
||||
├─ задача требует Xcode/lume → роль на хост-исполнителе
|
||||
└─ задача требует хоста по ssh → роль со ssh-ключом (command=)
|
||||
```
|
||||
|
||||
**Разграничение = статический роутинг по типам задач**, а не динамические права.
|
||||
|
||||
### Гибрид «контейнер + узкий хост-исполнитель»
|
||||
|
||||
| Вариант | Права | Динамика | Оценка |
|
||||
|---|---|---|---|
|
||||
| callee в контейнере | узкие, контролируемые | только `~/agents` | безопасно; Xcode/lume/docker недоступны |
|
||||
| callee на хосте | **полный доступ пользователя** | всё работает | ноль изоляции |
|
||||
| **гибрид** ✅ | контейнер для основного + узкий хост-исполнитель для Xcode/lume/docker | маунты не нужны | рекомендован |
|
||||
|
||||
🟡 Хост-исполнитель — дыра в изоляции **по определению**, но **узкая и явная**: три операции
|
||||
(xcodebuild, lume, docker build), а не «что угодно».
|
||||
|
||||
---
|
||||
|
||||
## 1.1b Роли: жизненный цикл и контроль
|
||||
|
||||
### Что такое роль
|
||||
|
||||
**Роль — YAML/MD-файл в каталоге.** Не «право», не «токен», а **описание листа графа**:
|
||||
какой провайдер, какой промпт, какие параметры, какой таймаут.
|
||||
|
||||
```yaml
|
||||
apiVersion: callee.metalagman.dev/v1alpha1
|
||||
kind: Role
|
||||
spec:
|
||||
description: Собирает Xcode-проект
|
||||
provider:
|
||||
type: generic_acp
|
||||
cmd: dsh-acp
|
||||
model: deepseek-chat
|
||||
timeout: 20m
|
||||
---
|
||||
Собери проект {{ .Params.project }} и верни отчёт об ошибках.
|
||||
```
|
||||
|
||||
### Кто их раздаёт и откуда они берутся
|
||||
|
||||
| Источник | Что даёт |
|
||||
|---|---|
|
||||
| Каталог по умолчанию | 6 стартовых ресурсов (`callee setup`) |
|
||||
| Импорт из git | `callee agent import baldaworks/prism-callee --prefix prism` |
|
||||
| **Наши собственные** | файлы в рабочем каталоге проекта / `~/.callee/` |
|
||||
|
||||
**Роли не выдаются динамически — они ЛЕЖАТ в каталоге.** Кто положил файл, тот и «выдал»
|
||||
роль. Никакого рантайм-механизма выдачи прав нет.
|
||||
|
||||
### Что раздаётся, а что нет
|
||||
|
||||
| Сущность | Динамически выдаётся? | Чем регулируется |
|
||||
|---|---|---|
|
||||
| Роль (файл графа) | ❌ статично | наличие файла в каталоге |
|
||||
| Провайдер (тип, `cmd`) | ❌ статично, или из `State` через DynamicRole | автор графа |
|
||||
| **Файлы** | ❌ | монтирование + рабочая копия (§1.1a) |
|
||||
| **SSH-ключ** | ❌ | наличие файла у процесса |
|
||||
| **Разрешение модели внутри сессии** | ⚠️ **да** — `allow_all`/`ask`/`deny_all` | конфиг Балды |
|
||||
|
||||
🔴 **Единственное, что реально запрашивается в рантайме — разрешение модели внутри ACP-сессии**
|
||||
(`ask` → вопрос в чат). Всё остальное статично.
|
||||
|
||||
### Ваша гипотеза: проверяю по пунктам
|
||||
|
||||
> «я ставлю задачу → приходит запрос "дать такую-то роль для такой-то задачи" → апрув → доступ появился»
|
||||
|
||||
| Часть гипотезы | Вердикт |
|
||||
|---|---|
|
||||
| Задача приходит в систему | ✅ да |
|
||||
| **Приходит запрос «выдать роль»** | ❌ **нет такого механизма.** Роли не выдаются, они лежат в каталоге |
|
||||
| **Апрув → у агента появляется доступ** | ⚠️ **частично — не к инструментарию, а к действию** |
|
||||
| **Без апрува доступа нет** | ✅ **верно, но иначе** |
|
||||
|
||||
**Что происходит на самом деле:** доступ у роли **есть всегда** — он определяется тем, чем
|
||||
запущен callee и что смонтировано. Апрув не выдаёт доступ, апрув **разрешает выполнить
|
||||
операцию**, которая уже технически возможна.
|
||||
|
||||
### Значит правильная формулировка
|
||||
|
||||
```
|
||||
Роль лежит в каталоге (доступ есть по определению)
|
||||
│
|
||||
▼
|
||||
Граф доходит до узла → Human («собрать Xcode в VM macos-27?») → пауза
|
||||
│
|
||||
├─ апрув → Script исполняется, потому что права у процесса УЖЕ были
|
||||
└─ отказ → граф останавливается, ничего не исполняется
|
||||
```
|
||||
|
||||
🔴 **Разница принципиальная.** Вы описали **capability-модель** (права выдаются на задачу).
|
||||
Callee работает по **статической модели** (права постоянны, гейты контролируют исполнение).
|
||||
|
||||
**Что это значит для вашей безопасности:** гейт `Human` защищает от **действия**, но не от
|
||||
**возможности**. Если у процесса есть ssh-ключ — ключ есть всегда, вне зависимости от апрувов.
|
||||
Изоляцию даёт **только то, чем процесс запущен и что смонтировано** — не граф.
|
||||
|
||||
### Что можно сделать, чтобы приблизиться к вашей модели
|
||||
|
||||
| Способ | Как |
|
||||
|---|---|
|
||||
| **Разные профили запуска** | контейнер «узкий» (без ssh, без docker) и хост-исполнитель «широкий» — выбор профиля роутером |
|
||||
| **Роль на задачу** | задача → своя роль с нужным `cmd`/таймаутом; доступ = какой профиль она выбрала |
|
||||
| **Апрув как гейт исполнения** | `Human` перед дорогой/опасной операцией |
|
||||
| **Белый список команд в Script** | `Script` не «любой shell», а конкретный скрипт с фиксированной командой |
|
||||
|
||||
---
|
||||
|
||||
## 1.2 Правила работы: Hermes-конфигурация в Балде
|
||||
|
||||
В Hermes у Alex накоплены: правила ведения документации (Obsidian — источник истины),
|
||||
@@ -248,21 +409,20 @@ spec:
|
||||
|
||||
## 2.5 Карта стека: кто кого дёргает
|
||||
|
||||
> ⚠️ Обновлено под топологию §1 (стек на Mac). Прежний вид — «Балда на Kraken + MCP +
|
||||
> мост → callee» — **устарел**, оставлен ниже как справка по демонтированным узлам.
|
||||
|
||||
### Актуально (топология «стек на Mac»)
|
||||
|
||||
```
|
||||
ВЫ (Mattermost / Telegram)
|
||||
ВЫ (Mattermost)
|
||||
│ задача словами
|
||||
▼
|
||||
Балда-оркестратор — Kraken, balda-mm:0.1.13, DeepSeek
|
||||
│ понимает задачу, читает Obsidian, решает куда идти, отвечает
|
||||
▼ MM API — исходящее соединение с Mac
|
||||
Балда-оркестратор — Mac, balda-mm:0.1.13, DeepSeek
|
||||
│ понимает задачу, читает Obsidian, планирует, держит крон, отвечает
|
||||
│ НЕ пишет код, НЕ собирает, НЕ ходит по хостам
|
||||
▼ MCP-инструмент executor_run
|
||||
balda-executor-mcp — Kraken, :8890, HTTP + X-Bridge-Secret
|
||||
│ транспорт без логики
|
||||
▼ Cloudflare Tunnel (agents-bridge.qentra.top)
|
||||
мост agents-bridge — Mac, :8790, launchd
|
||||
│ транспорт без логики: идемпотентность, таймаут 900с, лимит 1
|
||||
▼ docker exec
|
||||
callee — Mac, контейнер balda-executor
|
||||
▼
|
||||
callee — Mac
|
||||
│ ДВИЖОК ВОРКФЛОУ: компилирует граф, валидирует целиком до запуска
|
||||
│ МОДЕЛИ НЕ СОДЕРЖИТ: дирижёр — раздаёт роли, гоняет циклы, собирает артефакт
|
||||
├─ Role ────► ACP-процесс ───► МОДЕЛЬ (DeepSeek / позже Codex)
|
||||
@@ -270,15 +430,24 @@ callee — Mac, контейнер balda-executor
|
||||
└─ Human ───► пауза, ответ реплаем в треде MM
|
||||
▼
|
||||
bd (Beads) — трекинг Story → Tasks, живёт между сессиями
|
||||
▼
|
||||
артефакт → Балда → Mattermost
|
||||
```
|
||||
|
||||
### Демонтированные узлы (не нужны в новой топологии)
|
||||
|
||||
| Узел | Почему больше не нужен |
|
||||
|---|---|
|
||||
| `balda-executor-mcp` (:8890) | его работа — пропихнуть вызов к мосту; Балда на Mac → пропускать нечего |
|
||||
| мост `agents-bridge` (:8790) | был границей хостов; границы нет |
|
||||
| Cloudflare Tunnel (для этого потока) | остаётся только для внешнего доступа к MM |
|
||||
| `obsidian-mcp` на Kraken | Obsidian рядом с Балдой |
|
||||
|
||||
### Кто есть кто
|
||||
|
||||
| Компонент | Где | Что это |
|
||||
|---|---|---|
|
||||
| Балда | Kraken | Оркестратор верхнего уровня: понимает смысл задачи |
|
||||
| balda-executor-mcp | Kraken | Проброс по HTTP, логики нет |
|
||||
| мост `:8790` | Mac | Идемпотентность, таймаут, лимит 1, логики нет |
|
||||
| Балда | **Mac** | Оркестратор верхнего уровня: понимает смысл задачи, планирует, крон |
|
||||
| **callee** | Mac | Движок воркфлоу. Граф, роли, циклы. **Не модель** |
|
||||
| Role / DynamicRole | Mac | Узел, который зовёт модель |
|
||||
| **ACP** | Mac | Протокол «редактор ↔ агент». Транспорт, не модель |
|
||||
@@ -286,8 +455,8 @@ bd (Beads) — трекинг Story → Tasks, живёт между сесси
|
||||
| **Codex / Claude CLI** | Mac | Агент-харнесс: модель + умение править файлы и запускать команды |
|
||||
| **bd (Beads)** | Mac | Память задач: что сделано, что нет |
|
||||
| **prism** | Mac | Воркфлоу: specify → design → breakdown → human → apply → verify |
|
||||
| tunnels | — | Cloudflare: Kraken→Mac по HTTP. **Не VPN** |
|
||||
| **lume** | Mac | macOS-виртуалки. Только для задач, требующих настоящую macOS |
|
||||
| **lume** | Mac (хост) | macOS-виртуалки: `macos-15-golden`, `macos-27-golden`, `uitest-26.4.1-golden`, `pdf-hud-macos27` |
|
||||
| MM-сервер | **Kraken** | Только чат-сервер 24/7. Больше ничего |
|
||||
|
||||
📌 **`callee` не умеет ничего сам** — ни думать, ни писать код. Он берёт описание графа,
|
||||
проверяет его и по шагам вызывает: роль → модель, скрипт → shell, human → пауза.
|
||||
@@ -399,6 +568,9 @@ callee agent import baldaworks/prism-callee --path pack/callee/prism --prefix pr
|
||||
|
||||
## 5. Фазы
|
||||
|
||||
> ⚠️ Переписано под топологию §1 (стек на Mac). Прежняя фаза C3 («переписать `PROVIDERS`
|
||||
> в мосте») **отменена**: мост в новой топологии не нужен.
|
||||
|
||||
### C0 — ✅ ЗАКРЫТА 2026-09-29
|
||||
|
||||
Разведка npm: готовый ACP-адаптер к DeepSeek существует (§2.1). Свой адаптер не нужен.
|
||||
@@ -407,22 +579,39 @@ callee agent import baldaworks/prism-callee --path pack/callee/prism --prefix pr
|
||||
`/-/v1/search?text=...`. ⛔ Поиск по `scope:normahq` и `scope:baldaworks` даёт пусто —
|
||||
scoped-пакеты так не индексируются.
|
||||
|
||||
### C1 — установка в контейнер `balda-executor` (1-2 ч)
|
||||
### C1 — переезд стека на Mac (2-3 ч)
|
||||
|
||||
Ни `callee`, ни `bd` нет ни в контейнере, ни на хосте.
|
||||
Объём вырос относительно исходного варианта: теперь это не «установка callee в контейнер»,
|
||||
а **переезд Балды на Mac + установка инструментов рядом**.
|
||||
|
||||
| # | Шаг | Проверка |
|
||||
|---|---|---|
|
||||
| 1 | `npm i -g @baldaworks/callee` | `callee --version` |
|
||||
| 2 | `npm i -g @openma/deepseek-harness-acp` | `dsh-acp --help` |
|
||||
| 3 | `callee setup codex` → стартовые ресурсы | `callee agent list` содержит `workflows/investigate` |
|
||||
| 4 | Установить Beads `bd` | `bd where` |
|
||||
| 5 | Импорт prism-пака | `callee agent view prism/lifecycle --json` → `Router` |
|
||||
| 6 | Прогон стартового `investigate` | артефакт в stdout, exit 0 |
|
||||
| 1 | Запустить второй инстанс `balda-mm:0.1.13` на Mac | контейнер Up, лог `Balda bot started` |
|
||||
| 2 | 🔴 **Отдельный MM-бот и токен для Mac-инстанса** | два процесса на один WebSocket MM рвут события (`bad_seq`) |
|
||||
| 3 | `npm i -g @baldaworks/callee` на Mac | `callee --version` |
|
||||
| 4 | `npm i -g @openma/deepseek-harness-acp` | `dsh-acp --help` |
|
||||
| 5 | `callee setup codex` → стартовые ресурсы | `callee agent list` содержит `workflows/investigate` |
|
||||
| 6 | Установить Beads `bd` | `bd where` |
|
||||
| 7 | Импорт prism-пака | `callee agent view prism/lifecycle --json` → `Router` |
|
||||
| 8 | `obsidian-mcp` рядом с Балдой (том `~/obsidian:/vault`) | `/sse` отвечает |
|
||||
| 9 | Прогон стартового `investigate` | артефакт в stdout, exit 0 |
|
||||
|
||||
📌 Персистентность: установки живут в слое контейнера. Чтобы переживали пересборку —
|
||||
**Решения по хранению (принять на C1):** установки должны переживать пересборку образа —
|
||||
том или `Dockerfile`.
|
||||
|
||||
### C1a — доступы и исполнители (объём зависит от развилки)
|
||||
|
||||
Закрывает шесть сценариев из §2.5. **Объём определяется выбором в §6.7:**
|
||||
|
||||
| Что нужно | Как |
|
||||
|---|---|
|
||||
| `~/.ssh` в контейнере | монтирование **конкретных ключей** с `command=` в `authorized_keys`, не каталога целиком |
|
||||
| `docker build` | ❌ **не через `docker.sock`**; либо обёртка на хосте, либо хост-исполнитель |
|
||||
| `lume` | ❌ в контейнер не пробрасывается; хост-исполнитель |
|
||||
| `xcodebuild` | ❌ в Linux-контейнере невозможно; **lume VM с macOS** |
|
||||
| `~/Developer` | рабочая копия в `~/agents/<проект>` + git (см. §1.1a) |
|
||||
| Доступ к хостам (TrueNAS, Kraken) | ssh-ключ с ограничением `command=` |
|
||||
|
||||
### C2 — Role к DeepSeek (1 ч)
|
||||
|
||||
Описать `Role` по §2.3 и проверить один визит вживую.
|
||||
@@ -430,24 +619,14 @@ scoped-пакеты так не индексируются.
|
||||
**Гейт:** в логе видны `role_model` и `role_reasoning`. До успешного рендера провайдера
|
||||
эти поля опускаются — их появление означает, что рендер прошёл.
|
||||
|
||||
### C3 — подключение к мосту (2-3 ч)
|
||||
### C3 — ~~подключение к мосту~~ ОТМЕНЕНА
|
||||
|
||||
1. Бэкап `~/Developer/agents-bridge/executor.py`.
|
||||
2. Замена argv-таблицы `PROVIDERS`:
|
||||
|
||||
```python
|
||||
PROVIDERS = {
|
||||
"callee": ["callee", "agent", "run", "prism/lifecycle", "--message"],
|
||||
}
|
||||
```
|
||||
|
||||
3. `EXECUTOR_PROVIDER=callee` в `~/Docker/balda-executor/.env`.
|
||||
4. Перезапуск моста: `launchctl bootout` + `bootstrap`.
|
||||
5. Прогон задачи через мост, проверка `exit_code`.
|
||||
Мост `agents-bridge` в топологии «стек на Mac» не участвует. Фаза сохраняется только как
|
||||
**план отката** к топологии «Kraken-оркестратор», если переезд не оправдается.
|
||||
|
||||
### C4 — таск-трекинг (1-2 ч)
|
||||
|
||||
1. `bd` инициализируется в `/agents`.
|
||||
1. `bd` инициализируется в рабочей области.
|
||||
2. Прогон `prism:story` на реальной задаче.
|
||||
3. Проверить durable: прервать сессию, возобновить Story — состояние в Beads на месте.
|
||||
|
||||
@@ -472,9 +651,14 @@ PROVIDERS = {
|
||||
| 1 | Провайдер обеих сторон | DeepSeek | команда Alex |
|
||||
| 2 | Оркестрация | callee | документированная архитектура вместо самодельной |
|
||||
| 3 | Таск-трекинг | prism + Beads | задание Alex |
|
||||
| 4 | Host coding agent | callee CLI в контейнере `balda-executor` | Node 24 — родная среда; там смонтирован `~/agents`; мост уже умеет `docker exec` |
|
||||
| 5 | Мост `:8790` | сохранить, сменить argv | идемпотентность, таймауты, лимит 1 задача уже проверены; выбрасывать работающий слой ради эстетики незачем |
|
||||
| 4 | Где живёт стек | **Mac целиком** | исполнение работает с файлами Mac → обязано быть рядом |
|
||||
| 5 | Где MM-сервер | **Kraken** | единственный, кому нужна доступность 24/7 |
|
||||
| 6 | Тип провайдера | `generic_acp` | список типов закрытый, DeepSeek в нём нет |
|
||||
| 7 | 🔴 **Открыто: доступ к Xcode/lume/docker** | **не решено** | узкий контейнер (три операции недоступны) vs гибрид с хост-исполнителем |
|
||||
| 8 | Роли: где живут | статично, файлами в каталоге | рантайм-выдачи ролей в callee не существует (§1.1b) |
|
||||
| 9 | Права | `права процесса × монтирование × граф` | гейт `Human` защищает действие, но не возможность (§1.1a) |
|
||||
| 10 | Мост `:8790` / MCP `:8890` | **демонтируются** | лишние посредники без содержательной работы |
|
||||
| 11 | Старый инстанс на Kraken | **оставить живым как запасной** | откат без пересборки; ⚠️ требует отдельного MM-бота |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in new issue
Block a user