Workflow greenfield di Claude Code: dal repo vuoto al primo slice
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.

Cosa vuoi evitare con un avvio greenfield
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:
- Codice che “funziona sulla mia macchina” perché la configurazione vive nella memoria di qualcuno, non negli script.
- Un albero delle cartelle che riflette l'ordine di creazione, non il modo in cui l'app dovrebbe crescere.
- Un loop in cui ogni nuovo prompt riscrive scelte precedenti, così nulla diventa stabile.
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.
Decidi la prima slice prima di generare qualsiasi cosa
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:
- Si esegue localmente da un clone fresco con un comando unico
- Una funzionalità funzionante che puoi percorrere cliccando end-to-end
- Gli errori mostrano un messaggio umano (non uno stack trace)
- I dati persistono in qualcosa di semplice (anche un DB locale)
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.
Alcune decisioni iniziali che evitano rifacimenti
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:
- Forma dell'app: app singola o frontend + API
- Config:
.envin locale,.env.examplecommittato - Porte: una per il web, una per l'API, una per il DB (se necessario)
- Nomi: uno stile di casing per le cartelle, nomi servizi coerenti
- Segreti: mai commessi, ruotati se esposti
Esempio: 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.
Come chiedere a Claude Code di restare strutturato
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:
- Genera prima lo scheletro eseguibile più piccolo (pagina hello, endpoint health, o una schermata).
- Proponi una struttura di cartelle ed spiega ogni cartella in 1 frase.
- Aggiungi script che funzionano su una macchina pulita (install, dev, test, build) e indica prerequisiti.
- Mantieni i cambi in un unico blocco di dimensione PR e lista esattamente quali file verranno creati o modificati.
- Fermati dopo lo scaffolding e dimmi come eseguirlo.
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.
Passo dopo passo: da repo vuoto a uno scheletro eseguibile
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 struttura di cartelle che puoi mantenere mentre l'app cresce
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 davvero
Dentro 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”.
Script di build che rendono il progetto prevedibile
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:
- Le env richieste sono impostate (e non vuote)
- Le porte scelte sono libere
- L'app può avviarsi e rispondere a una richiesta semplice
- La connessione al database funziona (se usata)
- L'output di build esiste dopo
build
Costruisci la prima feature a vertical slice
La 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:
- La pagina si apre senza errori
- Puoi digitare un valore e premere Salva
- Il nuovo elemento appare immediatamente
- Il reload mostra il comportamento atteso (persistenza se storage reale, reset se fake)
- Input invalidi sono gestiti (titolo vuoto mostra un messaggio e non salva)
Rendi tutto abbastanza stabile per iterare
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:
- Un test smoke che dimostra che l'app parte e la route/schermata principale si rende
- Un test smoke che colpisce la slice end-to-end (anche se usa un DB di test)
- Messaggi d'errore chiari per un utente normale (non stack trace)
- Log di sviluppo che spiegano cosa è successo senza stampare segreti
- Dipendenze minime, versioni pinned, aggiornamenti fatti di proposito
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.
Trappole comuni quando usi l'AI per progetti greenfield
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:
- Generare più servizi, schermate e configurazioni in una sola volta invece di costruire prima un percorso eseguibile
- Tirare dentro auth, pagamenti, styling complesso e un modello dati completo prima che la prima feature funzioni end-to-end
- Lasciare istruzioni di setup in chat invece che in script (o in un singolo README)
- Dimenticare un template env pulito, così la macchina successiva non può avviare senza indovinare
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.
Checklist rapida prima di iniziare a iterare
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 è.
- Esecuzione con un comando: un nuovo sviluppatore può copiare un template env, impostare pochi valori richiesti e avviare l'app con un unico comando. Se servono passaggi extra (setup DB, migrazioni, seed), catturali in uno script.
- Script coprono le basi: comandi chiari per dev, test, build e un controllo smoke veloce.
- Struttura ovvia: il layout racconta una storia (codice app, config, script, test) senza leggere tutto il codebase.
- Percorso demo della vertical slice: puoi descrivere la demo in una frase, tipo “crea un elemento, vedi la lista, aggiorna, è ancora lì.”
- Punto di rollback: prima di grandi cambi hai un punto sicuro per tornare (un commit pulito, un tag, o un meccanismo di snapshot/rollback).
Se un elemento fallisce, sistemalo ora. Rifinire script e nomi è economico quando il repo è piccolo.
Prossimi passi: trasforma il workflow in un'abitudine ripetibile
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.
Domande frequenti
Cosa dovrei creare per primo in un repository vuoto?
Inizia con uno scheletro minimo eseguibile, poi realizza un percorso completo per una funzionalità. Chiedi a Claude Code la struttura dei file, gli script di configurazione e una schermata segnaposto prima di richiedere funzionalità più ampie.
Che cos'è una slice verticale?
Una slice verticale è una piccola funzionalità che funziona dalla schermata all'archiviazione e viceversa. Per esempio, un utente aggiunge un'attività, l'app la salva e l'attività compare in un elenco.
Come scelgo la mia prima slice verticale?
Scegli la storia utente più piccola che coinvolga l'interfaccia, un'azione e i dati. «Aggiungere un'attività e visualizzarla dopo l'aggiornamento» è una slice iniziale migliore rispetto a creare login, fatturazione e impostazioni.
Dovrei sviluppare web e mobile contemporaneamente?
Per la prima settimana concentrati su una sola piattaforma. Se inizi con un'app web React, evita di aggiungere schermate mobile o servizi aggiuntivi finché il primo flusso web non funziona.
Cosa significa davvero una configurazione con un solo comando?
Il comando di sviluppo dovrebbe funzionare su un clone nuovo dopo i passaggi di configurazione documentati. Dovrebbe avviare l'app, indicare dove viene eseguita e mostrare un errore chiaro quando manca la configurazione.
Come dovrei scrivere il prompt per lo scaffold iniziale a Claude Code?
Chiedi un piccolo scaffold con un albero dei file proposto, script per configurazione, sviluppo, test e build, oltre a istruzioni di esecuzione precise. Di' a Claude Code di fermarsi dopo lo scaffolding, così potrai eseguirlo prima di ampliare il progetto.
Come dovrei organizzare le cartelle man mano che l'app cresce?
Riunisci schermate, gestori e logica specifici di una funzionalità nella relativa cartella. Conserva in una cartella condivisa solo utility realmente comuni, client API, logging e componenti UI riutilizzabili.
Come dovrei gestire le variabili d'ambiente e i segreti?
Conserva i segreti locali in .env, escludi quel file da git e versione un .env.example con valori segnaposto sicuri. Così un altro sviluppatore può avviare il progetto senza esporre credenziali.
Quali script di build dovrebbe avere un nuovo progetto?
Usa un insieme piccolo e stabile: dev, build, test, lint, format e un controllo smoke. Il controllo smoke dovrebbe verificare che le impostazioni richieste esistano e che l'app possa avviarsi e rispondere a una semplice richiesta.
Come posso evitare che le modifiche generate dall'IA rendano disordinato il repository?
Apporta una piccola modifica alla volta, eseguila subito e condividi nel prompt successivo il risultato esatto o l'errore. Così individui dipendenze mancanti, import non funzionanti e ipotesi di configurazione prima che si diffondano nella codebase.