Quan un agent escriu codi que no compila, el diagnòstic és fàcil. El problema són les altres vegades: quan escriu codi que compila, sembla raonable i se sosté sobre una suposició falsa del teu projecte. Això no s'arregla amb millors instruccions, s'arregla donant-li manera de comprovar les coses. Anem amb d'on surten realment aquests errors i quin context cal donar-li perquè deixin de produir-se. Els exemples van sobre un projecte Laravel, que és on ens movem a AndorraDev, però la idea de donar a l'agent manera de verificar en comptes de deduir serveix amb qualsevol llenguatge i qualsevol agent.
Un agent s'inventa coses quan les ha de deduir
És útil deixar de pensar en "al·lucinacions" i començar a pensar en deduccions sense verificar.
Quan demanes a un agent que treballi sobre el teu projecte i no té manera de comprovar alguna cosa, no s'atura: omple el buit amb el que és més probable. Llegeix una migració de fa dos anys i conclou que la columna existeix. Veu un model amb una relació declarada i dona per fet que la clau forana hi és. Troba un mètode a la documentació d'un paquet i el crida, encara que la versió que tens instal·lada l'hagi reanomenat.
Cap d'aquestes tres coses no és una errada de raonament. Són inferències raonables a partir d'informació incompleta, i cadascuna produeix codi que sembla correcte i no ho és.
La manera de reduir-les no és demanar-li que no s'inventi res. És donar-li manera de comprovar.
Hi ha tres nivells de certesa i convé saber en quin ets
Tota la qüestió s'ordena bastant bé si separes d'on surt cada dada.
Nivell u: el que un humà va escriure. El fitxer de context del projecte, el README, els comentaris. És el més barat de llegir i el menys fiable, perquè ho va escriure algú que podia estar equivocat i perquè envelleix en silenci. Ningú no rep un avís quan el codi deixa d'assemblar-se al document que el descriu.
Nivell dos: el que diu el codi. Les migracions, els models, les rutes declarades. És verificable i és el que el projecte pretén ser. Continua sent una inferència: una migració et diu què es va intentar crear, no què hi ha a la base de dades avui.
Nivell tres: el que hi ha de debò. L'esquema real consultat, el nombre de files, les rutes que l'encaminador té registrades, els últims errors del registre. És el més car d'obtenir i és l'única cosa que no admet discussió.
La majoria de les configuracions es queden al nivell u, que és justament el que més es degrada.
El fitxer de context que vas escriure fa sis mesos ja menteix
Gairebé tothom comença i acaba aquí: un fitxer d'instruccions a l'arrel del repositori amb el que l'agent hauria de saber. És el correcte per a les convencions, i és exactament el pitjor possible per a qualsevol cosa que el codi pugui canviar sense avisar aquest fitxer.
Un fitxer d'instruccions del projecte és còmode: hi és sempre, no cal invocar res i descriu convencions que el codi no expressa. Per a això és insubstituïble.
El problema és quan es converteix en la font de veritat sobre l'esquema o l'arquitectura. Aleshores passen tres coses alhora. Es paga a cada torn de cada sessió, perquè ocupa context sempre. Es desactualitza sense avisar, tan bon punt algú reanomena una columna i no toca el document. I afirma amb la mateixa confiança el que és cert i el que és obsolet, perquè no hi ha res que ho contrasti.
En projectes grans és fàcil que aquest fitxer passi dels dos-cents kilobytes. A aquesta mida ja no és una ajuda: ningú no el revisa sencer, i bona part descriu codi que va canviar fa mesos.
La desviació d'esquema és l'exemple perfecte
Si hi ha un cas que il·lustra la diferència entre deduir i comprovar, és aquest.
Agafes l'esquema real de la base de dades i reconstrueixes l'esquema esperat a partir de les migracions. Després els compares, i les dues direccions del desajust signifiquen coses diferents:
Una columna que és a la base de dades i no a cap migració és un avís. Algú la va crear a mà, o va quedar d'una migració esborrada. El codi no sap que existeix.
Una columna que és a una migració i no a la base de dades és crític. Vol dir que aquesta migració no s'ha executat allà on estàs mirant, i qualsevol codi que la faci servir fallarà.
Un agent que només llegeix migracions no pot distingir aquests dos casos, perquè només en veu un costat. I això és exactament el tipus de cosa sobre la qual escriurà codi amb tota la confiança del món.
El mateix val per a les claus foranes òrfenes. Una migració et diu que la relació està declarada; només un recompte contra les dades reals et diu que hi ha nou files apuntant a un registre que ja no existeix. La consulta és una línia i converteix una sospita en un fet, que és justament la diferència entre un informe que serveix i un que cal verificar a mà.
Deriva l'API del codi instal·lat, no de la documentació
La documentació d'un paquet descriu una versió, i no necessàriament la teva. Un agent que la consulta està llegint sobre un projecte semblant al teu, mentre que la resposta exacta és a un ls de distància, dins de vendor.
Quan l'agent farà servir un paquet, la pregunta no és "què diu la documentació d'aquest paquet", és "quina versió tinc instal·lada i què exposa". I la resposta és al disc:
El fitxer de bloqueig mana sobre tota la resta. El composer.json del mateix paquet pot no portar versió, i una branca de desenvolupament no et diu res. La versió resolta al projecte que el consumeix és l'autoritat.
I el codi instal·lat mana sobre el fitxer de bloqueig. Un àlies de branca pot mentir sobre la versió; la presència o absència d'un fitxer, no. Comprovar que existeix la classe que faràs servir és més fiable que comprovar el número de versió.
Portat a l'extrem, el patró que més m'agrada és derivar els noms disponibles aplicant la mateixa regla que aplica el framework. Si saps que una eina es nomena convertint el nom de la seva classe a minúscules amb guions, llistar el directori de classes et dona el conjunt exacte de la versió instal·lada, al marge del que digui qualsevol documentació.
Detectar l'entorn en comptes d'assumir-lo
Dels comandaments que un agent proposa i no funcionen, la majoria no fallen per estar mal escrits: fallen perquè assumeixen on viu l'aplicació. I això canvia entre el teu portàtil, el contenidor i el servidor sense que res del codi ho digui.
"Executa aquesta consulta" significa coses diferents segons on visqui l'aplicació. Pot ser un docker exec a un contenidor el nom del qual cal esbrinar, una crida directa en local amb Herd o Valet, un camí de Windows natiu on l'escapament de la shell no és el de bash, o una sessió de WSL que sembla Linux i no sempre ho és.
La regla que funciona és comprovar abans d'executar i, sobretot, dir a l'informe quin entorn s'ha fet servir. Un resultat sense aquesta línia és un resultat que no pots reproduir.
Separar llegir d'escriure, sempre
La diferència entre una eina que es fa servir i una altra que es desinstal·la al cap d'una setmana poques vegades és en el que encerta. És en si la pots llançar sense por la primera vegada, quan encara no saps si tocarà alguna cosa que no havia de tocar.
Sense argument, l'eina només informa i no toca res. Amb l'ordre explícita d'arreglar, demana confirmació per cada canvi. I hi ha un mode intermedi que ensenya el diff sense aplicar-lo.
Sembla obvi i gairebé cap configuració no ho respecta. La conseqüència de no tenir-ho és que la gent deixa d'invocar anàlisis per si de cas, i llavors l'eina no serveix de res.
Hi ha un cas on això és especialment important: qualsevol operació que esborri fitxers. Consolidar cent migracions en una és enormement útil i és també l'operació que et pot deixar sense historial si s'executa sobre l'entorn equivocat.
Etiquetar la procedència dins de l'informe
Un informe automàtic arriba com un bloc homogeni: vint troballes amb el mateix aspecte i el mateix to. Res no distingeix la que es va comprovar contra la base de dades de la que es va deduir llegint una migració de fa dos anys, i aquesta distinció és justament la que decideix quina et pots creure.
Quan un informe barreja troballes deduïdes del codi amb troballes comprovades contra dades, la llista sencera val el que val el pitjor dels seus elements, perquè no saps quin és quin.
La solució és que cada línia digui d'on surt:
Orphaned Foreign Keys
operations.client_seller_id -> clients.id
[WARNING] 9 orphaned rows (verified against live data)
Schema Drift
table: invoices
[WARNING] column `legacy_ref` exists in DB but not in any migration
Aquest (verified against live data) és la diferència entre una troballa sobre la qual actues i una que has d'anar a comprovar. I la capçalera de l'informe hauria de dir en quin mode es va executar, perquè sàpigues per endavant quanta certesa estàs llegint.
Què hi ha per al mateix i en què es diferencia
Ningú no resol això amb una sola peça, i les que existeixen no competeixen entre elles: cadascuna cobreix un tram diferent del recorregut que va del que l'agent suposa al que pot comprovar. Val la pena veure-les juntes abans de triar.
El fitxer de context escrit a mà és el punt de partida de tots. Cost zero, sempre present, i és l'únic lloc on caben les convencions que el codi no expressa. El seu compromís ja l'hem vist: es paga en tokens sempre i es degrada sense avisar.
Laravel Boost resol el nivell tres molt bé: un servidor que exposa l'esquema real, les consultes, els últims errors i la informació de l'aplicació, i que a més escriu el context al disc perquè estigui disponible sense invocar res. El compromís és que és una dependència de desenvolupament al teu projecte, amb la seva instal·lació i el seu servidor en marxa. I el que dona és estat, no procediments: sap com està el teu projecte, no com consolidar cent migracions.
Un servidor genèric de base de dades et dona esquema real i res més. Retorna taules i columnes sense les convencions de l'ORM, sense saber què és una relació polimòrfica ni on viu el mapa de tipus.
L'anàlisi estàtica clàssica, del tipus Larastan o les inspeccions de l'IDE, és determinista i no al·lucina per construcció. El que no fa és parlar amb l'agent: el resultat viu a l'eina, no al context del model.
El que aporta un conjunt de procediments empaquetats és l'altre eix: com fer una tasca concreta bé, amb els passos, les fonts que cal consultar i el format de l'informe. No competeix amb l'anterior, s'hi recolza. El seu enfocament és recalcular a cada invocació: no deixa res al teu projecte ni ocupa context quan no el fas servir, i a canvi el cost de lectura es paga cada vegada. I com que són instruccions en text i no crides a funció, orienten el model en comptes de forçar-lo, que és el que les fa portables entre agents.
I si no fas servir Claude Code
Els principis no depenen de l'eina i valen per a qualsevol agent que treballi sobre el teu codi:
- Ordena les teves fonts per certesa i tingues clar en quin nivell està cada afirmació.
- Prefereix comprovar a deduir sempre que el cost ho permeti. Una consulta de recompte costa mil·lisegons i converteix una sospita en un fet.
- Deriva l'API del codi instal·lat, no de la documentació publicada.
- Detecta l'entorn i digues-ho al resultat.
- Separa el mode lectura del mode escriptura amb una ordre explícita.
- I etiqueta la procedència de cada troballa. Un informe sense procedència s'ha de verificar sencer, amb la qual cosa no ha estalviat res.
On és
És un plugin de Claude Code, no un paquet de Composer, així que no s'instal·la amb el gestor de dependències ni entra al teu projecte. S'afegeix des del mateix terminal:
/plugin marketplace add edulazaro/laraclaude
/plugin install laraclaude@edulazaro
El codi és a GitHub i és MIT. Són trenta-dos procediments escrits en Markdown, unes set mil línies, sense una sola línia de PHP: analitzar un model, auditar seguretat, consolidar migracions, generar components, detectar codi mort i comprovar l'estat de l'aplicació contra la base de dades real.
Si estàs ficant agents al teu flux de desenvolupament, la feina de debò no és al prompt, és a decidir d'on surt cada dada. Ho tractem a intel·ligència artificial i desenvolupament Laravel, i si ens expliques com treballes avui et diem què val la pena automatitzar.