Руководство по Kanban
Пошаговое описание четырёх сценариев использования, для которых разработана система Kanban в Hermes, с открытой панелью управления в браузере. Если вы ещё не читали обзор Kanban, начните с него — здесь предполагается, что вы знаете, что такое task, run, assignee и dispatcher.
Настройка
hermes kanban init # optional; first `hermes kanban <anything>` auto-inits
hermes dashboard # opens http://127.0.0.1:9119 in your browser
# click Kanban in the left nav
Панель управления — это самый удобный способ для вас наблюдать за системой. Агенты-воркеры, которых порождает dispatcher, никогда не видят панель управления или 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 для любой доски, созданной позже), поэтому каждая доска остаётся консистентной независимо от того, с какой стороны поступило изменение.
В этом руководстве везде используется доска default. Если вы хотите несколько изолированных очередей (по одной на проект / репозиторий / домен), смотрите раздел Boards (multi-project) в обзоре — те же самые потоки CLI / панели управления / воркеров работают для каждой доски, и воркеры физически не могут видеть tasks на других досках.
На протяжении всего руководства блоки кода с пометкой bash — это команды, которые выполняете вы. Блоки кода с пометкой # worker tool calls — это то, что модель запущенного воркера выводит в виде вызовов инструментов — показано здесь, чтобы вы могли видеть цикл целиком, а не потому что вам нужно выполнять их самостоятельно.
Обзор доски

Шесть колонок, слева направо:
-
Triage — сырые идеи; specifier уточнит спецификацию, прежде чем кто-то начнёт над ними работать. Нажмите кнопку ✨ Specify на любой карточке в Triage (или выполните
hermes kanban specify <id>//kanban specify <id>из чата), чтобы вспомогательная LLM превратила однострочное описание в полную спецификацию (цель, подход, критерии приёмки) и переместила его вtodoодним действием. Настройте, какая модель это выполняет, в разделеauxiliary.triage_specifierвconfig.yaml. -
Todo — создано, но ожидает зависимостей или ещё не назначено.
-
Ready — назначено и ожидает, пока dispatcher возьмёт его в работу.
-
In progress — воркер активно выполняет задачу. При включённых «Lanes by profile» (по умолчанию) эта колонка группируется по исполнителю, чтобы вы могли с одного взгляда видеть, чем занят каждый воркер.
-
Blocked — воркер запросил участие человека, или сработал circuit breaker.
-
Done — выполнено.
В верхней панели находятся фильтры поиска, tenant и assignee, переключатель «Lanes by profile» и кнопка Nudge dispatcher, которая запускает один такт диспетчеризации прямо сейчас, не дожидаясь следующего интервала демона. Нажатие на любую карточку открывает её панель справа.
Плоский вид
Если полосы профилей создают шум, отключите «Lanes by profile», и колонка In Progress свернётся в единый плоский список, упорядоченный по времени взятия в работу:

Сценарий 1 — Разработчик в одиночку выпускает фичу
Вы разрабатываете фичу. Классический поток: спроектировать схему, реализовать API, написать тесты. Три задачи с зависимостями родитель→потомок.
SCHEMA=$(hermes kanban create "Design auth schema" \
--assignee backend-dev --tenant auth-project --priority 2 \
--body "Design the user/session/token schema for the auth module." \
--json | jq -r .id)
API=$(hermes kanban create "Implement auth API endpoints" \
--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 "Write auth integration tests" \
--assignee qa-dev --tenant auth-project --priority 2 \
--parent $API \
--body "Cover happy path, wrong password, expired token, concurrent refresh."
Поскольку у API есть SCHEMA в качестве родителя, а у тестов — API, только SCHEMA начинает в статусе ready. Остальные две находятся в todo, пока их родители не будут завершены. Это работает механизм продвижения по зависимостям — никакой другой воркер не начнёт писать тесты, пока не появится API для тестирования.
На следующем такте dispatcher (по умолчанию 60 секунд, или сразу же, если вы нажали Nudge dispatcher) профиль backend-dev порождает воркера с HERMES_KANBAN_TASK=$SCHEMA в его окружении. Вот как выглядит цикл вызовов инструментов воркера изнутри агента:
# worker tool calls — NOT commands you run
kanban_show()
# → returns title, body, worker_context, parents, prior attempts, comments
# (worker reads worker_context, uses terminal/file tools to design the schema,
# write migrations, run its own checks, commit — the real work happens here)
kanban_heartbeat(note="schema drafted, writing migrations now")
kanban_complete(
summary="users(id, email, pw_hash), sessions(id, user_id, jti, expires_at); "
"refresh tokens stored as sessions with type='refresh'",
metadata={
"changed_files": ["migrations/001_users.sql", "migrations/002_sessions.sql"],
"decisions": ["bcrypt for hashing", "JWT for session tokens",
"7-day refresh, 15-min access"],
},
)
kanban_show по умолчанию устанавливает task_id в $HERMES_KANBAN_TASK, поэтому воркеру не нужно знать свой собственный id. kanban_complete записывает summary + metadata в текущую строку task_runs, закрывает этот run и переводит task в статус done — всё одним атомарным переходом через kanban_db.
Когда SCHEMA переходит в done, механизм зависимостей автоматически продвигает API в ready. Воркер API, начиная работу, вызовет kanban_show() и увидит сводку и метаданные SCHEMA, прикреплённые к родительской передаче — так он узнает решения по схеме без повторного чтения длинного документа.
Нажмите на выполненный task схемы на доске — панель покажет всё:

Раздел Run History внизу — ключевое дополнение. Одна попытка: результат completed, воркер @backend-dev, длительность, временная метка и полная сводка передачи. Блоб метаданных (changed_files, decisions) также хранится в run и передаётся любому нижестоящему воркеру, который читает этого родителя.
Вы можете просмотреть те же данные из терминала в любое время — эти команды выполняете вы, заглядывая в доску, а не воркер:
hermes kanban show $SCHEMA
hermes kanban runs $SCHEMA
# # OUTCOME PROFILE ELAPSED STARTED
# 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 — Ферма задач
У вас есть три воркера (переводчик, транскрибатор, копирайтер) и куча независимых задач. Вы хотите, чтобы все три работали параллельно и показывали видимый прогресс. Это самый простой сценарий использования kanban, под который и была оптимизирована исходная разработка.
Создайте работу:
for lang in Spanish French German; do
hermes kanban create "Translate homepage to $lang" \
--assignee translator --tenant content-ops
done
for i in 1 2 3 4 5; do
hermes kanban create "Transcribe Q3 customer call #$i" \
--assignee transcriber --tenant content-ops
done
for sku in 1001 1002 1003 1004; do
hermes kanban create "Generate product description: SKU-$sku" \
--assignee copywriter --tenant content-ops
done
Запустите gateway и отойдите — он содержит встроенный dispatcher, который подхватывает задачи всех трёх специализированных профилей на одной и той же kanban.db:
hermes gateway start
Теперь отфильтруйте доску по content-ops (или просто найдите «Transcribe») и вы увидите следующее:

Две транскрибации выполнены, одна выполняется, две готовы и ждут следующего такта dispatcher. Колонка In Progress сгруппирована по профилям (режим «Lanes by profile» по умолчанию), так что вы видите активную задачу каждого воркера без сканирования смешанного списка. Dispatcher переведёт следующую готовую задачу в статус running, как только текущая будет завершена. Три демона, работающие параллельно над тремя пулами назначений, опустошат всю очередь контента без дальнейшего участия человека.
Всё, что сказано в Сценарии 1 о структурированной передаче, остаётся в силе. Воркер-переводчик, завершая звонок, вызывает kanban_complete(summary="translated 4 pages, style matched existing marketing voice", metadata={"duration_seconds": 720, "tokens_used": 2100}) — полезно для аналитики и для любой последующей задачи, зависящей от этой.
Сценарий 3 — Ролевой конвейер с повторными попытками
Вот где Kanban действительно окупается по сравнению с плоским списком TODO. PM пишет спецификацию. Инженер реализует её. Reviewer отклоняет первую попытку. Инженер пробует снова с изменениями. Reviewer утверждает.
Вид панели управления, отфильтрованный по auth-project:

Трёхэтапная цепочка видна сразу: Spec: password reset flow (DONE, pm), Implement password reset flow (DONE, backend-dev), Review password reset PR (READY, reviewer). У каждого зелёный родитель внизу и дочерние элементы как зависимости.
Самая интересная часть — это задача реализации, потому что она была заблокирована и повторена. Вот полная хореография трёх агентов, показанная как вызовы инструментов, которые делает модель каждого воркера:
# --- PM worker spawns on $SPEC and writes the acceptance criteria ---
# worker tool calls
kanban_show()
kanban_complete(
summary="spec approved; POST /forgot-password sends email, "
"GET /reset/:token renders form, POST /reset applies new password",
metadata={"acceptance": [
"expired token returns 410",
"reused last-3 password returns 400 with message",
"successful reset invalidates all active sessions",
]},
)
# → $SPEC is done; $IMPL auto-promotes from todo to ready
# --- Engineer worker spawns on $IMPL (first attempt) ---
# worker tool calls
kanban_show() # reads $SPEC's summary + acceptance metadata in worker_context
# (engineer writes code, runs tests, opens PR)
# Reviewer feedback arrives — engineer decides the concerns are valid and blocks
kanban_block(
reason="Review: password strength check missing, reset link isn't "
"single-use (can be replayed within 30min)",
)
# → $IMPL transitions to blocked; run 1 closes with outcome='blocked'
Теперь вы (человек или отдельный профиль reviewer) читаете причину блокировки, решаете, что направление исправления понятно, и разблокируете задачу кнопкой «Unblock» на панели управления — или через CLI / slash-команду:
hermes kanban unblock $IMPL
# or from a chat: /kanban unblock $IMPL
Dispatcher переводит $IMPL обратно в ready и на следующем такте повторно порождает воркера backend-dev. Этот второй запуск — это новый run на той же задаче:
# --- Engineer worker spawns on $IMPL (second attempt) ---
# worker tool calls
kanban_show()
# → worker_context now includes the run 1 block reason, so this worker knows
# which two things to fix instead of re-reading the whole spec
# (engineer adds zxcvbn check, makes reset tokens single-use, re-runs tests)
kanban_complete(
summary="added zxcvbn strength check, reset tokens are now single-use "
"(stored + deleted on success)",
metadata={
"changed_files": [
"auth/reset.py",
"auth/tests/test_reset.py",
"migrations/003_single_use_reset_tokens.sql",
],
"tests_run": 11,
"review_iteration": 2,
},
)
Нажмите на задачу реализации. Панель покажет две попытки:

-
Run 1 —
blockedот@backend-dev. Замечания ревьюера отображаются сразу под результатом: «password strength check missing, reset link isn't single-use (can be replayed within 30min)». -
Run 2 —
completedот@backend-dev. Новая сводка, новые метаданные.
Каждый run — это строка в task_runs со своим результатом, сводкой и метаданными. История повторных попыток — не концептуальное дополнение поверх «последнего состояния» задачи, а основное представление. Когда повторно запущенный воркер открывает задачу, build_worker_context показывает ему предыдущие попытки, так что воркер второй итерации видит, почему первая была заблокирована, и устраняет именно эти замечания, вместо того чтобы начинать с нуля.
Reviewer берёт задачу следующей. Когда он открывает «Review password reset PR», он видит:

Ссылка на родителя — это выполненная задача реализации. Когда воркер reviewer запускается на «Review password reset PR» и вызывает kanban_show(), возвращаемый worker_context включает сводку и метаданные последнего завершённого run родителя — так reviewer читает «added zxcvbn strength check, reset tokens are now single-use» и уже имеет список изменённых файлов, прежде чем смотреть diff.
Сценарий 4 — Circuit breaker и восстановление после сбоя
Настоящие воркеры терпят неудачи. Отсутствующие credentials, OOM-убийства, временные сетевые ошибки. У dispatcher две линии защиты: circuit breaker, который автоматически блокирует задачу после N последовательных сбоев, чтобы доска не прокручивалась бесконечно, и обнаружение сбоев, которое отзывает задачу, чей PID воркера исчез до истечения TTL.
Circuit breaker — сбой, выглядящий как постоянный
Задача развёртывания, которая не может породить воркера, потому что AWS_ACCESS_KEY_ID не задан в окружении профиля:
hermes kanban create "Deploy to staging (missing creds)" \
--assignee deploy-bot --tenant ops
Dispatcher пытается породить воркера. Сбой порождения (RuntimeError: AWS_ACCESS_KEY_ID not set). Dispatcher снимает закрепление, увеличивает счётчик сбоев и пробует снова на следующем такте. После трёх последовательных сбоев (failure_limit по умолчанию) цепь размыкается: задача переходит в blocked с результатом gave_up. Больше никаких повторных попыток, пока человек не разблокирует её.
Нажмите на заблокированную задачу:

Три run, все с одной и той же ошибкой в поле error. Первые два — spawn_failed (можно повторить), третий — gave_up (терминальный). Журнал событий выше показывает полную последовательность: created → claimed → spawn_failed → claimed → spawn_failed → claimed → gave_up.
В терминале:
hermes kanban runs t_ef5d
# # OUTCOME PROFILE ELAPSED STARTED
# 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, уведомление gateway срабатывает при событии gave_up, так что вы узнаёте о проблеме, не заходя на доску.
Восстановление после сбоя — воркер умирает во время работы
Иногда порождение удаётся, но процесс воркера умирает позже — segfault, OOM, systemctl stop. Dispatcher опрашивает kill(pid, 0) и обнаруживает мёртвый pid; закрепление снимается, задача возвращается в ready, и следующий такт отдаёт её новому воркеру.
Пример в начальных данных — миграция, которая исчерпала память:
# Worker claims, starts scanning 2.4M rows, OOM kills it at ~2.3M
# Dispatcher detects dead pid, releases claim, increments attempt counter
# Retry with a chunked strategy succeeds
Панель показывает полную историю из двух попыток:

Run 1 — crashed, с ошибкой OOM kill at row 2.3M (process 99999 gone). Run 2 — completed, с "strategy": "chunked with LIMIT + WHERE id > last_id" в метаданных. Повторный воркер увидел сбой run 1 в своём контексте и выбрал более безопасную стратегию; метаданные делают очевидным для будущего наблюдателя (или автора постмортема), что изменилось.
Структурированная передача — почему summary и metadata важны
В каждом из описанных выше сценариев воркеры вызывали kanban_complete(summary=..., metadata=...) в конце. Это не украшение — это основной канал передачи между этапами рабочего процесса.
Когда воркер на задаче B запускается и вызывает kanban_show(), возвращаемый worker_context включает:
-
Предыдущие попытки B (предыдущие run: результат, сводка, ошибка, метаданные) — чтобы повторно запущенный воркер не повторял неудачный путь.
-
Результаты родительских задач — для каждого родителя: сводка и метаданные последнего завершённого run — чтобы нижестоящие воркеры видели, почему и как была выполнена вышестоящая работа.
Это заменяет танец «покопаться в комментариях и выходных данных работы», который преследует плоские kanban-системы. PM записывает критерии приёмки в метаданные спецификации, и воркер инженера видит их структурно в родительской передаче. Инженер записывает, какие тесты он запустил и сколько прошло, и воркер reviewer имеет этот список в руках, прежде чем открыть diff.
Защита от массового закрытия существует именно потому, что эти данные привязаны к run. hermes kanban complete a b c --summary X (вы, из CLI) будет отклонён — копирование одной и той же сводки для трёх задач почти всегда неверно. Массовое закрытие без флагов передачи всё ещё работает для обычного случая «я закончил кучу административных задач». Инструментальная поверхность вообще не предоставляет массового варианта; kanban_complete всегда работает с одной задачей за раз по той же причине.
Просмотр выполняющейся в данный момент задачи
Для полноты — вот панель задачи, которая всё ещё в работе (реализация API из Сценария 1, взятая backend-dev, но ещё не завершённая):

Статус — Running. Активный run отображается в разделе Run History с результатом active и без ended_at. Если этот воркер умрёт или истечёт время, dispatcher закроет этот run с соответствующим результатом и откроет новый при следующем закреплении — строка попытки никогда не исчезает.
Следующие шаги
-
Обзор Kanban — полная модель данных, словарь событий и справочник CLI.
-
hermes kanban --help— все подкоманды, все флаги. -
hermes kanban watch --kinds completed,gave_up,timed_out— просмотр событий в реальном времени через терминал по всей доске. -
hermes kanban notify-subscribe <task> --platform telegram --chat-id <id>— получать уведомление gateway, когда конкретная задача завершится.