Há menos de um mês escrevi um post inteiro explicando como usar três camadas de memória com Claude Code: Linear para estratégia, Beads para tática e Tasks para execução. Uma pirâmide bonita e elegante.

Pois é, não rolou.

Hoje aposento o Beads. E não por capricho, mas porque a realidade se encarregou de mostrar que uma ferramenta que te dá mais problemas do que resolve não é uma ferramenta. É um peso morto.

O que o Beads trazia

Para quem não leu o post original, Beads era um issue tracker baseado em git. Um plugin pro Claude Code que armazenava issues em arquivos JSONL dentro do seu repositório. A ideia era brilhante no papel:

  • Persistência no git: os issues viviam em .beads/ e eram commitados junto com seu código.
  • Dependências: um issue podia bloquear outro.
  • Offline: funcionava sem conexão.
  • O LLM via diretamente: sem APIs, sem configuração. O agente lia os arquivos e pronto.

A promessa: uma camada intermediária entre “o que eu quero fazer essa semana” (Linear) e “o que estou fazendo agora” (Tasks). A cola tática.

O que deu errado

Tudo ia bem até que parou de ir bem. E parou de ir bem de formas criativas.

O daemon do inferno

Beads roda um daemon em background para gerenciar o banco de dados SQLite e sincronizar com git. Parece razoável. Na prática:

DATABASE MISMATCH DETECTED!

This database belongs to a different repository:
  Database repo ID:  d1f9ca0c
  Current repo ID:   01eac8ea

⚠️ CRITICAL: This mismatch can cause beads to incorrectly
   delete issues during sync!

Essa mensagem te recebe ao iniciar qualquer sessão. O daemon falha, a sincronização falha, e você fica com issues que existem no seu SQLite local mas não no git, ou vice-versa. Um estado quântico de bugs: seus issues existem e não existem ao mesmo tempo.

A sincronização fantasma

bd sync é o comando para sincronizar seus issues com o remote do git. Exceto quando não funciona:

→ Pulling from remote...
Error: pulling: git pull failed: exit status 1
remote: Repository not found
fatal: repository 'https://git.frr.dev/frr/wuwei.git/' not found

Acontece que o beads pega o remote do git, mas se você tem vários remotes (coisa comum), ele pode escolher o errado. E se esse remote aponta para um repo que não existe ou mudou de nome, o daemon cospe erros em cada operação. Silenciosamente, seus issues param de sincronizar e você só percebe quando abre outra sessão e tudo sumiu.

O custo cognitivo

Cada sessão com Claude Code começava assim:

  1. Claude lê o prompt do beads (injetado via hooks)
  2. O daemon tenta iniciar
  3. Falha com um erro de mismatch
  4. Claude tenta bd sync
  5. Falha com um erro de remote
  6. Você diz “ignora isso”
  7. Agora sim, vamos trabalhar

Seis passos de fricção antes de fazer qualquer coisa produtiva. Seis passos que consomem contexto, tempo e paciência.

O que mudou

Duas coisas fizeram o Beads passar de “ferramenta útil com bugs” para “overhead desnecessário”:

1. Tasks amadureceu

Quando escrevi o post das três camadas, Tasks era básico. Agora tem:

  • TaskCreate com descrições, activeForm para spinners e metadados
  • TaskUpdate com dependências (addBlocks, addBlockedBy)
  • TaskList e TaskGet para inspeção
  • Persistência opcional entre sessões com CLAUDE_CODE_TASK_LIST_ID

Traduzindo: Tasks agora faz tudo o que Beads fazia para o trabalho intra-sessão. E faz sem daemon, sem SQLite, sem sincronização git e sem erros fantasmas.

2. O CLI do Linear chegou

O MCP do Linear era, sendo generoso, uma porcaria. Intermitente, lento e com um talento especial para falhar justo quando você mais precisava.

A alternativa era bater na API na mão com GraphQL. Que funciona, sim, até você tentar colocar caracteres especiais nas descrições dos issues:

1
2
3
4
5
6
7
8
# Tentativa 1: bash com interpolação de strings
# Resultado: JSON quebrado por parênteses e setas

# Tentativa 2: Python com urllib
# Resultado: 401 porque op read não é avaliado dentro do Python

# Tentativa 3: chorar um pouco
# Resultado: catártico mas improdutivo

E então descobri o linear CLI:

1
2
brew install schpet/tap/linear
linear auth login -k "$(op read 'op://FRR DEV/Linear/api-key')"

E criar um issue vira:

1
2
3
4
5
6
linear issue create --team RST --no-interactive \
  -t "Port: agent/loop" \
  --project "Phase 1: Core Loop" \
  --priority 1 \
  -l port \
  -d "Port agent loop (476 LOC). Heart of the agent."

Sem escaping de GraphQL. Sem daemon. Sem sincronização quebrada. Criei 49 issues em menos de um minuto com um script de bash. Com o MCP do Linear e com a API, levaria uma hora e meia de briga com o escapamento de caracteres.

A nova pirâmide (que já não é pirâmide)

O modelo de três camadas era bonito. Mas a realidade é que duas camadas são suficientes:

NecessidadeAntesAgora
Visão estratégicaLinear (MCP/API)Linear (linear CLI)
Trabalho táticoBeadsLinear (linear CLI)
Execução na sessãoTasksTasks

Linear + seu CLI cobre estratégia e tática. Tasks cobre execução. Beads não cobre nada que as outras duas não façam melhor.

Antes:
Linear (semanas) → Beads (dias) → Tasks (horas)

Agora:
Linear (semanas/dias) → Tasks (horas)

Menos camadas, menos fricção, menos coisas que podem quebrar.

Lição aprendida

Isso me lembra algo que sempre digo: a complexidade desnecessária é o inimigo silencioso. Beads resolvia um problema real (a amnésia do LLM entre sessões), mas fazia isso adicionando uma camada de infraestrutura que, no longo prazo, gerava mais problemas do que resolvia.

É a mesma história de sempre em engenharia: a solução certa às vezes não é adicionar algo, mas perceber que o que você já tem melhorou o suficiente para não precisar mais.

O MCP do Linear era uma porcaria –> chegou o CLI. Tasks era básico –> amadureceu. Beads ficou no meio, sem espaço.

O rm -rf definitivo

1
2
rm -rf .beads/
git add -A && git commit -m "chore: remove beads"

Duas linhas. Assim se aposenta uma ferramenta. Sem cerimônia, sem drama.

Beads foi útil enquanto foi. Agora não é mais. E tudo bem.


TL;DR: Aposento o Beads do meu fluxo de trabalho com Claude Code. O CLI do Linear (schpet/linear-cli) resolve a gestão de issues sem as dores do MCP nem da API GraphQL. Tasks amadureceu o suficiente para cobrir o tracking intra-sessão. Duas camadas bastam: Linear para estratégia e tática, Tasks para execução.

Posts anteriores sobre o tema: