Come ho integrato Claude Code nel mio workflow Laravel
Il punto di partenza
Pasto a Tavola è un sistema di gestione prenotazioni pasti per mense convenzionate. In produzione da gennaio 2024, con utenti reali e report automatici giornalieri, è cresciuto su tre codebase separate: un backend Laravel, due app React Native. Negli ultimi mesi si è aggiunto un chatbot admin che interroga i dati operativi in linguaggio naturale, tramite un modello Ollama locale. È questo pezzo che mi ha insegnato qualcosa di non ovvio sull’AI in produzione: quando ho disabilitato la modalità thinking per ridurre la latenza, il modello ha iniziato a produrre dati numerici scorretti sui report, una modalità di fallimento silenziosa, scoperta su dati reali. Il reasoning step non era un’opzione da ottimizzare via: era il meccanismo che teneva in piedi l’accuratezza. Il punto è rilevante anche qui: l’AI in un sistema reale si comporta in modo diverso rispetto a un ambiente controllato, e i fallimenti non sono sempre rumorosi.
Il backend ha una complessità che si è accumulata nel tempo: business logic non banale su prenotazioni e convenzioni, vincoli di qualità espliciti: analisi statica a livello elevato, formattazione automatica, una suite di test da ventitré file.
Quando Claude Code è entrato nel mio workflow, a febbraio 2026, il progetto aveva già oltre mille commit. Lavoravo da solo. Il problema non era scrivere codice più velocemente, ma mantenere coerenza architetturale mentre la codebase cresceva. Aggiungere una feature senza stravolgere i pattern esistenti. Refactorare senza introdurre regressioni silenziose. Tenere traccia di decisioni di design prese sei mesi prima.
È in questo contesto che uno strumento AI diventa interessante, non per la velocità grezza, ma per la capacità di gestire complessità distribuita nel tempo.
Il problema con l’uso ingenuo
La prima fase di utilizzo è quasi sempre sbagliata, e non è una colpa dello strumento. Chiedi di aggiungere una feature, ottieni codice che funziona. I tipi sono corretti. Eppure il codice introduce un metodo dove dovrebbe usarne uno già esistente, ignora l’observer che ricalcola i totali su ogni modifica al modello correlato, gestisce la validazione direttamente nel controller invece di delegarla a una classe dedicata.
Non sono bug. Sono violazioni di convenzione che si accumulano. In un progetto da mille commit, ogni deviazione dai pattern stabiliti ha un costo: la prossima volta che si legge quel codice, o lo legge l’agente in un’altra sessione, si trova un’eccezione che sembra un precedente, e il progetto deriva.
Il problema non è l’output dell’LLM: è che senza contesto, lavora nel vuoto. Genera codice valido in astratto, non codice coerente con questo progetto specifico.
La svolta: il CLAUDE.md come contratto
Il cambiamento più significativo è stato scrivere un CLAUDE.md, un file che Claude Code legge all’inizio di ogni sessione. Non è documentazione generica del progetto. È un contratto operativo con l’agente: descrive l’architettura a layer, i pattern obbligatori, le convenzioni Eloquent, i formati critici che non vanno mai modificati senza aggiornare i client a valle, gli anti-pattern da evitare esplicitamente.
La differenza in output è concreta. Prima di avere questo file, chiedevo di implementare un endpoint e ottenevo business logic nel controller. Dopo, il controller fa orchestrazione e risposta HTTP, la logica va nel service layer, perché il documento specifica esattamente questa separazione. Prima ottenevo validazione inline. Dopo, viene generata una classe Form Request dedicata, perché il documento lo prevede esplicitamente come convenzione obbligatoria.
Quello che ho capito è che un LLM non “capisce” il tuo progetto leggendo il codice: lo legge parzialmente, ne inferisce pattern, sbaglia su quelli impliciti. Il CLAUDE.md rende espliciti i vincoli che altrimenti restano taciti nella testa del developer. Non è documentazione per i colleghi: è context engineering per l’agente. La distinzione è sostanziale.
Gli artefatti che rendono il workflow replicabile
Il primo artefatto è un registro auto-generato da un comando Artisan dedicato: elenca in forma strutturata route, classi di validazione, componenti, gate, observer, task schedulati. Non è un README scritto a mano che invecchia: è un artefatto rigenerabile in qualsiasi momento dallo stato corrente del codice. In sessione, quando l’agente deve sapere se esiste già qualcosa per un certo scopo, può leggere questo file invece di eseguire ricerche multiple sul codebase. Le domande “esiste già qualcosa per X?” diventano molto più affidabili, e soprattutto l’inventario non diverge dalla realtà.
Il secondo è un backlog architetturale strutturato, un piano di miglioramenti con priorità, motivazioni e stato. Invece di descrivere informalmente “vorrei refactorare questo”, passo il backlog come input diretto alla sessione. L’agente lavora su un task con tutto il contesto dietro quella decisione: perché è stata presa, quali vincoli ci sono, cosa è già stato fatto.
I quality gate: dove l’umano non si può delegare
L’analisi statica e la suite di test non sono opzionali nel mio workflow: sono il filtro su ciò che Claude Code produce.
Il pattern che si è stabilizzato: l’agente genera codice, il quality gate lo interroga. Quando rileva un tipo errato o una chiamata non sicura, il ciclo non si chiude: si torna indietro. Questo non è un problema: è il comportamento corretto. Il quality gate esiste per trovare esattamente questi casi.
Quello che ho imparato dai pattern di errore è più interessante della semplice conta dei fallimenti. I blocchi ricorrenti appartengono a due categorie: tipi ritornati ambigui da query Eloquent quando la relazione caricata dinamicamente non è nota al type system, e uso di metodi che esistono in certi contesti ma non in altri. Entrambe le categorie sono prevedibili. Quando riconosco un certo tipo di richiesta, so già che l’output andrà verificato con attenzione su quel punto specifico.
Cosa funziona e cosa no
Claude Code produce output affidabile su task con pattern forti e contesto disponibile. Nuovi controller che seguono la struttura degli esistenti: ottimo. Generazione di test su business logic già scritta: buono. Refactoring guidato da regole esplicite: buono.
È meno affidabile, e richiede supervisione più attenta, sui task che implicano ragionamento su side effect tra sistemi distinti: quando un observer reagisce a una modifica, quando un’azione in un service ha conseguenze su un modello correlato che non è nel focus immediato della sessione. Non sbaglia sempre. Il problema è che la probabilità di errore silenzioso aumenta, e un errore silenzioso in produzione ha un costo molto più alto di qualsiasi velocità guadagnata in sviluppo.
Richiede anche supervisione sulle scelte che dipendono da conoscenza del dominio. L’agente sa che esiste un orario di cutoff per le prenotazioni perché il CLAUDE.md lo dice. Non sa perché esiste quel cutoff, né quali conseguenze operative ha una modifica a quella logica. Quella conoscenza rimane nel developer, e non è delegabile.
Quello che rimane
Lavorare con Claude Code su un progetto reale non ha cambiato cosa significa sviluppare software: ha cambiato il rapporto tra tempo dedicato a scrivere codice e tempo dedicato a ragionare su di esso. Su un team di uno, la pressione di stare dietro alla complessità crescente è concreta. L’agente gestisce l’esecuzione su task con pattern noti; il developer gestisce le decisioni che richiedono conoscenza del dominio e visione d’insieme.
Su Pasto a Tavola, questa divisione regge da quattro mesi su un progetto in produzione con utenti reali. È abbastanza per poterne parlare come di un workflow, non di un esperimento.