Documentação oficial desta página · v0.20.6
Tutorial do Kanban
Um passo a passo dos quatro casos de uso para os quais o sistema Kanban do Hermes foi desenhado, com o painel aberto no navegador. Se você ainda não leu a visão geral do Kanban, comece por lá — aqui se assume que você já sabe o que são tarefa, execução, responsável e despachante.
Preparação
hermes kanban init # opcional; o primeiro `hermes kanban <qualquer-coisa>` já inicializa
hermes dashboard # abre http://127.0.0.1:9119 no seu navegador
# clique em Kanban no menu da esquerda
O painel é o lugar mais confortável para você acompanhar o sistema. Os agentes trabalhadores que o despachante cria nunca veem o painel nem a CLI — eles operam o quadro por um conjunto de ferramentas kanban_* dedicado (kanban_show, kanban_list, kanban_complete, kanban_block, kanban_heartbeat, kanban_comment, kanban_attach, kanban_attach_url, kanban_attachments, kanban_create, kanban_link, kanban_unblock). As três superfícies — painel, CLI e ferramentas do trabalhador — passam pelo mesmo banco SQLite por quadro (~/.hermes/kanban.db para o quadro padrão, ~/.hermes/kanban/boards/<slug>/kanban.db para qualquer quadro que você criar depois), então cada quadro fica consistente não importa de que lado da cerca veio a mudança.
Este tutorial usa o quadro default do começo ao fim. Se você quer várias filas isoladas (uma por projeto / repositório / domínio), veja Quadros (multiprojeto) na visão geral — os mesmos fluxos de CLI / painel / trabalhador valem por quadro, e os trabalhadores fisicamente não conseguem ver tarefas de outros quadros.
Ao longo do tutorial, os blocos de código marcados como bash são comandos que você roda. Os blocos marcados com # worker tool calls são o que o modelo do trabalhador criado emite como chamadas de ferramenta — mostrados aqui para você ver o laço de ponta a ponta, não porque você fosse rodá-los algum dia.
O quadro de relance

Seis colunas, da esquerda para a direita:
- Triage — ideias cruas. Por padrão, o despachante roda sozinho o decompositor nas tarefas daqui: o decompositor embutido usa
auxiliary.kanban_decomposer, lê a sua lista de perfis + descrições e produz um grafo de tarefas filhas roteadas para os especialistas mais adequados. A tarefa original é mantida viva como mãe, para que o responsável dela (kanban.orchestrator_profile, ou o perfil padrão ativo quando não estiver definido) acorde de novo e julgue a conclusão quando tudo terminar. Alterne a pílula Orchestration: Auto/Manual no topo da página do kanban para trocar de modo. No modo Manual, clique em ⚗ Decompose em um cartão, ou rodehermes kanban decompose <id>//kanban decompose <id>. Para tarefas únicas que não precisam de ramificação, o ✨ Specify faz uma reescrita de especificação de uma tacada (objetivo, abordagem, critérios de aceitação) e promove paratodo. Configure os modelos emauxiliary.kanban_decomposereauxiliary.triage_specifiernoconfig.yaml. Veja Orquestração automática ou manual no guia principal do Kanban. - Todo — criada, mas esperando dependências, ou ainda sem responsável.
- Ready — com responsável, esperando o despachante reivindicar.
- In progress — um trabalhador está executando a tarefa agora. Com "Lanes by profile" ligado (o padrão), esta coluna se subagrupa por responsável, para você ver de relance o que cada trabalhador está fazendo.
- Blocked — um trabalhador pediu intervenção humana, ou o disjuntor desarmou.
- Done — concluída.
A barra de cima tem filtros de busca, de tenant e de responsável, além de um botão de alternância Lanes by profile e de um botão Nudge dispatcher, que roda um tique de despacho agora mesmo em vez de esperar o próximo intervalo do daemon. Clicar em qualquer cartão abre a gaveta dele à direita.
Visão plana
Se as faixas por perfil ficarem ruidosas, desligue "Lanes by profile" e a coluna In Progress vira uma lista plana única, ordenada por hora da reivindicação:

História 1 — Dev solo entregando uma funcionalidade
Você está construindo uma funcionalidade. Fluxo clássico: desenhar um esquema, implementar a API, escrever os testes. Três tarefas com dependências mãe→filha.
SCHEMA=$(hermes kanban create "Desenhar o esquema de autenticação" \
--assignee backend-dev --tenant auth-project --priority 2 \
--body "Desenhar o esquema de usuário/sessão/token do módulo de autenticação." \
--json | jq -r .id)
API=$(hermes kanban create "Implementar os endpoints da API de autenticação" \
--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 "Escrever os testes de integração de autenticação" \
--assignee qa-dev --tenant auth-project --priority 2 \
--parent $API \
--body "Cobrir o caminho feliz, senha errada, token expirado, refresh concorrente."
Como API tem SCHEMA como mãe, e tests tem API como mãe, só SCHEMA começa em ready. As outras duas ficam em todo até as mães concluírem. É o motor de promoção por dependência fazendo o trabalho dele — nenhum outro trabalhador vai pegar a escrita dos testes até existir uma API para testar.
No tique seguinte do despachante (60s por padrão, ou na hora se você apertar Nudge dispatcher), o perfil backend-dev sobe como trabalhador com HERMES_KANBAN_TASK=$SCHEMA no ambiente dele. É assim que o laço de chamadas de ferramenta do trabalhador se parece de dentro do agente:
# worker tool calls — NÃO são comandos que você roda
kanban_show()
# → devolve título, corpo, worker_context, mães, tentativas anteriores, comentários
# (o trabalhador lê o worker_context, usa as ferramentas de terminal/arquivo para desenhar
# o esquema, escrever migrações, rodar as próprias checagens, commitar — o trabalho real é aqui)
kanban_heartbeat(note="esquema rascunhado, escrevendo as migrações agora")
kanban_complete(
summary="users(id, email, pw_hash), sessions(id, user_id, jti, expires_at); "
"tokens de refresh guardados como sessions com type='refresh'",
metadata={
"changed_files": ["migrations/001_users.sql", "migrations/002_sessions.sql"],
"decisions": ["bcrypt para o hash", "JWT para tokens de sessão",
"refresh de 7 dias, acesso de 15 min"],
},
)
O kanban_show usa $HERMES_KANBAN_TASK como valor padrão de task_id, então o trabalhador não precisa saber o próprio id. O kanban_complete grava o resumo + os metadados na linha atual de task_runs, fecha aquela execução e transiciona a tarefa para done — tudo em um salto atômico por kanban_db.
Quando SCHEMA chega em done, o motor de dependências promove API para ready automaticamente. O trabalhador da API, ao pegar a tarefa, vai chamar kanban_show() e ver o resumo e os metadados de SCHEMA anexados à passagem de bastão da mãe — então ele conhece as decisões de esquema sem reler um documento de projeto longo.
Clique na tarefa de esquema concluída no quadro e a gaveta mostra tudo:

A seção Run History, ao pé da gaveta, é o acréscimo principal. Uma tentativa: desfecho completed, trabalhador @backend-dev, duração, marca de tempo e o resumo da passagem de bastão por inteiro. O blob de metadados (changed_files, decisions) também fica guardado na execução e é mostrado a qualquer trabalhador a jusante que leia essa mãe.
Você pode inspecionar os mesmos dados do seu terminal a qualquer momento — estes comandos são você espiando o quadro, não o trabalhador:
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); tokens de refresh ...
História 2 — Fazenda de frota
Você tem três trabalhadores (um tradutor, um transcritor e um redator) e uma pilha de tarefas independentes. Você quer os três puxando trabalho em paralelo e mostrando progresso visível. Este é o caso de uso mais simples do kanban e o que o projeto original otimizou.
Crie o trabalho:
for lang in Espanhol Francês Alemão; do
hermes kanban create "Traduzir a página inicial para $lang" \
--assignee translator --tenant content-ops
done
for i in 1 2 3 4 5; do
hermes kanban create "Transcrever a ligação #$i com cliente do 3º trimestre" \
--assignee transcriber --tenant content-ops
done
for sku in 1001 1002 1003 1004; do
hermes kanban create "Gerar descrição de produto: SKU-$sku" \
--assignee copywriter --tenant content-ops
done
Suba o gateway e vá cuidar de outra coisa — ele hospeda o despachante embutido, que pega as tarefas dos três perfis especialistas no mesmo kanban.db:
hermes gateway start
Agora filtre o quadro por content-ops (ou simplesmente busque "Transcrever") e você vê isto:

Duas transcrições prontas, uma rodando, duas prontas esperando o próximo tique do despachante. A coluna In Progress está agrupada por perfil (o padrão "Lanes by profile"), então você vê a tarefa ativa de cada trabalhador sem varrer uma lista misturada. O despachante vai promover a próxima tarefa pronta a executando assim que a atual concluir. Com três daemons trabalhando em três conjuntos de responsáveis em paralelo, a fila de conteúdo inteira se esvazia sem mais nenhuma intervenção humana.
Tudo o que a História 1 disse sobre passagem de bastão estruturada continua valendo aqui. Um trabalhador tradutor que conclui uma ligação emite kanban_complete(summary="traduzi 4 páginas, estilo alinhado com a voz de marketing existente", metadata={"duration_seconds": 720, "tokens_used": 2100}) — útil para análise de dados e para qualquer tarefa a jusante que dependa desta.
História 3 — Esteira de papéis com nova tentativa
É aqui que o Kanban se paga em relação a uma lista de TODO plana. Um PM escreve uma especificação. Uma pessoa de engenharia implementa. Um revisor rejeita a primeira tentativa. A engenharia tenta de novo com mudanças. O revisor aprova.
A visão do painel, filtrada por auth-project:

A captura de tela usa o modelo de cartão a jusante pré-criado: o cartão de implementação tem um filho revisor dedicado. Nesse modelo, a engenharia precisa chamar kanban_complete quando a implementação estiver pronta, para que o filho revisor consiga sair de todo. Nunca bloqueie a mãe de implementação só para pedir revisão.
Para fluxos em que o mesmo cartão é dono da implementação e da revisão, use o ciclo de vida de revisão de primeira classe. A coreografia completa de implementar → revisar → mudanças → revisar de novo é esta:
# --- Engenharia: primeira tentativa de implementação ---
kanban_show()
# (escreve o código, roda os testes, prepara o candidato)
kanban_request_review(
summary="fluxo de redefinição implementado; candidato pronto para revisão",
metadata={"changed_files": ["auth/reset.py"], "tests_run": 8},
reviewer="reviewer",
)
# → o mesmo cartão entra em revisão; a execução de implementação fecha com
# outcome='review_requested'
# --- Revisor: pede mudanças concretas ---
kanban_show()
# (inspeciona a passagem de bastão e o candidato)
kanban_request_changes(
reason="Adicione validação de força de senha e faça os tokens de redefinição serem de uso único."
)
# → a execução de revisão fecha com outcome='changes_requested'; o cartão volta
# para o backend-dev em ready/todo, sem mexer na contabilidade do laço de bloqueio
# --- Engenharia: segunda tentativa de implementação ---
kanban_show() # as evidências da revisão anterior estão no worker_context
# (aplica o retorno e roda os testes de novo)
kanban_request_review(
summary="adicionei validação zxcvbn e tokens de redefinição de uso único",
metadata={
"changed_files": [
"auth/reset.py",
"auth/tests/test_reset.py",
"migrations/003_single_use_reset_tokens.sql",
],
"tests_run": 11,
"review_iteration": 2,
},
reviewer="reviewer",
)
# --- Revisor: aprova ---
kanban_complete(summary="revisão aprovada; critérios de aceitação verificados")
# → done
O histórico de execuções da tarefa agora registra review_requested → changes_requested → review_requested → completed. Cada tentativa tem o próprio ator, resumo, metadados e desfecho, então a segunda passada da engenharia vê exatamente o que o revisor rejeitou, e a aprovação final continua auditável. O kanban_block está reservado para um escalonamento externo de verdade (acesso faltando, uma decisão de produto, infraestrutura indisponível), não para retorno normal de revisão.
Se você usar de propósito o modelo de cartão a jusante mostrado na captura de tela, o revisor abre Review password reset PR depois que a mãe de implementação conclui:

O worker_context do cartão do revisor inclui a passagem de bastão da implementação concluída. Esse é um fluxo de cartão separado; não misture com o kanban_request_review de mesmo cartão, senão você duplica a faixa de revisão.
História 4 — Disjuntor e recuperação de queda
Trabalhadores de verdade falham. Credenciais faltando, mortes por OOM, erros de rede passageiros. O despachante tem duas linhas de defesa: um disjuntor que bloqueia sozinho depois de N falhas consecutivas, para o quadro não se debater para sempre, e uma detecção de queda que recupera uma tarefa cujo PID de trabalhador desapareceu antes de o TTL expirar.
Disjuntor — falha com cara de permanente
Uma tarefa de implantação que não consegue subir o trabalhador porque AWS_ACCESS_KEY_ID não está definida no ambiente do perfil:
hermes kanban create "Implantar em staging (credenciais faltando)" \
--assignee deploy-bot --tenant ops \
--max-retries 3
O despachante tenta subir o trabalhador. A subida falha (RuntimeError: AWS_ACCESS_KEY_ID not set). O despachante libera a reivindicação, incrementa um contador de falhas e tenta de novo no tique seguinte. Como este exemplo define --max-retries 3, o disjuntor desarma depois de três falhas consecutivas: a tarefa vai para blocked com desfecho gave_up. Se você omitir a opção, o Hermes usa kanban.failure_limit (padrão: 2). Nenhuma nova tentativa até um humano desbloquear.
Clique na tarefa bloqueada:

Três execuções, todas com o mesmo erro no campo error. As duas primeiras são spawn_failed (dá para tentar de novo), a terceira é gave_up (terminal). O log de eventos acima mostra a sequência completa: created → claimed → spawn_failed → claimed → spawn_failed → claimed → gave_up.
No terminal:
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
Se Telegram / Discord / Slack estiverem ligados, uma notificação de gateway dispara no evento gave_up, então você fica sabendo da pane sem ter que olhar o quadro.
Recuperação de queda — o trabalhador morre em pleno voo
Às vezes a subida dá certo, mas o processo do trabalhador morre depois — segfault, OOM, systemctl stop. O despachante consulta kill(pid, 0) e detecta o pid morto; a reivindicação é liberada, a tarefa volta para ready, e o tique seguinte a entrega a um trabalhador novo.
O exemplo nos dados de semente é uma migração que estava ficando sem memória:
# O trabalhador reivindica, começa a varrer 2,4 mi de linhas, o OOM o mata perto de 2,3 mi
# O despachante detecta o pid morto, libera a reivindicação, incrementa o contador de tentativas
# A nova tentativa, com estratégia em blocos, dá certo
A gaveta mostra o histórico completo das duas tentativas:

Execução 1 — crashed, com o erro OOM kill at row 2.3M (process 99999 gone). Execução 2 — completed, com "strategy": "chunked with LIMIT + WHERE id > last_id" nos metadados. O trabalhador da nova tentativa viu a queda da execução 1 no contexto dele e escolheu uma estratégia mais segura; os metadados deixam óbvio, para um observador futuro (ou para quem escrever o post-mortem), o que mudou.
Passagem de bastão estruturada — por que summary e metadata importam
Em todas as histórias acima, os trabalhadores chamaram kanban_complete(summary=..., metadata=...) no fim. Isso não é enfeite — é o canal principal de passagem de bastão entre os estágios de um fluxo.
Quando um trabalhador da tarefa B sobe e chama kanban_show(), o worker_context que ele recebe de volta inclui:
- As tentativas anteriores de B (execuções passadas: desfecho, resumo, erro, metadados), para que um trabalhador em nova tentativa não repita um caminho que falhou.
- Os resultados das tarefas mãe — para cada mãe, o resumo e os metadados da execução concluída mais recente — para que os trabalhadores a jusante vejam por que e como o trabalho a montante foi feito.
Isso substitui a dança de "cavar nos comentários e na saída do trabalho" que atormenta os sistemas de kanban planos. Um PM escreve os critérios de aceitação nos metadados da especificação, e o trabalhador da engenharia os vê de forma estruturada na passagem de bastão da mãe. A engenharia registra quais testes rodou e quantos passaram, e o trabalhador do revisor já tem essa lista na mão antes de abrir um diff.
A trava de fechamento em lote existe porque esses dados são por execução. hermes kanban complete a b c --summary X (você, pela CLI) é recusado — copiar e colar o mesmo resumo em três tarefas está errado quase sempre. O fechamento em lote sem as opções de passagem de bastão continua funcionando para o caso comum de "terminei uma pilha de tarefas administrativas". A superfície de ferramentas nem expõe uma variante em lote; o kanban_complete é sempre de uma tarefa por vez, pelo mesmo motivo.
Desdobramento num cartão concluído — remediação de CI pelo vínculo com a mãe
O cartão de implementação da História 1 está done. Duas horas depois, o CI falha no branch mesclado. Não reabra o cartão concluído — cartões concluídos são história, e a passagem de bastão deles flui para frente. Crie um cartão de remediação tendo o cartão concluído como mãe:
hermes kanban create "Consertar o CI: test_backoff_jitter instável no 3.11" \
--assignee backend-dev \
--parent t_impl \
--workspace worktree --branch wt/ci-fix-backoff \
--body "A execução #4812 do CI falhou depois de t_impl concluir.
FAILED tests/test_retry.py::test_backoff_jitter - TimeoutError
Aceitação: tests/test_retry.py verde no 3.11 e no 3.12."
Três coisas fazem isso funcionar:
- Despacho imediato. Como a mãe já está
done, o filho é criado direto emready— o despachante pode reivindicá-lo no tique seguinte. (Um filho de uma mãe ainda aberta esperaria emtodo.) - Contexto herdado. O contexto do trabalhador de remediação inclui uma seção Parent task results com o resumo de conclusão e os metadados de
t_impl— os arquivos alterados e as decisões que o trabalhador original registrou — então ele sabe por que o código tem a forma que tem antes de ler uma linha dele. - Evidência fresca no corpo. O log do CI não existia quando
t_implconcluiu, então não pode estar na passagem de bastão da mãe — ele vai no corpo do cartão novo, junto com critérios de aceitação explícitos.
Prefira uma worktree/branch nova para o cartão de remediação. Fazer checkout do branch original dá ao trabalhador o estado do repositório, mas nada da justificativa — quem carrega isso é a passagem de bastão da mãe. O mesmo perfil de responsável costuma ser o certo: o perfil que escreveu o código tem as habilidades para consertá-lo.
Inspecionar uma tarefa em execução
Só para fechar — esta é a gaveta de uma tarefa ainda em voo (a implementação da API da História 1, reivindicada por backend-dev, mas ainda não concluída):

O status é Running. A execução ativa aparece na seção Run History com desfecho active e sem ended_at. Se este trabalhador morrer ou estourar o tempo, o despachante fecha esta execução com o desfecho adequado e abre uma nova na próxima reivindicação — a linha da tentativa nunca desaparece.
Próximos passos
- Visão geral do Kanban — o modelo de dados completo, o vocabulário de eventos e a referência da CLI.
hermes kanban --help— todo subcomando, toda opção.hermes kanban watch --kinds completed,gave_up,timed_out— fluxo ao vivo dos eventos terminais de todo o quadro.hermes kanban notify-subscribe <tarefa> --platform telegram --chat-id <id>— receba um toque do gateway quando uma tarefa específica terminar.