Архитектура динамических воркеров

Phase 26: Dynamic Worker Registry. Заменяет жёстко прописанный двух-агентный flow из Phase 24.5. Последнее обновление: 2026-04-06

Обзор

Phase 26 заменяет жёстко запрограммированную бинарную логику Consultant/Developer системой динамического реестра воркеров.

Воркеры объявляются в config/workers_registry.json. Каждый воркер определяет: id, label, icon, type (chat/terminal), model, max_turns, tools, system_prompt_skill, prompt_style (history/gsd), output_format, focus_dirs, log_category, builtin.

Встроенные воркеры:

CEO выбирает воркер через команды Telegram. Спеки — это мост между воркерами: Consultant их создаёт, CEO одобряет, Developer выполняет.

CEO (Telegram)
 │
 ├── /c <message>  ──► Consultant subprocess (read-only Claude)
 │                      │
 │                      ├── Анализирует код, ищет в вебе
 │                      └── Выводит блоки SPEC
 │                           │
 │                           ▼
 │                      spec_queue.json (status: "draft")
 │
 ├── /approve <id>  ──► статус спека → "approved"
 │                           │
 │                           ▼
 ├── /d <message>   ──► Developer (основной GSD loop)
 │                      │
 │                      ├── Читает одобренные спеки из очереди
 │                      ├── Реализует изменения
 │                      └── Помечает спек → "done"
 │
 ├── /reject <id>   ──► статус спека → "rejected"
 │
 └── /specs         ──► Список всех спеков с статусом

Модель данных

Интерфейс Spec

interface Spec {
  id: string;            // nanoid(8), напр. "a1b2c3d4"
  title: string;         // Однострочный заголовок из блока SPEC
  problem: string;       // Какую задачу решает
  approach: string;      // Технический подход (2-3 предложения)
  acceptance: string[];  // Список критериев приёмки
  files: string[];       // Затронутые пути к файлам
  complexity: "low" | "medium" | "high";
  status: SpecStatus;
  createdAt: string;     // ISO 8601
  updatedAt: string;     // ISO 8601
  consultantThread?: string; // ID треда, создавшего этот спек
}

type SpecStatus = "draft" | "approved" | "rejected" | "executing" | "done";

Машина состояний

  ИДЕЯ ──► КОНСУЛЬТАЦИЯ ──► ЧЕРНОВИК ──► РЕВЬЮ ──► ОДОБРЕН ──► ВЫПОЛНЯЕТСЯ ──► ГОТОВО
                                ↑                         │
                                +──── ОТКЛОНЁН ───────────+

Переходы:

Откуда Куда Триггер
draft Consultant выводит блок SPEC
draft approved CEO отправляет /approve <id>
draft rejected CEO отправляет /reject <id>
rejected draft Consultant пересматривает после обратной связи
approved executing Developer начинает реализацию
executing done Developer выполняет все критерии приёмки

API Endpoints

Все эндпоинты внутренние (маршрутизация master-бота), не HTTP API.

Эндпоинт Метод Auth Описание
/c <msg> Telegram только CEO Маршрутизировать сообщение к Consultant subprocess
/d <msg> Telegram только CEO Маршрутизировать сообщение к Developer (GSD loop)
/approve <id> Telegram только CEO Одобрить черновой спек
/reject <id> Telegram только CEO Отклонить черновой спек с опциональной обратной связью
/specs Telegram только CEO Список всех спеков с фильтром по статусу
/role Telegram только CEO Показать текущую активную роль
default Telegram только CEO Маршрутизировать к активной роли (consultant или developer)

Маршрутизация сообщений

handleMessage() master-бота маршрутизирует входящие сообщения Telegram:

function handleMessage(text: string, chatId: number) {
  if (text.startsWith("/c "))        → callWorker("consultant", text.slice(3))
  if (text.startsWith("/d "))        → callWorker("developer", text.slice(3))
  if (text.startsWith("/w:"))        → callWorker(parsedWorkerId, parsedText)
  if (text.startsWith("/approve "))  → approveSpec(text.slice(9).trim())
  if (text.startsWith("/reject "))   → rejectSpec(text.slice(8).trim())
  if (text === "/specs")             → listSpecs()
  if (text === "/role")              → showActiveRole()
  else                               → callWorker(activeWorkerId, text)
}

Унифицированный диспетч: getWorkerConfig(workerId)callWorker(workerId, text, options). Конфигурация воркера определяет модель, инструменты, стиль prompt и категорию логов. Маршрутизация по умолчанию использует active_role.json. Начальное умолчание: developer.

Компоненты фронтенда

WorkerPanel (Phase 26)

Универсальный диспетчер панелей. Рендерит ChatPanelView или TerminalPanelView в зависимости от worker.type.

ChatPanelView

Отображает разговоры с воркерами типа chat (Consultant, UI/UX Designer и др.).

Аспект Деталь
Источник данных /api/sse/logs/:name?category=${worker.log_category}
Отображение Чат-пузыри (CEO справа, воркер слева)
Определение SPEC Парсит блоки ### SPEC:, рендерит как карточки с кнопками approve/reject
Ввод Полная панель ввода с выбором модели, меню инструментов, голосовым вводом, вложениями файлов
Dev Result Кнопка для просмотра последнего ответа терминала Developer

TerminalPanelView

Отображает вывод воркеров типа terminal (Developer и др.).

Аспект Деталь
Источник данных /api/sse/logs/:name?category=${worker.log_category}
Отображение Записи логов в моноширинном шрифте с иконками инструментов, индикаторами обдумывания, состоянием обработки
Ввод Простая командная строка с кнопкой Send

Хук useSSEStream

Унифицированный SSE хук для обоих типов панелей. Обрабатывает дедупликацию (seenIds), определение состояния обработки и трансформацию записей в зависимости от worker.type.

Workers Bar

Верхняя панель, показывающая всех зарегистрированных воркеров в виде кнопок-переключателей. Клик добавляет/убирает панели. Раскладка сохраняется в localStorage для каждого проекта (citadel-workspace-active-${project.name}).

SpecPanel

Доска в стиле Kanban, показывающая жизненный цикл спеков.

Колонка Спеки
Draft status: "draft" — с кнопками approve/reject
Approved status: "approved" — ожидают Developer
In Progress status: "executing" — Developer работает
Done status: "done" — завершены
Rejected status: "rejected" — свёрнуты по умолчанию

RoleToggle

Визуальный индикатор в заголовке pod-а проекта, показывающий активную роль/воркер.

Клик на переключатель отправляет информацию команды /role; реальное переключение ролей — только через команды Telegram (безопасность: никаких мутаций с фронтенда).

Модель безопасности

Ограничения инструментов воркеров

Инструменты воркеров объявлены в workers_registry.json. Функция callWorker() читает worker.tools и передаёт --allowedTools в Claude CLI:

Это гарантирует, что воркеры типа chat (Consultant, UI Designer) НЕ МОГУТ:

Изоляция воркеров

Структура хранилища

Все файлы состояния хранятся в рабочей директории проекта в state/:

state/
├── active_role.json          # { "role": "developer"|"consultant", "since": ISO8601 }
├── consultant_thread.json    # { "threadId": "...", "startedAt": ISO8601 }
├── spec_queue.json           # Spec[] массив — все спеки с статусом
└── logs/
    ├── consultant-YYYY-MM-DD.log   # JSONL разговор Consultant
    └── specs-YYYY-MM-DD.log        # JSONL переходы состояний спеков

active_role.json

{
  "role": "developer",
  "since": "2026-04-05T10:00:00Z"
}

consultant_thread.json

{
  "threadId": "thread_abc123",
  "startedAt": "2026-04-05T10:00:00Z",
  "messageCount": 12
}

spec_queue.json

[
  {
    "id": "a1b2c3d4",
    "title": "Add rate limiting to CRM endpoints",
    "problem": "CRM API has no rate limiting, vulnerable to abuse",
    "approach": "Add sliding window rate limiter middleware using in-memory Map with IP-based tracking",
    "acceptance": [
      "Rate limiter middleware applied to all /api/crm/* routes",
      "100 requests per minute per IP",
      "429 response with Retry-After header"
    ],
    "files": ["shared/crm-routes.ts", "shared/rate-limiter.ts"],
    "complexity": "medium",
    "status": "approved",
    "createdAt": "2026-04-05T10:05:00Z",
    "updatedAt": "2026-04-05T10:12:00Z"
  }
]

Worker Registry

Все воркеры объявлены в config/workers_registry.json:

{
  "version": 1,
  "workers": [
    {
      "id": "consultant",
      "label": "Consultant",
      "icon": "\ud83d\udcac",
      "type": "chat",
      "model": "claude-sonnet-4-5",
      "max_turns": 5,
      "tools": ["Read", "Glob", "Grep", "WebSearch", "WebFetch"],
      "system_prompt_skill": "consultant_system.md",
      "prompt_style": "history",
      "output_format": "text",
      "focus_dirs": [],
      "log_category": "consultant",
      "builtin": true
    }
  ]
}
Поле Тип Описание
id string Уникальный идентификатор воркера (используется в маршрутизации, хранилище, SSE)
label string Отображаемое имя в UI
icon string Emoji-иконка для pill/заголовка
type "chat" | "terminal" Тип панели: chat-пузыри или моноширинные логи
model string ID модели Claude
max_turns number Максимальное количество агентных ходов за вызов
tools string[] | "all" Whitelist разрешённых инструментов или "all" для полного доступа
system_prompt_skill string | null Путь к системному prompt в директории skills/
prompt_style "history" | "gsd" Стиль разговора (добавлять историю vs GSD prompt)
output_format "text" | "stream-json" Режим обработки вывода
focus_dirs string[] Директории для фокусировки (вставляются в prompt)
log_category string Категория JSONL-лога (маппится на SSE-параметр ?category=)
builtin boolean Поставляется ли этот воркер вместе с Arc OS

Конфигурация ролей

Конфигурация ролей на уровне проекта в config/project_roles.json:

{
  "version": 1,
  "defaults": {
    "activeRole": "developer",
    "specAutoApprove": false,
    "maxDraftSpecs": 20
  }
}

Логирование

Все взаимодействия с Consultant и переходы состояний спеков логируются в формате JSONL.

Записи consultant-*.log

{"ts":"2026-04-05T10:05:00Z","role":"ceo","text":"How should we add caching?"}
{"ts":"2026-04-05T10:05:15Z","role":"consultant","text":"Based on analysis...","specs":["a1b2c3d4"]}

Записи specs-*.log

{"ts":"2026-04-05T10:05:15Z","event":"created","specId":"a1b2c3d4","title":"Add caching layer"}
{"ts":"2026-04-05T10:12:00Z","event":"approved","specId":"a1b2c3d4","by":"ceo"}
{"ts":"2026-04-05T10:30:00Z","event":"executing","specId":"a1b2c3d4"}
{"ts":"2026-04-05T11:00:00Z","event":"done","specId":"a1b2c3d4"}

Поддерживается Rick (Orchestrator). Phase 26 — Dynamic Workers.