# Callee + Prism — инструменты оркестрации и таск-трекинга > Создан 2026-09-29. Опорная заметка к [[personal/plans/balda-callee-prism-plan]]. > Назначение: справочник по контрактам callee и prism, чтобы не перечитывать > доки апстрима при каждой правке ресурсов. --- ## 1. Что это | Инструмент | Репозиторий | Лицензия | Что делает | |---|---|---|---| | **callee** | `baldaworks/callee` | MIT | воркфлоу как версионируемые Markdown/YAML-ресурсы | | **prism** | `baldaworks/prism` | MIT | плагин в coding agent: жизненный цикл Story/Epic | | **prism-callee** | `baldaworks/prism-callee` | MIT | те же воркфлоу через callee-агентов | | **Beads** | `gastownhall/beads` | — | durable-состояние (`bd`), носитель состояния prism | 📌 Версия callee на 2026-09-29 — **`0.22.2`** (npm `@baldaworks/callee`, meta-пакет с optionalDependencies на платформенные бинарники: `darwin-arm64`, `darwin-x64`, `linux-arm64`, `linux-x64`, `win32-x64`). --- ## 2. callee — контракты ### 2.1 Типы узлов (10 публичных kinds, `callee.metalagman.dev/v1alpha1`) | Группа | Kind | Поведение | |---|---|---| | Листья | `Role` | промпт + один или несколько ходов в одной свежей ACP-сессии | | | `DynamicRole` | то же, но конфиг провайдера рендерится из состояния визита | | | `Script` | детерминированный локальный шаг через `sh`/`bash` | | | `Human` | пауза, один непустой ответ оператора | | Типизированные оценки | `TypeSafeJev` | нативный оценщик System One/Jev | | | `OpenRouterDecision` | OpenRouter Decisions API | | Композиты | `Sequential` | дети один раз, в порядке исходника | | | `Parallel` | fan-out и join | | | `Loop` | повтор детей в границах до эскалации | | | `Router` | ровно один именованный или дефолтный ребёнок | ### 2.2 Исполнение ``` Markdown/YAML → decode + schema/semantic/template validation → registry + static graph resolution ⛔ отвергает: невалидные ресурсы, битые ссылки, циклы, дубли resource ID, дубли effective ID в resolved tree → resolved root tree + required parameter keys → runner + ОДИН shared ephemeral state-объект → ОДИН корневой артефакт в stdout (пишется ПОСЛЕ cleanup) ``` ⚠️ Диагностика идёт в **stderr**, артефакт — в **stdout**. Непустой stderr **не** означает провал. Успех определять по **exit status**. **Порядок визита узла:** счётчик → слияние `spec.state` со state входящего ребра → рендер строковых листьев по **одному** pre-node снапшоту → атомарный коммит state- модификатора → поведение по типу → `agent finished` со статусом и длительностью. 🔴 При провале рендера state: **ни одна часть модификатора не коммитится, провайдер не стартует.** ### 2.3 Провайдеры — ЗАКРЫТЫЙ список | `type` | Команда по умолчанию | Предусловие | |---|---|---| | `codex` | сам callee + `bridge codex` | авторизованный Codex CLI | | `claude` | `npx -y @zed-industries/claude-code-acp@latest` | Node + npx + креды адаптера | | `opencode` | `opencode acp` | OpenCode CLI | | `copilot` | `copilot --acp --stdio` | Copilot CLI | | `grok` | `grok agent stdio` | Grok CLI или `XAI_API_KEY` | | `cursor` | `agent acp` | Cursor CLI | | `generic_acp` | **нет — требует непустой `cmd`** | любой ACP-исполняемый файл | 🔴 **Gemini не является валидным типом.** DeepSeek — тоже нет → только через `generic_acp`. **Поля провайдера:** | Поле | Контракт | |---|---| | `type` | обязателен, из закрытого списка | | `cmd` | **одно имя исполняемого файла, НЕ shell-строка**; для `generic_acp` обязателен | | `model` / `reasoning` / `mode` | опциональны; пустые → дефолт бэкенда | | `extraArgs` | упорядоченный argv-список; каждый элемент непустой | | `timeout` | Go duration, **по умолчанию `15m`** | ⚠️ Конфиг провайдера обязан быть **вложенным** — плоские поля в `spec` не поддержаны. **Таймаут независим для:** старта процесса, создания и подготовки сессии, **каждого** хода. Корневой прогон целиком он **не** ограничивает. **Переиспользование процесса:** одинаковые effective `type` + полностью резолвленный `cmd` → один процесс. `model`/`mode`/`reasoning` на идентичность процесса **не влияют**. Сессия всегда создаётся свежая. ### 2.4 DynamicRole — провайдер из состояния Все поля провайдера — шаблоны: `type`, `cmd`, `model`, `reasoning`, `mode`, `timeout`, **каждый** элемент `extraArgs`. | Факт | Значение | |---|---| | Источники | `.Prompt`, текущий `.Input`, **один** согласованный post-node снапшот `.State`, `.Params` | | Недоступно | `.Output`, env, файловая система, сеть, часы, рандом, криптография, мутаторы | | Рендер | ровно **один раз на визит**; валидируется **до** поиска процесса | | Периметр | конфиг фиксирован на весь визит, включая REPL-ходы | | Повтор | новый визит Loop рендерит заново из актуального состояния | | Ошибка | рендер или валидация падают → визит падает, ничего не стартует | 📌 В `callee agent view` DynamicRole помечается `provider=runtime`; JSON-view сохраняет авторские шаблоны. Обычный `callee doctor` валидирует ресурс, шаблон и граф, но готовность провайдера **откладывает** — исполняемый файл проверяется только при достижении узла. 📌 После рендера в lifecycle-событиях появляются `role_model` и `role_reasoning`. **До** успешного рендера эти поля опускаются — их появление = рендер прошёл. 🔴 **Безопасность:** state-driven `cmd` и `extraArgs` могут выбирать исполняемый код. Не подавать туда недоверенный вывод модели без ограничения авторской шаблонной логикой. `cmd` остаётся одним исполняемым файлом, `extraArgs` — argv-списком; shell не участвует. ### 2.5 Script и Human **Script:** результат пишется в `State.scripts[effectiveId]` — `status` (`passed`/`failed`), `exitCode` (`-1` при таймауте), `stdout`, `stderr`, `timedOut`. 🔴 **Таймаут всегда валит воркфлоу.** Ненулевой exit валит, если не задан `onNonZero: continue`. **Human:** рендерит тело, показывает на **управляющем терминале**, просит один непустой ответ. Пишется в `State[responseKey]` и дублируется в `State.outputs[effectiveId]`. > 🔴 **Requires interactive mode** and an interactor backed by a controlling terminal. > Explicit non-interactive mode **rejects a Human anywhere in the resolved tree during > preflight, including beneath an unselected Router branch**. **Следствие:** воркфлоу с `Human` **не запускается** в non-interactive режиме вообще — и проверка идёт до всякой логики, по всему resolved tree. Запуск через `docker exec` без `-t` даёт non-interactive → `Human` невозможен. ### 2.6 Эскалация Принадлежит **рёбрам**, а не определениям ресурсов. `Role` может эскалировать в ближайший включающий `Loop` **только если каждое** ребро от Loop к этому вхождению имеет `canEscalate: true` (опущенное = `false`). Вложенный `Loop` открывает **новую границу авторизации** — потомки не наследуют полномочия внешнего. ### 2.7 Команды ```bash npx --yes @baldaworks/callee@latest setup callee agent list callee agent view [--json] callee agent run --message "..." [--repl-timeout D] callee agent import --path --prefix [--force] callee doctor ``` --- ## 3. Prism — таск-трекинг ### 3.1 Жизненные циклы **Story:** Specify → Design → Breakdown → **Human approval** → Apply → Verify. Фазы: `phase:story:specify` → `design` → `breakdown` → `human` → `apply` → `verify`. **Epic:** Frame → Architecture → Roadmap → **approval** → Deliver Stories → Validation. Фазы: `phase:epic:frame` → `architecture` → `roadmap` → `approval` → `delivery` → `validation`. ### 3.2 Правила | Правило | Значение | |---|---| | Дети Epic | только **Stories** | | Дети Story | только **Tasks** | | Вложенные Epic, Task напрямую в Epic | **невалидно** | | Фиксированный диапазон числа детей | **нет** — оценка качественная (покрытие, связность, ревьюимость, верифицируемость, ацикличность) | | `Apply` | 🔴 **каждый переход требует явной авторизации человека** | | Одобрение Epic → Story | **не переносится** | | Критерии приёмки | показываются **только** по явному запросу оператора | При паузах prism останавливается только на: необходимом уточнении, одобрении перед реализацией, блокерах. ### 3.3 Установка и импорт **В coding agent** (независимая установка, например Codex): ```bash codex plugin marketplace add baldaworks/prism codex plugin add prism@prism # обновление: codex plugin marketplace upgrade prism → повторить add → новый thread ``` **Callee-агенты** (отдельный репозиторий, требует `callee >= 0.19.0` + `bd`): ```bash callee agent import baldaworks/prism-callee \ --path pack/callee/prism \ --prefix prism # обновление/починка: тот же вызов + --force ``` **Проверка:** ```bash callee agent list | grep '^prism/' callee agent view prism/lifecycle --json # 🔴 kind ДОЛЖЕН быть Router callee agent view prism/story --json callee agent view prism/epic --json bd where ``` 🔴 **`Sequential` вместо `Router` = устаревший импорт** → обновлять `--force`. `--agent-root pack/callee` — только для поддержки самого репозитория. > «Each repository installs and validates independently — installing one plugin does > not install the other.» ### 3.4 Штатный и прямой запуск | Способ | Команда | Что даёт | |---|---|---| | Штатный (рекомендован) | `$prism-callee:lifecycle <запрос>` | резолвит Beads-цель, **персистит фазовые метки**, поддерживает resume | | Прямой Story | `callee agent run prism/story --message "..."` | исполняет граф, но **не** резолвит Beads-элемент и не персистит метки | | Прямой Epic | `callee agent run prism/epic --message "..."` | то же ограничение | 📌 «The coding agent owns durable state and approval. Callee executes the selected graph; **approval never transfers from an Epic to a Story.**» --- ## 4. DeepSeek как ACP-провайдер Провайдер callee — `generic_acp`, `cmd: dsh-acp`, пакет **`@openma/deepseek-harness-acp@0.4.33`** (Apache-2.0, Node `>= 22.15`, `bin: dsh-acp` → `dist/bin.js`). Обёртка вокруг официального DeepSeek Harness. | Способ передачи кред | Значение | |---|---| | Флаг | `api-key`, либо `api-key:` при нескольких провайдерах | | Env | **`DEEPSEEK_API_KEY`** | | Env | **`DEEPSEEK_BASE_URL`** — OpenAI-совместимый endpoint override | Приоритет: **флаги → переменные окружения → дефолты**. 📌 `DEEPSEEK_BASE_URL` — OpenAI-совместимый override → смена провайдера сводится к смене одной переменной, без правки графа. 📌 Официальный `@deepseek-ai/dsh-acp` **не подошёл**: pre-release (последние версии сплошь `-rc`/`-alpha`), `bin: null` — библиотека, а не запускаемый сервер. --- ## 5. Питфоллы 1. 🔴 **`Human` требует TTY** — non-interactive режим отвергает граф целиком, включая невыбранные ветки Router. Запуск через `docker exec` без `-t` = non-interactive. 2. 🔴 **`cmd` — одно имя файла.** Аргументы только в `extraArgs`, иначе провайдер не стартует. 3. 🔴 **Не подавать вывод модели в `cmd`/`extraArgs`** — исполнение произвольного кода. 4. ⚠️ **`prism/lifecycle` обязан быть `Router`** — иначе устаревший импорт. 5. ⚠️ **Непустой stderr ≠ провал** — судить по exit status. 6. ⚠️ **Таймаут Script валит весь воркфлоу** — не «продолжает с ошибкой». 7. ⚠️ **Concurrency группы `Parallel`** используют один живой shared state. 8. ⚠️ **Поиск npm по `scope:normahq` / `scope:baldaworks` даёт пусто** — эти scoped-пакеты через search-API не индексируются. Искать прямыми URL `registry.npmjs.org/%2f`. --- ## Связанные заметки - [[personal/plans/balda-callee-prism-plan]] — план внедрения - [[personal/plans/balda-mm-phase4-agents]] — Фаза 4 (мост, приёмка) - [[personal/tech/agents-bridge]] — мост :8790 - [[personal/tech/balda-executor-mcp]] — MCP-сервер делегирования