Files
obsidian-vault/personal/tech/callee-prism.md
T

275 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 <codex|claude|grok|copilot|opencode|cursor>
callee agent list
callee agent view <id> [--json]
callee agent run <id> --message "..." [--repl-timeout D]
callee agent import <owner/repo> --path <pack> --prefix <pfx> [--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:<provider>` при нескольких провайдерах |
| 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/<scope>%2f<name>`.
---
## Связанные заметки
- [[personal/plans/balda-callee-prism-plan]] — план внедрения
- [[personal/plans/balda-mm-phase4-agents]] — Фаза 4 (мост, приёмка)
- [[personal/tech/agents-bridge]] — мост :8790
- [[personal/tech/balda-executor-mcp]] — MCP-сервер делегирования