Fluxos de trabalho

Workflows do Claude Code: Subagents, Revisão de Código e Depuração

Charles Krzentowski10 min read

Já domina o básico. O seu CLAUDE.md está afinado, os hooks disparam sem falhar, os servidores MCP dão ao Claude acesso direto às suas ferramentas. Mas continua a trabalhar com um Claude de cada vez. Uma conversa, uma tarefa, um thread de execução.

E se pudesse correr cinco?

Os setups com padrões de workflow explícitos e definições de agentes alcançam 7.0/10 em média na nossa análise. A diferença entre utilizadores ocasionais e power users não é a configuração — é a forma como orquestram o trabalho. Este guia cobre os padrões que produzem os melhores resultados.

Subagents: delegar como um gestor, não como um micro-gestor

Um subagent é uma sessão separada do Claude Code que trata de uma tarefa específica. A sua sessão principal mantém-se focada enquanto os subagents trabalham em peças isoladas em paralelo. Pense nisso como distribuir tarefas a colegas de equipa — cada um recebe um briefing claro e entrega um resultado concreto.

Quando os subagents fazem sentido (e quando não)

Boas tarefas para subagents:

  • Peças independentes que não precisam de contexto partilhado
  • Múltiplos ficheiros que precisam de alterações mas não dependem uns dos outros
  • Tarefas de exploração (investigar uma abordagem) enquanto continua a construir
  • Trabalho repetitivo em ficheiros semelhantes (atualizar 10 rotas API da mesma forma)

Más tarefas para subagents:

  • Qualquer coisa que requeira o contexto completo da sua conversa atual
  • Alterações onde o ficheiro A depende do que decidiu no ficheiro B
  • Edições rápidas que são mais rápidas inline

A pergunta-chave: se pudesse dar a tarefa a um colega com apenas um briefing escrito — sem contexto verbal — é um bom candidato a subagent.

Como delimitar bem uma tarefa de subagent

Tarefas vagas produzem resultados vagos. "Melhora a API de utilizadores" não dá ao Claude nada a que se agarrar. Uma tarefa bem delimitada tem este aspeto:

## Tarefa: Adicionar validação de entrada aos endpoints de utilizador

### Ficheiros a modificar
- src/api/users/route.ts
- src/api/users/[id]/route.ts

### Ficheiros a ler (para contexto)
- src/lib/schemas.ts
- src/types/user.ts

### Requisitos
- Adicionar validação zod a todos os corpos de request POST/PUT
- Retornar 400 com mensagens de erro estruturadas para entradas inválidas
- NÃO modificar endpoints GET ou DELETE
- NÃO alterar a camada de base de dados

### Concluído quando
- Ficheiros de rotas modificados com validação
- Esquemas zod novos ou atualizados em src/lib/schemas.ts

Repare no scope explícito de ficheiros, requisitos claros e definição de "concluído". O subagent sabe exatamente o que tocar, o que deixar em paz e quando parar.

O padrão Director: executar subagents em paralelo

Para features maiores, pode usar o Claude como realizador — planear o trabalho e depois despachar subagents para cada peça:

Você: "Preciso de um sistema de notificações. Planeia o trabalho e usa subagents."

Claude (Director):
1. Fase de planeamento: esquema de notificação, endpoints API, componentes UI
2. Subagent 1: Criar migração de BD e esquema Prisma
3. Subagent 2: Implementar endpoints API (GET /notifications, POST /mark-read)
4. Subagent 3: Construir o componente de sino de notificação e dropdown
5. Integração: juntar tudo e testar

Cada subagent recebe uma tarefa delimitada. A sessão director trata da integração e assegura que as peças encaixam. Este padrão funciona particularmente bem porque os subagents começam limpos — sem peso de contexto acumulado de uma conversa longa.

Uso este padrão para qualquer feature que toque mais de 3 ficheiros. Cinco terminais em paralelo, cada um com um subagent a tratar de uma peça, enquanto a sessão principal guarda a visão geral.

Revisão de código: o workflow diário de maior valor

A revisão de código é um dos usos mais fortes do Claude Code — e um dos menos aproveitados. Em vez de rever o seu próprio código (que o seu cérebro racionaliza automaticamente como correto) ou esperar por um colega, o Claude encontra problemas em segundos.

O método Fix-First

A maioria das ferramentas de revisão dá-lhe uma lista de problemas. Depois tem de corrigir cada um manualmente. Isso é ao contrário.

O método Fix-First: o Claude corrige problemas mecânicos diretamente e só lhe pergunta sobre os ambíguos:

## Como rever código (ponha isto num skill ou CLAUDE.md)

1. Ler o diff COMPLETO primeiro — compreender a alteração inteira
2. AUTO-CORRIGIR problemas mecânicos:
   - Tratamento de erros em falta → adicionar try/catch
   - Erros de tipos óbvios → corrigir o tipo
   - Violações de estilo → corrigir
3. Agrupar decisões ambíguas numa ÚNICA pergunta:
   - "Encontrei 3 decisões de design a confirmar: [A], [B], [C]"
4. Nunca assinalar issues já resolvidas no diff
5. Saída: CRÍTICO (tem de corrigir) e INFORMATIVO (vale considerar)

Não quer uma lista de 15 picuinhices quando 12 podiam ter sido auto-corrigidas. O método Fix-First respeita o seu tempo.

Revisão pré-commit na prática

Configure um alias de shell para uso diário:

alias ccreview='claude -p "Revê as alterações staged (git diff --staged). Corrige problemas mecânicos. Assinala o que for crítico."'

Ou como um skill com mais funcionalidade:

<!-- .claude/skills/pre-commit-review.md -->
---
name: pre-commit-review
description: Rever alterações staged antes de commit
---

1. Executar `git diff --staged`
2. Para cada ficheiro:
   - Tratamento de erros: operações async em try/catch?
   - Segurança: secrets hardcoded, injeção SQL, XSS?
   - Tipos: `any` que devia ser específico?
   - Testes: funções modificadas têm atualizações de testes?
3. AUTO-CORRIGIR problemas mecânicos
4. Reportar CRÍTICO (bloqueia commit) e INFORMATIVO
5. Se nada crítico: sugerir mensagem de commit

Escreva /pre-commit-review antes de cada commit. O Claude verifica o seu trabalho, corrige as coisas pequenas e assinala os problemas reais. Demora 15 segundos e apanha coisas que passaria por cima numa sexta às 18h.

Test-Driven Development: escreva a spec, deixe o Claude implementar

O TDD com Claude Code funciona de forma diferente do TDD a solo. Você descreve o que uma função deve fazer. O Claude escreve o teste. Você verifica se o teste captura a sua intenção. Depois o Claude escreve o código que o passa.

Funciona porque um teste é uma especificação inequívoca. Quando descreve uma funcionalidade em palavras, o Claude pode interpretá-la de forma diferente da que pretendia. Quando a expressa como teste, o comportamento esperado é explícito — entradas, saídas, casos-limite.

O ciclo

1. Você descreve o que a função deve fazer
2. Claude escreve o teste
3. Você verifica que o teste captura a sua intenção
4. Claude escreve a implementação que passa o teste
5. Claude executa o teste para confirmar
6. Repetir

Um exemplo concreto: construir um rate limiter

Você: "Preciso de um rate limiter. 100 requests por minuto por IP. Retornar
429 quando excedido, incluir header Retry-After. Escreve o teste primeiro."

O Claude escreve:

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { createRateLimiter } from './rate-limiter';

describe('Rate Limiter', () => {
  beforeEach(() => {
    vi.useFakeTimers();
  });

  it('should allow requests under the limit', () => {
    const limiter = createRateLimiter({ maxRequests: 100, windowMs: 60000 });
    const result = limiter.check('192.168.1.1');
    expect(result.allowed).toBe(true);
    expect(result.remaining).toBe(99);
  });

  it('should block requests over the limit', () => {
    const limiter = createRateLimiter({ maxRequests: 2, windowMs: 60000 });
    limiter.check('192.168.1.1');
    limiter.check('192.168.1.1');
    const result = limiter.check('192.168.1.1');
    expect(result.allowed).toBe(false);
    expect(result.retryAfter).toBeGreaterThan(0);
  });

  it('should reset after the window expires', () => {
    const limiter = createRateLimiter({ maxRequests: 1, windowMs: 60000 });
    limiter.check('192.168.1.1');
    vi.advanceTimersByTime(61000);
    const result = limiter.check('192.168.1.1');
    expect(result.allowed).toBe(true);
  });

  it('should track IPs independently', () => {
    const limiter = createRateLimiter({ maxRequests: 1, windowMs: 60000 });
    limiter.check('192.168.1.1');
    const result = limiter.check('192.168.1.2');
    expect(result.allowed).toBe(true);
  });
});

Lê o teste. Quatro cenários: abaixo do limite, acima do limite, reset da janela, isolamento por IP. Parece correto. Dá luz verde ao Claude, e ele escreve a implementação que passa nos quatro testes. O teste serviu como contrato que ambos concordaram antes de se escrever uma linha de código de produção.

Depuração: a abordagem sistemática que realmente funciona

Depurar com o Claude é poderoso, mas pode andar em círculos se o deixar. O Claude mantém mais contexto e explora mais hipóteses do que você — mas precisa de estrutura para não derrapar.

O workflow de depuração de 7 passos

Ponha isto no seu CLAUDE.md ou num skill de depuração:

Ao depurar:
1. REPRODUZIR — executar o caso que falha, capturar o erro exato
2. HIPÓTESES — listar 3 possíveis causas, ordenadas por probabilidade
3. INVESTIGAR — verificar a causa mais provável primeiro
4. REGISTAR — adicionar logging em cada fronteira async se não conseguir ver onde a execução para
5. IDENTIFICAR — localizar a linha ou função exata
6. CORRIGIR — aplicar a correção mínima
7. VERIFICAR — executar o caso que falhava para confirmar que a correção funciona

A regra crítica: nunca saltar o passo 7. Os nossos dados mostram que 40% das sessões de depuração que correm mal fazem-no porque uma correção foi anunciada mas nunca verificada. "Deveria funcionar agora" não é prova. Execute.

A regra das três tentativas

Este padrão separa depuração produtiva de desperdício de tempo:

Se o Claude não encontrou a causa raiz após três tentativas, pare. Não o deixe continuar a adivinhar — hipóteses cada vez mais rebuscadas tornam o problema mais difícil de diagnosticar. Em vez disso, escolha um de três caminhos:

Opção A: Nova hipótese. Recuar completamente. Reformular o problema do zero.

Opção B: Revisão humana. O Claude mostra-lhe tudo o que encontrou e você acrescenta contexto.

Opção C: Instrumentar e esperar. Adicionar logging abrangente e reproduzir o problema. Deixar os logs dizerem-lhe onde a execução para em vez de adivinhar.

Na dúvida: primeiro adicionar logging

As sessões de depuração mais produtivas começam por estabelecer observabilidade antes de tentar corrigir o que quer que seja:

// Antes: falhas silenciosas — sem ideia de onde parte
async function processOrder(orderId: string) {
  const order = await db.orders.findUnique({ where: { id: orderId } });
  const payment = await chargePayment(order.amount);
  await db.orders.update({ where: { id: orderId }, data: { status: 'paid' } });
}

// Depois: cada passo é visível
async function processOrder(orderId: string) {
  console.log('[processOrder] início', { orderId });

  const order = await db.orders.findUnique({ where: { id: orderId } });
  console.log('[processOrder] pedido carregado', { found: !!order, amount: order?.amount });

  if (!order) {
    console.error('[processOrder] pedido não encontrado', { orderId });
    throw new Error(`Order ${orderId} not found`);
  }

  const payment = await chargePayment(order.amount);
  console.log('[processOrder] resultado pagamento', { paymentId: payment.id, status: payment.status });

  await db.orders.update({ where: { id: orderId }, data: { status: 'paid' } });
  console.log('[processOrder] concluído', { orderId });
}

Quando algo fica pendurado ou falha, a última linha de log diz-lhe exatamente onde a execução parou. Esta técnica poupa mais tempo de depuração do que qualquer análise elaborada.

Padrões de prompting que dão melhores resultados

A forma como formula instruções importa mais do que pensa. Estes são os padrões que consistentemente produzem melhor código.

Defina como é "concluído"

Mau: "Melhora a autenticação."

Bom: "Adiciona rate limiting ao endpoint de login. 5 tentativas por email a cada 15 minutos. Retorna 429 com header Retry-After. Escreve testes para o limite e o reset. Não toques no endpoint de registo."

O segundo prompt não tem ambiguidade. O Claude pode executá-lo sem fazer uma única pergunta de esclarecimento.

Declare restrições explicitamente

- NÃO modificar ficheiros em src/legacy/ — esse código está congelado
- O build tem de passar com Node 18 (nada de APIs Node 20+)
- Manter o tamanho do bundle abaixo de 200KB — verificar com `npm run analyze`

Peça um plano para qualquer coisa que toque 3+ ficheiros

Planeia como implementarias uma camada de cache para respostas API. Mostra-me:
1. Que ficheiros criarias ou modificarias
2. A estratégia de invalidação de cache
3. Como se integra com o middleware existente

Não escrevas código ainda. Apenas o plano.

Reveja o plano, ajuste-o, depois deixe o Claude executar. Isto apanha erros estruturais antes de se propagarem por múltiplos ficheiros. Mudar um plano não custa nada. Desfazer uma abordagem errada meio implementada custa horas.

Como tudo se liga

O seu setup dá ao Claude conhecimento do projeto. A sua automatização aplica padrões. As suas integrações dão ao Claude acesso à infraestrutura. Os workflows determinam como o Claude opera no dia-a-dia.

Comece pela revisão pré-commit — é a vitória mais fácil e a que vai usar todos os dias. Depois experimente subagents na próxima vez que tiver um feature que toque 4+ ficheiros. Analise o seu setup para ver onde está a sua orquestração de workflows.

Perguntas frequentes

Quantos subagents podem correr ao mesmo tempo?

Depende da sua máquina (RAM, CPU) e limites de taxa da API. Numa máquina de desenvolvimento típica, 3-5 subagents concorrentes funcionam bem. Cada um é uma sessão separada que consome tokens, por isso fique atento ao seu consumo se pagar por API.

Devo usar subagents para tudo?

Não. Acrescentam overhead — mudança de contexto, criação de sessão, e o risco de um subagent perder contexto que a sessão principal tem. Um bom teste: se pudesse dar a tarefa a um colega com apenas um briefing escrito (sem explicação verbal necessária), é candidato a subagent. Se precisasse de uma conversa de 10 minutos para explicar o contexto, mantenha na sessão principal.

O que faço quando a correção do Claude não funciona?

Primeiro, certifique-se de que o Claude realmente verificou a correção executando o teste que falhava. Se genuinamente não funciona, não deixe o Claude tentar a mesma abordagem outra vez. Diga "essa abordagem não funcionou — propõe uma causa raiz diferente." Após três tentativas falhadas, escale: nova hipótese, revisão humana, ou adicionar logging e recolher dados.

O Claude Code consegue fazer pair programming?

Sim, e funciona melhor com uma divisão específica: você conduz as decisões de arquitetura, o Claude trata da implementação. Descreva o que quer a alto nível, deixe o Claude propor o código, reveja, itere. O anti-padrão é deixar o Claude tomar decisões de arquitetura sem o seu input — essas acumulam-se, e quando nota uma viragem errada, o Claude já construiu três camadas por cima.

Como lido com grandes refactorings?

Divida em fases, um subagent por fase. Fase 1: "Renomear todas as ocorrências de OldService para NewService." Fase 2: "Atualizar todos os chamadores para a nova assinatura de API." Fase 3: "Remover métodos depreciados e atualizar testes." Cada fase é delimitada e testável. A sessão principal acompanha o progresso e trata da integração entre fases.

FAQ

Quantos subagents podem correr ao mesmo tempo?
Depende da sua máquina (RAM, CPU) e limites de taxa da API. Numa máquina de desenvolvimento típica, 3-5 subagents concorrentes funcionam bem. Cada um é uma sessão separada que consome tokens, por isso fique atento ao seu consumo se pagar por API.
Devo usar subagents para tudo?
Não. Acrescentam overhead — mudança de contexto, criação de sessão, e o risco de um subagent perder contexto que a sessão principal tem. Um bom teste: se pudesse dar a tarefa a um colega com apenas um briefing escrito (sem explicação verbal necessária), é candidato a subagent. Se precisasse de uma conversa de 10 minutos para explicar o contexto, mantenha na sessão principal.
O que faço quando a correção do Claude não funciona?
Primeiro, certifique-se de que o Claude realmente verificou a correção executando o teste que falhava. Se genuinamente não funciona, não deixe o Claude tentar a mesma abordagem outra vez. Diga "essa abordagem não funcionou — propõe uma causa raiz diferente." Após três tentativas falhadas, escale: nova hipótese, revisão humana, ou adicionar logging e recolher dados.
O Claude Code consegue fazer pair programming?
Sim, e funciona melhor com uma divisão específica: você conduz as decisões de arquitetura, o Claude trata da implementação. Descreva o que quer a alto nível, deixe o Claude propor o código, reveja, itere. O anti-padrão é deixar o Claude tomar decisões de arquitetura sem o seu input — essas acumulam-se, e quando nota uma viragem errada, o Claude já construiu três camadas por cima.
Como lido com grandes refactorings?
Divida em fases, um subagent por fase. Fase 1: "Renomear todas as ocorrências de OldService para NewService." Fase 2: "Atualizar todos os chamadores para a nova assinatura de API." Fase 3: "Remover métodos depreciados e atualizar testes." Cada fase é delimitada e testável. A sessão principal acompanha o progresso e trata da integração entre fases.