Files
obsidian-vault/personal/plans/balda-callee-prism-plan.md
T

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 ч)

  1. Бэкап ~/Developer/agents-bridge/executor.py.
  2. Замена argv-таблицы PROVIDERS:
PROVIDERS = {
    "callee": ["callee", "agent", "run", "prism/lifecycle", "--message"],
}
  1. EXECUTOR_PROVIDER=callee в ~/Docker/balda-executor/.env.
  2. Перезапуск моста: launchctl bootout + bootstrap.
  3. Прогон задачи через мост, проверка exit_code.

C4 — таск-трекинг (1-2 ч)

  1. bd инициализируется в /agents.
  2. Прогон prism:story на реальной задаче.
  3. Проверить 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. Питфоллы

  1. ⚠️ PROVIDERS в мосте — argv-список. Промпт должен остаться одним последним элементом, иначе передача рвётся.
  2. ⚠️ .env не перебивает plist. --host жёстко в ProgramArguments; смена аргументов требует bootout + bootstrap. Проверка: lsof -nP -iTCP:8790 -sTCP:LISTEN → должно быть *:8790.
  3. ⚠️ prism/lifecycle должен быть Router — Sequential означает устаревший импорт, лечится --force.
  4. ⚠️ Provider cmd — одно имя файла, не shell-строка. Аргументы — только в extraArgs.
  5. ⚠️ Никогда не маршрутизировать вывод модели в cmd/extraArgs.
  6. ⚠️ Установки в контейнере не переживают пересборку — том или Dockerfile.
  7. ⚠️ docker-compose (дефис) на Mac, docker compose (пробел) на Kraken.
  8. ⚠️ 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.

НЕ начинать работу без явного «поехали». Ничего не удалять без отдельного подтверждения.


Связанные заметки