Kanban — Многопрофильное взаимодействие агентов

Хотите пошаговое руководство? Прочитайте учебник по Kanban — четыре пользовательских кейса (одиночная разработка, управление флотом, конвейер ролей с повтором и автоматический выключатель) со скриншотами панели для каждого. Эта страница — справочник; учебник — повествование.

Hermes Kanban — это устойчивая доска задач, общая для всех ваших профилей Hermes, которая позволяет нескольким именованным агентам совместно работать без хрупких внутрипроцессных роев субагентов. Каждая задача — это строка в ~/.hermes/kanban.db; каждая передача — это строка, которую любой может прочитать и записать; каждый работник — это полноценный процесс ОС со своей собственной идентичностью.

Два интерфейса: модель общается через инструменты, вы — через CLI

У доски два входа, оба работают через одну и ту же ~/.hermes/kanban.db:

Оба интерфейса проходят через один и тот же слой kanban_db, поэтому чтение видит согласованное представление, а запись не может рассинхронизироваться. Остальная часть страницы показывает примеры CLI, потому что их легко копировать, но у каждой команды CLI есть эквивалент вызова инструмента, который использует модель.

Это та форма, которая покрывает рабочие нагрузки, с которыми delegate_task не справляется:

Полное обоснование дизайна, сравнительный анализ с Cline Kanban / Paperclip / NanoClaw / Google Gemini Enterprise и восемь канонических паттернов совместной работы см. в docs/hermes-kanban-v1-spec.pdf в репозитории.

Kanban vs. delegate_task

Они выглядят похоже, но это не один и тот же примитив.

delegate_task Kanban
Форма RPC-вызов (fork → join) Устойчивая очередь сообщений + конечный автомат
Родитель Блокируется до возврата дочернего процесса Отправил и забыл после create
Идентичность дочернего процесса Анонимный субагент Именованный профиль с постоянной памятью
Возобновляемость Нет — не удалось = не удалось Блокировать → разблокировать → перезапустить; сбой → восстановить
Человек в цикле Не поддерживается Комментарий / разблокировка в любой момент
Агентов на задачу Один вызов = один субагент N агентов за время жизни задачи (повтор, ревью, доработка)
Журнал аудита Теряется при сжатии контекста Постоянные строки в SQLite навсегда
Координация Иерархическая (вызывающий → вызываемый) Равноправная — любой профиль читает/пишет любую задачу

Различие в одном предложении: delegate_task — это вызов функции; Kanban — это очередь работ, где каждая передача — это строка, которую любой профиль (или человек) может видеть и редактировать.

Используйте delegate_task, когда родительскому агенту нужен короткий ответ с рассуждениями перед продолжением, без участия людей, результат возвращается в контекст родителя.

Используйте Kanban, когда работа пересекает границы агентов, должна переживать перезапуски, может потребовать ввода от человека, может быть подхвачена другой ролью или должна быть обнаружимой постфактум.

Они сосуществуют: работник kanban может вызывать delegate_task внутри своего выполнения.

Основные концепции

Доски (многопроектные)

Доски позволяют разделять несвязанные потоки работ — по одной на проект, репозиторий или домен — в изолированные очереди. Новая установка имеет ровно одну доску с названием default (БД в ~/.hermes/kanban.db для обратной совместимости). Пользователи, которым нужен только один поток работ, никогда не должны знать о досках; эта функция является опциональной.

Изоляция по доскам абсолютна:

Управление досками из CLI

# See what's on disk. Fresh installs show only "default".
hermes kanban boards list

# Create a new board.
hermes kanban boards create atm10-server \
    --name "ATM10 Server" \
    --description "Minecraft modded server ops" \
    --icon 🎮 \
    --switch                   # optional: make it the active board

# Operate on a specific board without switching.
hermes kanban --board atm10-server list
hermes kanban --board atm10-server create "Restart ATM server" --assignee ops

# Change which board is "current" for subsequent calls.
hermes kanban boards switch atm10-server
hermes kanban boards show             # who's active right now?

# Rename the display name (the slug is immutable — it's the directory name).
hermes kanban boards rename atm10-server "ATM10 (Prod)"

# Archive (default) — moves the board's dir to boards/_archived/<slug>-<ts>/.
# Recoverable by moving the dir back.
hermes kanban boards rm atm10-server

# Hard delete — `rm -rf` the board dir. No recovery.
hermes kanban boards rm atm10-server --delete

Порядок разрешения доски (наивысший приоритет первый):

  1. Явный --board <slug> в вызове CLI.

  2. Переменная окружения HERMES_KANBAN_BOARD (устанавливается диспетчером при порождении работника, поэтому работники не видят другие доски).

  3. ~/.hermes/kanban/current — slug, сохранённый командой hermes kanban boards switch.

  4. default.

Slug проверяются: строчные буквы, цифры, дефисы и подчёркивания, 1-64 символа, должны начинаться с буквы или цифры. Ввод в верхнем регистре автоматически приводится к нижнему. Всё остальное (слеши, пробелы, точки, ..) отклоняется на уровне CLI, чтобы трюки с path traversal не могли назвать доску.

Управление досками из панели управления

hermes dashboard → вкладка Kanban показывает переключатель досок вверху, как только появляется более одной доски (или любая доска имеет задачи). Пользователи с одной доской видят только маленькую кнопку + Новая доска; переключатель скрыт, пока он не понадобится.

Все API-эндпоинты панели управления принимают ?board=<slug> для определения области доски. Веб-сокет событий привязывается к доске при подключении; переключение в интерфейсе открывает новый WS для новой доски.

Быстрый старт

Команды ниже — это вы (человек) настраиваете доску и создаёте задачи. Как только задача назначена, диспетчер порождает назначенный профиль как работника, и с этого момента модель управляет задачей через вызовы инструментов kanban_*, а не команды CLI — см. Как работники взаимодействуют с доской.

# 1. Create the board (you)
hermes kanban init

# 2. Start the gateway (hosts the embedded dispatcher)
hermes gateway start

# 3. Create a task (you — or an orchestrator agent via kanban_create)
hermes kanban create "research AI funding landscape" --assignee researcher

# 4. Watch activity live (you)
hermes kanban watch

# 5. See the board (you)
hermes kanban list
hermes kanban stats

Когда диспетчер подхватывает t_abcd и порождает профиль researcher, первое, что делает модель этого работника — вызывает kanban_show(), чтобы прочитать свою задачу. Она не запускает hermes kanban show t_abcd.

Диспетчер, встроенный в gateway (по умолчанию)

Диспетчер работает внутри процесса gateway. Ничего устанавливать, никакого отдельного сервиса для управления — если gateway запущен, готовые задачи будут подхвачены на следующем такте (60 с по умолчанию).

# config.yaml
kanban:
  dispatch_in_gateway: true        # default
  dispatch_interval_seconds: 60    # default

Переопределите флаг конфигурации во время выполнения через HERMES_KANBAN_DISPATCH_IN_GATEWAY=0 для отладки. Применяется стандартное наблюдение gateway: запустите hermes gateway start напрямую или подключите gateway как systemd-юзер-юнит (см. документацию gateway). Без запущенного gateway задачи в статусе ready остаются на месте до его появления — hermes kanban create предупреждает об этом при создании.

Запуск hermes kanban daemon как отдельного процесса устарел; используйте gateway. Если вы действительно не можете запустить gateway (политика безголового хоста запрещает долгоживущие сервисы и т.д.), запасной выход --force сохраняет старый отдельный демон на один цикл релиза, но запуск как встроенного в gateway диспетчера, ТАК И отдельного демона против одной и той же kanban.db вызывает гонки захвата и не поддерживается.

Идемпотентное создание (для автоматизации / webhook-ов)

# First call creates the task. Any subsequent call with the same key
# returns the existing task id instead of duplicating.
hermes kanban create "nightly ops review" \
    --assignee ops \
    --idempotency-key "nightly-ops-$(date -u +%Y-%m-%d)" \
    --json

Массовые команды CLI

Все глаголы жизненного цикла принимают несколько идентификаторов, чтобы вы могли очистить пакет одной командой:

hermes kanban complete t_abc t_def t_hij --result "batch wrap"
hermes kanban archive  t_abc t_def t_hij
hermes kanban unblock  t_abc t_def
hermes kanban block    t_abc "need input" --ids t_def t_hij

Как работники взаимодействуют с доской

Работники не вызывают hermes kanban через оболочку. Когда диспетчер порождает работника, он устанавливает HERMES_KANBAN_TASK=t_abcd в окружении дочернего процесса, и эта переменная окружения активирует выделенный набор инструментов kanban в схеме модели. Тот же набор инструментов также доступен оркестраторным профилям, которые включают kanban в своей конфигурации наборов инструментов. Эти инструменты читают и изменяют доску напрямую через слой Python kanban_db, так же, как это делает CLI. Запущенный работник вызывает их как любые другие инструменты; он никогда не видит и не нуждается в CLI hermes kanban.

Инструмент Назначение Обязательные параметры
kanban_show Читает текущую задачу (заголовок, тело, предыдущие попытки, родительские передачи, комментарии, полный предварительно отформатированный worker_context). По умолчанию использует идентификатор задачи из окружения.
kanban_list Выводит сводки задач с фильтрами по assignee, status, tenant, видимости архивных и лимиту. Предназначен для оркестраторов, обнаруживающих работу на доске.
kanban_complete Завершает с summary + metadata структурированной передачей. как минимум одно из summary / result
kanban_block Эскалирует для ввода человека с указанием reason. reason
kanban_heartbeat Сигнализирует о жизнеспособности во время длительных операций. Чистый побочный эффект.
kanban_comment Добавляет постоянную заметку в ветку задачи. task_id, body
kanban_create (Оркестраторы) Разветвляет дочерние задачи с assignee, опциональными parents, skills и т.д. title, assignee
kanban_link (Оркестраторы) Добавляет ребро зависимости parent_id → child_id после факта. parent_id, child_id
kanban_unblock (Оркестраторы) Перемещает заблокированную задачу обратно в ready. task_id

Типичный оборот работника выглядит так:

# Model's tool calls, in order:
kanban_show()                                     # no args — uses HERMES_KANBAN_TASK
# (model reads the returned worker_context, does the work via terminal/file tools)
kanban_heartbeat(note="halfway through — 4 of 8 files transformed")
# (more work)
kanban_complete(
    summary="migrated limiter.py to token-bucket; added 14 tests, all pass",
    metadata={"changed_files": ["limiter.py", "tests/test_limiter.py"], "tests_run": 14},
)

Оркестраторный работник вместо этого разветвляется:

kanban_show()
kanban_create(
    title="research ICP funding 2024-2026",
    assignee="researcher-a",
    body="focus on seed + series A, North America, AI-adjacent",
)
#  returns {"task_id": "t_r1", ...}
kanban_create(title="research ICP funding — EU angle", assignee="researcher-b", body="…")
#  returns {"task_id": "t_r2", ...}
kanban_create(
    title="synthesize findings into launch brief",
    assignee="writer",
    parents=["t_r1", "t_r2"],                     # promotes to ready when both complete
    body="one-pager, 300 words, neutral tone",
)
kanban_complete(summary="decomposed into 2 research tasks + 1 writer; linked dependencies")

Инструменты «(Оркестраторы)» — kanban_list, kanban_create, kanban_link, kanban_unblock и kanban_comment для чужих задач — доступны через тот же набор инструментов; соглашение (принудительно применяемое навыком kanban-orchestrator) заключается в том, что профили работников не разветвляют и не маршрутизируют постороннюю работу, а профили оркестраторов не выполняют реализационную работу. Работники, порождённые диспетчером, всё ещё ограничены областью задачи для деструктивных операций жизненного цикла и не могут изменять несвязанные задачи.

Почему инструменты вместо вызова hermes kanban через оболочку

Три причины:

  1. Переносимость бэкенда. Работники, чей терминальный инструмент указывает на удалённый бэкенд (Docker / Modal / Singularity / SSH), запускали бы hermes kanban complete внутри контейнера, где hermes не установлен и ~/.hermes/kanban.db не смонтирована. Инструменты kanban работают в собственном Python-процессе агента и всегда достигают ~/.hermes/kanban.db независимо от терминального бэкенда.

  2. Нет хрупкости экранирования оболочки. Передача --metadata '{"files": [...]}' через shlex + argparse — это скрытая грабля. Структурированные аргументы инструмента обходят это полностью.

  3. Лучшие ошибки. Результаты инструментов — это структурированный JSON, о котором модель может рассуждать, а не строки stderr, которые ей нужно парсить.

Нулевой след в схеме для обычных сессий. Обычная сессия hermes chat имеет ноль инструментов kanban_* в своей схеме. check_fn на каждом инструменте возвращает True только когда установлен HERMES_KANBAN_TASK, что происходит только когда диспетчер породил этот процесс. Никакого раздувания инструментов для пользователей, которые никогда не используют kanban.

Навыки kanban-worker и kanban-orchestrator обучают модель, какой инструмент вызывать когда и в каком порядке.

kanban_complete(summary=..., metadata={...}) намеренно гибок: summary — это человекочитаемое закрытие, а metadata — это машиночитаемая передача, которую нижестоящие агенты, рецензенты или панели могут использовать повторно без извлечения из прозы.

Для инженерных и ревью-задач предпочтительна следующая опциональная форма metadata:

{
  "changed_files": ["path/to/file.py"],
  "verification": ["pytest tests/hermes_cli/test_kanban_db.py -q"],
  "dependencies": ["parent task id or external issue, if any"],
  "blocked_reason": null,
  "retry_notes": "what failed before, if this was a retry",
  "residual_risk": ["what was not tested or still needs human review"]
}

Эти ключи — соглашение, а не требование схемы. Полезное свойство в том, что каждый работник оставляет достаточно доказательств, чтобы следующий читатель мог быстро ответить на четыре вопроса:

  1. Что изменилось?

  2. Как это было проверено?

  3. Что может разблокировать или повторить это, если оно не удастся?

  4. Какой риск всё ещё намеренно оставлен открытым?

Храните секреты, сырые логи, токены, OAuth-материалы и несвязанные транскрипты вне metadata. Вместо этого храните указатели и сводки. Если у задачи нет файлов или тестов, скажите об этом явно в summary и используйте metadata для тех доказательств, которые существуют, таких как URL-адреса источников, идентификаторы задач или шаги ручного ревью.

Навык работника (worker skill)

Любой профиль, который должен иметь возможность работать с задачами kanban, должен загрузить навык kanban-worker. Он обучает работника полному жизненному циклу через вызовы инструментов, а не команды CLI:

  1. При запуске вызвать kanban_show() для чтения заголовка + тела + родительских передач + предыдущих попыток + полной ветки комментариев.

  2. cd $HERMES_KANBAN_WORKSPACE (через терминальный инструмент) и выполнять работу там.

  3. Вызывать kanban_heartbeat(note="...") каждые несколько минут во время длительных операций.

  4. Завершить с kanban_complete(summary="...", metadata={...}) или kanban_block(reason="..."), если застряли.

kanban-worker — это встроенный навык, синхронизируемый в каждый профиль во время установки и обновления — отдельного шага установки из Skills Hub нет. Убедитесь, что он присутствует в том профиле, который вы используете для работников kanban (researcher, writer, ops и т.д.):

hermes -p <your-worker-profile> skills list | grep kanban-worker

Если встроенная копия отсутствует, восстановите её для этого профиля:

hermes -p <your-worker-profile> skills reset kanban-worker --restore

Диспетчер также автоматически передаёт --skills kanban-worker при порождении каждого работника, поэтому работник всегда имеет библиотеку паттернов, даже если конфигурация навыков профиля по умолчанию не включает её.

Прикрепление дополнительных навыков к конкретной задаче

Иногда для одной задачи нужен специализированный контекст, который профиль исполнителя не носит по умолчанию — задача перевода, требующая навыка translation, задача ревью, требующая github-code-review, аудит безопасности, требующий security-pr-audit. Вместо редактирования профиля исполнителя каждый раз прикрепляйте навыки непосредственно к задаче.

От агента-оркестратора (обычный случай — один агент направляет работу другому), используйте массив skills инструмента kanban_create:

kanban_create(
    title="translate README to Japanese",
    assignee="linguist",
    skills=["translation"],
)

kanban_create(
    title="audit auth flow",
    assignee="reviewer",
    skills=["security-pr-audit", "github-code-review"],
)

От человека (CLI / слэш-команда), повторяйте --skill для каждого:

hermes kanban create "translate README to Japanese" \
    --assignee linguist \
    --skill translation

hermes kanban create "audit auth flow" \
    --assignee reviewer \
    --skill security-pr-audit \
    --skill github-code-review

Из панели управления, введите навыки через запятую в поле skills встроенной формы создания.

Эти навыки дополняют встроенный kanban-worker — диспетчер передаёт один флаг --skills <name> для каждого (и для встроенного), поэтому работник порождается со всеми загруженными. Имена навыков должны соответствовать навыкам, которые фактически установлены в профиле исполнителя (запустите hermes skills list, чтобы увидеть, что доступно); установка во время выполнения не производится.

Навык оркестратора (orchestrator skill)

Хорошо ведущий себя оркестратор не выполняет работу сам. Он декомпозирует цель пользователя на задачи, связывает их, назначает каждую специалисту и отходит в сторону. Навык kanban-orchestrator кодирует это как паттерны вызовов инструментов: правила против искушения, стандартный список специалистов (researcher, writer, analyst, backend-eng, reviewer, ops) и плейбук декомпозиции, основанный на kanban_create / kanban_link / kanban_comment.

Канонический оборот оркестратора (два параллельных исследователя передают писателю):

# Goal from user: "draft a launch post on the ICP funding landscape"
kanban_create(title="research ICP funding, NA angle",  assignee="researcher-a", body="…")  #  t_r1
kanban_create(title="research ICP funding, EU angle",  assignee="researcher-b", body="…")  #  t_r2
kanban_create(
    title="synthesize ICP funding research into launch post draft",
    assignee="writer",
    parents=["t_r1", "t_r2"],        # promoted to 'ready' when both researchers complete
    body="one-pager, neutral tone, cite sources inline",
)                                     #  t_w1
# Optional: add cross-cutting deps discovered later without re-creating tasks
kanban_link(parent_id="t_r1", child_id="t_followup")
kanban_complete(
    summary="decomposed into 2 parallel research tasks → 1 synthesis task; writer starts when both researchers finish",
)

kanban-orchestrator — это встроенный навык. Он синхронизируется в каждый профиль во время установки и обновления, поэтому отдельного шага установки из Skills Hub нет. Убедитесь, что он присутствует в вашем профиле оркестратора:

hermes -p orchestrator skills list | grep kanban-orchestrator

Если встроенная копия отсутствует, восстановите её для этого профиля:

hermes -p orchestrator skills reset kanban-orchestrator --restore

Для лучших результатов сочетайте его с профилем, чьи наборы инструментов ограничены операциями с доской (kanban, gateway, memory), чтобы оркестратор буквально не мог выполнять задачи реализации, даже если попытается.

Панель управления (GUI)

CLI и слэш-команда /kanban достаточны для безголового управления доской, но визуальная доска часто является правильным интерфейсом для людей в цикле: триаж, кросс-профильный надзор, чтение веток комментариев и перетаскивание карточек между колонками. Hermes поставляет это как встроенный плагин панели управления в plugins/kanban/ — не основная функция, не отдельный сервис — следуя модели, описанной в Расширение панели управления.

Откройте его с помощью:

hermes kanban init      # one-time: create kanban.db if not already present
hermes dashboard        # "Kanban" tab appears in the nav, after "Skills"

Что даёт плагин

Визуально цель — знакомый макет Linear / Fusion: тёмная тема, заголовки колонок со счётчиками, цветные точки статуса, чипы-пилюли для приоритета и арендатора. Плагин читает только CSS-переменные темы (--color-*, --radius, --font-mono, ...), поэтому он автоматически перекрашивается под активную тему панели.

Архитектура

GUI — это строго слой чтения-через-БД + записи-через-kanban_db без собственной доменной логики:

┌────────────────────────┐      WebSocket (tails task_events)
│   React SPA (plugin)   │ ◀──────────────────────────────────┐
│   HTML5 drag-and-drop  │                                    │
└──────────┬─────────────┘                                    │
           │ REST over fetchJSON                              │
           ▼                                                  │
┌────────────────────────┐     writes call kanban_db.*        │
│  FastAPI router        │     directly — same code path      │
│  plugins/kanban/       │     the CLI /kanban verbs use      │
│  dashboard/plugin_api.py                                    │
└──────────┬─────────────┘                                    │
           │                                                  │
           ▼                                                  │
┌────────────────────────┐                                    │
│  ~/.hermes/kanban.db   │ ───── append task_events ──────────┘
│  (WAL, shared)         │
└────────────────────────┘

REST-поверхность

Все маршруты смонтированы под /api/plugins/kanban/ и защищены эфемерным токеном сессии панели:

Метод Путь Назначение
GET /board?tenant=<name>&include_archived=… Полная доска, сгруппированная по столбцам статусов, плюс арендаторы + исполнители для выпадающих фильтров
GET /tasks/:id Задача + комментарии + события + связи
POST /tasks Создать (обёртка над kanban_db.create_task, принимает triage: bool и parents: [id, …])
PATCH /tasks/:id Статус / исполнитель / приоритет / заголовок / тело / результат
POST /tasks/bulk Применить один и тот же патч (статус / архив / исполнитель / приоритет) ко всем id в ids. Ошибки по отдельным id сообщаются без прерывания остальных
POST /tasks/:id/comments Добавить комментарий
POST /tasks/:id/specify Запустить спецификатор триажа — вспомогательная LLM дополняет тело задачи и переводит её из triage в todo. Возвращает {ok, task_id, reason, new_title}; ok=false с человекочитаемой причиной для «не в триаже» / нет aux-клиента / ошибка LLM — это 200, а не 4xx
POST /links Добавить зависимость (parent_idchild_id)
DELETE /links?parent_id=…&child_id=… Удалить зависимость
POST /dispatch?max=…&dry_run=… Толкнуть диспетчера — пропустить ожидание в 60 с
GET /config Читать настройки dashboard.kanban из config.yamldefault_tenant, lane_by_profile, include_archived_by_default, render_markdown
WS /events?since=<event_id> Потоковая передача строк task_events в реальном времени

Каждый обработчик — это тонкая обёртка — плагин состоит из ~700 строк Python (маршрутизатор + хвост WebSocket + массовый обработчик + читатель конфига) и не добавляет новой бизнес-логики. Крошечный помощник _conn() автоматически инициализирует kanban.db при каждом чтении и записи, поэтому свежая установка работает, открыл ли пользователь сначала панель, обратился ли к REST API напрямую или запустил hermes kanban init.

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

Любой из этих ключей в dashboard.kanban в ~/.hermes/config.yaml изменяет значения по умолчанию вкладки — плагин читает их при загрузке через GET /config:

dashboard:
  kanban:
    default_tenant: acme              # preselects the tenant filter
    lane_by_profile: true             # default for the "lanes by profile" toggle
    include_archived_by_default: false
    render_markdown: true             # set false for plain <pre> rendering

Каждый ключ опционален и возвращается к показанному значению по умолчанию.

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

Промежуточное ПО HTTP-аутентификации панели явно пропускает /api/plugins/ — маршруты плагинов не аутентифицированы по замыслу, потому что панель по умолчанию привязывается к localhost. Это означает, что REST-поверхность kanban доступна любому процессу на хосте.

WebSocket делает один дополнительный шаг: он требует эфемерный токен сессии панели в качестве параметра запроса ?token=… (браузеры не могут установить Authorization на запросе обновления), что соответствует паттерну, используемому мостом PTY в браузере.

Если вы запускаете hermes dashboard --host 0.0.0.0, каждый маршрут плагина — включая kanban — становится доступным из сети. Не делайте этого на общем хосте. Доска содержит тела задач, комментарии и пути к рабочим пространствам; атакующий, получивший доступ к этим маршрутам, получает доступ на чтение ко всей вашей поверхности совместной работы, а также может создавать / переназначать / архивировать задачи.

Задачи в ~/.hermes/kanban.db намеренно не зависят от профиля (в этом и заключается примитив координации). Если вы откроете панель с hermes -p <profile> dashboard, доска всё равно покажет задачи, созданные любым другим профилем на хосте. Один и тот же пользователь владеет всеми профилями, но об этом стоит знать, если сосуществуют несколько персон.

Обновления в реальном времени

task_events — это таблица SQLite только для добавления с монотонным id. Эндпоинт WebSocket хранит последний виденный идентификатор события каждого клиента и отправляет новые строки по мере их поступления. Когда приходит всплеск событий, фронтенд перезагружает (очень дешёвый) эндпоинт доски — проще и корректнее, чем пытаться обновлять локальное состояние из каждого типа события. Режим WAL означает, что цикл чтения никогда не блокирует транзакции BEGIN IMMEDIATE диспетчера.

Расширение

Плагин использует стандартный контракт плагинов панели Hermes — см. Расширение панели управления для полного описания манифеста, слотов оболочки, слотов в рамках страницы и SDK плагинов. Дополнительные колонки, пользовательское оформление карточек, макеты с фильтрацией по арендатору или полные замены tab.override — всё это выразимо без форка этого плагина.

Чтобы отключить без удаления: добавьте dashboard.plugins.kanban.enabled: false в config.yaml (или удалите plugins/kanban/dashboard/manifest.json).

Граница области

GUI намеренно тонкий. Всё, что делает плагин, доступно из CLI; плагин просто делает это удобным для людей. Автоматическое назначение, бюджеты, шлюзы управления и представления организационной структуры остаются в пользовательском пространстве — профиль маршрутизатора, другой плагин или повторное использование tools/approval.py — именно так, как перечислено в разделе «вне области применения» спецификации дизайна.

Справочник команд CLI

Это интерфейс, которым вы (или скрипты, cron, панель управления) управляете доской. Работники, работающие внутри диспетчера, используют инструментальный интерфейс kanban_* для тех же операций — и CLI здесь, и инструменты там проходят через kanban_db, поэтому два интерфейса согласованы по построению.

hermes kanban init                                     # create kanban.db + print daemon hint
hermes kanban create "<title>" [--body ...] [--assignee <profile>]
                                [--parent <id>]... [--tenant <name>]
                                [--workspace scratch|worktree|dir:<path>]
                                [--priority N] [--triage] [--idempotency-key KEY]
                                [--max-runtime 30m|2h|1d|<seconds>]
                                [--skill <name>]...
                                [--json]
hermes kanban list [--mine] [--assignee P] [--status S] [--tenant T] [--archived] [--json]
hermes kanban show <id> [--json]
hermes kanban assign <id> <profile>                    # or 'none' to unassign
hermes kanban link <parent_id> <child_id>
hermes kanban unlink <parent_id> <child_id>
hermes kanban claim <id> [--ttl SECONDS]
hermes kanban comment <id> "<text>" [--author NAME]

# Bulk verbs — accept multiple ids:
hermes kanban complete <id>... [--result "..."]
hermes kanban block <id> "<reason>" [--ids <id>...]
hermes kanban unblock <id>...
hermes kanban archive <id>...

hermes kanban tail <id>                                # follow a single task's event stream
hermes kanban watch [--assignee P] [--tenant T]        # live stream ALL events to the terminal
        [--kinds completed,blocked,] [--interval SECS]
hermes kanban heartbeat <id> [--note "..."]            # worker liveness signal for long ops
hermes kanban runs <id> [--json]                       # attempt history (one row per run)
hermes kanban assignees [--json]                       # profiles on disk + per-assignee task counts
hermes kanban dispatch [--dry-run] [--max N]           # one-shot pass
        [--failure-limit N] [--json]
hermes kanban daemon --force                           # DEPRECATED — standalone dispatcher (use `hermes gateway start` instead)
        [--failure-limit N] [--pidfile PATH] [-v]
hermes kanban stats [--json]                           # per-status + per-assignee counts
hermes kanban log <id> [--tail BYTES]                  # worker log from ~/.hermes/kanban/logs/
hermes kanban notify-subscribe <id>                    # gateway bridge hook (used by /kanban in the gateway)
        --platform <name> --chat-id <id> [--thread-id <id>] [--user-id <id>]
hermes kanban notify-list [<id>] [--json]
hermes kanban notify-unsubscribe <id>
        --platform <name> --chat-id <id> [--thread-id <id>]
hermes kanban context <id>                             # what a worker sees
hermes kanban specify [<id> | --all] [--tenant T]      # flesh out a triage-column idea
        [--author NAME] [--json]                       #   into a full spec and promote to todo
hermes kanban gc [--event-retention-days N]            # workspaces + old events + old logs
        [--log-retention-days N]

Все команды также доступны как слэш-команда в интерактивном CLI и в шлюзе обмена сообщениями (см. слэш-команда /kanban ниже).

Слэш-команда /kanban {#kanban-slash-command}

Каждый глагол hermes kanban <action> также доступен как /kanban <action> — из интерактивной сессии hermes chat и с любой платформы шлюза (Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Mattermost, email, SMS). Оба интерфейса вызывают одну и ту же точку входа hermes_cli.kanban.run_slash(), которая использует то же дерево argparse hermes kanban, поэтому поверхность аргументов, флаги и формат вывода идентичны в CLI, /kanban и hermes kanban. Вам не нужно выходить из чата, чтобы управлять доской.

/kanban list
/kanban show t_abcd
/kanban create "write launch post" --assignee writer --parent t_research
/kanban comment t_abcd "looks good, ship it"
/kanban unblock t_abcd
/kanban dispatch --max 3
/kanban specify t_abcd                  # flesh out a triage one-liner into a real spec
/kanban specify --all --tenant engineering  # sweep every triage task in one tenant

Заключайте многословные аргументы в кавычки так же, как в оболочке — run_slash разбирает остаток строки с помощью shlex.split, поэтому "..." и '...' оба работают.

Использование во время выполнения: /kanban обходит защиту запущенного агента

Шлюз обычно ставит в очередь слэш-команды и сообщения пользователей, пока агент ещё думает — это предотвращает случайное начало второго хода, пока первый в полёте. /kanban явно освобождён от этой защиты. Доска находится в ~/.hermes/kanban.db, а не в состоянии запущенного агента, поэтому чтение (list, show, context, tail, watch, stats, runs) и запись (comment, unblock, block, assign, archive, create, link, …) проходят немедленно, даже в середине хода.

В этом и заключается смысл разделения:

Автоподписка при /kanban create (только шлюз)

Когда вы создаёте задачу из шлюза с помощью /kanban create "…", исходный чат (платформа + id чата + id ветки) автоматически подписывается на терминальные события этой задачи (completed, blocked, gave_up, crashed, timed_out). Вы получите одно сообщение на каждое терминальное событие — включая первую строку сводки результата работника при completed — без необходимости опрашивать или запоминать идентификатор задачи.

you> /kanban create "transcribe today's podcast" --assignee transcriber
bot> Created t_9fc1a3  (ready, assignee=transcriber)
     (subscribed  you'll be notified when t_9fc1a3 completes or blocks)

 ~8 minutes later 

bot>  t_9fc1a3 completed by transcriber
     transcribed 42 minutes, saved to podcast/2026-05-04.md

Подписки автоматически удаляются, когда задача достигает done или archived. Если вы создаёте задачу скриптом с --json (машинный вывод), автоподписка пропускается — предполагается, что скриптовые вызывающие хотят управлять подписками явно через /kanban notify-subscribe.

Усечение вывода в мессенджерах

Платформы шлюзов имеют практические ограничения длины сообщений. Если /kanban list, /kanban show или /kanban tail производят более ~3800 символов вывода, ответ усекается с нижним колонтитулом … (усечено; используйте `hermes kanban …` в вашем терминале для полного вывода). Интерфейс CLI не имеет такого ограничения.

Автодополнение

В интерактивном CLI при вводе /kanban и нажатии Tab циклически перебирается встроенный список подкоманд (list, ls, show, create, assign, link, unlink, claim, comment, complete, block, unblock, archive, tail, dispatch, context, init, gc). Остальные глаголы, перечисленные в справочнике CLI выше (watch, stats, runs, log, assignees, heartbeat, notify-subscribe, notify-list, notify-unsubscribe, daemon), также работают — их просто ещё нет в списке подсказок автодополнения.

Паттерны совместной работы

Доска поддерживает следующие восемь паттернов без каких-либо новых примитивов:

Паттерн Форма Пример
P1 Разветвление N однотипных задач, одна роль «исследовать 5 аспектов параллельно»
P2 Конвейер цепочка ролей: разведчик → редактор → писатель сборка ежедневной сводки
P3 Голосование / кворум N однотипных + 1 агрегатор 3 исследователя → 1 рецензент выбирает
P4 Долгоживущий журнал тот же профиль + общая директория + cron хранилище Obsidian
P5 Человек в цикле работник блокируется → пользователь комментирует → разблокировка неоднозначные решения
P6 @упоминание встроенная маршрутизация из прозы @reviewer look at this
P7 Рабочее пространство в рамках ветки /kanban here в ветке ветки шлюза для каждого проекта
P8 Управление флотом один профиль, N объектов 50 соцсетей
P9 Спецификатор триажа сырая идея → triagehermes kanban specify расширяет тело → todo «превратить эту однострочку в задачу со спецификацией»

Примеры работы каждого см. в docs/hermes-kanban-v1-spec.pdf.

Мультиарендаторное использование

Когда один флот специалистов обслуживает несколько бизнесов, помечайте каждую задачу арендатором:

hermes kanban create "monthly report" \
    --assignee researcher \
    --tenant business-a \
    --workspace dir:~/tenants/business-a/data/

Работники получают $HERMES_TENANT и пространственно именуют свои записи в памяти по префиксу. Доска, диспетчер и определения профилей общие; только данные ограничены по области.

Уведомления шлюза

Когда вы запускаете /kanban create … из шлюза (Telegram, Discord, Slack и т.д.), исходный чат автоматически подписывается на новую задачу. Фоновый уведомитель шлюза опрашивает task_events каждые несколько секунд и доставляет одно сообщение на каждое терминальное событие (completed, blocked, gave_up, crashed, timed_out) в этот чат. Для завершённых задач также отправляется первая строка --result работника, чтобы вы видели результат без необходимости /kanban show.

Вы можете управлять подписками явно из CLI — полезно, когда скрипт / cron хочет уведомить чат, из которого он не был инициирован:

hermes kanban notify-subscribe t_abcd \
    --platform telegram --chat-id 12345678 --thread-id 7
hermes kanban notify-list
hermes kanban notify-unsubscribe t_abcd \
    --platform telegram --chat-id 12345678 --thread-id 7

Подписка автоматически удаляется, когда задача достигает done или archived; очистка не требуется.

Прогоны (Runs) — одна строка на попытку

Задача — это логическая единица работы; прогон — это одна попытка её выполнения. Когда диспетчер захватывает готовую задачу, он создаёт строку в task_runs и указывает tasks.current_run_id на неё. Когда эта попытка заканчивается — выполнено, заблокировано, аварийно завершено, истекло время, не удалось породить, восстановлено — строка прогона закрывается с outcome, и указатель задачи очищается. Задача, которая была предпринята трижды, имеет три строки task_runs.

Почему две таблицы вместо простого изменения задачи: вам нужна полная история попыток для реальных посмертных анализов («вторая попытка рецензента получила одобрение, третья объединила»), и вам нужно чистое место для хранения метаданных каждой попытки — какие файлы изменились, какие тесты запускались, какие выводы отметил рецензент. Это факты прогона, а не факты задачи.

Прогоны — это также место, где живёт структурированная передача. Когда работник завершает задачу (через kanban_complete(...)), он может передать:

Нижестоящие дочерние задачи читают summary + metadata самого последнего завершённого прогона каждого родителя. Повторяющие работники читают предыдущие попытки своей задачи (outcome, summary, ошибка), чтобы не повторять путь, который уже не удался.

# What a worker actually does — a tool call, from inside the agent loop:
kanban_complete(
    summary="implemented token bucket, keys on user_id with IP fallback, all tests pass",
    metadata={"changed_files": ["limiter.py", "tests/test_limiter.py"], "tests_run": 14},
    result="rate limiter shipped",
)

Та же передача доступна из CLI, когда вам (человеку) нужно закрыть задачу, которую работник не может — например, задача, которая была заброшена, или та, которую вы отметили выполненной вручную с панели управления:

hermes kanban complete t_abcd \
    --result "rate limiter shipped" \
    --summary "implemented token bucket, keys on user_id with IP fallback, all tests pass" \
    --metadata '{"changed_files": ["limiter.py", "tests/test_limiter.py"], "tests_run": 14}'

# Review the attempt history on a retried task:
hermes kanban runs t_abcd
#   #  OUTCOME       PROFILE           ELAPSED  STARTED
#   1  blocked       worker               12s  2026-04-27 14:02
#        → BLOCKED: need decision on rate-limit key
#   2  completed     worker                8m   2026-04-27 15:18
#        → implemented token bucket, keys on user_id with IP fallback

Прогоны отображаются на панели управления (раздел «История прогонов» в боковой панели, одна цветная строка на попытку) и в REST API (GET /api/plugins/kanban/tasks/:id возвращает массив runs[]). PATCH /api/plugins/kanban/tasks/:id с {status: "done", summary, metadata} передаёт оба в ядро, поэтому кнопка «отметить выполненным» на панели эквивалентна CLI. Строки task_events несут run_id, к которому они принадлежат, чтобы интерфейс мог группировать их по попыткам, и событие completed встраивает первую строку сводки в свою полезную нагрузку (ограничено 400 символами), чтобы уведомители шлюза могли отображать структурированные передачи без второго SQL-запроса.

Предостережение по массовому закрытию. hermes kanban complete a b c --summary X отклоняется — структурированная передача выполняется для каждого прогона, поэтому копирование одной и той же сводки для N задач почти всегда неправильно. Массовое закрытие без --summary / --metadata всё ещё работает для обычного случая «я закончил кучу административных задач».

Восстановленные прогоны при изменениях статуса. Если вы перетаскиваете выполняющуюся задачу с running на панели (обратно в ready или прямо в todo) или архивируете задачу, которая всё ещё выполнялась, текущий прогон закрывается с outcome='reclaimed', а не остаётся осиротевшим. Строка task_runs всегда находится в терминальном состоянии, когда tasks.current_run_id равно NULL, и наоборот — этот инвариант соблюдается в CLI, панели, диспетчере и уведомителе.

Синтетические прогоны для завершений без захвата. Завершение или блокировка задачи, которая никогда не была захвачена (например, человек закрывает задачу ready с панели с сводкой, или пользователь CLI запускает hermes kanban complete <ready-task> --summary X) иначе потеряла бы передачу. Вместо этого ядро вставляет строку прогона с нулевой длительностью (started_at == ended_at), несущую summary / metadata / reason, чтобы история попыток оставалась полной. run_id события completed / blocked указывает на эту строку.

Обновление боковой панели в реальном времени. Когда поток событий WebSocket панели сообщает о новых событиях для задачи, которую пользователь просматривает в данный момент, боковая панель перезагружается (через счётчик событий для каждой задачи, встроенный в список зависимостей её useEffect). Закрытие и повторное открытие больше не требуется, чтобы увидеть новую строку прогона или обновлённый результат.

Прямая совместимость

Два nullable столбца в tasks зарезервированы для маршрутизации рабочих процессов v2: workflow_template_id (к какому шаблону принадлежит эта задача) и current_step_key (какой шаг в этом шаблоне активен). Ядро v1 игнорирует их для маршрутизации, но позволяет клиентам их записывать, поэтому релиз v2 сможет добавить механизм маршрутизации без ещё одной миграции схемы.

Справочник событий

Каждый переход добавляет строку в task_events. Каждая строка несёт опциональный run_id, чтобы интерфейсы могли группировать события по попыткам. Виды группируются в три кластера для удобства фильтрации (hermes kanban watch --kinds completed,gave_up,timed_out):

Жизненный цикл (что изменилось в задаче как логической единице):

Вид Полезная нагрузка Когда
created {assignee, status, parents, tenant} Задача вставлена. run_id равен NULL.
promoted todo → ready, потому что все родители достигли done. run_id равен NULL.
claimed {lock, expires, run_id} Диспетчер атомарно захватил задачу ready для порождения.
completed {result_len, summary?} Работник записал --result / --summary, и задача перешла в done. summary — это первая строка передачи (ограничение 400 символов); полная версия находится в строке прогона. Если complete_task вызван для никогда не захваченной задачи с полями передачи, синтезируется прогон нулевой длительности, чтобы run_id всё равно указывал на что-то.
blocked {reason} Работник или человек переключил задачу в blocked. Синтезирует прогон нулевой длительности при вызове для никогда не захваченной задачи с --reason.
unblocked blocked → ready, либо вручную, либо через /unblock. run_id равен NULL.
archived Скрыто с доски по умолчанию. Если задача всё ещё выполнялась, несёт run_id прогона, который был восстановлен как побочный эффект.

Редактирования (изменения, инициированные человеком, которые не являются переходами):

Вид Полезная нагрузка Когда
assigned {assignee} Исполнитель изменён (включая снятие назначения).
edited {fields} Заголовок или тело обновлены.
reprioritized {priority} Приоритет изменён.
status {status} Перетаскивание на панели записало статус напрямую (напр. todo → ready). Несёт run_id прогона, который был восстановлен при перетаскивании с running; в противном случае run_id равен NULL.

Телеметрия работника (о процессе выполнения, не о логической задаче):

Вид Полезная нагрузка Когда
spawned {pid} Диспетчер успешно запустил процесс работника.
heartbeat {note?} Работник вызвал hermes kanban heartbeat $TASK для сигнала жизнеспособности во время длительных операций.
reclaimed {stale_lock} TTL захвата истёк без завершения; задача возвращается в ready.
crashed {pid, claimer} PID работника больше не жив, но TTL ещё не истёк.
timed_out {pid, elapsed_seconds, limit_seconds, sigkill} max_runtime_seconds превышен; диспетчер отправил SIGTERM (затем SIGKILL после 5 с льготного периода) и вернул в очередь.
spawn_failed {error, failures} Одна попытка порождения не удалась (отсутствует PATH, рабочее пространство не монтируется и т.д.). Счётчик увеличивается; задача возвращается в ready для повторной попытки.
gave_up {failures, error} Автоматический выключатель сработал после N последовательных spawn_failed. Задача автоматически блокируется с последней ошибкой. N по умолчанию = 5; переопределяется через --failure-limit.

hermes kanban tail <id> показывает их для одной задачи. hermes kanban watch транслирует их по всей доске.

Вне области применения

Kanban намеренно однопользовательский. ~/.hermes/kanban.db — это локальный SQLite-файл, и диспетчер порождает работников на той же машине. Запуск общей доски на двух хостах не поддерживается — нет примитива координации для «работник X на хосте A, работник Y на хосте B», и путь обнаружения сбоев предполагает, что PID-ы локальны для хоста. Если вам нужно несколько хостов, запустите независимую доску на каждом хосте и используйте delegate_task / очередь сообщений для их соединения.

Спецификация дизайна

Полный дизайн — архитектура, корректность конкурентности, сравнение с другими системами, план реализации, риски, открытые вопросы — находится в docs/hermes-kanban-v1-spec.pdf. Прочитайте его перед отправкой любого PR, изменяющего поведение.