Voltar ao blog

Triagem de Tarefas Bloqueadas em Desenvolvimento Paralelo

Voce pode rodar 10 agentes de IA de programacao em paralelo agora. De a cada um um issue, aponte-os para um banco de dados beads compartilhado e deixe-os trabalhar. Agentes criam subtarefas, registram bugs que descobrem, atualizam status e fecham issues quando terminam. E genuinamente produtivo.

Ate algo bloquear.

Quando um humano e bloqueado, ele diz algo. Posta no Slack, sinaliza no standup, vai ate a mesa de alguem. Agentes nao fazem nada disso. Um agente bate em uma dependencia que nao consegue resolver e ou trava silenciosamente ou comeca a contornar o problema de formas que criam mais problemas. Tres agentes podem estar presos na mesma tarefa upstream nao resolvida e voce so vai saber quando se perguntar por que nada foi entregue em quatro horas.

Esse e o problema de triagem para desenvolvimento com agentes. Nao "como fazemos standups melhores" mas "como enxergamos o que esta travado em uma frota de trabalhadores autonomos que nao reclamam." Veja o que aprendemos construindo o Beadbox, um dashboard em tempo real para beads que mostra exatamente o que seus agentes estao fazendo, no que estao bloqueados e o que acabou de ficar disponivel.

Va direto ao que importa:

Como agentes criam cadeias de bloqueio

Agentes geram problemas de dependencia de forma diferente de times humanos. Entender os modos de falha importa porque as respostas de triagem sao diferentes.

Agentes nao modelam dependencias antecipadamente. Um arquiteto humano decompoe uma feature em tarefas e pensa na ordenacao. Um agente de programacao recebe uma tarefa, comeca a trabalhar e descobre no meio da implementacao que precisa de algo que ainda nao existe. Ele pode criar um novo issue para essa dependencia. Pode tentar construir inline e criar uma bagunca. Pode simplesmente parar. Nenhum desses resultados e visivel a menos que voce esteja monitorando o banco de issues.

Agentes trabalham mais rapido do que grafos de dependencia atualizam. O Agente-3 fecha uma tarefa que o Agente-7 estava esperando, mas o Agente-7 nao sabe porque verificou os bloqueadores 10 minutos atras. Enquanto isso, o Agente-7 ainda esta ocioso ou trabalhando em algo de menor prioridade. O desbloqueio aconteceu, mas a informacao nao se propagou.

Dependencias circulares emergem da decomposicao paralela. Quando multiplos agentes decompoe trabalho simultaneamente, podem criar ciclos que nenhum agente individual enxerga. O Agente-1 cria a Tarefa A que depende da Tarefa B. O Agente-2 cria a Tarefa B que depende da Tarefa C. O Agente-3 cria a Tarefa C que depende da Tarefa A. Cada dependencia fazia sentido localmente. O ciclo so e visivel de cima.

Contencao de recursos e invisivel. Dois agentes precisam modificar o mesmo arquivo, ou ambos precisam do ambiente de staging, ou ambos precisam que a mesma biblioteca compartilhada esteja em estado estavel. Nao ha dependencia registrada porque nenhum agente sabe que o outro existe. Ambos desaceleram e nenhum reporta por que.

O fio condutor: agentes produzem situacoes de bloqueio mais rapido do que as reportam. O supervisor (voce) precisa de ferramentas que surfacem bloqueios automaticamente, nao ferramentas que esperem alguem levantar uma bandeira.

Deteccao automatica de dependencias

A solucao e dados de dependencia explicitos, consultaveis, criados no momento da tarefa e verificados continuamente. Veja como funciona com beads, o issue tracker Git-native em que rodamos nossa frota de agentes.

Agentes registram dependencias quando criam tarefas:

# Agente cria uma tarefa e descobre que precisa de uma API que nao existe
API_TASK=$(bd create \
  --title "Implement /api/v2/orders endpoint" \
  --type task --priority 2 --json | jq -r '.id')

# Agente cria sua propria tarefa e declara a dependencia
UI_TASK=$(bd create \
  --title "Build order history page" \
  --type task --priority 2 --json | jq -r '.id')

bd dep add "$UI_TASK" "$API_TASK"

Esse bd dep add e uma unica chamada CLI. Qualquer agente de IA (Claude Code, Cursor, Copilot Workspace) pode executa-lo. Sem biblioteca de cliente de API, sem danca de autenticacao. A dependencia agora e dado estruturado, consultavel por qualquer outro agente ou script.

Deteccao de ciclos roda automaticamente:

# beads verifica o grafo completo de dependencias em busca de ciclos
bd dep cycles

# Saida quando existem ciclos:
# CYCLE DETECTED: beads-a1b -> beads-c3d -> beads-e5f -> beads-a1b

Em um grafo de 5.000 dependencias, isso leva ~70ms. Rode como hook pos-commit ou em um cron de 5 minutos. Quando tres agentes independentemente criam um ciclo de dependencia, voce detecta em minutos ao inves de descobrir horas depois quando os tres estao parados.

Encontre todas as tarefas bloqueadas em um comando:

bd blocked --json | jq -r '.[] |
  "BLOCKED: \(.id) \(.title)\n  waiting on: \(.blocked_by | join(", "))\n  assignee: \(.owner // "unassigned")\n"'

Saida:

BLOCKED: beads-x7q Build order history page
  waiting on: beads-m2k Implement /api/v2/orders endpoint
  assignee: agent-3

BLOCKED: beads-r4p Deploy staging environment
  waiting on: beads-j9w Fix Docker build, beads-n1c Update TLS certificates
  assignee: agent-7

Agora voce sabe que o Agente-3 e o Agente-7 estao travados, no que estao travados e o que precisa acontecer para desbloquea-los. Toda essa consulta levou 30ms em um banco de 10K issues.

Detecte PRs bloqueados por convencoes de nome de branch:

#!/bin/bash
# blocked-prs.sh: encontrar PRs cujas dependencias nao foram mergeadas

for pr in $(gh pr list --json number,headRefName --jq '.[].headRefName'); do
  ISSUE_ID=$(echo "$pr" | grep -oE 'beads-[a-z0-9]+')
  [ -z "$ISSUE_ID" ] && continue

  BLOCKERS=$(bd show "$ISSUE_ID" --json | jq -r '.blocked_by[]' 2>/dev/null)
  for blocker in $BLOCKERS; do
    BLOCKER_STATUS=$(bd show "$blocker" --json | jq -r '.status')
    if [ "$BLOCKER_STATUS" != "closed" ]; then
      echo "PR ($pr) bloqueado: $ISSUE_ID esperando $blocker ($BLOCKER_STATUS)"
    fi
  done
done

Vinte linhas de shell. Roda localmente, le dados locais, diz quais PRs dos seus agentes nao podem ser mergeados ainda e por que.

Um workflow de triagem CLI-first

Triagem em um workflow com agentes nao e uma reuniao. E um script que roda em loop. O supervisor (humano ou agente) olha o que esta travado e toma uma decisao para cada item.

Aqui esta o script de triagem que realmente rodamos:

#!/bin/bash
# triage.sh: triagem de bloqueadores da frota de agentes

echo "========================================="
echo "RELATORIO DE TRIAGEM: $(date +%Y-%m-%d %H:%M)"
echo "========================================="

# 1. O que esta bloqueado?
echo -e "\n--- TAREFAS BLOQUEADAS ---"
bd blocked --json | jq -r '.[] |
  "[\(.priority)] \(.id) \(.title)
    bloqueado por: \(.blocked_by | join(", "))
    responsavel: \(.owner // "nao atribuido")\n"'

# 2. O que esta disponivel para agentes pegarem?
echo -e "\n--- PRONTO (desbloqueado, aberto) ---"
bd ready --json | jq -r '.[] |
  "[\(.priority)] \(.id) \(.title) (\(.owner // "nao atribuido"))"'

# 3. Quais agentes ficaram quietos?
echo -e "\n--- IN_PROGRESS PARADOS (sem atualizacao em 2h) ---"
CUTOFF=$(date -v-2H +%Y-%m-%dT%H:%M:%S 2>/dev/null || date -d '2 hours ago' --iso-8601=seconds)
bd list --status=in_progress --json | jq -r --arg cutoff "$CUTOFF" '.[] |
  select(.updated_at < $cutoff) |
  "PARADO: \(.id) \(.title) (ultima atualizacao: \(.updated_at), responsavel: \(.owner // "desconhecido"))"'

# 4. Saude das dependencias
echo -e "\n--- CICLOS DE DEPENDENCIA ---"
bd dep cycles 2>&1 || echo "Nenhum ciclo detectado."

echo -e "\n--- ESTATISTICAS DA FROTA ---"
bd stats

Para times humanos, "parado" significa 48 horas sem atualizacao. Para agentes, 2 horas de silencio em uma tarefa em andamento e um sinal de alerta. Ou o agente esta travado e nao reportando, ou crashou. De qualquer forma, voce precisa olhar.

A arvore de decisao para cada item bloqueado:

  1. Outro agente pode desbloquear? Repriorize a tarefa bloqueante, atribua um agente disponivel.
  2. A dependencia e falsa? Agentes as vezes registram dependencias excessivamente conservadoras durante o planejamento. Se o bloqueio nao e real, remova-o: bd dep remove beads-x7q beads-m2k (remove a dependencia de x7q em m2k, desbloqueando x7q instantaneamente).
  3. O trabalho pode ser dividido? Faca o agente bloqueado fazer as partes que nao precisam da dependencia. Crie uma tarefa de acompanhamento para o resto.
  4. E um bloqueio externo? Algo que so um humano pode resolver (chave de API, decisao de design, concessao de acesso). Marque, anote a resolucao esperada e reatribua o agente para outro trabalho pronto.

A opcao 2 acontece constantemente com agentes. Eles modelam dependencias com base no entendimento do codebase no momento do planejamento. Quando a implementacao comeca, a forma real do trabalho revela que metade daquelas dependencias era desnecessaria.

Visibilidade em tempo real do trabalho dos agentes

Rodar um script de triagem a cada 30 minutos deixa lacunas. Quando agentes trabalham rapido, muita coisa acontece entre verificacoes. A pergunta se torna: voce consegue ver bloqueios se formarem em tempo real?

Como o Beadbox faz:

O banco de dados beads vive em um diretorio .beads/ no seu sistema de arquivos. Cada bd update, bd create ou bd close que um agente executa escreve nesse diretorio. Beadbox monitora com fs.watch() e envia mudancas para a UI via WebSocket em milissegundos.

O efeito pratico: o Agente-5 roda bd update beads-x7q --status=closed no terminal. O dashboard do Beadbox imediatamente mostra aquela tarefa como fechada, e qualquer tarefa que estava bloqueada por ela aparece como recem-disponivel. Voce ve a cascata sem rodar nenhum comando.

Isso importa porque trabalho com agentes cria rajadas. Um agente pode fechar tres tarefas em 90 segundos, cada uma desbloqueando trabalho diferente a jusante. Um dashboard baseado em polling com intervalo de refresh de 30 segundos mostraria um estado intermediario confuso. Propagacao sub-segundo mostra o quadro completo conforme acontece.

Se voce nao usa Beadbox, filesystem watches ainda funcionam:

# Monitore o banco beads para mudancas, alerte sobre novos bloqueios
# Nota: fswatch dispara a cada escrita. Em producao voce faria debounce
# (ex., sleep 2 apos cada trigger) para evitar ruido durante rajadas de escrita.
fswatch -o .beads/ | while read; do
  BLOCKED_COUNT=$(bd blocked --json | jq length)
  if [ "$BLOCKED_COUNT" -gt 0 ]; then
    echo "$(date): $BLOCKED_COUNT tarefas atualmente bloqueadas"
    # Envie para ntfy, webhook Slack, ou qualquer sistema de notificacao
  fi
done

Feche o loop com CI:

# No seu passo pos-build de CI: feche automaticamente o issue quando o build passar
if [ "$BUILD_STATUS" = "success" ]; then
  ISSUE_ID=$(echo "$BRANCH_NAME" | grep -oE 'beads-[a-z0-9]+')
  if [ -n "$ISSUE_ID" ]; then
    bd update "$ISSUE_ID" --status=closed
    bd comments add "$ISSUE_ID" --author ci \
      "Build passed. Commit: $COMMIT_SHA. Closing automatically."
  fi
fi

Quando o CI fecha aquele issue, tudo que estava bloqueado por ele se torna desbloqueado. Se um agente esta monitorando bd ready para novo trabalho, ele pega a tarefa desbloqueada automaticamente. Sem humano no loop para desbloqueios rotineiros.

Essa e a diferenca entre ferramentas que rastreiam status e ferramentas que o propagam. A maioria dos softwares de gerenciamento de projetos faz o primeiro: voce atualiza um cartao, o cartao muda de cor. Propagacao significa que efeitos a jusante (desbloquear dependentes, surfacear trabalho disponivel, atualizar progresso) acontecem sem ninguem clicar em nada.

Avaliando ferramentas de triagem para workflows com agentes

Se voce esta buscando ferramentas para gerenciar uma frota de agentes, os requisitos sao diferentes do que um time humano precisa.

Obrigatorio: CLI que agentes podem chamar. Se seu issue tracker so tem interface web, agentes nao conseguem usa-lo. Eles precisam rodar comandos shell. bd create, bd update, bd blocked sao one-liners que qualquer agente de programacao ja sabe executar. APIs REST tambem funcionam, mas exigem tokens de autenticacao, clientes HTTP e tratamento de erros. Unix pipes sao mais simples.

Obrigatorio: grafo de dependencias consultavel. "Bloqueado" como label de status e inutil para automacao. Voce precisa de A depende de B como dado estruturado para que scripts possam percorrer o grafo, detectar ciclos e calcular o que esta pronto.

Obrigatorio: leituras locais sub-segundo. Quando agentes consultam trabalho disponivel, o tempo de resposta importa. Um round-trip de API de 2 segundos por consulta, multiplicado por 10 agentes consultando a cada minuto, cria overhead mensuravel. beads retorna resultados de bd ready em 30ms em um banco de 10K issues porque tudo e local.

Desejavel: propagacao de mudancas em tempo real. Se agentes criam e resolvem 50 issues por hora, voce precisa ver o estado conforme muda, nao em intervalos de refresh.

Sinal de alerta: "deteccao de bloqueadores com IA." Ferramentas que alegam detectar bloqueadores analisando descricoes de issues produzem falsos positivos e perdem bloqueadores reais que nunca foram escritos. Declaracoes explicitas com bd dep add vencem inferencia.

Sinal de alerta: ferramentas que exigem navegador para triagem. Desbloquear uma tarefa por interface web leva 5-15 segundos de cliques. Pela CLI, bd dep remove leva 18ms. Em 50 tarefas bloqueadas, sao 1 minuto vs 12 minutos. Quando voce supervisiona agentes que se movem rapido, velocidade de triagem e seu gargalo.

Como ferramentas comuns lidam com bloqueio

Capacidade Jira Linear GitHub Issues beads + Beadbox
Rastreamento de dependencias Plugin (Advanced Roadmaps) Relations (parcial) Referencias em tasklist First-class bd dep add
Status bloqueado automatico Manual Manual Manual Automatico a partir de deps
Deteccao de ciclos Nao Nao Nao Nativo (bd dep cycles)
CLI para agentes Jira CLI (terceiros) Linear CLI (limitado) gh (sem deps) Completo (bd blocked, bd ready)
Propagacao em tempo real Webhook (server-side) Webhook (server-side) Webhook (server-side) fs.watch (sub-segundo, local)
Funciona offline / local Nao Nao Nao Sim (modo embedded)
Scriptavel por agentes API + tokens de auth API + tokens de auth gh CLI bd CLI (Unix pipes)

O loop do supervisor

Aqui esta o workflow que rodamos diariamente, gerenciando mais de 10 agentes de IA em um unico projeto:

  1. Agentes declaram dependencias no momento da criacao da tarefa. Cada bd create que tem um pre-requisito recebe um bd dep add imediatamente. E uma unica chamada CLI extra por tarefa.

  2. Um agente supervisor roda bd blocked a cada 30 minutos. Se algo esta recem-bloqueado, ele resolve o bloqueador (repriorizar, reatribuir) ou sinaliza para o humano.

  3. Beadbox roda na tela do humano. O dashboard mostra o grafo completo de dependencias com tarefas bloqueadas destacadas em tempo real. Na maioria das vezes, a automacao cuida de desbloqueios rotineiros. Quando nao consegue (dependencia externa, decisao arquitetural, concessao de acesso), o humano ve o problema imediatamente e intervem.

  4. Tarefas paradas sao sinalizadas agressivamente. Um agente que nao atualizou sua tarefa em andamento em 2 horas esta travado ou crashou. O supervisor verifica e ou da um nudge no agente, reatribui o trabalho ou investiga.

  5. Dependencias falsas sao podadas continuamente. Agentes declaram dependencias em excesso durante o planejamento. Conforme a implementacao revela a forma real do trabalho, o supervisor (ou os proprios agentes) removem dependencias que se mostraram desnecessarias. Um grafo limpo e um grafo util.

O principio subjacente: agentes sao rapidos mas nao auto-conscientes. Eles nao sabem o que outros agentes estao fazendo, nao percebem quando bloqueadores sao resolvidos e nao reclamam quando estao travados. O trabalho do supervisor e ser o sistema nervoso que conecta tudo isso. Dados de dependencia estruturados, consultados automaticamente e renderizados visualmente, e o que torna isso possivel.


Beadbox e gratuito durante o beta. Ele mostra o que seus agentes estao fazendo, o que esta bloqueado e o que acabou de ficar disponivel, em tempo real.

brew tap beadbox/cask && brew install --cask beadbox

Se voce ja usa beads, o Beadbox le seu diretorio .beads/ existente sem etapa de importacao. Experimente.