Учебное пособие по Канбану

Пошаговое руководство по использованию четырех сценариев, для которого была разработана система Канбан в Hermes с открытой панелью управления в браузере. Если вы ещё не читали обзор Канбана, начните с него — здесь предполагается, что вы знаете, что такое задача (задача), запуск (запуск), исполнитель (исполнитель) и диспетчер (диспетчер).

Настройка

hermes kanban init           # опционально; первая команда `hermes kanban <anything>` инициализирует автоматически
hermes dashboard             # открывает http://127.0.0.1:9119 в браузере
# нажмите Kanban в левой навигации

Панель управления — самое удобное место для вас, чтобы наблюдать за системой. Агенты-исполнители, которые обеспечивают диспетчер, никогда не поддерживают панель или CLI — они управляют доской через специальный набор инструментов kanban_* (kanban_show, kanban_list, kanban_complete, kanban_block, kanban_heartbeat, kanban_comment, kanban_create, kanban_link, kanban_unblock). Все три поверхности — панель, CLI, инструменты исполнителя — маршрутизируются через одну и ту же SQLite БД для каждой доски (~/.hermes/kanban.db для доски по умолчанию, ~/.hermes/kanban/boards/<slug>/kanban.db для любой созданной позже доски), поэтому данная доска согласована, независимо от того, с какой стороны поступило изменение.

Это руководство использует доску «по умолчанию» (по умолчанию) на всем протяжении. Если вам нужно несколько изолированных очередей (по одному на проект/репозиторий/домен), см. Доски (мультипроектные) в обзоре — те же потоки CLI/панели/исполнителя применяются для каждой доски, и исполнители физически не могут видеть задачи на других досках.

На всем протяжении руководства блоки кода, помеченные как bash, — это команды, которые выполняют вы. Блоки кода, помеченные как # вызовы инструментов исполнителя, — это то, что модель порождённого исполнителя испускает как вызовы инструментов — показано здесь, чтобы вы могли видеть цикл от начала до конца, а не потому, что вы когда-либо будете выполнять их сами.

Доска с первого взглядаОбзор доски Kanban

Шесть колонок слева направо:

Верхняя панель имеет фильтры для поиска, арендатора и исполнителя, а также переключатель «Полосы по профилю» и кнопку «Подтолкнуть диспетчера», которая запускает один такт диспетчеризации прямо сейчас, не ожидая следующего интервала демона. Нажатие на любую карточку открывает ее боковую панель справа.

Плоский вид

Если полосы профиля шумят, отключите «Дорожки по профилю», и колонка In Progress свернётся в единый плоский список, упорядоченный по времени захвата:Доска с выключенными полосами по профилю

История 1 — Соло-разработчик, выпускающий функционал

Вы разрабатываете функционал. Классический поток: спроектировать схему, реализовать API, написать тесты. Три задачи с зависимостями родитель→потомок.

SCHEMA=$(hermes kanban create "Спроектировать схему аутентификации" \
    --assignee backend-dev --tenant auth-project --priority 2 \
    --body "Спроектировать схему пользователь/сессия/токен для модуля аутентификации." \
    --json | jq -r.id)

API=$(hermes kanban create "Реализовать конечные точки API аутентификации" \
    --assignee backend-dev --tenant auth-project --priority 2 \
    --parent $SCHEMA \
    --body "POST /register, POST /login, POST /refresh, POST /logout." \
    --json | jq -r.id)

hermes kanban create "Написать интеграционные тесты аутентификации" \
    --assignee qa-dev --tenant auth-project --priority 2 \
    --parent $API \
    --body "Покрыть happy path, неправильный пароль, истекший токен, одновременное обновление."

поскольку API имеет SCHEMA в качестве родителя, а tests имеет API в качестве родителя, только SCHEMA начинается в ready. Остальные двое находятся в делах, пока их родители не завершатся. Это механизм продвижения по зависимостям — ни один другой исполнитель не возьмётся за составление тестов, пока не будет API для тестирования.

В следующий такт диспетчера (60 секунд по умолчанию или сразу, если вы нажмете Подтолкнуть диспетчера) профиль backend-dev генерируется как исполнитель с HERMES_KANBAN_TASK=$SCHEMA в его ходе. Вот как выглядит цикл вызова инструментов исполнителя от агента:

# вызовы инструментов исполнителя — НЕ команды, которые вы выполняете
kanban_show()
# → возвращает заголовок, тело, worker_context, родителей, предыдущие попытки, комментарии

# (исполнитель читает worker_context, использует инструменты терминала/файла для проектирования схемы,
#  пишет миграции, запускает собственные проверки, коммитит — реальная работа происходит здесь)

kanban_heartbeat(note="схема набросана, пишу миграции сейчас")

kanban_complete(
    summary="users(id, email, pw_hash), sessions(id, user_id, jti, expires_at); "
            "refresh-токены хранятся как сессии с type='refresh'",
    metadata={
        "changed_files": ["migrations/001_users.sql", "migrations/002_sessions.sql"],
        "decisions": ["bcrypt для хеширования", "JWT для токенов сессий",
                      "7 дней refresh, 15 минут access"],
    },
)

kanban_show по умолчанию использует task_id из $HERMES_KANBAN_TASK, поэтому исполнителю не нужно знать свой собственный идентификатор. kanban_complete записывает сводку + метаданные в текущую строку task_runs, закрывает этот запуск и переводит задачу в done — всё за один атомарный переход через kanban_db.

Когда SCHEMA достигает done, механизм зависимостей автоматически переводит API в ready. API-исполнитель, когда подхватывает задачу, вызывает kanban_show() и увидит сводку и метаданные SCHEMA, прикреплённые к родительской передаче — так, что он знает решения по схеме, не перечитывая длинный документ дизайна.

Нажмите на завершённую задачу схемы на доске, и боковая панель покажет всё:Соло-разработчик — завершённая задача схемы, боковая панель

Раздел Run History (История запусков) внизу — ключевое дополнение. Одна попытка: результат завершен, исполнитель @backend-dev, длительность, временная метка и полная сводка передачи. Блоб метаданных (changed_files, decisions) также сохраняется при запуске и отображается для любого нижестоящего исполнителя, который читает этого родителя.

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

hermes kanban show $SCHEMA
hermes kanban runs $SCHEMA
# #  РЕЗУЛЬТАТ       ПРОФИЛЬ        ПРОШЛО  НАЧАЛО
# 1  completed      backend-dev        0s  2026-04-27 19:34
#     → users(id, email, pw_hash), sessions(id, user_id, jti, expires_at); refresh tokens...

История 2 — Ферма исполнителей

У вас три исполнителя (переводчик, транскрибатор, копирайтер) и куча разнообразных задач. Вы хотите, чтобы все три работали параллельно и продемонстрировали видимый прогресс. Это самый простой вариант использования Канбана, для которого и была сохранена исходная идея.

создать работу:

for lang in Испанский Французский Немецкий; do
    hermes kanban create "Перевести домашнюю страницу на $lang" \
        --assignee translator --tenant content-ops
done
for i in 1 2 3 4 5; do
    hermes kanban create "Расшифровать звонок клиента Q3 №$i" \
        --assignee transcriber --tenant content-ops
done
for sku in 1001 1002 1003 1004; do
    hermes kanban create "Сгенерировать описание товара: SKU-$sku" \
        --assignee copywriter --tenant content-ops
done

Запустите шлюз и отойдите — он содержит встроенный диспетчер, который подхватывает задачи всех трёх профилей-специалистов на том же kanban.db:

hermes gateway start

Теперь отфильтруйте доску по content-ops (или просто найдите «Расшифровать»), и вы получите это:Вид фермы, отфильтрованный по задачам транскрибирования

Две одна транскрибация завершена, результат две готовы и ждем следующего такого же диспетчера. Колонка Выполняется сгруппирована по профилю (по умолчанию "Дорожки по профилю"), так что вы видите активную задачу каждого исполнителя без сложного смешанного списка. Диспетчер переведет эту готовую задачу в состояние выполнения, как только текущая завершится. С тремя демонами, работающими в трёх пулах исполнителей, всякая очередь контент обрабатывается без дальнейшего соблюдения человека.

Все, что сказано в Истории 1 о структурированной передаче, остается в силе и здесь. Исполнитель-переводчик, завершая вызов, испускает kanban_complete(summary="переведено 4 страницы, соответствует существующему стилевому маркетинговому тону", Metadata={"duration_секунды": 720, "tokens_used": 2100}) — полезно для аналитики и для любой нижестоящей задачи, определяемой этой.

История 3 — Конвейер роли с повторной попыткой

Это случай, когда Канбан действительно окупается по сравнению с английском языке TODO. В личку напишу спецификацию. Инженер реализовал её. Рецензент отклоняет первый город. Инженер пробует снова с изменениями. Рецензент одобряет.

Вид панели, отфильтрованный по auth-project:Вид конвейера для многофункциональной задачи

Трехэтапная цепочка видна сразу: Спецификация: процедура сброса пароля (DONE, pm), Реализовать процедуру сброса пароля (DONE, backend-dev), Просмотр PR для сброса пароля (ГОТОВО, рецензент). у каждого из его родителя зелёным внизу и потомков как смотря.

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

# --- Исполнитель-PM порождается на $SPEC и пишет критерии приёмки ---
# вызовы инструментов исполнителя
kanban_show()
kanban_complete(
    summary="спецификация утверждена; POST /forgot-password отправляет email, "
            "GET /reset/:token отображает форму, POST /reset применяет новый пароль",
    metadata={"acceptance": [
        "истёкший токен возвращает 410",
        "повторное использование последних 3 паролей возвращает 400 с сообщением",
        "успешный сброс инвалидирует все активные сессии",
    ]},
)
# → $SPEC завершена; $IMPL автоматически переводится из todo в ready

# --- Исполнитель-инженер порождается на $IMPL (первая попытка) ---
# вызовы инструментов исполнителя
kanban_show()   # читает сводку $SPEC и метаданные приёмки в worker_context
# (инженер пишет код, запускает тесты, открывает PR)
# Приходит обратная связь от рецензента — инженер решает, что замечания обоснованны, и блокирует
kanban_block(
    reason="Рецензия: отсутствует проверка сложности пароля, ссылка сброса не "
           "одноразовая (может быть воспроизведена в течение 30 мин)",
)
# → $IMPL переходит в blocked; запуск 1 закрывается с результатом 'blocked'

Теперь вы (человек или отдельный рецензент профиля) читаете причину блокировки, решаете, что направление исправления ясности, и разблокируете с панели панели кнопку «Разблокировать» — или из CLI/слэш-команды:

hermes kanban unblock $IMPL
# или из чата: /kanban unblock $IMPL

Диспетчер переводит $IMPL обратно в ready, а на следующий такт снова криптовалюта-исполнитель backend-dev. Это второе порождение — это новый запуск той же задачи:

# --- Исполнитель-инженер порождается на $IMPL (вторая попытка) ---
# вызовы инструментов исполнителя
kanban_show()
# → worker_context теперь включает причину блокировки запуска 1, так что этот исполнитель
#   знает, какие две вещи исправить, не перечитывая всю спецификацию
# (инженер добавляет проверку zxcvbn, делает токены сброса одноразовыми, перезапускает тесты)
kanban_complete(
    summary="добавлена проверка сложности zxcvbn, токены сброса теперь одноразовые "
            "(хранятся + удаляются при успехе)",
    metadata={
        "changed_files": [
            "auth/reset.py",
            "auth/tests/test_reset.py",
            "migrations/003_single_use_reset_tokens.sql",
        ],
        "tests_run": 11,
        "review_iteration": 2,
    },
)

Нажмите на задачу реализации. Боковая панель показывает две попытки:Задача реализации с двумя запусками — сначала заблокировано, затем завершено

Каждый запуск — это строка в task_runs со своим результатом, сводкой и метаданными. Исторические достижения — не концептуальная дополнительная мысль, наложенная поверхностная задача с «последним состоянием», — это повторение обширного представления. Когда повторяющий исполнитель берет на себя ответственность, build_worker_context показывает ему сообщение о предупреждении, так что исполнитель второй попытки думает, почему первая попытка была заблокирована, и сохраняет именно эти важные замечания, вместо того, чтобы начинать с нуля.

Рецензент подхватывает эту задачу. Когда он открывает «Просмотр пароля для сброса PR», он видит:Вид боковой панели рецензента для конвейера

Ссылка на родителя — это завершённая поставка. Когда исполнитель рецензента генерирует запрос на Просмотр пароля сброса PR и вызывает kanban_show(), возвращаемый worker_context включает сводку + метаданные последнего завершения запуска родителя - так что рецензент читает "добавлена ​​проверка сложности zxcvbn, токены сброса теперь одноразовые" и имеет список измененных файлов вручную, прежде чем смотреть diff.

История 4 — Автоматический выключатель и восстановление после сбоя

Настоящие исполнители ломаются. Отсутствующие учётные данные, связанные с ООМ, временные сетевые ошибки. У диспетчера есть две линии защиты: автоматический выключатель, который автоматически блокирует вызов после N последовательных сбоев, чтобы доска не отключалась постоянно, и обнаружение сбоев, которое выполняет функцию, чей PID исполнителя исчез до истечения TTL.

Автоматический выключатель — постоянная ошибка

Задача развёртывания, которая не может породить своего исполнителя, потому что AWS_ACCESS_KEY_ID не установлен в профиле обслуживания:

hermes kanban create "Развернуть на staging (отсутствуют учётные данные)" \
    --assignee deploy-bot --tenant ops

Диспетчер предлагает предложить исполнителя. Порождение не удаётся («RuntimeError: AWS_ACCESS_KEY_ID не установлен»). Диспетчер освобождает захват, увеличивает счётчик сбоев и снова пробуждается на следующем такте. После трех последовательных сбоев (значение по умолчанию failure_limit) цепь срабатывает: задача перехода в blocked с результатом gave_up. Больше никаких повторных вмешательств, пока человек не разблокирует ее.

Нажмите на заблокированную задачу:Автоматический выключатель — 2 spawn_failed + 1 Give_up

Три запуска, все с одного, и одна и та же ошибка в поле «ошибка». Первые два — spawn_failed (повторяемые), третье – gave_up (терминальный). Журнал событий выше показывает полную последовательность: создано → заявлено → spawn_failed → заявлено → spawn_failed → заявлено → Give_up.

В терминале:

hermes kanban runs t_ef5d
# #   РЕЗУЛЬТАТ        ПРОФИЛЬ        ПРОШЛО  НАЧАЛО
# 1   spawn_failed    deploy-bot          0s  2026-04-27 19:34
#! AWS_ACCESS_KEY_ID not set in deploy-bot env
# 2   spawn_failed    deploy-bot          0s  2026-04-27 19:34
#! AWS_ACCESS_KEY_ID not set in deploy-bot env
# 3   gave_up         deploy-bot          0s  2026-04-27 19:34
#! AWS_ACCESS_KEY_ID not set in deploy-bot env

Если подключены Telegram/Discord/Slack, шлюз реализует событие gave_up, так что вы узнаете о себе, не заходя на доску.

Восстановление после сбоя — сбой исполнителя на середине работы

Иногда порождение удаётся, но процесс исполнителя умирает позже — segfault, OOM, systemctl stop. Диспетчер опрашивает kill(pid, 0) и обнаруживает мёртвый PID; захват освобождается, задача возвращается в состояние «готово», и на следующий такте она получает нового исполнителя.

Пример начальных данных — миграция, которая обеспечивает память:

# Исполнитель захватывает, начинает сканирование 2.4M строк, OOM убивает его на ~2.3M
# Диспетчер обнаруживает мёртвый PID, освобождает захват, увеличивает счётчик попыток
# Повторная попытка с разбитой на части стратегией завершается успешно

Боковая панель показывает всю историю двух вариантов:Сбой и восстановление — 1 сбой + 1 завершено

Запуск 1 — вылетел, с ошибкой OOM kill at row 2.3M (процесс 99999 пропал). Запуск 2 — «завершен», с «стратегией»: «разбит с помощью LIMIT + WHERE id > Last_id» в его метаданных. Повторный исполнитель увидел сбой запуска 1 в двенадцать и выбрал более безопасную погоду; метаданные делают очевидным для будущего наблюдателя (или автора посмертного разбора), что изменилось.

Структурированная передача — почему summary и metadata важны

В каждой истории вышестоящие исполнители вызывали kanban_complete(summary=..., Metadata=...) в конце. Это не украшение — это основной канал передачи данных между этапами рабочего процесса.

Когда возникает исполнительная задача B, возникает kanban_show(), полученный worker_context включает:

Это заменяет танец «покопаться в комментариях и вести работу», который предшествует плоским системам Канбан. Премьер-министр пишет критерии принятия в метаданных, а инженер-исполнитель просматривает их структурно в родительской передаче. Инженер записывает, какие тесты он запустил и сколько прошло, и исполнитель-рецензента имеет этот список под рукой, прежде чем открывать разницу.

Защита от такого массового закрытия существует, потому что данные определяются при запуске. hermes kanban Complete a b c --summary X (вы, из CLI) отклоняется — копирование одной и той же сводки для трех задач почти всегда неверно. Массовое закрытие без передачи флагов всё ещё работает для распространённого случая "я закончил согласовывать задачи урегулирования". Поверхностный инструмент вообще не обеспечивает массовый вариант; kanban_complete всегда работает с одним компонентом по той же причине.

Просмотр задачи, выполняемой на данный момент

Для полноты — вот боковая панель задачи, ещё выполняющаяся (реализация API из Истории 1, захвачена backend-dev, но ещё не завершена):Захваченная, выполняемая задача

Статус — Бег. Активный запуск отображается в разделе «История запусков» с результатом «active» и без «ended_at». Если этот исполнитель умрёт или истечёт таймаут, диспетчер закроет этот запуск с соответствующим следствием и откроет новый при следующем запросе — строка попытки никогда не исчезает.

дальнейшее шаги