Voltar ao blog

Triagem de tarefas bloqueadas em desenvolvimento paralelo

Triagem de tarefas bloqueadas em desenvolvimento paralelo

Você pode rodar 10 agentes IA de programação em paralelo hoje. Dê um issue para cada um, aponte-os para uma base beads compartilhada e deixe-os trabalhar. Os agentes criam subtarefas, reportam bugs que descobrem, atualizam status e fecham issues quando terminam. É genuinamente produtivo.

Até que algo bloqueia.

Quando um humano é bloqueado, ele fala. Posta no Slack, menciona no standup, vai até a mesa de alguém. Agentes não fazem nada disso. Um agente encontra uma dependência que não consegue resolver e cala em silêncio ou tenta contornar o problema de maneiras que criam mais problemas. Três agentes podem estar presos na mesma tarefa upstream não resolvida sem que você saiba, até que se pergunte por que nada foi entregue nas últimas quatro horas.

Este é o problema de triagem no desenvolvimento agentique. Não "como melhorar nossos standups" mas "como ver o que está travado através de uma frota de trabalhadores autônomos que não reclamam." Aqui está o que aprendemos construindo o Beadbox, um dashboard em tempo real para beads que mostra exatamente o que seus agentes estão fazendo, no que estão bloqueados e o que acabou de ficar disponível.

Vá direto ao que interessa:

Como agentes criam cadeias de bloqueio

Os agentes geram problemas de dependência de forma diferente das equipes humanas. Entender os modos de falha importa porque as respostas de triagem são diferentes.

Agentes não modelam dependências antecipadamente. Um arquiteto humano decompõe uma funcionalidade em tarefas e pensa na ordem. Um agente de programação recebe uma tarefa, começa a trabalhar e descobre no meio da implementação que precisa de algo que ainda não existe. Ele pode criar um novo issue para essa dependência. Pode tentar construí-la inline e criar uma bagunça. Pode simplesmente parar. Nenhum desses resultados é visível sem monitorar o banco de dados de issues.

Agentes trabalham mais rápido do que os grafos de dependências se atualizam. O Agente-3 fecha uma tarefa que o Agente-7 esperava, mas o Agente-7 não sabe porque verificou os bloqueios há 10 minutos. Enquanto isso, o Agente-7 continua ocioso ou trabalhando em algo de menor prioridade. O desbloqueio aconteceu, mas a informação não se propagou.

Dependências circulares emergem da decomposição paralela. Quando múltiplos agentes decompõem trabalho simultaneamente, podem criar ciclos que nenhum agente isolado 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 dependência fazia sentido localmente. O ciclo só é visível de cima.

A contenção de recursos é invisível. Dois agentes precisam modificar o mesmo arquivo, ou usar o ambiente de staging, ou a mesma biblioteca compartilhada em estado estável. Nenhuma dependência é registrada porque nenhum agente sabe que o outro existe. Ambos desaceleram e nenhum reporta o motivo.

O fio condutor: agentes produzem situações de bloqueio mais rápido do que as reportam. O supervisor (você) precisa de ferramentas que revelam bloqueios automaticamente, não ferramentas que esperam alguém levantar uma bandeira.

Detecção automática de dependências

A solução são dados de dependência explícitos, consultáveis, criados no momento da tarefa e verificados continuamente. Veja como funciona com o beads, o tracker de issues Git-native no qual rodamos nossa frota de agentes.

Agentes registram dependências ao criar tarefas:

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

# O agente cria sua própria tarefa e declara a dependência
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 é uma única chamada CLI. Qualquer agente IA de programação (Claude Code, Cursor, Copilot Workspace) pode executá-lo. Sem biblioteca cliente, sem dança de autenticação. A dependência agora é dado estruturado, consultável por qualquer outro agente ou script.

Detecção de ciclos roda automaticamente:

# beads verifica o grafo completo de dependências para ciclos
bd dep cycles

# Saída quando ciclos existem:
# CYCLE DETECTED: beads-a1b -> beads-c3d -> beads-e5f -> beads-a1b

Em um grafo de 5.000 dependências, isso leva cerca de 70 ms. Execute como hook pós-commit ou em cron a cada 5 minutos. Quando três agentes criam independentemente um ciclo de dependências, você detecta em minutos ao invés de descobrir horas depois com os três parados.

Mostrar 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"'

Saída:

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 você sabe que o Agente-3 e o Agente-7 estão travados, no que estão travados e o que precisa acontecer para desbloqueá-los. A consulta inteira levou 30 ms em um banco de 10.000 issues.

Detectar PRs bloqueadas por convenções de nomes de branches:

#!/bin/bash
# blocked-prs.sh: encontrar PRs cujas dependências ainda não 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) blocked: $ISSUE_ID waiting on $blocker ($BLOCKER_STATUS)"
    fi
  done
done

Vinte linhas de shell. Roda localmente, lê dados locais, diz quais PRs dos seus agentes ainda não podem ser mergeadas e por quê.

Um workflow de triagem CLI-first

Triagem em um workflow agentique não é uma reunião. É um script que roda em loop. O supervisor (humano ou agente) olha o que está travado e toma uma decisão para cada item.

Aqui está o script de triagem que realmente usamos:

#!/bin/bash
# triage.sh: triagem de bloqueios da frota agentique

echo "========================================="
echo "TRIAGE REPORT: $(date +%Y-%m-%d %H:%M)"
echo "========================================="

# 1. O que está bloqueado?
echo -e "\n--- BLOCKED TASKS ---"
bd blocked --json | jq -r '.[] |
  "[\(.priority)] \(.id) \(.title)
    blocked by: \(.blocked_by | join(", "))
    assignee: \(.owner // "unassigned")\n"'

# 2. O que está disponível para os agentes?
echo -e "\n--- READY (unblocked, open) ---"
bd ready --json | jq -r '.[] |
  "[\(.priority)] \(.id) \(.title) (\(.owner // "unassigned"))"'

# 3. Quais agentes ficaram silenciosos?
echo -e "\n--- STALE IN-PROGRESS (no update in 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) |
  "STALE: \(.id) \(.title) (last update: \(.updated_at), assignee: \(.owner // "unknown"))"'

# 4. Saúde das dependências
echo -e "\n--- DEPENDENCY CYCLES ---"
bd dep cycles 2>&1 || echo "No cycles detected."

echo -e "\n--- FLEET STATS ---"
bd stats

Para equipes humanas, "stale" significa 48 horas sem atualização. Para agentes, 2 horas de silêncio em uma tarefa em progresso é sinal de alerta. Ou o agente está preso e não reporta, ou crashou. Nos dois casos, você precisa investigar.

A árvore de decisão para cada item bloqueado:

  1. Outro agente pode desbloqueá-lo? Repriorize a tarefa bloqueadora, designe um agente disponível.
  2. A dependência é falsa? Agentes às vezes declaram dependências excessivamente conservadoras durante o planejamento. Se o bloqueio não é real, remova: bd dep remove beads-x7q beads-m2k (remove a dependência de x7q em m2k, desbloqueando x7q instantaneamente).
  3. O trabalho pode ser dividido? Faça o agente bloqueado trabalhar nas partes que não precisam da dependência. Crie uma tarefa de acompanhamento para o resto.
  4. É um bloqueio externo? Algo que só um humano pode resolver (chave de API, decisão de design, concessão de acesso). Etiquete, anote a resolução esperada e reatribua o agente para outro trabalho disponível.

A opção 2 acontece constantemente com agentes. Eles modelam dependências baseados em seu entendimento do codebase no momento do planejamento. Quando a implementação começa, a forma real do trabalho revela que metade dessas dependências era desnecessária.

Visibilidade em tempo real sobre o trabalho dos agentes

Rodar um script de triagem a cada 30 minutos deixa lacunas. Quando agentes trabalham rápido, muita coisa acontece entre as verificações. A pergunta se torna: você consegue ver bloqueios se formarem em tempo real?

Como o Beadbox faz isso:

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

O efeito prático: o Agente-5 executa bd update beads-x7q --status=closed em um terminal. O dashboard do Beadbox mostra imediatamente essa tarefa como fechada, e qualquer tarefa que dependia dela aparece como recém-disponível. Você vê a cascata sem executar nenhum comando.

Isso importa porque o trabalho agentique produz rajadas. Um agente pode fechar três tarefas em 90 segundos, cada uma desbloqueando trabalho downstream diferente. Um dashboard baseado em polling com intervalo de 30 segundos mostraria um estado intermediário confuso. Propagação em menos de um segundo mostra o cenário completo à medida que acontece.

Se você não usa o Beadbox, a vigilância do sistema de arquivos funciona do mesmo jeito:

# Monitorar o banco beads para mudanças, alertar sobre novos bloqueios
# Nota: fswatch dispara a cada escrita. Em produção, aplique debounce
# (ex. sleep 2 após cada disparo) para evitar ruído durante rajadas.
fswatch -o .beads/ | while read; do
  BLOCKED_COUNT=$(bd blocked --json | jq length)
  if [ "$BLOCKED_COUNT" -gt 0 ]; then
    echo "$(date): $BLOCKED_COUNT tasks currently blocked"
    # Direcionar para ntfy, webhook Slack, ou qualquer sistema de notificação
  fi
done

Fechar o ciclo com a CI:

# Na etapa pós-build da CI: fechar automaticamente o issue quando o build passa
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 a CI fecha esse issue, tudo que ele bloqueava fica desbloqueado. Se um agente monitora bd ready para novo trabalho, ele pega a tarefa desbloqueada automaticamente. Nenhum humano no loop para desbloqueios rotineiros.

Esta é a diferença entre ferramentas que rastreiam status e ferramentas que o propagam. A maioria dos softwares de gerenciamento de projetos faz o primeiro: você atualiza um card, o card muda de cor. Propagação significa que os efeitos downstream (desbloquear dependentes, revelar trabalho disponível, atualizar rollups de progresso) acontecem sem ninguém clicar em nada.

Avaliando ferramentas de triagem para workflows agentiques

Se você está procurando ferramentas para gerenciar uma frota de agentes, os requisitos diferem do que uma equipe humana precisa.

Indispensável: CLI que agentes possam chamar. Se seu tracker só tem interface web, agentes não podem usá-lo. Eles precisam executar comandos shell. bd create, bd update, bd blocked são one-liners que qualquer agente de programação já sabe executar. APIs REST também funcionam, mas exigem tokens de auth, clientes HTTP e tratamento de erros. Pipes Unix são mais simples.

Indispensável: grafo de dependências consultável. "Bloqueado" como rótulo de status é inútil para automação. Você precisa de "A depende de B" como dado estruturado para que scripts possam percorrer o grafo, detectar ciclos e calcular o que está pronto.

Indispensável: leituras locais em menos de um segundo. Quando agentes consultam trabalho disponível, 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 mensurável. beads retorna resultados de bd ready em 30 ms em um banco de 10.000 issues porque tudo é local.

Desejável: propagação de mudanças em tempo real. Se agentes criam e resolvem 50 issues por hora, você precisa ver o estado conforme muda, não em intervalos de atualização.

Sinal de alerta: "detecção de bloqueios por IA." Ferramentas que alegam detectar bloqueios analisando descrições de issues produzem falsos positivos e perdem bloqueios reais que nunca foram documentados. Declarações explícitas bd dep add vencem a inferência.

Sinal de alerta: ferramentas que exigem navegador para triagem. Desbloquear uma tarefa via interface web leva de 5 a 15 segundos de cliques. Via CLI, bd dep remove leva 18 ms. Em 50 tarefas bloqueadas, isso é 1 minuto contra 12 minutos. Quando você supervisiona agentes que se movem rápido, a velocidade de triagem é seu gargalo.

Como ferramentas comuns lidam com bloqueio

Capacidade Jira Linear GitHub Issues beads + Beadbox
Rastreamento de dependências Plugin (Advanced Roadmaps) Relations (parcial) Referências tasklist Nativo bd dep add
Status bloqueado automático Manual Manual Manual Automático via deps
Detecção de ciclos Não Não Não Integrada (bd dep cycles)
CLI para agentes Jira CLI (terceiros) Linear CLI (limitado) gh (sem deps) Completo (bd blocked, bd ready)
Propagação em tempo real Webhook (lado servidor) Webhook (lado servidor) Webhook (lado servidor) fs.watch (sub-segundo, local)
Funciona offline / local Não Não Não Sim (modo embutido)
Scriptável por agentes API + tokens auth API + tokens auth CLI gh CLI bd (pipes Unix)

O loop do supervisor

Aqui está o workflow que executamos diariamente, gerenciando 10+ agentes IA em um único projeto:

  1. Agentes declaram dependências na criação das tarefas. Cada bd create que tem um pré-requisito recebe um bd dep add imediatamente. É uma única chamada CLI extra por tarefa.

  2. Um agente supervisor executa bd blocked a cada 30 minutos. Se algo ficou recém-bloqueado, ele resolve o bloqueio por conta própria (repriorização, reatribuição) ou sinaliza para o humano.

  3. Beadbox roda na tela do humano. O dashboard mostra o grafo completo de dependências com tarefas bloqueadas destacadas em tempo real. Na maioria das vezes, a automação cuida dos desbloqueios rotineiros. Quando não consegue (dependência externa, decisão arquitetural, concessão de acesso), o humano vê o problema imediatamente e intervém.

  4. Tarefas paradas são sinalizadas agressivamente. Um agente que não atualizou sua tarefa em progresso há 2 horas está preso ou crashou. O supervisor verifica e ou relança o agente, reatribui o trabalho, ou investiga.

  5. Falsas dependências são podadas continuamente. Agentes declaram dependências em excesso durante o planejamento. À medida que a implementação revela a forma real do trabalho, o supervisor (ou os próprios agentes) remove dependências que se mostraram desnecessárias. Um grafo limpo é um grafo útil.

O princípio subjacente: agentes são rápidos mas não auto-conscientes. Não sabem o que outros agentes estão fazendo, não percebem quando bloqueios se resolvem e não reclamam quando estão presos. O papel do supervisor é ser o sistema nervoso que conecta tudo isso. Dados de dependência estruturados, consultados automaticamente e renderizados visualmente, é o que torna isso possível.


Beadbox é gratuito durante a beta. Ele mostra o que seus agentes estão fazendo, o que está bloqueado e o que acabou de ficar disponível, em tempo real.

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

Se você já usa o beads, o Beadbox lê seu diretório .beads/ existente sem nenhuma etapa de importação. Experimente.