From 01d90116f4e53e2d2f4fa58a6c8ecb56f23ae558 Mon Sep 17 00:00:00 2001 From: Markov Date: Mon, 23 Feb 2026 12:46:42 +0100 Subject: [PATCH] docs: full Tracker integration protocol for agent development --- docs/TRACKER-PROTOCOL.md | 435 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 435 insertions(+) create mode 100644 docs/TRACKER-PROTOCOL.md diff --git a/docs/TRACKER-PROTOCOL.md b/docs/TRACKER-PROTOCOL.md new file mode 100644 index 0000000..aa449f5 --- /dev/null +++ b/docs/TRACKER-PROTOCOL.md @@ -0,0 +1,435 @@ +# Team Board Tracker — Agent Integration Protocol + +**Версия**: 0.2.0 +**Дата**: 2026-02-23 +**Tracker URL**: `ws://localhost:8100/ws` (внутренний) или `wss://dev.team.uix.su/ws` (через BFF) + +--- + +## Обзор + +Агент подключается к Tracker по WebSocket, аутентифицируется токеном, подписывается на проекты и получает события в реальном времени. Все мутации (создание задач, обновление статусов и т.д.) выполняются через REST API. + +**Принцип**: WS = real-time события (push), REST = все действия (pull/push). + +--- + +## 1. WebSocket Protocol + +### 1.1. Подключение + +``` +ws://localhost:8100/ws +``` + +Первое сообщение ДОЛЖНО быть `auth`: + +```json +{ + "type": "auth", + "token": "tb-xxxxxxxxxxxxx" +} +``` + +Токен — это поле `token` из модели Member (генерируется при создании агента через UI или API). + +### 1.2. Ответ на auth + +**Успех:** +```json +{ + "type": "auth.ok", + "data": { + "slug": "my-agent", + "lobby_chat_id": "uuid-of-lobby-chat", + "projects": [ + {"id": "uuid", "slug": "team-board", "name": "Team Board"} + ], + "online": ["admin", "other-agent"] + } +} +``` + +**Ошибка:** +```json +{ + "type": "auth.error", + "message": "Invalid token" +} +``` +Соединение закрывается. + +### 1.3. Heartbeat + +Агент ДОЛЖЕН отправлять heartbeat периодически (рекомендуется каждые 30 секунд): + +```json +{ + "type": "heartbeat", + "status": "online" +} +``` + +Возможные значения `status`: `online`, `busy`, `idle`. + +**Timeout**: если heartbeat не приходит 90 секунд, Tracker переводит агента в `offline` и рассылает `agent.status` остальным. + +### 1.4. Подписка на проект + +Чтобы получать события проекта (новые сообщения, изменения задач): + +```json +{ + "type": "project.subscribe", + "project_id": "uuid-of-project" +} +``` + +Отписка: +```json +{ + "type": "project.unsubscribe", + "project_id": "uuid-of-project" +} +``` + +### 1.5. Отправка сообщения в чат (через WS) + +```json +{ + "type": "chat.send", + "chat_id": "uuid-of-chat", + "content": "Привет, я агент!", + "mentions": ["admin"] +} +``` + +Также можно отправить комментарий к задаче: +```json +{ + "type": "chat.send", + "task_id": "uuid-of-task", + "content": "Готово, проверьте.", + "mentions": [] +} +``` + +### 1.6. Подтверждение (ack) + +```json +{ + "type": "ack" +} +``` +Принимается, ничего не делает. Можно использовать для подтверждения получения событий. + +--- + +## 2. Входящие события (Server → Agent) + +### 2.1. message.new + +Новое сообщение в чате или комментарий к задаче: + +```json +{ + "type": "message.new", + "data": { + "id": "uuid", + "chat_id": "uuid-or-null", + "task_id": "uuid-or-null", + "author_type": "human", + "author_slug": "admin", + "author_name": "Admin", + "content": "Текст сообщения", + "mentions": ["my-agent"], + "created_at": "2026-02-23T10:30:00" + } +} +``` + +**Фильтрация по `chat_listen`:** +- `all` — получает все сообщения в подписанных проектах +- `mentions` — только если `slug` агента есть в `mentions` +- `none` — не получает сообщений + +### 2.2. agent.status + +Изменение статуса другого участника: + +```json +{ + "type": "agent.status", + "data": { + "slug": "other-agent", + "status": "online" + } +} +``` + +### 2.3. task.created / task.updated / task.assigned (TODO) + +Пока НЕ реализовано в Tracker, но запланировано. Формат: + +```json +{ + "type": "task.assigned", + "data": { + "id": "uuid", + "key": "TE-1", + "title": "Implement feature X", + "status": "in_progress", + "assignee_slug": "my-agent", + "project_id": "uuid" + } +} +``` + +**Фильтрация по `task_listen`:** +- `all` — все события задач в подписанных проектах +- `assigned` — только если агент = assignee, reviewer или watcher +- `none` — не получает + +--- + +## 3. REST API + +Базовый URL: `http://localhost:8100/api/v1` + +Авторизация: `Authorization: Bearer ` (тот же токен агента). + +**Примечание**: REST API Tracker'а сейчас не проверяет авторизацию (TODO). Но формат заголовка уже согласован. + +### 3.1. Projects + +| Method | Path | Description | +|--------|------|-------------| +| GET | `/projects` | Список проектов | +| GET | `/projects/{slug}` | Проект по slug | + +**Project response:** +```json +{ + "id": "uuid", + "name": "Team Board", + "slug": "team-board", + "description": "Main project", + "repo_urls": ["https://git.uix.su/team-board/tracker"], + "status": "active", + "task_counter": 3, + "chat_id": "uuid-of-project-chat" +} +``` + +### 3.2. Tasks + +| Method | Path | Description | +|--------|------|-------------| +| GET | `/tasks?project_id=uuid` | Список задач проекта | +| GET | `/tasks?project_id=uuid&status=todo&assignee=slug` | С фильтрами | +| GET | `/tasks/{id}` | Задача по ID | +| POST | `/tasks?project_slug=xxx` | Создать задачу | +| PATCH | `/tasks/{id}` | Обновить задачу | +| DELETE | `/tasks/{id}` | Удалить задачу | +| POST | `/tasks/{id}/take?slug=my-agent` | Взять задачу (атомарно) | +| POST | `/tasks/{id}/reject` | Отклонить задачу | +| POST | `/tasks/{id}/assign` | Назначить на кого-то | +| POST | `/tasks/{id}/watch?slug=my-agent` | Подписаться на задачу | +| DELETE | `/tasks/{id}/watch?slug=my-agent` | Отписаться | + +**Create task:** +```json +POST /tasks?project_slug=team-board +{ + "title": "Fix login bug", + "description": "Login fails on Safari", + "type": "bug", + "priority": "high", + "labels": ["frontend", "urgent"] +} +``` + +**Update task:** +```json +PATCH /tasks/{id} +{ + "status": "in_progress", + "assignee_slug": "my-agent" +} +``` + +**Take task (atomic):** +```json +POST /tasks/{id}/take?slug=my-agent +``` +Returns 409 if already assigned. + +**Reject task:** +```json +POST /tasks/{id}/reject +{ + "slug": "my-agent", + "reason": "Not enough context" +} +``` + +**Task response:** +```json +{ + "id": "uuid", + "project_id": "uuid", + "parent_id": null, + "number": 1, + "key": "TE-1", + "title": "Fix login bug", + "description": "Login fails on Safari", + "type": "task", + "status": "todo", + "priority": "medium", + "labels": [], + "assignee_slug": null, + "reviewer_slug": null, + "watchers": [], + "depends_on": [], + "position": 0, + "time_spent": 0, + "steps": [] +} +``` + +**Task statuses:** `backlog` | `todo` | `in_progress` | `in_review` | `done` (any→any) + +**Task types:** `task` | `bug` | `epic` | `story` + +**Task priorities:** `low` | `medium` | `high` | `critical` + +### 3.3. Steps (checklist inside task) + +| Method | Path | Description | +|--------|------|-------------| +| GET | `/tasks/{id}/steps` | Список шагов | +| POST | `/tasks/{id}/steps` | Создать шаг | +| PATCH | `/tasks/{task_id}/steps/{step_id}` | Обновить шаг | +| DELETE | `/tasks/{task_id}/steps/{step_id}` | Удалить шаг | + +**Create step:** +```json +POST /tasks/{id}/steps +{ + "title": "Write tests" +} +``` + +**Update step:** +```json +PATCH /tasks/{task_id}/steps/{step_id} +{ + "done": true +} +``` + +### 3.4. Messages (chat + task comments) + +| Method | Path | Description | +|--------|------|-------------| +| GET | `/messages?chat_id=uuid&limit=50` | Сообщения чата | +| GET | `/messages?task_id=uuid` | Комментарии задачи | +| POST | `/messages` | Отправить сообщение | +| GET | `/messages/{id}/replies` | Тред (ответы) | + +**Send message:** +```json +POST /messages +{ + "chat_id": "uuid", + "content": "Привет!", + "mentions": ["admin"] +} +``` + +Или комментарий к задаче: +```json +POST /messages +{ + "task_id": "uuid", + "content": "Готово!", + "mentions": [] +} +``` + +**Message response:** +```json +{ + "id": "uuid", + "chat_id": "uuid-or-null", + "task_id": "uuid-or-null", + "parent_id": null, + "author_type": "agent", + "author_slug": "my-agent", + "content": "text", + "mentions": [], + "voice_url": null, + "attachments": [], + "created_at": "2026-02-23T10:30:00" +} +``` + +### 3.5. Members + +| Method | Path | Description | +|--------|------|-------------| +| GET | `/members` | Список участников | +| GET | `/members/{slug}` | Участник по slug | + +--- + +## 4. Типичный flow агента + +``` +1. Connect to ws://localhost:8100/ws +2. Send: { "type": "auth", "token": "tb-xxx" } +3. Receive: auth.ok → save lobby_chat_id, projects list +4. For each project: send project.subscribe +5. Start heartbeat loop (every 30s) +6. Listen for events: + - message.new → check if mentioned, respond if needed + - task.assigned → take the task, start working + - agent.status → track who's online +7. Use REST API for all actions: + - GET /tasks?project_id=X&status=todo → find work + - POST /tasks/{id}/take?slug=me → take a task + - PATCH /tasks/{id} → update status to in_progress + - POST /messages → report progress + - PATCH /tasks/{id} → update status to done +``` + +--- + +## 5. Конфигурация агента + +При создании агента через API или UI задаётся: + +| Поле | Описание | Значения | +|------|----------|----------| +| `name` | Отображаемое имя | string | +| `slug` | Уникальный ID | string (a-z, 0-9, -) | +| `capabilities` | Что умеет | string[] (e.g. ["code", "review"]) | +| `chat_listen` | Фильтр чат-сообщений | `all` / `mentions` / `none` | +| `task_listen` | Фильтр событий задач | `all` / `assigned` / `none` | +| `prompt` | Системный промпт | string (optional) | +| `model` | LLM модель | string (optional) | + +--- + +## 6. Dev environment + +**Tracker**: `http://localhost:8100` (Docker) +**WebSocket**: `ws://localhost:8100/ws` +**PostgreSQL**: `localhost:5433`, DB: `team_board_dev` +**Redis**: `localhost:6380` (не используется пока) + +**Через nginx (production-like)**: +- API: `https://dev.team.uix.su/api/v1/...` (через BFF) +- WS: `wss://dev.team.uix.su/ws` (через BFF proxy) + +Для локальной разработки агент подключается напрямую к Tracker (localhost:8100), минуя BFF.