27 KiB
Team Board — Идеи и концепция
Суть проекта
Team Board — платформа для управления командой AI-агентов, работающих над проектами.
Ключевая идея: Несколько AI-агентов работают как команда разработчиков. Человек видит всё: задачи, код, переписку. Полная прозрачность.
Проблема, которую решаем
Один универсальный AI-ассистент:
- Контекст переполняется при разных задачах
- Сложно параллельно вести несколько направлений
- Нет специализации — один промпт на всё
Решение: Команда специализированных агентов, каждый со своей ролью и контекстом.
Архитектура: Tracker-Centric
Принцип
Tracker = центральный сервис. Всё остальное — клиенты.
┌─────────────────────────────────────────────────────┐
│ WEB CLIENT │
│ ┌───────────┐ ┌────────────┐ │
│ │ Next.js │ ←→ │ BFF │ (свой бэкенд) │
│ │ фронтенд │ │ Python │ │
│ └───────────┘ │ + Authentik│ │
│ └─────┬──────┘ │
└──────────────────────────┼──────────────────────────┘
│ ws (внутренняя сеть)
┌────────────▼────────────┐
│ TRACKER │
│ (внутренний сервис) │
│ НЕ выставлен наружу │
│ │
│ - проекты │
│ - доски (канбан) │
│ - задачи + подзадачи │
│ - чаты │
│ - события │
│ - БД (PostgreSQL) │
└────────────┬────────────┘
│ ws
┌─────────────────┼─────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Агент 1 │ │ Агент 2 │ │ Агент N │
│ (Claude) │ │ (Codex) │ │ (Gemini) │
│ отд. сервис │ │ отд. сервис │ │ отд. сервис │
└──────────────┘ └──────────────┘ └──────────────┘
Компоненты
| Компонент | Описание |
|---|---|
| Tracker | Ядро: проекты, задачи, чаты, события. Внутренний, WebSocket сервер |
| Web Client | Next.js + BFF (Python). Авторизация через Authentik. Единственное что торчит наружу |
| Агенты | Отдельные сервисы. Подключаются к трекеру по WebSocket |
Репозитории
team-board/
├── tracker/ — ядро (Python, WebSocket, PostgreSQL)
├── web-client/ — Next.js + BFF
└── docs/ — документация
Агенты — отдельные репозитории (шаблон + конкретные).
Канбан-доска
Колонки
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│ Backlog │ │ TODO │ │ In Prog │ │ Review │ │ Done │
├──────────┤ ├──────────┤ ├──────────┤ ├──────────┤ ├──────────┤
│ [draft] │ │ [ready] │ │ [active] │ │ [review] │ │[complete]│
│ [draft] │ │ [ready] │ │ │ │ │ │[complete]│
│ │ │ │ │ │ │ │ │ │
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘
Статусы задач
| Статус | Описание |
|---|---|
draft |
Черновик. Можно обсуждать, но не выполнять |
ready |
Готова к выполнению. Перенос из Backlog → TODO автоматически ставит этот статус |
in_progress |
Агент взял в работу |
review |
На ревью у другого агента |
completed |
Выполнена |
blocked |
Заблокирована зависимостью |
Жизненный цикл задачи
1. Человек создаёт задачу → draft (Backlog)
2. Обсуждение в чате проекта
3. Человек перетаскивает в TODO → статус меняется на ready
4. Агент берёт задачу → in_progress
5. Агент завершает → review
6. Ревьюер проверяет → completed / возврат в in_progress
Задачи
Структура задачи
Задача:
id: uuid
проект: project_id
название: "Реализовать API авторизации"
описание: "Markdown текст с деталями"
статус: draft | ready | in_progress | review | completed | blocked
# Лейблы (как в Jira — произвольные, создаются в трекере)
лейблы: ["coding", "api", "backend", "urgent"]
# PR (вручную или по лейблу)
требует_pr: true | false
# Назначение
назначен: agent_id (или null)
# Вложенные файлы
файлы:
- name: "schema.sql"
type: "text/sql"
content: "..."
- name: "mockup.png"
type: "image/png"
url: "/files/task-123/mockup.png"
# Подзадачи (неограниченная вложенность)
подзадачи:
- название: "Написать модели"
назначен: agent-coder
статус: completed
- название: "Code review"
назначен: agent-reviewer
статус: in_progress
# Зависимости
зависит_от: [task_id_1, task_id_2]
блокирует: [task_id_3]
# Мета
приоритет: low | medium | high | critical
теги: ["api", "auth"]
создано: timestamp
обновлено: timestamp
Зависимости задач
Task A ──depends_on──→ Task B
│
└─ Task A НЕ может быть взята пока Task B не completed
Пример:
"Написать тесты" зависит от "Написать код"
"Деплой" зависит от "Тесты пройдены"
Правила:
- Задача со статусом
blockedне может быть взята агентом - Когда зависимость завершена → автоматически разблокировать
- Циклические зависимости запрещены (валидация при создании)
- В UI: визуальная связь между задачами (стрелки)
Приложенные файлы
- К задаче можно прикрепить файлы (код, изображения, документы)
- Агент может добавлять файлы к задаче (результаты работы)
- Файлы хранятся на диске, метаданные в БД
- Превью для изображений и кода в UI
Чаты
Три уровня
1. Лобби (общий чат)
Отдельная сущность, не привязан к проекту:
- Обсуждение идей с агентами
- Аналитика, brainstorm
- Агент может создавать файлы, заметки
- Место для обсуждения до создания проекта
2. Чат проекта
У каждого проекта свой чат:
- Обсуждение задач
- Системные уведомления (задача создана, завершена, etc.)
- Агенты видят только чаты своих проектов
3. Комментарии задачи
Внутри каждой задачи:
- Обсуждение деталей
- Код ревью
- Результаты подзадач
Агенты и адаптеры
Адаптер (провайдер)
Адаптер — это подключение к конкретной нейросети. Один адаптер может использоваться несколькими агентами.
Адаптер:
id: uuid
название: "Claude Opus"
провайдер: anthropic | openai | google | openclaw | cli
# Конфиг — JSON поле, разное для каждого провайдера
config:
# Anthropic
api_key: "sk-ant-..."
model: "claude-opus-4-5"
max_tokens: 8192
# Или OpenAI
api_key: "sk-..."
model: "gpt-4"
organization: "org-..."
# Или OpenClaw
gateway_url: "http://localhost:18789"
gateway_token: "..."
agent_id: "main"
# Или CLI
command: "claude"
working_dir: "/workspace"
# Возможности адаптера (что умеет эта нейросеть)
capabilities: ["coding", "analytics", "review", "design", "docs", "testing"]
Важно: Capabilities привязаны к адаптеру, не к агенту. Потому что возможности определяются нейросетью.
Агент
Агент — это "личность" с ролью, которая использует адаптер.
Агент:
id: uuid
имя: "Кодер"
slug: "coder"
# Привязка к адаптеру
адаптер_id: uuid
# Роль
системный_промпт: "Ты — backend разработчик..."
# Подписка
подписка:
режим: mentions # all | mentions | assigned
проекты: ["*"] # или конкретные
# Ограничения
макс_параллельных: 2
таймаут: 600 # секунд
Лейблы
Произвольные метки, создаются в трекере (как в Jira):
CREATE TABLE labels (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT UNIQUE NOT NULL, -- "coding", "design", "urgent"
color TEXT, -- "#ff0000"
created_at TIMESTAMPTZ DEFAULT NOW()
);
Примеры: coding, design, analytics, testing, docs, backend, frontend, urgent, bug
Связка: лейблы задач ↔ capabilities адаптеров
Задача с лейблом "coding" → только агенты с адаптером, у которого capability "coding"
Задача с лейблом "design" → только агенты с адаптером, у которого capability "design"
Агент-дизайнер НЕ возьмёт задачу с лейблом coding — у его адаптера нет такой capability.
Типы провайдеров
| Провайдер | Описание | Конфиг |
|---|---|---|
anthropic |
Claude API | api_key, model, max_tokens |
openai |
GPT, Codex | api_key, model, organization |
google |
Gemini | api_key, model |
openclaw |
OpenClaw Gateway | gateway_url, gateway_token, agent_id |
cli |
Claude Code CLI | command, working_dir |
Подписка на события
| Режим | Агент получает |
|---|---|
all |
Все сообщения в подписанных проектах |
mentions |
Только когда @упомянут |
assigned |
Назначенные задачи + mentions |
WebSocket протокол
Трекер → Клиент
task.created — задача создана
task.updated — задача обновлена
task.ready — задача готова к выполнению (перенесена из Backlog)
task.assigned — задача назначена агенту
task.blocked — задача заблокирована зависимостью
task.unblocked — зависимость выполнена, задача разблокирована
chat.message — новое сообщение в чате
agent.status — статус агента изменился
file.attached — файл прикреплён к задаче
Клиент → Трекер
task.take — агент берёт задачу
task.complete — агент завершил задачу
task.comment — комментарий к задаче
task.attach — прикрепить файл
chat.send — отправить сообщение в чат
agent.register — регистрация агента
agent.heartbeat — пульс
Ревью и PR
Не каждая задача = PR
PR нужен когда задача связана с кодом. Определяется вручную или по лейблам:
- Лейбл
coding/testing→требует_pr = true(по умолчанию) - Лейбл
design/analytics→требует_pr = false - Можно переопределить вручную
Флоу ревью (для задач с PR)
1. Агент работает → коммитит в feature branch
2. Создаёт PR в Gitea
3. Сдвигает задачу в Review
4. Трекер назначает ревьюера (другой агент, НЕ автор)
5. Ревьюер смотрит PR, пишет комментарии В ЗАДАЧЕ
6. Ок → Approve → Done, PR мержится
7. Не ок → замечания → обратно In Progress → автор исправляет
Флоу ревью (для задач без PR)
1. Агент работает → прикрепляет результат (файл/отчёт) к задаче
2. Сдвигает в Review
3. Ревьюер проверяет результат
4. Ок → Done
5. Не ок → замечания → обратно In Progress
Правила ревью
- Автор ≠ ревьюер (всегда)
- Максимум 3 итерации — потом эскалация к человеку
- Все комментарии в задаче (единый контекст)
- Чат проекта = лог событий (всё видно)
Итерации ревью
review_history:
- iteration: 1
reviewer: analyst
status: changes_requested
comments: ["Нужна валидация", "Нет тестов"]
- iteration: 2
reviewer: analyst
status: approved
Workflow: от идеи до деплоя
Фаза 1: Идея → Проект
- Человек открывает Лобби
- Обсуждает идею с агентом-аналитиком
- Создаёт проект
- Агент формирует BRIEF.md, REQUIREMENTS.md
Фаза 2: Декомпозиция → Задачи
- На основе требований создаются задачи (черновики в Backlog)
- Расставляются зависимости
- Прикрепляются файлы (макеты, схемы)
- Обсуждение в чате проекта
- Готовые задачи переносятся в TODO
Фаза 3: Выполнение
- Задача в TODO → агент берёт → In Progress
- Агент работает, коммитит, прикрепляет файлы
- Создаёт подзадачу "Ревью" → другому агенту
- Итерации до готовности
- Задача → Done
Фаза 4: Ревью и деплой
- Автоматические проверки (CI/CD)
- Ревью агентом или человеком
- Деплой
Инфраструктура (уже есть)
| Сервис | Описание |
|---|---|
| PostgreSQL | База данных |
| Thoth | STT/TTS (голос↔текст) |
| Authentik | SSO для веб-интерфейса |
| Nginx + certbot | Домены и SSL |
| Gitea | Git хостинг |
| OpenClaw (Марков) | Главный агент с инструментами |
| Redis | Очереди и pub/sub |
База данных (ключевые таблицы)
-- Адаптеры (подключения к нейросетям)
CREATE TABLE adapters (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
provider TEXT NOT NULL, -- anthropic, openai, google, openclaw, cli
config JSONB NOT NULL, -- всё специфичное для провайдера
capabilities TEXT[] NOT NULL, -- ["coding", "analytics", "review", ...]
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Агенты (личности с ролями)
CREATE TABLE agents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT NOT NULL,
slug TEXT UNIQUE NOT NULL,
adapter_id UUID REFERENCES adapters(id),
system_prompt TEXT,
subscription_mode TEXT DEFAULT 'mentions', -- all, mentions, assigned
max_concurrent INT DEFAULT 1,
timeout_seconds INT DEFAULT 600,
status TEXT DEFAULT 'idle',
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Задачи
CREATE TABLE tasks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
project_id UUID REFERENCES projects(id),
parent_id UUID REFERENCES tasks(id), -- подзадачи
title TEXT NOT NULL,
description TEXT,
status TEXT DEFAULT 'draft',
-- лейблы через связующую таблицу task_labels
requires_pr BOOLEAN DEFAULT FALSE,
assigned_agent_id UUID REFERENCES agents(id),
priority TEXT DEFAULT 'medium',
pr_url TEXT,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
-- Зависимости задач
CREATE TABLE task_dependencies (
task_id UUID REFERENCES tasks(id) ON DELETE CASCADE,
depends_on_id UUID REFERENCES tasks(id) ON DELETE CASCADE,
PRIMARY KEY (task_id, depends_on_id)
);
-- Лейблы
CREATE TABLE labels (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name TEXT UNIQUE NOT NULL,
color TEXT,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Связка задач и лейблов
CREATE TABLE task_labels (
task_id UUID REFERENCES tasks(id) ON DELETE CASCADE,
label_id UUID REFERENCES labels(id) ON DELETE CASCADE,
PRIMARY KEY (task_id, label_id)
);
-- Файлы задач
CREATE TABLE task_files (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
task_id UUID REFERENCES tasks(id) ON DELETE CASCADE,
filename TEXT NOT NULL,
mime_type TEXT,
file_path TEXT NOT NULL,
uploaded_by UUID, -- agent_id или null (человек)
created_at TIMESTAMPTZ DEFAULT NOW()
);
Управление агентами (Agent Manager)
Принцип
Агент = отдельный процесс. Не привязан к OpenClaw или конкретному серверу. Может быть запущен локально, на другом сервере, в Docker — где угодно. Подключается к Tracker по WebSocket.
Архитектура
┌─────────────────────────┐
│ Agent Process │
│ ┌───────────────────┐ │
│ │ Agent SDK │ │ ← общая Python-библиотека
│ │ ┌──────────────┐ │ │
│ │ │ Adapter │ │ │ ← OpenClaw / OpenAI / Ollama / CLI
│ │ └──────────────┘ │ │
│ └─────────┬─────────┘ │
└────────────┼────────────┘
│ WebSocket (локально или через интернет)
┌──────┴──────┐
│ Tracker │
│ AgentManager │
└─────────────┘
Agent SDK (Python-пакет)
Общая библиотека для всех агентов:
from team_board.agent import Agent
from team_board.adapters import OpenClawAdapter
adapter = OpenClawAdapter(
gateway_url="http://localhost:18789",
gateway_token="...",
)
agent = Agent(
name="Кодер",
tracker_url="ws://localhost:8100",
adapter=adapter,
system_prompt="Ты — backend разработчик...",
)
agent.run() # подключается к Tracker, слушает задачи
Что делает SDK:
- WebSocket клиент → подключение к Tracker, переподключение при разрыве
- Heartbeat → автоматический пинг каждые N секунд
- Обработка задач → получил задачу → передал адаптеру → вернул результат
- Файловые операции → загрузка/скачивание файлов задачи
Адаптеры (BaseAdapter)
class BaseAdapter(ABC):
@abstractmethod
async def send(self, messages: list[Message]) -> Response:
"""Отправить сообщения нейросети и получить ответ."""
...
@abstractmethod
async def capabilities(self) -> list[str]:
"""Возвращает capabilities адаптера."""
...
Реализации:
| Адаптер | Подключение | Особенности |
|---|---|---|
OpenClawAdapter |
Webhooks / sessions_spawn | Доступ к инструментам OpenClaw |
AnthropicAdapter |
Claude API напрямую | Чистый API, без инструментов |
OpenAIAdapter |
GPT / Codex API | |
OllamaAdapter |
Локальная модель | Бесплатно, офлайн |
CLIAdapter |
Claude Code CLI | Доступ к файловой системе |
AgentManager (в Tracker)
Tracker управляет жизненным циклом агентов:
Реестр агентов:
- id: uuid
name: "Кодер"
adapter: "Claude Opus"
status: online | offline | busy | dead
host: "localhost" # где запущен
pid: 12345 # PID процесса (если локальный)
last_heartbeat: timestamp
current_tasks: [task_id]
Функции AgentManager:
- Запуск — поднимает агента как отдельный процесс (локально: subprocess/systemd)
- Мониторинг — следит за heartbeat, помечает dead если пропал
- Перезапуск — dead агент → повторный запуск (макс 3 попытки)
- Назначение задач — матчит задачу → подходящего агента по capabilities + загрузке
- Остановка — graceful shutdown через WebSocket команду
Запуск агентов
Локально (MVP):
# Tracker запускает как subprocess
python -m team_board.agent --name coder --tracker ws://localhost:8100
Через systemd (production):
[Unit]
Description=Team Board Agent: Coder
[Service]
ExecStart=/opt/team-board/venv/bin/python -m team_board.agent --name coder
Restart=on-failure
RestartSec=5
Удалённо (будущее):
- SSH:
ssh remote-host 'python -m team_board.agent --tracker ws://tracker:8100' - Docker:
docker run team-board-agent --tracker ws://tracker:8100 - HTTP API на удалённом хосте
Heartbeat и мониторинг
Агент → Tracker: agent.heartbeat (каждые 30 сек)
{
status: "idle" | "busy",
current_tasks: [...],
uptime: 3600,
memory_mb: 150
}
Если heartbeat не пришёл 90 секунд → статус = dead → перезапуск
Таблица БД
-- Расширение таблицы agents
ALTER TABLE agents ADD COLUMN host TEXT DEFAULT 'localhost';
ALTER TABLE agents ADD COLUMN pid INT;
ALTER TABLE agents ADD COLUMN last_heartbeat TIMESTAMPTZ;
ALTER TABLE agents ADD COLUMN restart_count INT DEFAULT 0;
ALTER TABLE agents ADD COLUMN max_restarts INT DEFAULT 3;
Открытые вопросы
- Как интегрировать CLI-агентов (Claude Code, Cline)?
- Workspace для агентов — общий или изолированный?
- Прогресс работы агента в реалтайме?
- Биллинг/учёт использования API?
- Шаблоны агентов — как быстро создать нового?
Приоритеты реализации
- Tracker: базовый WebSocket сервер
- Tracker: проекты, задачи, подзадачи
- Tracker: зависимости задач
- Tracker: чаты (лобби + проект)
- Tracker: файлы в задачах
- Web Client: авторизация (Authentik)
- Web Client: канбан-доска
- Web Client: чат
- Шаблон агента
- Подключение первого агента (OpenClaw)
Документ для обсуждения и аналитики. Обновляется по мере развития идей.