Gebruik een Claude Code greenfield-workflow om structuur, scripts en een eerste vertical slice in te richten die je kunt draaien, testen en week na week verbeteren.

Beginnen met een lege repo voelt als vrijheid, maar verandert vaak in rommelige vaart: veel gegenereerde bestanden, een halfwerkende build en geen duidelijke plek voor de volgende wijziging. Het doel van een Claude Code greenfield-workflow is die chaos van de eerste week te vermijden.
Enkele mislukking die steeds terugkomen:
Vroege beslissingen zijn pijnlijk om terug te draaien omdat alles erop stapelt. Een verwarrende structuur wordt steeds versterkt. Een handmatige build verandert in tien verschillende setups. Als je niet vroeg een simpel dev-commando vastlegt, kun je niet zeggen of een wijziging de app kapot maakte of alleen de omgeving.
Als in dit artikel staat “draaiende app”, bedoelen we iets specifieks: één commando dat het project start, voorspelbare output print en hard faalt wanneer iets ontbreekt. Je moet je lokale installatie kunnen verwijderen, de repo klonen, dat commando uitvoeren en hetzelfde resultaat zien.
Een “vertical slice” is de kleinste end-to-end feature die bewijst dat je app echt is. Geen UI-mock. Niet alleen een databasetabel. Het is één dunne lijn door het hele systeem, zoals een pagina met een formulier, één API-endpoint dat data opslaat, één database-write en read, en één zichtbaar resultaat terug op de pagina.
Als je de app met één commando kunt draaien en één vertical slice kunt opleveren, heb je een basis waarop je kunt itereren zonder te gokken.
Een duidelijke eerste slice houdt je repo netjes en je prompts gefocust. Dit is het moment om te beslissen wat je end-to-end wilt demonstreren, niet wat je hoopt dat het volledige product wordt.
Kies het kleinste gebruikersverhaal dat bewijst dat de app over het hele pad werkt. Een goede slice raakt UI, data en één echte actie. Voorbeeld: “Als gebruiker kan ik een taak toevoegen en deze na refresh in een lijst zien.” Het is klein, maar dwingt routing, validatie, opslag en een basis scherm af.
Kies één doelplatform voor week 1 en houd je daaraan. Als je web begint, doe dan alleen web. Voeg geen mobiele schermen toe “voor het geval”. Zelfs als je later een platform zoals Koder.ai wilt gebruiken, krijg je betere resultaten als de eerste slice in één spoor blijft (React web, of een Go API, of Flutter).
Definieer wat “klaar voor week 1” in gewone termen betekent:
Schrijf daarna drie non-goals op die de scope beschermen. Bijvoorbeeld: geen auth, geen thema-systeem, geen achtergrondtaken.
Als die beslissingen zijn opgeschreven, kan je generatie-prompt strikt zijn: bouw alleen wat de slice ondersteunt en laat de rest als TODO achter.
Voordat je Claude vraagt iets te genereren, leg je een paar standaarden vast. Ze lijken klein, maar voorkomen het “alles later hernoemen”-probleem.
Bepaal eerst de vorm van de app. Als je echt een browser-UI en een backend nodig hebt, begin dan met twee duidelijke delen (frontend + API) en een gedeelde plek voor contracten (API-types of een eenvoudige schema). Als de app een server-rendered webapp kan zijn, houd het in één codebase zodat lokaal ontwikkelen simpel blijft.
Stem vervolgens af op configuratieregels. Gebruik een lokaal env-bestand, houd het uit git en commit een template (bijv. .env.example) met veilige placeholders en korte commentaren. Dat maakt onboarding makkelijker en vermindert lekken van secrets.
Kies standaard dev-ports en houd ze stabiel. Poorten belanden in scripts, docs en foutmeldingen, dus ze later veranderen is vervelend. Doe hetzelfde voor namen: mappen, services en pakketten moeten één conventie volgen. Consistentie is belangrijker dan de “perfecte” conventie.
Een eenvoudige set beslissingen om mee te starten:
.env lokaal, .env.example gecommitVoorbeeld: je kiest web op poort 3000 en api op poort 8080. Je env-template bevat API_URL=http://localhost:8080 en DATABASE_URL=.... Wanneer Claude later scripts en docs genereert, valt alles op zijn plek in plaats van te drijven.
Begin door te vragen om een uitvoerbare scaffold, niet “de hele app.” De snelste weg naar rommelige output is vragen om features voordat je een plek hebt om ze te plaatsen.
Wees expliciet over structuur. Vraag om een mappenlayout met korte commentaren die uitleggen wat waar hoort en wat niet. Dat dwingt beslissingen naar voren in plaats van bestanden overal te verspreiden.
Een simpele manier om het gedisciplineerd te houden is regels in de prompt te zetten:
Hier is een prompt die je kunt hergebruiken en aanpassen:
You are working in an empty repo. Create a minimal runnable skeleton.
Constraints:
- Keep it small: no real features yet.
- Propose a clear folder structure and add brief comments in each folder’s README.
- Add scripts for: setup, dev, test, build. They must work on a fresh machine.
- Tell me exactly how to run it, and what output I should see.
- After generating, stop and wait for my “ran it” confirmation.
Output:
1) File tree
2) Key files (only)
3) Run instructions
Houd de lus strak. Vraag niet om vijf wijzigingen tegelijk. Genereer één kleine wijziging, voer het uit, plak de exacte fout (of succes), en vraag dan om een minimale fix. Die generate-run-adjust-ritme houdt het project voorspelbaar en maakt het moeilijker dat de structuur afdrijft.
Begin met één belofte: iedereen kan de repo clonen en één commando uitvoeren om iets werkends te zien. Dat geeft je een stabiele basis voordat je een AI vraagt echte features toe te voegen.
Maak de repo aan en schrijf een kleine README terwijl alles vers is. Houd het praktisch: prerequisites, het ene dev-commando en hoe tests uit te voeren (ook als tests voorlopig leeg zijn).
Kies daarna een top-level layout die overeenkomt met de vorm die je koos.
Als je meerdere deploybare onderdelen bouwt (bijv. frontend + API) kan een workspace-structuur helpen:
/
apps/
packages/
scripts/
docs/
README.md
Als je één enkele app bouwt, houd het eenvoudiger en vermijd extra niveaus totdat je ze nodig hebt.
Voeg nu de minimale guardrails toe zodat code consistent blijft. Kies één formatter en één linter, accepteer hun defaults en voeg één configbestand voor elk toe. Het doel is schone diffs, niet perfecte regels op dag één.
Maak de developer experience voorspelbaar met één commando dat altijd werkt vanuit de repo-root. Hier is een eenvoudig voorbeeld:
{
"scripts": {
"dev": "echo \"start dev server here\"",
"build": "echo \"build here\"",
"test": "echo \"tests here\"",
"lint": "echo \"lint here\""
}
}
Voordat je iets anders genereert, voer dat dev-commando uit, bevestig dat het netjes afsluit (of een placeholder-server opstart), en maak je eerste commit met alleen scaffolding. Als een teamgenoot (of jijzelf later) de setup van nul kan reproduceren, ben je klaar om de eerste slice te bouwen.
Een goede greenfield-structuur doet twee dingen: het helpt je code snel te vinden en geeft Claude minder ruimte om elke keer nieuwe patronen te verzinnen als je om een wijziging vraagt. Het doel is niet perfectie. Het is stabiliteit.
Als je binnen één app werkt (of binnen een apps/<name>/-map), houdt een eenvoudige interne layout zich meestal goed:
src/ app-code (features, gedeelde onderdelen, entry points)config/ niet-geheime configuratietests/ hogere-level tests die lezen als gebruikersgedragscripts/ hulpscripts (dev-setup, db-reset, release-taken)docs/ korte notities en checklists die je daadwerkelijk bijhoudtBinnen src/ scheid feature-code van gedeelde code op basis van wijzigingspatronen. Feature-code verandert vaak en moet dicht bij elkaar leven. Gedeelde code moet saai en herbruikbaar zijn.
Een praktische regel: zet UI-schermen, handlers en feature-specifieke logica onder src/features/<featureName>/.... Zet dingen zoals logging, API-clients, design system componenten en generieke utilities onder src/shared/.... Als een helper alleen zin heeft voor één feature, houd het dan in die feature, ook al lijkt het herbruikbaar. Verplaats het later wanneer je een tweede echt gebruik hebt.
Mapnamen moeten doel beschrijven, niet techniek. “features” en “shared” blijven betekenisvol als je stack verandert. Vermijd namen als “misc” of “new.”
Houd docs/ klein. Een goede starter is een docs/checklists.md met een paar regels: hoe te draaien, hoe te testen, hoe een nieuwe feature-map toe te voegen en wat “done” betekent.
Een repo voelt echt als iedereen dezelfde commando’s kan uitvoeren en hetzelfde resultaat krijgt. Scripts zijn vangrails: ze verminderen giswerk, houden wijzigingen klein en maken het duidelijk wanneer iets kapot is.
Begin met een kleine set commando’s en houd ze saai. Als iemand nieuw komt (of je terugkomt over twee weken), moeten ze geen speciale flags of verborgen stappen nodig hebben.
Hier is een eenvoudig basissetje dat je op elke stack kunt aanpassen:
{
"scripts": {
"dev": "node ./scripts/dev.js",
"build": "node ./scripts/build.js",
"test": "node ./scripts/test.js",
"test:quick": "node ./scripts/test.js --quick",
"test:full": "node ./scripts/test.js --full",
"format": "node ./scripts/format.js",
"lint": "node ./scripts/lint.js",
"smoke": "node ./scripts/smoke.js"
}
}
Maak het dev-script het pad dat iedereen gebruikt. Het moet de app starten, printen waar het draait en logs leesbaar houden. Als de server niet kan starten, faal dan snel met één duidelijke boodschap (ontbrekende env-var, poort al in gebruik, database niet bereikbaar).
Het build-script moet altijd een schone output-map maken. Verwijder eerst de oude output en produceer dan verse artifacts. Dat voorkomt vreemde bugs door bestanden van gisteren.
Voor tests: splits snelle checks van trage checks. Snelle tests draaien bij elke wijziging (unit tests, type checks). Full tests bevatten integratiechecks en draaien voor merge.
Houd stijl consistent met één commando. Een simpele regel: format repareert, lint klaagt aan.
Voeg tenslotte een smoke-check toe die de basics valideert voordat je tijd aan debugging verliest:
buildJe eerste vertical slice moet bewijzen dat de app end-to-end werkt, niet alleen dat de UI er goed uitziet. Dat betekent één kleine feature die scherm, logica en wat opslag raakt, zelfs als die opslag tijdelijk is.
Kies iets saai maar bruikbaars, zoals “Add a note” of “Create a task.” Houd het klein genoeg om in één sessie af te ronden, maar compleet genoeg zodat je kunt doorklikken en echte statuswijziging ziet.
Een goede slice heeft vier delen: één route of scherm, één formulier, één save-actie en één weergave. Voorbeeld: een “New Task”-pagina met een titelveld, een Save-knop die één functie aanroept en een lijst die opgeslagen taken toont.
Begin met een placeholder-store om snel te kunnen werken. Een in-memory array, een lokaal JSON-bestand of een eenvoudige stub-interface is prima. Het belangrijkste is dat je de grens creëert die je later vervangt. Als je code vandaag taskRepository.save(task) aanroept, wordt overschakelen naar een echte database later een kleine wijziging, niet een rewrite.
Houd de UI simpel. Sla discussies over design systems, lege staten en animaties over.
Acceptatiechecks die je in twee minuten kunt doen:
Als je een uitvoerbaar skelet en één vertical slice hebt, verschuift het doel: zorg dat breuk duidelijk is en fixes snel. Hier gaan veel greenfield-starts mis, niet omdat de feature moeilijk is, maar omdat kleine wijzigingen verrassingen veroorzaken.
Stel een kleine stabiliteitslat die je elke keer haalt als je een slice toevoegt:
Concreet voorbeeld: je eerste slice laat een gebruiker een “Project” aanmaken en in een lijst zien. Voeg een test toe die de server start, de create-endpoint aanroept, daarna de lijst ophaalt en controleert dat het nieuwe item verschijnt. Als het faalt, moet het luid falen met één behulpzame boodschap, zoals “Create Project endpoint returned 500”, niet een muur van output.
Voor foutafhandeling: houd het bij een kleine set consistente responses. Validatiefouten geven een korte boodschap terug (“Naam is verplicht”) en een veldnaam. Onverwachte fouten geven “Er ging iets mis. Probeer het opnieuw.” Details bewaren voor logs.
Logging is het meest nuttig wanneer het antwoordt op: welke request, welke gebruiker (of anoniem), wat faalde en waar. In dev: voeg een request-id en timing toe, maar vermijd het dumpen van tokens, wachtwoorden, API-keys of volledige payloads standaard.
Voeg een kleine health-check toe. Op web kan dat een /health-endpoint zijn dat ok teruggeeft. Op mobiel kan het een “Connected”-staat zijn die op “Offline” springt wanneer de app de backend niet kan bereiken. Het is een snelle indicatie voordat je het verkeerde gaat debuggen.
De snelste manier om een greenfield-start te verspillen is het model vragen om een hele app en die pas later draaien. Grote generaties verbergen kleine fouten: missende dependencies, verkeerde importpaden, scripts die tools aannemen die je niet hebt. Behandel elke output als iets dat je binnen enkele minuten moet kunnen draaien.
Een andere valkuil is het ontwerpen van de perfecte architectuur voordat er een feature is. Debatteren over mapnamen voelt productief, maar zonder een echte slice kun je niet zien wat onhandig is. Een simpele structuur die één werkend pad ondersteunt is beter dan een slimme die je nog niet getest hebt.
Command-drift komt ook vaak voor. De AI voegt een nieuwe manier toe om de server te starten, jij voegt er nog een voor tests, en voor je het weet weet niemand welk commando “het” commando is. Als een collega de repo clonet en vraagt “Hoe start ik dit?”, betaal je al rente.
Fouten die het meeste herwerk veroorzaken:
Een eenvoudig voorbeeld: je genereert een “volledige” app met login, theming en billing, maar de eerste run faalt omdat een secret key mist en er geen .env.example bestaat. Daarna besteed je een uur aan setup in plaats van te leren of de feature nuttig is.
Wees eerlijk: één uitvoerbaar commando, één kleine feature, één env-template, en breid dan uit.
Voeg niet “nog één feature” toe voordat het project morgen (of door iemand anders) makkelijk op te pakken is. Snelheid is geen doel op zich. Voorspelbaarheid wel.
Als iets faalt, los het nu op. Het aanscherpen van scripts en namen is goedkoop als de repo klein is.
Een greenfield-start betaalt zich alleen uit als je het kunt herhalen. Nadat je eerste vertical slice end-to-end draait, vries je de goede onderdelen in een kleine template: dezelfde mappenpatronen, dezelfde scriptnamen en dezelfde manier om UI, API en data te verbinden.
Behandel je eerste slice als een referentie-implementatie. Wanneer je slice #2 start, kopieer je de vorm, niet de code. Als slice #1 een route, een handler, een data-access-layer en een basis-test heeft, moet slice #2 hetzelfde pad volgen.
Houd planning licht. Een één-pagina notitie is genoeg voor de volgende 2–3 slices: het doel en de gebruikersactie voor elke slice (één zin), de data die je nodig hebt, de “done”-checks en risico’s om vroeg te testen.
Maak onderhoud tot gewoonte. Eens per week een korte opruimronde: schroef scripts aan, werk de README bij met nieuwe setup-stappen en verfris je env-example zodat onboarding makkelijk blijft.
Als je een chat-first build-lus verkiest, is Koder.ai (koder.ai) een optie die planningmodus, snapshots en rollback ondersteunt, en die broncode kan exporteren wanneer je het project elders wilt voortzetten.
Het doel is een workflow die je zonder nadenken kunt draaien: plan 2–3 slices, bouw één slice, stabiliseer, herhaal.