Ship It With AI Mihai Cvasnievschi

AGENTS.md ca infrastructură de echipă

15 min de citit


AGENTS.md vs CLAUDE.md: care e diferența?

Nume și convenții. Standardul neutru față de vendor pentru fișierul de instrucțiuni al echipei este AGENTS.md, cu suport nativ în Codex CLI, Cursor, GitHub Copilot, Gemini CLI, Aider, Zed, Windsurf și altele. Varianta specifică Claude Code este CLAUDE.md. Formatul e markdown în ambele cazuri; semantica de încărcare e echivalentă. Dacă ai ajuns la capitolul ăsta dinspre ecosistemul Claude Code, citește AGENTS.md ca „fișierul pe care agentul tău îl citește la începutul sesiunii” - disciplina pe care o predă capitolul e identică, indiferent de numele fișierului. Acolo unde manualul discută comportament specific Claude Code, folosesc CLAUDE.md; în rest folosesc numele vendor-neutral.


AGENTS.md este stratul definit manual al componentei principale Memory, numit în Capitolul 1. E suprafața care se partajează în echipă - stratul pe care echipa îl scrie, îl dă la review și îl deține în source control. Sistemul de memorie automată (Auto Memory, Auto Dream) e per developer și în mare parte automat; capitolul ăsta se concentrează pe stratul deținut manual, pentru că acolo trăiește disciplina la nivel de echipă. Urmează cele șase lucruri care intră în AGENTS.md, regula bugetului de 200 de linii și modurile de eșec pe care le vezi în practică.


O echipă cu care am lucrat anul trecut folosea un coding agent de șase luni când un senior engineer a venit la mine cu o nemulțumire. „De fiecare dată când generăm un endpoint de API, trebuie să repar validarea. Mereu aceeași corecție. Agentul pune validarea în stratul greșit.”

Am pus întrebarea evidentă. „De ce nu e regula scrisă undeva?”

Pauză lungă. „N-am scris-o niciodată. Doar o tot reparăm.”

Așa că am făcut socoteala împreună. În ultima lună, agentul generase douăsprezece endpoint-uri noi. Același senior engineer mutase validarea din stratul de controller în stratul de service în unsprezece din cele douăsprezece. Pierduse poate cincisprezece minute pe fiecare corecție, cu tot cu dus-întorsul din review-ul PR-ului. Trei ore din luna lui, în fiecare lună, pe aceeași corecție. Echipa înghițise costul ăsta ca parte din „munca normală de review” și încetase să-l mai observe.

Am scris o singură linie în AGENTS.md: „Adnotările Bean Validation stau pe DTO-uri, la granița controller-ului; metodele din stratul de service au încredere în input-urile lor.” Am adăugat-o și în template-ul de pull request al echipei, ca reminder pentru revieweri. Am marcat endpoint-urile existente care erau deja corecte ca exemple de referință.

Următoarele douăsprezece endpoint-uri: zero corecții pe stratul de validare. Trei ore pe lună de timp de senior engineer, eliminate de o singură linie de configurare. Regula nu a făcut agentul perfect; a eliminat acea corecție anume, repetată la nesfârșit.

AGENTS.md e ceea ce transformă „agentul face întruna greșeala asta” în „agentul nu mai face greșeala asta”. E infrastructură de echipă în același sens în care script-urile de build sunt infrastructură de echipă - cod versionat în repo, pe care echipa îl întreține pentru că echipa se bazează pe el.


Există și un mod de eșec al AGENTS.md care e inversul poveștii de succes de mai sus. O echipă de banking cu care am lucrat la începutul lui 2026 avea un AGENTS.md care crescuse în șase luni până pe la nouă sute de linii. Fiecare PR care scotea la iveală un edge case nou năștea o regulă nouă. Fiecare retro de echipă adăuga o convenție nouă. Fișierul era cuprinzător, bine organizat și întreținut riguros. Și totuși nu mai funcționa. Agentul începuse să ignore tocmai regulile la care echipa ținea cel mai mult - chiar regulile adăugate în sprint-urile cele mai recente -, pentru că, pe context lung, calitatea cu care modelul respectă instrucțiunile scade uniform pe măsură ce crește numărul lor. Cele mai importante reguli ale echipei se înecau în propria lor meticulozitate.

Soluția n-a avut nimic spectaculos. Am tăiat AGENTS.md de la nouă sute de linii la nouăzeci. Convențiile specifice proiectului care nu trebuiau încărcate la fiecare sesiune le-am mutat în skill-uri care se activează la detecție. Documentarea greșelilor din trecut am mutat-o în documentul de arhitectură, unde trăia ca proză, nu ca instrucțiuni. Rata de conformare pe regulile rămase a sărit în sus într-o săptămână. Pattern-ul pe care îl predau acum: dacă AGENTS.md-ul tău a trecut de două sute de linii, fișierul nu devine mai util, devine tot mai ignorat. Taie-l, mută materialul în skill-uri și tratează regulile care supraviețuiesc ca pe cele care duc greul.


Ce este AGENTS.md?

AGENTS.md e un fișier markdown care stă în rădăcina repository-ului. Agentul de cod îl citește la începutul sesiunii, înainte de orice prompt al utilizatorului. E documentul care transformă „ce i se pare agentului rezonabil” în „ce a convenit echipa ta că e rezonabil”. Fără el, sesiunea de agent a fiecărui developer are altă părere despre cum se scrie cod în codebase-ul tău. Cu el, părerea e a echipei - versionată în git, semnată de autor, verificabilă în pull request.

AGENTS.md e cea mai importantă piesă nouă de infrastructură pentru livrarea susținută cu agenți. O echipă fără AGENTS.md face programare cu agenți așa cum face deployment un startup la început de drum - manual, pe bază de tribal knowledge, din memoria instituțională a unui singur senior engineer care se nimerește să fie în cameră. O echipă cu un AGENTS.md bine întreținut face programare cu agenți așa cum fac deployment organizațiile de inginerie mature - automatizat, repetabil, deținut de echipă, supraviețuind plecărilor din echipă.


În AGENTS.md intră șase lucruri. Le iau pe rând, cu exemple concrete din codebase-uri de banking, pentru că acolo îmi fac cea mai mare parte din muncă.

Unu: pattern-urile interzise. Lucruri pe care agentul nu are voie să le facă niciodată. Fiecare e o singură linie. Fiecare are un motiv de o linie.

Nu construi niciodată SQL prin concatenare de string-uri. Folosește întotdeauna parametri legați (bound parameters). (Motiv: un SQL injection pe query-urile de clienți e un incident vizibil pentru autoritatea de reglementare.) Nu loga niciodată câmpuri PII - nici pe cele evidente (număr de cont, CNP), nici compozitele mai puțin evidente (nume complet plus data nașterii). (Motiv: GDPR, articolul 5(1)(c), minimizarea datelor.) Nu-ți implementa niciodată propria criptografie. Folosește wrapper-ul cripto aprobat al echipei, com.bank.crypto.SecureCrypto. (Motiv: în 2024 am livrat în producție AES-CBC cu IV hardcodat; nu repetăm experiența.) Nu modifica niciodată istoricul migrărilor de bază de date. Migrările sunt append-only. (Motiv: rollback-ul unei migrări modificate corupe schema în moduri ireversibile.)

Fiecare pattern interzis e un zid pe care agentul nu-l trece. Dacă agentul crede că regula e greșită într-un caz anume, va semnala dezacordul în răspunsul lui - iar echipa fie explică excepția, fie actualizează regula.

Doi: jurnalul de greșeli. Un log al eșecurilor pe care echipa chiar le-a văzut, fiecare cu regula care previne repetarea. Exemplu:

2026-03-03: am livrat un bug în care agentul a generat un query JPQL care ocolea filtrul multi-tenant. Cauza-rădăcină: promptul nu menționa multi-tenancy; agentul a presupus single-tenant. Fix: query-urile extind acum clasa de bază MultiTenantQueryBuilder, care impune filtrarea pe tenant. Regulă adăugată.

Jurnalul de greșeli crește în timp. Și se curăță periodic: intrările rezolvate structural (problema de fond nu mai e posibilă) se șterg. Jurnalul e documentație care își câștigă locul prin prevenție, nu prin volum. Fiecare intrare ar trebui să fie o regulă care a prevenit efectiv o recidivă cel puțin o dată.

Trei: convențiile de Spring Boot specifice echipei. (Sau de React, sau de orice stack folosești. Spring Boot e exemplul meu.)

Doar constructor injection, nu field injection. (Mai ușor de testat.) @Transactional doar pe metodele de service care modifică starea, nu pe cele de citire. (Evită tranzacții read-only care țin lock-uri inutile.) Repository-urile extind BaseRepository<Entity> pentru filtrarea multi-tenant. (Vezi intrarea din jurnalul de greșeli, 2026-03-03.) DTO-urile de la granița controller-ului folosesc adnotări Bean Validation. Serviciile interne au încredere în input-urile lor.

Fiecare convenție e o linie. Agentul le citește și le aplică din oficiu. Codul nou respectă convențiile. Codul vechi care nu le respectă e adus treptat în linie pe măsură ce agentul trece prin el.

Patru: comenzile de build și de test. Incantațiile exacte pe care le folosește echipa.

Build: mvn clean verify Rulează toate testele: mvn test Rulează testele unei singure clase: mvn test -Dtest=ClassName Rulează scanarea de securitate: mvn dependency-check:check Rulează linting-ul: mvn spotless:check

Sună banal. Nu e. Fără secțiunea asta, agentul ghicește comenzile. De obicei nimerește aproape, dar din când în când greșește, iar asta produce eșecuri derutante. Cu secțiunea asta, agentul folosește exact comenzile echipei, fără ghicit.

Cinci: unde se găsesc lucrurile. Convențiile structurale ale repository-ului.

Serviciile stau în src/main/java/com/bank/service/ Repository-urile în src/main/java/com/bank/repository/ DTO-urile în src/main/java/com/bank/dto/ Testele oglindesc structura din main, în src/test/java/com/bank/ Migrările de bază de date în src/main/resources/db/migration/ (Flyway) Configurarea în src/main/resources/application.yml

Agentul citește asta și știe unde să pună fișierele noi. Fără asta, merge pe cea mai bună presupunere dedusă din structura existentă - de regulă corectă, dar ocazional greșită în moduri care încalcă convențiile echipei.

Șase: glosarul de domeniu. Termeni specifici business-ului tău.

„Customer” înseamnă utilizator final al băncii, nu client corporate. Clienții corporate sunt „Counterparties”. „Transfer” acoperă atât mișcările intra-bancare, cât și pe cele inter-bancare. „Wire” înseamnă strict inter-bancar. „Holds” sunt rezervări de fonduri pe termen scurt, diferite de „blocks”, care sunt restricții legale pe termen lung.

Glosarul dezambiguizează termeni pe care agentul i-ar interpreta altfel în sensul lor generic. În context bancar, „transfer” înseamnă ceva precis. În pretraining-ul agentului, „transfer” înseamnă o grămadă de lucruri. Glosarul ancorează agentul în sensul tău.


AGENTS.md trebuie să stea sub două sute de linii. E o constrângere fermă, nu o recomandare.

Două sute e bugetul pentru că AGENTS.md se încarcă în contextul agentului la fiecare început de sesiune. Fiecare linie costă context pe care agentul l-ar putea folosi pentru task-ul propriu-zis. Două sute de linii încap confortabil, fără să sufoce capacitatea de raționament. Dacă AGENTS.md-ul tău a trecut de două sute de linii, face prea multe. Cele două moduri de eșec:

Modul de eșec A: prea multe reguli. Echipa a acumulat reguli în timp și nu le-a scos niciodată din uz pe cele care nu se mai aplică. Fă un audit. Elimină regulile care nu s-au declanșat în ultimele șase luni. Mută regulile rar aplicabile în skill-uri care se încarcă la detecție, nu la fiecare sesiune.

Modul de eșec B: prea multă vorbă. Fiecare regulă e un paragraf în loc de o linie. Strânge. Agentul nu are nevoie de trei fraze de justificare pentru fiecare regulă; are nevoie de regulă. Justificările își au locul în comentarii în AGENTS.md sau în documentația linkată.

Plafonul de două sute de linii te obligă să ai o opinie. Opinia e valoarea.


AGENTS.md se versionează în git. Trece prin review în pull request. E semnat de autor. Modificările la AGENTS.md trec prin același proces de review ca modificările de cod, pentru că AGENTS.md este cod, în sensul că agentul execută pe baza lui.

Când un developer adaugă o regulă nouă, pull request-ul are cel puțin un reviewer. Reviewerul întreabă: „ce eșec previne regula asta? când am văzut-o ultima oară?” Dacă răspunsul e „n-am văzut-o, dar cred că s-ar putea întâmpla”, regula nu intră. Reviewerul pune frână. Regulile speculative se adună și umflă fișierul; doar regulile născute din eșecuri reale își merită locul.

Am văzut echipe care își întrețin AGENTS.md-ul de peste un an, la calitate constantă. Pattern-ul e același peste tot: un champion îl deține, championul se rotește trimestrial, fiecare modificare trece prin review, limita de sub două sute de linii se respectă, iar jurnalul de greșeli crește, apoi scade, apoi crește, apoi scade, pe măsură ce codebase-ul se maturizează.

Asta e infrastructură de inginerie. Tratează-o ca atare.


Când agentul minte cu încredere.

O subsecțiune separată, pentru că orice practician se lovește de asta săptămânal.

Agentul mai face uneori referire la fișiere care nu există. La o semnătură de funcție pe care biblioteca n-o expune de fapt. La o opțiune de configurare scoasă din uz acum trei versiuni. Output-ul arată plauzibil. E greșit.

Fenomenul se numește halucinație - ăsta e termenul politicos. Termenul mai direct e că agentul inventează ca să fie de ajutor. Agentul nu știe că inventează. Agentul generează tokeni care se potrivesc pe pattern-uri din cod similar pe care l-a văzut, iar pattern-ul, întâmplător, nu se potrivește cu realitatea ta specifică.

Trei tactici care reduc costul.

Unu: obligă agentul să citească înainte să citeze. Dacă agentul e pe punctul de a face referire la un fișier, ar trebui să fi citit acel fișier în sesiunea curentă, suficient de recent încât citirea să-i apară în contextul recent. AGENTS.md poate impune asta: „Înainte să faci referire la orice funcție, citește în sesiunea curentă fișierul care o definește. Citările fără o citire prealabilă se tratează ca ciorne de verificat.”

Doi: verifică încrucișat tool call-urile cu grep. După ce agentul produce cod care apelează o funcție de bibliotecă, dă un grep prin codebase după numele funcției. Dacă grep nu întoarce nimic, funcția probabil nu există (sau există într-o dependență vendored pe care agentul n-o vede). Verificarea e mecanică și prinde în câteva secunde cele mai frecvente halucinații.

Trei: formate structurate de citare, cu hook-uri de verificare. Dacă agentul citează fișier și număr de linie („vezi ImpactCalculator.java, linia 142”), o regulă hookify poate verifica dacă linia există înainte ca agentul să meargă mai departe. Hook-ul are câteva linii de bash. Prinde orice citare fabricată.

Pattern-ul general: nu te încrede în nimic din ce agentul nu tocmai a demonstrat că știe. Workflow-ul de review de arhitectură din capitolul următor e o formă a acestei discipline aplicată la nivel de codebase. Verificarea încrucișată, citirea forțată și hook-ul de citare sunt forme ale ei aplicate la nivel de fișier și de funcție.

Halucinația e cel mai mediatizat mod de eșec al agentului și cel pentru care se supracorectează cel mai des. Nu trebuie să verifici tot ce face agentul. Trebuie să verifici exact acele afirmații ale agentului care, dacă sunt greșite, se propagă și se amplifică. Citările de fișiere și de funcții sunt primele pe lista aia.


O comparație concretă: AGENTS.md prost vs AGENTS.md bun.

Diferența dintre un AGENTS.md care ajută și unul care nu ajută se vede de obicei într-o singură regulă. Ia o regulă despre validare, de care aproape orice echipă va avea nevoie.

Prost:

Respectă întotdeauna standardele noastre de cod. Ai grijă la validare. Folosește arhitectura corectă. Nu face modificări riscante.

Bine:

Validarea de la granița controller-ului aparține DTO-urilor, prin adnotări Bean Validation. Serviciile au încredere în DTO-urile validate și nu re-validează. Nu adăuga niciodată adnotări de validare în metodele de service. Exemple: UserCreateController, AccountUpdateController.

Varianta proastă sună responsabil. Îi spune agentului să fie atent, să respecte standardele, să folosească arhitectura corectă. E și inutilă. „Atent” nu e o constrângere pe care agentul s-o poată verifica. „Arhitectura corectă” depinde de un context pe care regula nu-l oferă. Agentul va citi regula, va produce cod care o încalcă, iar echipa va trage concluzia că AGENTS.md nu funcționează.

Varianta bună e aplicabilă. Numește stratul (DTO-urile la granița controller-ului), mecanismul (adnotările Bean Validation), regula (serviciile au încredere, nu re-validează) și două exemple concrete pe care agentul le poate folosi drept tipar. O regulă ca asta prinde greșeli în review. Varianta proastă nu prinde nimic.

Pattern-ul: regulile care numesc stratul, mecanismul și cel puțin un exemplu sunt reguli pe care agentul le poate aplica. Regulile care fac semn vag spre principii sunt reguli pe care agentul le va ignora.