Workflows

Claude Code Workflows: Subagents, Code Review en Debugging

Charles Krzentowski9 min read

Je beheerst de basis. Je CLAUDE.md zit goed, je hooks vuren betrouwbaar, je MCP-servers geven Claude directe toegang tot je tools. Maar je werkt nog steeds met één Claude tegelijk. Eén gesprek, één taak, één thread.

Wat als je er vijf tegelijk kon draaien?

Setups met expliciete workflow-patronen en agentdefinities scoren gemiddeld 7.0/10 in onze analyse. Het verschil tussen casual gebruikers en power users is niet de configuratie — het is hoe ze hun werk orkestreren. Deze handleiding behandelt de patronen die de beste resultaten opleveren.

Subagents: delegeren als een manager, niet als een micromanager

Een subagent is een aparte Claude Code sessie die een specifieke taak afhandelt. Je hoofdsessie blijft gefocust terwijl subagents in parallel aan geïsoleerde stukken werken. Zie het als taken uitdelen aan teamgenoten — ieder krijgt een helder briefing en levert een concreet resultaat op.

Wanneer subagents zinvol zijn (en wanneer niet)

Goede subagent-taken:

  • Onafhankelijke stukken die geen gedeelde context nodig hebben
  • Meerdere bestanden die wijzigingen nodig hebben maar niet van elkaar afhangen
  • Verkenningstaken (een aanpak onderzoeken) terwijl jij doorbouwt
  • Repetitief werk over vergelijkbare bestanden (10 API-routes op dezelfde manier updaten)

Slechte subagent-taken:

  • Alles wat de volledige context van je lopende gesprek vereist
  • Wijzigingen waar bestand A afhangt van wat je in bestand B besloot
  • Snelle bewerkingen die inline sneller klaar zijn

De kernvraag: als je de taak aan een collega zou kunnen geven met alleen een geschreven briefing — zonder mondeling overleg — is het een goede subagent-kandidaat.

Hoe je een subagent-taak goed afbakent

Vage subagent-taken leveren vage resultaten. "Verbeter de gebruikers-API" geeft Claude niets om op te steunen. Zo ziet een goed afgebakende taak eruit:

## Taak: Invoervalidatie toevoegen aan gebruikers-endpoints

### Te wijzigen bestanden
- src/api/users/route.ts
- src/api/users/[id]/route.ts

### Te lezen bestanden (voor context)
- src/lib/schemas.ts
- src/types/user.ts

### Vereisten
- Zod-validatie toevoegen aan alle POST/PUT request bodies
- 400 retourneren met gestructureerde foutmeldingen bij ongeldige invoer
- GET of DELETE endpoints NIET wijzigen
- Databaselaag NIET wijzigen

### Klaar wanneer
- Gewijzigde route-bestanden met validatie
- Nieuwe of bijgewerkte zod-schema's in src/lib/schemas.ts

Let op de expliciete bestandsscope, heldere vereisten en een definitie van "klaar". De subagent weet precies wat aan te raken, wat met rust te laten en wanneer te stoppen.

Het Director-patroon: parallelle subagents orkestreren

Voor grotere features kun je Claude als regisseur inzetten — het werk plannen en dan subagents voor elk stuk uitsturen:

Jij: "Ik heb een notificatiesysteem nodig. Plan het werk en gebruik subagents."

Claude (Director):
1. Planningsfase: notificatieschema, API-endpoints, UI-componenten
2. Subagent 1: Databasemigratie en Prisma-schema maken
3. Subagent 2: API-endpoints implementeren (GET /notifications, POST /mark-read)
4. Subagent 3: Notificatiebel-component en dropdown bouwen
5. Integratie: alles samenvoegen en testen

Elke subagent krijgt een afgebakende taak. De director-sessie handelt de integratie af en zorgt dat de stukken passen. Dit patroon werkt bijzonder goed omdat subagents schoon starten — zonder opgehoopt contextgewicht van een lang gesprek.

Ik gebruik dit patroon voor elk feature dat meer dan 3 bestanden raakt. Vijf parallelle terminals, elk met een subagent die één stuk afhandelt, terwijl de hoofdsessie het grote plaatje bewaakt.

Code review: de dagelijkse workflow met de meeste waarde

Code review is een van Claude Code's sterkste toepassingen — en een van de minst benutte. In plaats van je eigen code te reviewen (die je brein automatisch als correct rationaliseert) of op een collega te wachten, vindt Claude problemen in seconden.

De Fix-First methode

De meeste review-tools geven je een lijst problemen. Daarna moet je elk handmatig oplossen. Dat is omslachtig.

De Fix-First methode: Claude lost mechanische problemen direct op en vraagt je alleen over de dubbelzinnige:

## Hoe code reviewen (zet dit in een skill of CLAUDE.md)

1. Eerst het VOLLEDIGE diff lezen — de complete wijziging begrijpen
2. Mechanische problemen AUTO-FIXEN:
   - Ontbrekende foutafhandeling → try/catch toevoegen
   - Duidelijke typefouten → type corrigeren
   - Stijlschendingen → oplossen
3. Dubbelzinnige beslissingen in ÉÉN vraag bundelen:
   - "Ik vond 3 ontwerpbeslissingen om te bevestigen: [A], [B], [C]"
4. Nooit issues markeren die al in het diff zijn opgelost
5. Uitvoer: KRITIEK (moet opgelost) en INFORMATIEF (overweeg verbetering)

Je wilt geen lijst van 15 muggenzifterijen als er 12 automatisch opgelost hadden kunnen worden. De Fix-First methode respecteert je tijd.

Pre-commit review in de praktijk

Stel een shell-alias in voor dagelijks gebruik:

alias ccreview='claude -p "Review de staged wijzigingen (git diff --staged). Fix mechanische problemen. Markeer kritieke zaken."'

Of als skill met meer mogelijkheden:

<!-- .claude/skills/pre-commit-review.md -->
---
name: pre-commit-review
description: Staged wijzigingen reviewen voor commit
---

1. `git diff --staged` uitvoeren
2. Per bestand:
   - Foutafhandeling: async operaties in try/catch?
   - Beveiliging: hardcoded secrets, SQL-injectie, XSS?
   - Types: `any` dat specifiek moet zijn?
   - Tests: hebben gewijzigde functies test-updates?
3. Mechanische problemen AUTO-FIXEN
4. KRITIEK (blokkeer commit) en INFORMATIEF rapporteren
5. Als geen kritieke issues: commit-bericht voorstellen

Typ /pre-commit-review voor elke commit. Claude controleert je werk, fixt de kleine dingen en markeert de echte problemen. Het duurt 15 seconden en vangt zaken op die je vrijdag om 18:00 zou missen.

Test-Driven Development: schrijf de spec, laat Claude implementeren

TDD met Claude Code werkt anders dan TDD in je eentje. Jij beschrijft wat een functie moet doen. Claude schrijft de test. Jij verifieert dat de test je bedoeling vastlegt. Dan schrijft Claude de code die de test doet slagen.

Het werkt omdat een test een ondubbelzinnige specificatie is. Als je een feature in woorden beschrijft, kan Claude het anders interpreteren dan bedoeld. Als je het als test uitdrukt, is het verwachte gedrag expliciet — invoer, uitvoer, randgevallen.

De cyclus

1. Jij beschrijft wat de functie moet doen
2. Claude schrijft de test
3. Jij verifieert dat de test je bedoeling vastlegt
4. Claude schrijft de implementatie die de test doet slagen
5. Claude voert de test uit om te bevestigen
6. Herhaal

Een concreet voorbeeld: een rate limiter bouwen

Jij: "Ik heb een rate limiter nodig. 100 requests per minuut per IP. Retourneer
429 wanneer overschreden, inclusief Retry-After header. Schrijf eerst de test."

Claude schrijft:

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);
  });
});

Je leest de test. Vier scenario's: onder de limiet, boven de limiet, window-reset, IP-isolatie. Ziet er goed uit. Je geeft Claude groen licht, en het schrijft de implementatie die alle vier de tests haalt. De test fungeerde als contract waar jullie het over eens waren voordat er één regel productiecode geschreven werd.

Debugging: de systematische aanpak die echt werkt

Debugging met Claude is krachtig, maar het kan rondjes draaien als je het laat gaan. Claude houdt meer context vast en onderzoekt meer hypothesen dan jij — maar het heeft structuur nodig om niet te ontsporen.

De 7-stappen debugging-workflow

Zet dit in je CLAUDE.md of een debugging-skill:

Bij debugging:
1. REPRODUCEREN — het falende geval uitvoeren, exacte fout vastleggen
2. HYPOTHESEN — 3 mogelijke oorzaken opsommen, op waarschijnlijkheid gerangschikt
3. ONDERZOEKEN — de meest waarschijnlijke oorzaak eerst controleren
4. LOGGEN — logging toevoegen op elke async-grens als je niet kunt zien waar de uitvoering stopt
5. IDENTIFICEREN — de exacte regel of functie lokaliseren
6. OPLOSSEN — de minimale fix toepassen
7. VERIFIËREN — het oorspronkelijke falende geval uitvoeren om de fix te bevestigen

De cruciale regel: sla stap 7 nooit over. Onze data toont dat 40% van de debugging-sessies die misgaan, dit doen omdat een fix geclaimd maar nooit geverifieerd werd. "Zou nu moeten werken" is geen bewijs. Draai het.

De drie-pogingen-regel

Dit patroon scheidt productief debuggen van tijdverspilling:

Als Claude na drie pogingen de oorzaak niet heeft gevonden, stop. Laat het niet blijven gokken — steeds wildere hypothesen maken het probleem moeilijker te diagnosticeren. Kies in plaats daarvan een van drie paden:

Optie A: Nieuwe hypothese. Volledig terugstappen. Het probleem helemaal opnieuw bekijken.

Optie B: Menselijke review. Claude laat je alles zien wat het tot nu toe heeft gevonden, en jij voegt context toe.

Optie C: Instrumenteren en wachten. Uitgebreide logging toevoegen en het probleem reproduceren. De logs vertellen je waar de uitvoering stopt in plaats van te gokken.

Bij twijfel: eerst logging toevoegen

De meest productieve debugging-sessies beginnen met het opzetten van observability voordat er iets gefixt wordt:

// Voor: stille fouten — geen idee waar het breekt
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' } });
}

// Na: elke stap is zichtbaar
async function processOrder(orderId: string) {
  console.log('[processOrder] start', { orderId });

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

  if (!order) {
    console.error('[processOrder] order niet gevonden', { orderId });
    throw new Error(`Order ${orderId} not found`);
  }

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

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

Wanneer iets hangt of faalt, vertelt de laatste logregel je precies waar de uitvoering stopte. Deze techniek bespaart meer debugging-tijd dan welke slimme analyse ook.

Prompting-patronen die betere resultaten opleveren

Hoe je instructies formuleert, maakt meer verschil dan je denkt. Dit zijn de patronen die consequent betere code produceren.

Definieer hoe "klaar" eruitziet

Slecht: "Verbeter de authenticatie."

Goed: "Voeg rate limiting toe aan het login-endpoint. 5 pogingen per email per 15 minuten. Retourneer 429 met Retry-After header. Schrijf tests voor de limiet en de reset. Wijzig het registratie-endpoint niet."

De tweede prompt heeft geen dubbelzinnigheid. Claude kan het uitvoeren zonder een enkele verduidelijkingsvraag.

Benoem beperkingen expliciet

- Wijzig GEEN bestanden in src/legacy/ — die code is bevroren
- De build moet slagen met Node 18 (geen Node 20+ APIs)
- Houd de bundle-grootte onder 200KB — controleer met `npm run analyze`

Vraag een plan bij 3+ bestanden

Plan hoe je een caching-laag voor API-responses zou implementeren. Laat me zien:
1. Welke bestanden je zou aanmaken of wijzigen
2. De cache-invalidatiestrategie
3. Hoe het integreert met de bestaande middleware

Schrijf nog geen code. Alleen het plan.

Review het plan, pas het aan, laat Claude dan uitvoeren. Dit vangt structurele fouten op voordat ze zich verspreiden over meerdere bestanden. Een plan wijzigen kost niets. Een half geïmplementeerde verkeerde aanpak ongedaan maken kost uren.

Hoe alles samenkomt

Je setup geeft Claude projectkennis. Je automatisering handhaaft standaarden. Je integraties geven Claude toegang tot je infrastructuur. Workflows bepalen hoe Claude dagelijks opereert.

Begin met pre-commit review — dat is de gemakkelijkste winst en degene die je elke dag zult gebruiken. Probeer daarna subagents de volgende keer dat je een feature hebt dat 4+ bestanden raakt. Beoordeel je setup om te zien waar je workflow-orkestratie staat.

Veelgestelde vragen

Hoeveel subagents kunnen tegelijk draaien?

Dat hangt af van je machine (RAM, CPU) en API-limieten. Op een typische ontwikkelmachine werken 3-5 gelijktijdige subagents goed. Elke subagent is een aparte sessie die tokens verbruikt, dus houd je gebruik in de gaten als je per API betaalt.

Moet ik voor alles subagents gebruiken?

Nee. Ze voegen overhead toe — contextwisseling, sessie-aanmaak, en het risico dat een subagent context mist die de hoofdsessie wel heeft. Een goede test: als je de taak aan een collega zou kunnen geven met alleen een geschreven briefing (geen mondeling overleg nodig), is het een subagent-kandidaat. Als je 10 minuten uitleg nodig zou hebben, houd het dan in de hoofdsessie.

Wat doe ik als Claudes fix niet werkt?

Zorg er eerst voor dat Claude de fix daadwerkelijk heeft geverifieerd door de falende test te draaien. Als de fix echt niet werkt, laat Claude niet dezelfde aanpak opnieuw proberen. Zeg "die aanpak werkte niet — stel een andere oorzaak voor." Na drie mislukte pogingen: escaleren met een nieuwe hypothese, menselijke review, of logging toevoegen en data verzamelen.

Kan Claude Code pair programming doen?

Ja, en het werkt het best met een specifieke verdeling: jij stuurt de architectuurbeslissingen, Claude handelt de implementatie af. Beschrijf op hoog niveau wat je wilt, laat Claude de code voorstellen, review, itereer. Het anti-patroon is Claude architectuurbeslissingen laten nemen zonder jouw input — die stapelen op, en tegen de tijd dat je een verkeerde afslag opmerkt, heeft Claude drie lagen erbovenop gebouwd.

Hoe pak ik grote refactorings aan?

Opsplitsen in fasen, één subagent per fase. Fase 1: "Hernoem alle voorkomens van OldService naar NewService." Fase 2: "Werk alle callers bij naar de nieuwe API-signatuur." Fase 3: "Verwijder verouderde methoden en werk tests bij." Elke fase is afgebakend en testbaar. De hoofdsessie volgt de voortgang en handelt de integratie tussen fasen af.

FAQ

Hoeveel subagents kunnen tegelijk draaien?
Dat hangt af van je machine (RAM, CPU) en API-limieten. Op een typische ontwikkelmachine werken 3-5 gelijktijdige subagents goed. Elke subagent is een aparte sessie die tokens verbruikt, dus houd je gebruik in de gaten als je per API betaalt.
Moet ik voor alles subagents gebruiken?
Nee. Ze voegen overhead toe — contextwisseling, sessie-aanmaak, en het risico dat een subagent context mist die de hoofdsessie wel heeft. Een goede test: als je de taak aan een collega zou kunnen geven met alleen een geschreven briefing (geen mondeling overleg nodig), is het een subagent-kandidaat. Als je 10 minuten uitleg nodig zou hebben, houd het dan in de hoofdsessie.
Wat doe ik als Claudes fix niet werkt?
Zorg er eerst voor dat Claude de fix daadwerkelijk heeft geverifieerd door de falende test te draaien. Als de fix echt niet werkt, laat Claude niet dezelfde aanpak opnieuw proberen. Zeg "die aanpak werkte niet — stel een andere oorzaak voor." Na drie mislukte pogingen: escaleren met een nieuwe hypothese, menselijke review, of logging toevoegen en data verzamelen.
Kan Claude Code pair programming doen?
Ja, en het werkt het best met een specifieke verdeling: jij stuurt de architectuurbeslissingen, Claude handelt de implementatie af. Beschrijf op hoog niveau wat je wilt, laat Claude de code voorstellen, review, itereer. Het anti-patroon is Claude architectuurbeslissingen laten nemen zonder jouw input — die stapelen op, en tegen de tijd dat je een verkeerde afslag opmerkt, heeft Claude drie lagen erbovenop gebouwd.
Hoe pak ik grote refactorings aan?
Opsplitsen in fasen, één subagent per fase. Fase 1: "Hernoem alle voorkomens van OldService naar NewService." Fase 2: "Werk alle callers bij naar de nieuwe API-signatuur." Fase 3: "Verwijder verouderde methoden en werk tests bij." Elke fase is afgebakend en testbaar. De hoofdsessie volgt de voortgang en handelt de integratie tussen fasen af.