16 KiB
Executable File
Балда → Callee + Prism: делегирование
Обновлён 2026-09-29. Статус: C0 закрыта, C1-C5 не начаты. Часть personal/projects/balda/balda-mm-delegation-plan.
1. Целевая архитектура
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
Разделение ролей
| Слой | Владелец |
|---|---|
| Граф воркфлоу, валидация, state | callee |
| Durable-состояние + одобрение | coding agent |
| Исполнение модели | ACP-процесс |
Разделение расходов
| Роль | Где | Провайдер |
|---|---|---|
| Оркестратор верхнего уровня | Kraken | DeepSeek deepseek-chat |
| Исполнитель-роли callee | Mac, контейнер | DeepSeek |
📌 «DeepSeek с обоих концов» = обе стороны на DeepSeek. Подписочный Codex подключается
позже заменой State.provider в DynamicRole — без правки графа.
2. Провайдер DeepSeek для callee
2.1 ACP-адаптер — выбран @openma/deepseek-harness-acp@0.4.33
Свой адаптер писать не надо.
| Значение | |
|---|---|
| Пакет | @openma/deepseek-harness-acp |
| Версия | 0.4.33 |
bin |
dsh-acp → dist/bin.js — запускаемый ACP-сервер |
| Родословная | обёртка вокруг официального DeepSeek Harness |
| Node | >= 22.15 (в контейнере 24.21.0 ✅) |
| Лицензия | Apache-2.0 |
| Зависимости | @agentclientprotocol/sdk 1.4.0, tar, zod |
Установка (standalone-вариант, подходит для generic_acp):
npm i -g @openma/deepseek-harness-acp
# запуск: dsh-acp
2.2 Креды
Приоритет: флаги → переменные окружения → дефолты.
| Способ | Значение |
|---|---|
| Флаг | api-key, либо api-key:<provider> при нескольких провайдерах |
| Env | DEEPSEEK_API_KEY |
| Env | DEEPSEEK_BASE_URL — OpenAI-совместимый endpoint override |
🔴 DEEPSEEK_BASE_URL — это OpenAI-совместимый override, значит переезд на Colex
сводится к смене одной переменной, без правки графа.
📌 Ключ DEEPSEEK_API_KEY лежит в ~/.hermes/hermes-whale/.env (длина 35).
📌 Креды не попадают в конфиг клиента: адаптер переиспользует ключ из credential store
(dsh web / dsh-acp login), либо берёт DEEPSEEK_API_KEY из окружения процесса.
2.3 Конфигурация Role
Тип провайдера — generic_acp, потому что список поддерживаемых типов закрытый:
codex, claude, opencode, copilot, grok, cursor, generic_acp.
DeepSeek в нём отсутствует.
provider:
type: generic_acp
cmd: dsh-acp # одно имя исполняемого файла, НЕ shell-строка
model: deepseek-chat
timeout: 20m
| Поле | Контракт |
|---|---|
cmd |
одно имя исполняемого файла; для generic_acp обязателен |
extraArgs |
упорядоченный argv-список; каждый элемент непустой |
model / reasoning / mode |
опциональны; пустые → дефолт бэкенда |
timeout |
Go duration, по умолчанию 15m |
| Конфиг провайдера | обязан быть вложенным (spec.provider.*), плоские поля не поддержаны |
2.4 DynamicRole — провайдер из состояния
Все поля провайдера — шаблоны, рендерятся из состояния в момент визита:
kind: DynamicRole
spec:
provider:
type: '{{ .State.provider }}'
model: '{{ .State.model }}'
timeout: '{{ .State.timeout }}'
state:
provider: generic_acp
model: deepseek-chat
timeout: 20m
| Факт | Значение |
|---|---|
| Что рендерится | type, cmd, model, reasoning, mode, timeout, каждый extraArgs |
| Из чего | .Prompt, текущий .Input, один согласованный post-node снапшот .State, .Params |
| Чего нельзя | .Output, env, файловая система, сеть, часы, рандом, криптография, мутаторы |
| Когда валидируется | до поиска и старта процесса; ошибка → визит падает, провайдер не стартует |
| Периметр визита | конфиг фиксирован на весь визит, включая REPL-ходы; новый визит Loop рендерит заново |
| Переиспользование процесса | одинаковые effective type+cmd → один процесс; сессия всегда новая |
🔴 Безопасность: state-driven cmd и extraArgs могут выбирать исполняемый код.
Не подавать туда вывод модели без ограничения через авторскую шаблонную логику.
3. Prism — таск-трекинг
3.1 Callee и prism — независимые установки
Установка одного плагина не ставит другой.
baldaworks/prism |
baldaworks/prism-callee |
|
|---|---|---|
| Что это | плагин в coding agent (Codex/Claude/Grok/Copilot/Cursor) | callee-агенты для тех же воркфлоу |
| Требования | coding agent + bd (Beads) |
coding agent + bd + callee ≥ 0.19.0 |
| Команды | $prism:story, $prism:epic, $prism:lifecycle |
$prism-callee:lifecycle |
| Состояние | Beads (bd) |
Beads (bd) |
Импорт callee-агентов:
callee agent import baldaworks/prism-callee --path pack/callee/prism --prefix prism
🔴 Проверка импорта: callee agent view prism/lifecycle --json → kind Router.
Sequential = устаревший импорт, обновлять --force.
3.2 Жизненный цикл
Story: Specify → Design → Breakdown → Human approval → Apply → Verify.
Фазы: phase:story:specify → design → breakdown → human → apply → verify.
Epic: Frame → Architecture → Roadmap → approval → Deliver Stories → Validation.
| Правило | Значение |
|---|---|
| Дети Epic | только Stories |
| Дети Story | только Tasks |
| Вложенные Epic / Task напрямую в Epic | невалидно |
| Фиксированного диапазона числа детей | нет — оценка качественная |
| Apply | каждый переход требует явной авторизации человека |
| Одобрение Epic → Story | не переносится |
4. Одобрения в Mattermost — работают
Одобрение проходит ответом в треде, как в Slack.
| Механизм | Статус |
|---|---|
| Вопрос с опциями (markdown-нумерация) | ✅ questionfmt + questioncmd + deliveryfmt, покрыто тестами |
| Приём ответа реплаем | ✅ BuildInboundReply через RootID (channel/mattermost/inbound.go) |
ask как режим разрешений |
✅ mattermost в списке каналов (permissions/service.go) |
📌 ask — это режим политики разрешений агента; механизм вопросов — отдельный слой.
Оба в MM работают.
⛔ Инлайн-кнопок и реакций в MM нет — только Telegram. Событие reaction
сознательно отбрасывается в channel/mattermost/ingress.go.
5. Фазы
C0 — ✅ ЗАКРЫТА 2026-09-29
Разведка npm: готовый ACP-адаптер к DeepSeek существует (§2.1). Свой адаптер не нужен.
Метод поиска: прямые URL registry.npmjs.org/<scope>%2f<name> и
/-/v1/search?text=.... ⛔ Поиск по scope:normahq и scope:baldaworks даёт пусто —
scoped-пакеты так не индексируются.
C1 — установка в контейнер balda-executor (1-2 ч)
Ни callee, ни bd нет ни в контейнере, ни на хосте.
| # | Шаг | Проверка |
|---|---|---|
| 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 |
📌 Персистентность: установки живут в слое контейнера. Чтобы переживали пересборку —
том или Dockerfile.
C2 — Role к DeepSeek (1 ч)
Описать Role по §2.3 и проверить один визит вживую.
Гейт: в логе видны role_model и role_reasoning. До успешного рендера провайдера
эти поля опускаются — их появление означает, что рендер прошёл.
C3 — подключение к мосту (2-3 ч)
- Бэкап
~/Developer/agents-bridge/executor.py. - Замена argv-таблицы
PROVIDERS:
PROVIDERS = {
"callee": ["callee", "agent", "run", "prism/lifecycle", "--message"],
}
EXECUTOR_PROVIDER=calleeв~/Docker/balda-executor/.env.- Перезапуск моста:
launchctl bootout+bootstrap. - Прогон задачи через мост, проверка
exit_code.
C4 — таск-трекинг (1-2 ч)
bdинициализируется в/agents.- Прогон
prism:storyна реальной задаче. - Проверить durable: прервать сессию, возобновить Story — состояние в Beads на месте.
C5 — сквозная приёмка (1 ч)
От учётки Alex, не подставным аккаунтом:
@balda добавь CSV-экспорт в отчёт
→ Specify → Design → Breakdown → Human approval → Apply → Verify
→ ответ в Mattermost + артефакт
Доказательство — лента qentra:balda-test, автор поста cbwsorzwoigbtrdnteugnx4aqo.
6. Решения
| # | Вопрос | Решение | Почему |
|---|---|---|---|
| 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 задача уже проверены; выбрасывать работающий слой ради эстетики незачем |
| 6 | Тип провайдера | generic_acp |
список типов закрытый, DeepSeek в нём нет |
7. Питфоллы
- ⚠️
PROVIDERSв мосте — argv-список. Промпт должен остаться одним последним элементом, иначе передача рвётся. - ⚠️
.envне перебивает plist.--hostжёстко вProgramArguments; смена аргументов требуетbootout+bootstrap. Проверка:lsof -nP -iTCP:8790 -sTCP:LISTEN→ должно быть*:8790. - ⚠️
prism/lifecycleдолжен бытьRouter—Sequentialозначает устаревший импорт, лечится--force. - ⚠️ Provider
cmd— одно имя файла, не shell-строка. Аргументы — только вextraArgs. - ⚠️ Никогда не маршрутизировать вывод модели в
cmd/extraArgs. - ⚠️ Установки в контейнере не переживают пересборку — том или
Dockerfile. - ⚠️
docker-compose(дефис) на Mac,docker compose(пробел) на Kraken. - ⚠️ Node
>= 22.15требуется адаптером (в образе 24.21.0).
8. Риски
| Риск | Оценка | Митигация |
|---|---|---|
Импорт prism/* устаревает при обновлении |
средний | проверять kind: Router после каждого импорта |
| callee обновляется и меняет контракт | средний | пиннить версию в ресурсах |
| Мост теряет работоспособность после смены argv | низкий | бэкап executor.py, откат одной правкой |
| Стоимость DeepSeek растёт | низкий | исполнитель-роли — короткие визиты |
| Установка в контейнер не переживёт пересборку | низкий | том или Dockerfile |
9. Порядок и запреты
Порядок: C1 → C2 → C3 → C4 → C5.
НЕ трогать в ~/Developer/balda: go.mod, Dockerfile.release, go.sum,
internal/apps/balda/app.go, internal/apps/balda/preflight.go — вне PR-дерева,
нужны для сборки стенда. git checkout -- . / stash / reset --hard их снесёт.
См. personal/plans/balda-mm-pr-plan §5.
НЕ начинать работу без явного «поехали». Ничего не удалять без отдельного подтверждения.
Связанные заметки
- personal/tech/callee-prism — справочник по контрактам callee и prism
- personal/projects/balda/balda-mm-delegation-plan — общий план Фаз 1-5
- personal/plans/balda-mm-phase4-agents — Фаза 4 (мост :8790, приёмка)
- personal/plans/balda-mm-pr-plan — Фаза 2 (PR #8)
- personal/projects/balda/balda-kraken-mm-deploy — Фаза 3
- personal/tech/agents-bridge — мост :8790
- personal/tech/balda-executor-mcp — MCP-сервер делегирования