Usa il workflow greenfield di Claude Code per impostare struttura, script e la prima vertical slice che puoi eseguire, testare e migliorare settimana dopo settimana.

Partire da un repo vuoto dà la sensazione di libertà, ma spesso si trasforma in slancio disordinato: molti file generati, una build a metà funzionante e nessun posto chiaro dove mettere la prossima modifica. Lo scopo del workflow greenfield di Claude Code è evitare quel caos della prima settimana.
Alcuni fallimenti si ripetono spesso:
Le decisioni iniziali sono dolorose da annullare perché tutto si accumula sopra di esse. Una struttura confusa continua a essere rinforzata. Una build manuale si trasforma in dieci setup diversi. Se non fissi presto un comando di sviluppo semplice, non puoi capire se una modifica ha rotto l'app o solo l'ambiente.
Quando in questo post si parla di “app in esecuzione”, si intende qualcosa di specifico: un comando che avvia il progetto, stampa output prevedibile e fallisce in modo evidente quando manca qualcosa. Dovresti poter cancellare la tua installazione locale, clonare il repo, eseguire quel comando e vedere lo stesso risultato.
Una “vertical slice” è la caratteristica end-to-end più piccola che dimostra che la tua app è reale. Non una mockup UI. Non solo una tabella del database. È una linea sottile attraverso tutto il sistema: una pagina con un form, un endpoint API che salva dati, una scrittura/lettura sul database e un risultato visibile sulla pagina.
Se riesci a eseguire l'app con un comando e spedire una vertical slice, hai una base su cui iterare senza indovinare.
Una prima slice chiara mantiene il repo ordinato e i prompt concentrati. Questo è il momento di decidere cosa vuoi dimostrare end-to-end, non cosa speri che diventi il prodotto completo.
Scegli la user story più piccola che dimostri che l'app funziona su tutto il percorso. Una buona slice tocca UI, dati e un'azione reale. Esempio: “Come utente, posso aggiungere un task e vederlo apparire in una lista dopo il refresh.” È minuscola, ma obbliga a routing, validazione, storage e una schermata di base.
Scegli una piattaforma target per la settimana 1 e resta su quella. Se inizi col web, fai solo web. Non aggiungere schermate mobile “per sicurezza”. Anche se prevedi di usare una piattaforma come Koder.ai più avanti, otterrai risultati migliori se la prima slice rimane in una sola corsia (React web, o una API Go, o Flutter).
Definisci cosa significa “fatto per la settimana 1” in termini semplici:
Poi annota tre non-obiettivi che proteggono lo scope. Per esempio: niente auth, niente sistema di temi, niente job in background.
Una volta scritte queste decisioni, il prompt di generazione può essere stringente: costruisci solo ciò che supporta la slice e lascia tutto il resto come TODO.
Prima di chiedere a Claude di generare qualcosa, blocca una manciata di default. Sembrano piccoli, ma impediscono il caos del tipo “rinomina tutto dopo”.
Per prima cosa, decidi la forma dell'app. Se hai davvero bisogno di una UI in browser e di un backend, inizia con due parti chiare (frontend + API) e un posto condiviso per i contratti (tipi API o uno schema semplice). Se l'app può essere un'app web server-rendered singola, mantienila in un unico codebase così lo sviluppo locale resta semplice.
Poi concorda regole di configurazione. Usa un file env locale, tienilo fuori da git e committa un template invece (per esempio, .env.example) con placeholder sicuri e commenti brevi. Questo rende l'onboarding più facile e riduce la fuga di segreti.
Scegli porte di default per lo sviluppo e mantienile stabili. Le porte finiscono negli script, nella documentazione e nei messaggi d'errore, quindi cambiarle dopo è fastidioso. Fai lo stesso per i nomi: cartelle, servizi e pacchetti dovrebbero seguire una convenzione sola. La coerenza conta più della convenzione “perfetta”.
Un semplice set iniziale di decisioni:
.env in locale, .env.example committatoEsempio: scegli web sulla porta 3000 e api sulla porta 8080. Il tuo template env include API_URL=http://localhost:8080 e DATABASE_URL=.... Quando Claude genera script e documentazione dopo, tutto si incastra invece di deragliare.
Inizia chiedendo uno scaffold eseguibile, non “l'app intera”. La strada più veloce verso output disordinato è richiedere funzionalità prima di avere un posto dove metterle.
Sii esplicito sulla struttura. Chiedi un layout di cartelle con brevi commenti che spieghino cosa appartiene dove e cosa non ci dovrebbe essere. Questo forza le decisioni in anticipo invece di spargere file man mano.
Un modo semplice per mantenere disciplina è impostare regole nel prompt:
Ecco un prompt che puoi riusare e adattare:
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
Poi mantieni il loop stretto. Non chiedere cinque cambi contemporaneamente. Genera una piccola modifica, eseguila, incolla l'errore esatto (o il successo), poi chiedi una correzione minima. Quel ritmo genera-esegui-regola mantiene il progetto prevedibile e rende più difficile che la struttura drifti.
Inizia con una promessa: chiunque può clonare il repo ed eseguire un comando per vedere qualcosa che funziona. Questo ti dà una base stabile prima di chiedere a un'AI di aggiungere funzionalità reali.
Crea il repo e scrivi un README minimo mentre tutto è fresco. Mantienilo pratico: prerequisiti, il comando dev unico e come eseguire i test (anche se i test sono vuoti per ora).
Poi scegli un layout top-level che corrisponda alla forma dell'app che hai scelto.
Se stai costruendo più pezzi distribuibili (per esempio, frontend + API), un layout workspace può aiutare:
/
apps/
packages/
scripts/
docs/
README.md
Se costruisci un'app singola, mantienila più semplice ed evita livelli extra finché non servono.
Ora aggiungi le guardie minime così il codice resta coerente. Scegli un formatter e un linter, accetta i loro default e aggiungi un singolo file di config per ciascuno. L'obiettivo è diff puliti, non regole perfette al giorno uno.
Rendi l'esperienza sviluppatore prevedibile con un comando che funziona sempre dalla radice del repo. Ecco una forma semplice:
{
"scripts": {
"dev": "echo \"start dev server here\"",
"build": "echo \"build here\"",
"test": "echo \"tests here\"",
"lint": "echo \"lint here\""
}
}
Prima di generare altro, esegui quel comando dev, conferma che esce pulito (o avvia un server placeholder), poi fai il primo commit solo con lo scaffolding. Se un collega (o il futuro te) può riprodurre l'ambiente da zero, sei pronto a costruire la prima slice.
Una buona struttura greenfield fa due cose: aiuta a trovare il codice rapidamente e dà a Claude meno spazio per inventare nuovi pattern ogni volta che chiedi una modifica. L'obiettivo non è la perfezione. È la stabilità.
Se lavori dentro una singola app (o dentro una cartella apps/<name>/), un layout interno semplice solitamente regge bene:
src/ codice dell'app (feature, pezzi condivisi, entry points)config/ configurazione non segretatests/ test di alto livello che si leggono come comportamenti utentescripts/ script helper (setup dev, reset db, task di rilascio)docs/ appunti brevi e checklist che mantieni davveroDentro src/, separa il codice delle feature dal codice condiviso basandoti su pattern di cambiamento. Il codice delle feature cambia spesso e dovrebbe vivere vicino. Il codice condiviso dovrebbe essere noioso e riutilizzabile.
Una regola pratica: metti schermate UI, handler e logica specifica sotto src/features/<featureName>/.... Metti cose come logging, client API, componenti del design system e utilità generiche sotto src/shared/.... Se un helper ha senso solo per una feature, tienilo in quella feature anche se sembra riutilizzabile. Spostalo più tardi quando hai un secondo vero utilizzo.
I nomi delle cartelle dovrebbero descrivere lo scopo, non la tecnologia. “features” e “shared” restano significativi se cambi stack. Evita nomi come “misc” o “new”.
Mantieni docs/ piccolo. Un buon starter è un docs/checklists.md con poche righe: come eseguire, come testare, come aggiungere una nuova cartella feature e cosa significa “fatto”.
Un repo sembra reale quando chiunque può eseguire gli stessi comandi e ottenere lo stesso risultato. Gli script sono guardrail: riducono le incertezze, mantengono i cambi piccoli e rendono ovvio quando qualcosa si rompe.
Inizia con un piccolo set di comandi e mantienili noiosi. Se qualcuno nuovo entra (o torni dopo due settimane), non dovrebbe servire flag speciali o passaggi nascosti.
Ecco una baseline adattabile a qualsiasi stack:
{
"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"
}
}
Rendi lo script dev il percorso felice. Dovrebbe avviare l'app, stampare dove sta girando e mantenere i log leggibili. Se il server non può partire, must fail fast con un messaggio chiaro (variabile d'env mancante, porta già in uso, database non raggiungibile).
Lo script build dovrebbe sempre creare una cartella di output pulita. Cancella la vecchia output prima, poi produci artefatti freschi. Questo evita bug strani causati da file di ieri.
Per i test, separa controlli veloci da quelli lenti. I test rapidi girano a ogni modifica (unit test, type check). I test completi includono controlli di integrazione e girano prima della merge.
Mantieni lo stile con un comando solo. Una regola semplice: il format corregge, il lint segnala.
Infine, aggiungi un controllo smoke che valida le basi prima di perdere tempo a debuggarlo:
buildLa tua prima vertical slice dovrebbe dimostrare che l'app funziona end-to-end, non solo che la UI è carina. Questo significa una piccola feature che tocca la schermata, la logica e qualche forma di storage, anche se temporanea.
Scegli qualcosa noioso e utile, come “Aggiungi una nota” o “Crea un task”. Mantienilo piccolo abbastanza da finire in una sessione, ma completo quanto basta per poter cliccare e vedere un cambiamento di stato reale.
Una buona slice ha quattro parti: una route o schermata, un form, un'azione di salvataggio e una visualizzazione. Esempio: una pagina “Nuovo Task” con un campo titolo, un pulsante Salva che chiama una funzione unica e una lista che mostra i task salvati.
Inizia con uno store placeholder così puoi andare veloce. Un array in memoria, un file JSON locale o un'interfaccia stub sono ok. L'importante è creare il confine che poi sostituirai. Se il codice chiama taskRepository.save(task) oggi, passare a un database reale dopo diventa una piccola modifica, non una riscrittura.
Mantieni la UI semplice. Salta dibattiti su design system, stati vuoti e animazioni.
Controlli di accettazione che puoi fare in due minuti:
Dopo che hai uno scheletro eseguibile e una vertical slice, l'obiettivo cambia: rendere il fallimento ovvio e la correzione rapida. Qui molti greenfield falliscono, non perché la feature sia difficile, ma perché piccole modifiche iniziano a causare sorprese.
Stabilisci una piccola barra di stabilità che incontri ogni volta che aggiungi una slice:
Esempio concreto: la tua prima slice permette a un utente di creare un “Project” e vederlo in una lista. Aggiungi un test che avvia il server, chiama l'endpoint di creazione, poi recupera la lista e verifica che il nuovo item appaia. Se fallisce, deve fallire rumorosamente con un messaggio utile, tipo “Create Project endpoint returned 500”, non una montagna di output.
Per la gestione errori, mantieni un piccolo set di risposte coerenti. Gli errori di validazione ritornano un messaggio corto (“Il nome è richiesto”) e il campo. Errori inaspettati ritornano “Qualcosa è andato storto. Riprova.” Conserva i dettagli nei log.
Il logging è più utile quando risponde a: quale richiesta, quale utente (o anonimo), cosa è fallito e dove. In dev, includi un request id e i tempi, ma evita di stampare token, password, chiavi API o payload completi di default.
Aggiungi un piccolo health check. Sul web può essere un endpoint /health che ritorna ok. Su mobile può essere uno stato “Connected” che diventa “Offline” quando l'app non raggiunge il backend. È un segnale rapido prima di debuggare la cosa sbagliata.
Il modo più rapido per sprecare un avvio greenfield è chiedere al modello un'app intera, poi eseguirla molto dopo. Generazioni grandi nascondono errori piccoli: dipendenze mancanti, path di import sbagliati, script che assumono strumenti non presenti. Tratta ogni output come qualcosa che dovresti poter eseguire in pochi minuti.
Un'altra trappola è progettare l'architettura perfetta prima che esista una feature. Dibattere sui nomi delle cartelle sembra produttivo, ma senza una vera slice non puoi sapere cosa è scomodo. Una struttura semplice che supporta un percorso funzionante batte una intelligente che non hai testato.
Il command drift è comune. L'AI aggiunge un nuovo modo per avviare il server, tu ne aggiungi un altro per i test e presto nessuno sa quale sia il comando “ufficiale”. Se un collega clona il repo e chiede “Come eseguo questo?”, stai già pagando interessi.
Errori che causano più rifacimenti:
Un esempio semplice: generi un'app “completa” con login, theming e billing, ma la prima esecuzione fallisce perché manca una chiave segreta e non c'è .env.example. Poi passi un'ora a sistemare il setup invece di imparare se la feature è utile.
Sii onesto: un comando eseguibile, una piccola feature, un template env, poi espandi.
Prima di aggiungere “solo un'altra feature”, assicurati che il progetto sia facile da riprendere domani (o da qualcun altro). La velocità non è l'unico obiettivo. La prevedibilità lo è.
Se un elemento fallisce, sistemalo ora. Rifinire script e nomi è economico quando il repo è piccolo.
Un avvio greenfield paga solo se puoi ripeterlo. Dopo che la tua prima vertical slice funziona end-to-end, congela le parti buone in un piccolo template: stessi pattern di cartelle, stessi nomi di script e lo stesso modo di collegare UI, API e dati.
Tratta la tua prima slice come una reference implementation. Quando inizi la slice #2, copia la forma, non il codice. Se la slice #1 ha una route, un handler, un livello di accesso ai dati e un test base, la slice #2 dovrebbe seguire lo stesso percorso.
Mantieni la pianificazione leggera. Una nota di una pagina basta per le prossime 2-3 slice: l'obiettivo e l'azione utente per ciascuna slice (una frase), i dati necessari, i check di “done” e i rischi da testare presto.
Poi rendi la manutenzione un'abitudine. Una volta a settimana fai una breve pulizia: stringi gli script, aggiorna il README con eventuali nuovi passi di setup e aggiorna il file env example così l'onboarding resta facile.
Se preferisci un loop di costruzione orientato alla chat, Koder.ai (koder.ai) è un'opzione che supporta la planning mode più snapshot e rollback, e può esportare il codice sorgente quando vuoi portare il progetto altrove.
L'obiettivo è un workflow che puoi eseguire senza pensarci: pianifica 2-3 slice, costruisci una slice, stabilizza, ripeti.