Voltar ao blog

Desenvolvimento orientado por especificacoes com Claude Code

Desenvolvimento orientado por especificacoes com Claude Code

O desenvolvedor que digita "add user authentication" no Claude Code recebe um resultado diferente toda vez. Talvez JWT. Talvez cookies de sessao. Talvez um fluxo OAuth2 completo com refresh tokens e PKCE. O agente nao sabe o que voce quer porque voce nao disse. Voce deu uma direcao, nao um destino.

Os desenvolvedores que vejo obtendo resultados consistentes e prontos para entrega do Claude Code compartilham um habito: escrevem uma especificacao antes de passar trabalho para o agente. Nao um romance. Nao um ticket do Jira com tres frases de contexto. Um documento concreto que define como "pronto" se parece antes que alguem escreva uma linha de codigo.

Isso nao e sabedoria nova. Desenvolvimento spec-first precede a IA por decadas. Mas com agentes, o custo de pular a spec e maior e o beneficio de escrever uma e maior. Um desenvolvedor humano pode parar no meio da implementacao e perguntar "espera, voce quis dizer autenticacao por senha ou SSO?" Um agente vai escolher um silenciosamente e seguir em frente. Quando voce perceber, ele construiu a coisa errada, e voce gastou 20 minutos revisando codigo que precisa ser descartado.

Este artigo percorre o ciclo de vida orientado por specs que uso com Claude Code todos os dias: como escrever especificacoes contra as quais agentes podem executar, o checkpoint de plano-antes-do-codigo que pega mal-entendidos cedo, e um protocolo de verificacao mais rigoroso que "compila."

Por que "so construa" falha com agentes

Vamos ser especificos sobre o modo de falha. Quando voce da ao Claude Code uma instrucao vaga, tres coisas dao errado:

Suposicoes silenciosas. O agente preenche cada lacuna na sua spec com suas proprias suposicoes. As vezes sao razoaveis. As vezes nao. Voce nao sabera em qual categoria esta ate ler o output. Com instrucoes vagas, voce acaba lendo o output com mais cuidado do que teria gasto escrevendo uma spec.

Resultados nao reproduziveis. Execute o mesmo prompt vago duas vezes e voce obtem duas implementacoes diferentes. Nao apenas nomes de variaveis ou formatacao diferentes. Decisoes arquiteturais diferentes. Bibliotecas diferentes. Estrategias de tratamento de erros diferentes. Se voce nao pode reproduzir o output, nao pode construir um processo confiavel ao redor dele.

Revisao se torna o gargalo. Quando o agente toma todas as decisoes, voce precisa verificar todas as decisoes. Um diff de 400 linhas onde voce entende cada escolha leva 5 minutos de revisao. Um diff de 400 linhas onde o agente escolheu o schema do banco, a forma da API, os codigos de erro e a logica de validacao leva 30 minutos porque voce esta reconstruindo a spec a partir da implementacao.

A solucao nao sao prompts melhores. E antecipar as decisoes que importam em um documento contra o qual o agente pode executar.

O ciclo de vida orientado por especificacoes

O fluxo de trabalho tem cinco fases. Cada uma tem uma condicao de entrada clara e uma condicao de saida clara.

Fase 1: Brainstorming. Voce explora o espaco do problema. Quais sao as restricoes? Quais abordagens existem? O que voce tentou antes? Aqui e onde voce pensa em voz alta, sozinho ou com Claude Code em modo conversacional. Condicao de saida: voce tem uma abordagem preferida e entende os tradeoffs.

Fase 2: Revisao. Voce testa a abordagem sob pressao. O que pode dar errado? Quais casos extremos existem? Isso conflita com algo ja no codebase? Se voce trabalha com multiplos agentes, aqui um agente de arquitetura ou segunda opiniao e valioso. Condicao de saida: voce esta confiante de que a abordagem e solida.

Fase 3: Spec. Voce escreve o que decidiu. Declaracao do problema, abordagem proposta, arquivos a modificar, criterios de aceitacao verificaveis mecanicamente e um plano de testes. Este e o contrato. Condicao de saida: alguem (humano ou agente) poderia ler esta spec e saber exatamente o que construir e como verificar.

Fase 4: Implementacao. O agente executa contra a spec. Nao contra uma ideia vaga. Contra um documento concreto com criterios testaveis. Condicao de saida: o agente afirma ter concluido e postou evidencias de verificacao.

Fase 5: Verificacao. Voce (ou um agente de QA) confirma que a implementacao corresponde a spec. Nao "parece certo" mas "satisfaz cada criterio de aceitacao." Condicao de saida: cada criterio esta verificado, e os que falharam voltam para a Fase 4.

O insight chave: as fases 1-3 sao baratas. Levam 10-20 minutos para uma funcionalidade de porte medio. A fase 4 leva o tempo que a implementacao necessitar. A fase 5 leva 5-10 minutos. Pular as fases 1-3 nao economiza 10-20 minutos. Custa o tempo para revisar, depurar e refazer trabalho que foi na direcao errada.

Como e uma boa spec para agentes

Aqui esta um template de spec real. Nao e uma user story. Nao e um documento de requisitos de produto. E um documento de trabalho que diz a um agente exatamente o que construir.

## Problem
The filter bar resets when switching workspaces. Users lose their
filter state and have to re-apply filters every time they switch.

## Approach
Persist filter state per-workspace in localStorage. Key the stored
state by workspace database path so filters don't bleed across
workspaces.

## Files to Modify
- lib/local-storage.ts: Add getWorkspaceFilters / setWorkspaceFilters
- components/filter-bar.tsx: Read initial state from localStorage,
  write on every change
- hooks/use-workspace.ts: Trigger filter restore on workspace switch

## Acceptance Criteria
1. Select workspace A, set filters to status=open + type=bug
2. Switch to workspace B. Filters reset to defaults.
3. Switch back to workspace A. Filters restore to status=open + type=bug.
4. Close the browser tab, reopen. Filters for the active workspace
   are still applied.
5. bd list --status=open --type=bug output matches the filtered table.

## Out of Scope
- Server-side filter persistence
- Filter presets / saved filter combinations
- URL-based filter state (query params)

## Test Plan
- Unit test: getWorkspaceFilters returns stored value for matching
  workspace path
- Unit test: setWorkspaceFilters writes correct key format
- Manual test: steps 1-5 from acceptance criteria above

Note o que esta spec contem e o que nao contem. Nao explica como localStorage funciona. Claude Code sabe disso. Nao justifica por que escolhemos localStorage em vez de URL params. Isso aconteceu na fase de brainstorming. Lista cada arquivo que o agente deve tocar, o que significa que se o agente comecar a modificar arquivos fora desta lista, isso e um sinal de alerta. Inclui uma secao de fora do escopo, que impede o agente de fazer gold plating.

Os criterios de aceitacao sao a parte mais importante. Cada um e uma acao concreta com um resultado observavel. Nao "filtros devem persistir." Isso e ambiguo. "Mude para o workspace A, verifique que os filtros sao status=open + type=bug" e testavel. Um agente pode executar isso. Um revisor de QA pode verificar.

O padrao plano-antes-do-codigo

Aqui esta um protocolo que pega a maioria dos erros de implementacao antes que se tornem codigo: exigir que o agente poste seu plano de implementacao antes de escrever qualquer coisa.

Na pratica, parece um comentario estruturado na tarefa. Antes do agente abrir qualquer arquivo, ele escreve exatamente o que pretende fazer.

PLAN: Persist filter state per-workspace using localStorage.

1. Add workspace-scoped storage helpers to lib/local-storage.ts:
   - getWorkspaceFilters(dbPath: string): FilterState | null
   - setWorkspaceFilters(dbPath: string, filters: FilterState): void
   - Key format: "beadbox:filters:{dbPath}"

2. Update components/filter-bar.tsx:
   - On mount, read stored filters for current workspace
   - On every filter change, write to localStorage
   - Accept databasePath as prop (currently not passed)

3. Update hooks/use-workspace.ts:
   - On workspace switch, emit event that filter-bar listens for
   - Filter-bar reads new workspace's stored filters on event

4. Threading databasePath:
   - filter-bar needs databasePath from the workspace context
   - Will add it to the WorkspaceProvider context value

Files: lib/local-storage.ts, components/filter-bar.tsx,
       hooks/use-workspace.ts, components/workspace-provider.tsx

Test: Unit tests for storage helpers, manual test of all 5
acceptance criteria.

O agente leva cerca de 30 segundos para produzir isso. Voce leva cerca de 2 minutos para ler. E nesses 2 minutos, voce pode detectar problemas que levariam 20 minutos para corrigir apos a implementacao:

  • O agente esta tocando arquivos fora da spec? (Adicionar workspace-provider.tsx nao estava na spec. Isso esta ok ou e scope creep?)
  • A abordagem faz sentido? (Usar um event emitter para mudancas de workspace pode ser overengineering. Uma mudanca de prop mais simples pode funcionar.)
  • Faltam etapas? (E quanto a limpeza de entradas antigas no localStorage quando um workspace e removido?)

O plano e um checkpoint. Se parece correto, diga ao agente para prosseguir. Se parece errado, corrija o plano. De qualquer forma, voce investiu 2 minutos em vez de 20.

Este e o problema que o Beadbox resolve.

Visibilidade em tempo real do que toda a sua frota de agentes esta fazendo.

Experimente gratis durante o beta →

Verificacao nao e "compila"

O modo de falha mais comum que vejo com Claude Code nao e que agentes escrevam codigo ruim. E que ninguem verificou o output contra a spec.

O agente diz "DONE." O desenvolvedor olha o diff por cima, acha razoavel e faz merge. Dois dias depois alguem descobre que a funcionalidade nao trata o caso extremo #3 dos criterios de aceitacao. Agora voce esta depurando em producao em vez de ter pego no passo de verificacao de 5 minutos.

Verificacao significa checar mecanicamente cada criterio de aceitacao. Nao "parece funcionar." Nao "os testes passam" (testes podem estar errados ou incompletos). Cada criterio da spec recebe uma verificacao concreta.

Veja como um relatorio de conclusao adequado se parece:

DONE: Filter bar now persists selected filters across workspace
switches using per-workspace localStorage.

Changes:
- lib/local-storage.ts: Added getWorkspaceFilters/setWorkspaceFilters
  with key format "beadbox:filters:{dbPath}"
- components/filter-bar.tsx: Reads stored filters on mount, writes
  on change. Accepts databasePath prop.
- hooks/use-workspace.ts: Triggers filter restore on workspace switch
  via callback prop.

QA Verification:
1. Open http://localhost:41420, select workspace A
2. Set filters to status=open, type=bug
3. Switch to workspace B via header dropdown
4. Switch back to workspace A
5. Verify filters are still status=open, type=bug
   -> Confirmed: filters restore correctly
6. Close tab, reopen. Filters persist.
   -> Confirmed: localStorage key present, filters applied on mount
7. Run: bd list --status=open --type=bug
   -> Output matches filtered table contents (14 beads)

Acceptance criteria:
- [x] Filters persist across workspace switches (steps 2-5)
- [x] Filters survive browser restart (step 6)
- [x] Filtered view matches bd CLI output (step 7)
- [x] Filters don't bleed between workspaces (step 3: workspace B
      shows defaults)

Unit tests: 3 added (storage read/write/key format). All passing.

Commit: a1b2c3d

A diferenca entre isso e "DONE: Fixed the filter bar" e a diferenca entre um passe de QA de 5 minutos e uma investigacao de 30 minutos. Cada afirmacao no comentario DONE e respaldada por uma verificacao especifica. Cada criterio de aceitacao e mapeado para uma etapa de verificacao. O revisor sabe exatamente o que foi construido, como foi verificado e onde olhar se algo parecer estranho.

Beads como container de specs

O ciclo de vida que acabei de descrever precisa de um lugar para viver. A spec, o comentario do plano, a implementacao, o relatorio de conclusao, os resultados de verificacao. Tudo anexado a uma tarefa, em um unico lugar.

Este e o problema que beads resolve. Beads e um issue tracker open-source e local-first projetado para exatamente este fluxo de trabalho. Cada "bead" e uma tarefa com uma descricao (sua spec), um thread de comentarios (planos e relatorios de conclusao), um status (open, in_progress, ready_for_qa, closed) e metadados como prioridade, dependencias e atribuicoes.

Veja como o ciclo de vida orientado por specs funciona na pratica com o CLI bd:

Crie o bead com sua spec:

bd create --title "Persist filter state across workspace switches" \
  --description "## Problem
The filter bar resets when switching workspaces...

## Acceptance Criteria
1. Select workspace A, set filters...
2. Switch to workspace B..." \
  --type feature --priority p2

O agente reivindica o trabalho e posta um plano:

bd update bb-a1b2 --claim --actor eng1
bd comments add bb-a1b2 --author eng1 "PLAN: Persist filter state
per-workspace using localStorage.

1. Add workspace-scoped storage helpers...
2. Update filter-bar component...
3. ..."

O agente conclui o trabalho e posta um relatorio:

bd comments add bb-a1b2 --author eng1 "DONE: Filter bar now persists
selected filters across workspace switches.

QA Verification:
1. Open http://localhost:41420...

Acceptance criteria:
- [x] Filters persist across workspace switches
- [x] Filters survive browser restart
...

Commit: a1b2c3d"

bd update bb-a1b2 --status ready_for_qa

QA assume e verifica:

bd show bb-a1b2  # Leia a spec e o comentario DONE
# Execute as etapas de verificacao
bd comments add bb-a1b2 --author qa1 "QA PASS: All 5 acceptance
criteria verified. Filters persist, restore, and match bd CLI output."

Todo o ciclo de vida esta no bead. A spec e a descricao. O plano e um comentario. O relatorio de conclusao e um comentario. O resultado de QA e um comentario. Daqui a seis meses, se alguem perguntar "como a persistencia de filtros funciona e por que escolhemos localStorage em vez de URL params?", a resposta esta no thread de comentarios do bead.

Quando voce passa uma unica spec por este pipeline, um terminal e bd show e suficiente. Mas este fluxo de trabalho mostra seu verdadeiro valor quando voce executa multiplas specs em paralelo.

Escalando o desenvolvimento orientado por especificacoes

Imagine o cenario real: voce tem tres agentes Claude Code, cada um implementando uma spec diferente. O Agente A esta construindo uma funcionalidade de persistencia de filtros. O Agente B esta adicionando um novo endpoint de API para estatisticas de workspace. O Agente C esta corrigindo um bug de reconexao WebSocket. Cada um esta em algum ponto do ciclo de vida orientado por specs.

No terminal, voce precisaria executar bd list para ver todos os beads ativos, depois bd show em cada um para verificar o status e ler o ultimo comentario. Sao seis comandos para obter uma foto de tres fluxos de trabalho paralelos. Multiplique por cinco ou dez agentes e voce esta gastando mais tempo verificando status do que revisando planos.

Aqui e onde Beadbox se encaixa. Beadbox e um dashboard em tempo real que mostra o estado de cada bead no seu workspace. Quais specs estao abertas e esperando um agente. Quais tem planos postados que precisam da sua revisao. Quais estao em andamento. Quais estao prontas para verificacao de QA. Tudo se atualiza em tempo real enquanto agentes escrevem comentarios e mudam status atraves do CLI bd.

Voce nao precisa do Beadbox para fazer desenvolvimento orientado por specs. O CLI lida com todo o ciclo de vida. Mas quando voce esta executando multiplos fluxos de trabalho spec-driven em paralelo, poder ver o pipeline de relance em vez de consultar o status de cada agente individualmente muda a velocidade com que voce pode revisar planos, desbloquear agentes e detectar trabalho parado.

Beadbox e gratuito durante o beta, e o CLI beads sobre o qual funciona e open-source.

O que permanece verdade independente das ferramentas

Seja usando beads, GitHub Issues, Linear ou arquivos de texto simples, o padrao orientado por specs funciona porque aborda uma assimetria fundamental em como agentes operam: sao rapidos na execucao e fracos no julgamento. Cada minuto que voce gasta escrevendo uma spec clara economiza multiplos minutos revisando output incorreto, depurando suposicoes silenciosas e refazendo trabalho que foi na direcao errada.

Os principios:

  1. Defina "pronto" antes de "comecar." Criterios de aceitacao nao sao opcionais. Sao a unica coisa que torna a verificacao possivel.

  2. Planos sao checkpoints, nao burocracia. Um comentario de plano de 30 segundos economiza reescritas de 20 minutos. Revise o plano, nao o codigo.

  3. Verificacao e um protocolo, nao uma sensacao. "Parece bom para mim" nao e verificacao. Mapear cada criterio de aceitacao para uma verificacao concreta e verificacao.

  4. A spec e a unica fonte de verdade. Quando implementacao e spec discordam, a implementacao esta errada. Esta regra existe porque agentes nao questionarao um plano ruim. Vao executa-lo fielmente e produzir output fielmente incorreto.

  5. Limites de escopo previnem deriva. Uma lista explicita de arquivos a modificar e uma secao de fora do escopo impedem o agente de "melhorar" coisas que voce nao pediu para melhorar.

O investimento e pequeno: 10-20 minutos escrevendo uma spec para uma funcionalidade que leva uma hora para implementar. O retorno e grande: resultados consistentes, output revisavel e um registro permanente do que foi construido e por que.

Se voce esta construindo fluxos de trabalho como estes, de uma estrela no Beadbox no GitHub.

Like what you read?

Beadbox is a real-time dashboard for AI agent coordination. Free during the beta.

Share