O oră obișnuită de lucru în modul Manual. Agentul citește proiectul, propune o modificare, vă cere să rulați testele, apoi urmează altă modificare și alte teste. La a douăzecea întrebare apăsați "Yes" aproape fără să vă uitați. Și, printre aceste întrebări, se strecoară o modificare în folderul legacy/, de care nimeni nu s-a mai atins de mult și nici n-ar trebui să se atingă.

Articolul acesta arată cum să păstrați întrebările doar pentru situațiile în care decizia chiar vă aparține. În Claude Code aveți pentru asta reguli de permisiune: trei liste în fișierul de setări, care stabilesc ce poate face agentul imediat, pentru ce să vă întrebe și ce să nu facă deloc. Să vedem la ce folosesc, cum se citesc și cum puteți pune în ordine fișierul cu reguli pe care probabil îl aveți deja.

O singură setare pentru toate

Modul de permisiuni e un singur buton pentru întreaga sesiune. Îl puteți roti în orice direcție, dar schimbarea se aplică mereu pe toată sesiunea, în bloc.

În modul strict Manual, agentul vă întreabă înainte de fiecare modificare și aproape înaintea fiecărei comenzi. Întrebarea vă protejează doar cât timp o citiți. Când sunt prea multe, nu le mai citiți, iar protecția rămâne doar pe hârtie.

În modul mai liber acceptEdits, modificările se fac fără să vă întrebe, la fel și comenzile pentru fișiere, precum rm și mv. E comod pentru propriul dumneavoastră cod. Dar modul nu face diferența între foldere: o modificare în legacy/ trece la fel de discret ca oriunde altundeva în proiect.

Puteți scrie în CLAUDE.md "nu atinge legacy/". Agentul va încerca să respecte indicația, însă e o rugăminte adresată modelului, nu o interdicție. Regulile de permisiune le verifică însuși Claude Code, înainte ca acțiunea să fie executată, iar textul din CLAUDE.md sau din prompt nu le influențează.

Acțiunile au costuri diferite în caz de greșeală, dar modul le tratează la fel. Testele ar trebui să ruleze fără întrebări. Modificările într-un modul al altcuiva ar trebui să le vedeți. Agentul n-ar trebui să intre deloc într-un folder înghețat. Trei acțiuni, trei răspunsuri diferite, iar modul nu le poate diferenția.

Trei liste

Regulile vă oferă exact aceste trei răspunsuri:

  • allow - execută fără să întrebe. Elimină zgomotul: acțiunile frecvente și sigure nu vă mai întrerup;
  • ask - întreabă întotdeauna. Păstrează întrebarea acolo unde decizia e a dumneavoastră, indiferent de mod, chiar și în cel mai liber;
  • deny - nu execută. Agentul primește un refuz, iar dumneavoastră nici nu vedeți întrebarea. Se aplică în orice mod.

Regulile se trec într-un fișier de setări, de exemplu în .claude/settings.json al proiectului. Pentru proiectul din introducere, ar putea arăta așa:

{
  "permissions": {
    "allow": [
      "Bash(npm test)"
    ],
    "ask": [
      "Edit(src/partner/**)"
    ],
    "deny": [
      "Edit(legacy/**)",
      "Bash(git push *)"
    ]
  }
}

Aici, src/partner/ e un modul al altcuiva, pe care îl modificați cu grijă, legacy/ e o parte înghețată a proiectului, iar npm test e verificarea pe care agentul o rulează de zece ori într-o sarcină. Cele două asteriscuri înseamnă "tot ce se află în folder, la orice nivel de adâncime".

Să vedem acum ce se schimbă în sesiune. Aceleași cinci acțiuni, în trei variante:

AcțiuneManual fără reguliacceptEdits fără reguliacceptEdits cu reguli
Modificare în restul folderului src/întreabăfără întrebarefără întrebare
Modificare în src/partner/întreabăfără întrebareîntreabă
Modificare în legacy/întreabăfără întrebarerefuză
npm testîntreabăîntreabăfără întrebare
git pushîntreabăîntreabărefuză

Uitați-vă la ultima coloană. Sesiunea rulează într-un mod rapid: codul propriu se modifică fără opriri, iar testele pornesc singure. A rămas o singură întrebare, despre locul unde chiar vreți să vedeți modificarea. Cele două acțiuni interzise nu mai depind de cât de obosiți sunteți spre seară.

De asta sunt utile regulile. Scopul nu e să-i dați agentului mai multe permisiuni, ci să le organizați după costul unei greșeli. Așa puteți lucra într-un mod mai liber fără să pierdeți controlul asupra zonelor importante.

O acțiune poate corespunde mai multor reguli, așa că Claude Code verifică listele într-o ordine strictă:

Ordinea de verificare a regulilor. Acțiunea agentului este comparată mai întâi cu lista deny: dacă se potrivește, este refuzată. Dacă nu, urmează lista ask: potrivirea declanșează o întrebare în orice mod. Apoi lista allow: potrivirea permite executarea fără întrebare. Dacă nu se potrivește nimic, decide modul: în Manual agentul întreabă, în acceptEdits modificarea se aplică direct.Acțiunea agentuluicomandă, modificare, citireSe potrivește cu deny?Se potrivește cu ask?Se potrivește cu allow?Refuzacțiunea nu va fi executatăÎntrebareîn orice modFără întrebarese execută imediatNicio potrivire - decide modulîn Manual agentul întreabă, în acceptEdits modificarea se aplică directdadadanununu
Decide prima regulă care se potrivește, în ordine de sus în jos

Schema se parcurge de sus în jos, iar fiecare acțiune a agentului trece din nou prin ea. De îndată ce se potrivește o regulă, verificarea se oprește, iar o regulă mai specifică nu primește prioritate. Dacă deny conține Bash(git push *), nicio regulă din allow nu va permite push-ul. Interdicția nu poate fi anulată din greșeală, ceea ce e bine.

Merită să rețineți separat dreptunghiul de jos. Dacă acțiunea nu se potrivește cu nicio listă, asta nu înseamnă "permisă". Decide modul: în Manual agentul vă întreabă, în acceptEdits modificarea se aplică direct. Cu alte cuvinte, regulile nu anulează modul, ci îl particularizează în situațiile pe care le-ați indicat.

Cum se citește o regulă

O regulă scrisă aproape corect e mai rea decât lipsa ei. Fără regulă știți că nu există o limită. Cu una imprecisă, credeți că limita există, dar protejează altceva decât vă imaginați.

Formatul e același pentru toate regulile: numele instrumentului, apoi între paranteze o precizare despre ce anume vizează. Fără paranteze, regula se aplică tuturor apelurilor instrumentului, așa că Bash în deny îi ia agentului accesul la întregul terminal.

Fișiere

Pentru fișiere aveți nevoie de două instrumente: Edit pentru orice modificare și Read pentru citire. Calea se scrie cu un șablon, ca în .gitignore: un asterisc înseamnă orice nume într-un singur folder, două înseamnă orice nivel de imbricare. O cale fără slash la început se raportează la folderul în care a fost pornită sesiunea, așa că lansați Claude Code din rădăcina proiectului.

O greșeală frecventă e să scrieți Write(legacy/**). Agentul are un instrument cu acest nume, dar Claude Code verifică regulile pentru fișiere doar cu Edit și Read. Va accepta regula cu Write, vă va avertiza la pornire și nu o va mai verifica ulterior. În schimb, Edit acoperă toate metodele încorporate de modificare a fișierelor, inclusiv crearea unora noi.

Mai e și o suprapunere utilă: interdicția de citire, de exemplu Read(./.env) în deny, îl oprește pe agent și să modifice acel fișier.

Comenzi

Regula Bash(...) compară textul comenzii. Asteriscul înlocuiește orice text, inclusiv spațiile, iar potrivirea depinde de trei detalii:

  • fără asterisc, regula se potrivește cu o singură comandă, literă cu literă;
  • asteriscul se pune după subcomandă. Bash(git log *) permite doar git log cu orice opțiuni, pe când Bash(git *) permite orice comandă git, inclusiv push;
  • spațiul dinaintea asteriscului face parte din regulă: Bash(ls *) nu se potrivește cu lsof, dar Bash(ls*) se potrivește.
Cum se potrivește regula unei comenzi cu textul. Pentru regula Bash(git log *), partea git log este comparată literă cu literă, iar asteriscul acoperă --oneline main, deci regula permite doar git log cu orice opțiuni. Pentru Bash(git *), doar git este comparat literă cu literă, iar asteriscul acoperă push origin main, așa că regula permite orice comandă git, inclusiv push.Bash(git log *)Bash(git *)doar git log, cu orice opțiuniorice comandă git, inclusiv pushgit log--oneline maingitpush origin mainînainte de asterisc: literă cu literăîn locul asteriscului: orice text
Limita regulii este dată de textul dinaintea asteriscului

Partea albastră se compară cu comanda literă cu literă, iar asteriscul acoperă complet partea portocalie, indiferent ce conține. Așadar, textul dinaintea asteriscului stabilește cât de largă e regula. În primul caz e git log, deci nu permite nimic în afară de consultarea istoricului. În al doilea e doar git, iar după asterisc poate urma push, ștergerea unei ramuri sau resetarea modificărilor. Când citiți o regulă scrisă de altcineva, începeți cu întrebarea asta: ce apare înaintea asteriscului?

RegulăSe potriveșteNu se potrivește
Bash(npm test)npm testnpm test --watch
Bash(npm run *)npm run build, npm run lint --fixnpm install
Bash(git log *)git log, git log --onelinegit push
Bash(git *)orice comandă git, inclusiv git push-
Edit(src/partner/**)modificarea oricărui fișier din src/partner/modificarea src/app.js
Read(./.env)citirea fișierului .env din rădăcina proiectuluicitirea fișierului .env.example

Claude Code împarte comenzile compuse de tipul a && b în părți. allow le permite doar dacă fiecare parte se potrivește cu propria regulă. ask și deny se aplică dacă se potrivește măcar una. Așadar, permisiunea pentru npm test nu va permite și npm test && git push.

Există reguli și pentru alte instrumente, de exemplu mcp__github__* pentru toate instrumentele unui server MCP sau WebFetch(domain:example.com) pentru încărcarea paginilor de pe un anumit site. Logica e aceeași, așa că nu le vom analiza separat aici.

În ce fișier păstrați regulile

O regulă pusă în fișierul greșit poate strica lucrurile pe nesimțite. Dacă puneți o interdicție în fișierul personal, colegii nu o au, iar agentul lor intră în legacy/ ca și cum nimic nu s-ar fi întâmplat. Dacă puneți o permisiune comodă pentru dumneavoastră în fișierul comun, ajunge la toți cei care descarcă proiectul.

FișierRegulile cuiAjunge în Git
~/.claude/settings.jsonale dumneavoastră, în toate proiectele de pe acest calculatornu, se află în folderul personal
.claude/settings.jsoncomune tuturor celor care lucrează la proiectda, fișierul este inclus în commit
.claude/settings.local.jsonale dumneavoastră, doar în proiectul acestanu

Pe lângă aceste trei fișiere, organizația poate distribui propriul fișier de setări, ale cărui reguli nu pot fi suprascrise. În proiectele de exercițiu, de obicei nu există așa ceva.

Listele din fișiere diferite nu se contrazic, ci se adună: lista allow din fișierul dumneavoastră se adaugă la lista allow comună. Ordinea de verificare rămâne aceeași pentru toate, iar deny din orice fișier are prioritate față de allow din oricare altul. De aici rezultă o împărțire simplă. Puneți limitele proiectului, cum ar fi legacy/, .env sau push, în fișierul comun, ca să ajungă la toată lumea odată cu repository-ul. Preferințele personale de lucru merg în fișierul local.

Fișierul comun are o particularitate de siguranță. Regulile sale allow intră în vigoare doar după ce confirmați că aveți încredere în folder: la prima pornire în proiect, Claude Code vă întreabă acest lucru și vă arată ce urmează să permită fișierul. Regulile ask și deny se aplică imediat, fiindcă doar restricționează. Un repository străin care își permite singur tot terminalul nu obține nimic până nu vă dați acordul.

Puteți verifica ce se aplică de fapt cu două comenzi. /permissions afișează toate regulile și fișierul din care provine fiecare; tot de aici le puteți adăuga sau șterge. Linia Setting sources din /status enumeră fișierele încărcate. Claude Code preia modificările făcute în fișiere fără repornire. Fișierul de setări folosește JSON strict: un comentariu cu // sau o virgulă după ultimul element îl va invalida, iar Claude Code vă va avertiza la pornire.

Fișierul care se scrie singur

Când agentul vă întreabă despre o comandă și alegeți "Yes, and don't ask again", Claude Code adaugă regula allow în .claude/settings.local.json. Dacă fișierul nu exista încă, îl creează și se asigură că nu va ajunge în commit-uri. La modificările fișierelor, lucrurile stau altfel: acordul se aplică până la sfârșitul sesiunii și nu este scris în fișier.

Analizăm un settings.local.json real

Probabil aveți deja fișierul acesta, deși nu dumneavoastră l-ați scris. De fiecare dată când ați ales "nu mai întreba", s-a adăugat o linie, iar după câteva săptămâni agentul primește mai multe permisiuni decât credeți. Iată un bloc real, acumulat în câteva săptămâni de lucru la un proiect Python:

{
  "permissions": {
    "allow": [
      "Bash(python3 *)",
      "Bash(PYTHONIOENCODING=utf-8 python3 *)",
      "Bash(git status *)",
      "Bash(git log *)",
      "Bash(git diff *)",
      "Bash(git show *)",
      "Bash(git branch *)",
      "Bash(git add *)",
      "Bash(git commit *)",
      "Bash(git fetch *)"
    ]
  }
}

Înainte să citiți analiza, încercați și dumneavoastră. Ce linii ați păstra, pe care le-ați restrânge și pe care le-ați șterge?

Bash(python3 *)
Cea mai largă regulă din fișier. Permite rularea oricărui script și a oricărui cod prin python3 -c. Iar Python poate face orice: șterge fișiere, accesează rețeaua, pornește alte programe. Practic, regula permite executarea oricărui lucru fără întrebare. Ar trebui restrânsă la scriptul pentru care a fost adăugată, de exemplu Bash(python3 scripts/build.py *).

Bash(PYTHONIOENCODING=utf-8 python3 *)
Aceeași comandă, cu o variabilă de mediu în față. Regula allow permite această formă doar dacă variabila face parte dintr-o listă scurtă de variabile considerate sigure dinainte. Dacă nu e pe listă, Bash(python3 *) nu acoperă comanda, agentul vă întreabă separat, iar butonul salvează încă o regulă. Probabil așa a apărut și linia aceasta. O restrângeți la fel, la un script anume.

git status, git log, git diff, git show
În forma obișnuită, aceste comenzi doar citesc, iar Claude Code le execută fără să întrebe și fără reguli. Liniile nu fac rău, dar nici nu adaugă mare lucru. Ștergeți-le, iar fișierul va fi mai scurt și mai clar.

Bash(git branch *)
Pare inofensivă: afișează lista de ramuri. Dar regula compară textul, iar git branch -D feature începe tot cu git branch. Ramura va fi ștearsă fără întrebare. Mai bine eliminați linia. Dacă întrebarea despre lista de ramuri devine deranjantă, permiteți comanda exactă Bash(git branch), fără asterisc.

git add și git fetch
Prima adaugă modificări pentru un commit viitor, a doua descarcă istoricul nou de pe server fără să atingă fișierele de lucru. Ambele se pot anula ușor, așa că le puteți păstra.

Bash(git commit *)
Agentul face commit fără să vă întrebe, înainte să citiți diff-ul. Tocmai aici e nevoie de o întrebare: commit-ul e momentul în care aprobați modificarea. Mutați linia în ask. Nu e suficient să o ștergeți. În Manual, agentul vă va întreba oricum, dar ask păstrează întrebarea în orice mod, inclusiv în cel mai liber.

Ce lipsește din fișier
git push. E bine că nu apare, dar asta depinde doar de faptul că nimeni n-a ales vreodată "nu mai întreba" pentru push. E mai sigur să adăugați interdicția explicit.

Iată rezultatul analizei:

{
  "permissions": {
    "allow": [
      "Bash(python3 scripts/build.py *)",
      "Bash(PYTHONIOENCODING=utf-8 python3 scripts/build.py *)",
      "Bash(git add *)",
      "Bash(git fetch *)"
    ],
    "ask": [
      "Bash(git commit *)"
    ],
    "deny": [
      "Bash(git push *)"
    ]
  }
}

Din cele zece linii au rămas șase, fiecare cu rolul ei. Numărul întrebărilor aproape că nu a crescut: build-ul rulează singur, iar agentul vă întreabă doar înainte de commit. Dacă interdicția pentru push se aplică întregii echipe, mutați-o în fișierul comun .claude/settings.json, conform regulii din secțiunea anterioară.

Permisiunea pentru un program întreg

Regulile de tipul Bash(python3 *), Bash(node *), Bash(npm *) sau Bash(npx *) par să permită un singur instrument. De fapt, permit orice cod pe care îl poate rula instrumentul respectiv. Permiteți un anumit script sau o anumită comandă, nu întregul program.

Ce nu detectează regula

Agentul primește un refuz. Pentru el e un răspuns obișnuit al instrumentului, iar lucrul continuă. Uneori caută o altă cale de a face același lucru. În situația asta e important să știți exact ce verifică regula.

Regula Bash(...) compară textul comenzii, nu programul care va porni. Prin urmare, interdicția acoperă forma obișnuită a comenzii, dar nu toate variantele:

  • Bash(git push *) în deny nu oprește git -C . push. Comanda e aceeași, forma de scriere diferă;
  • Bash(rm *) nu oprește /bin/rm sau bash -c 'rm ...';
  • interdicția pentru Read(...) nu împiedică un script Python să deschidă singur fișierul.

Nu renunțați la reguli din cauza asta. Agentul scrie aproape întotdeauna comanda în forma obișnuită, iar deny o detectează. Totuși, regula nu e un zid (și documentația Claude Code spune asta explicit). Ca să nu fie nevoit agentul să caute ocoliri, explicați interdicția și în CLAUDE.md: "legacy/ este înghețat; dacă sarcina cere o modificare acolo, oprește-te și întreabă". Regula impune limita, CLAUDE.md o explică, iar împreună funcționează mai bine decât separat.

Dacă limita trebuie garantată, există și alte mecanisme: un hook care verifică fiecare comandă înainte de execuție și un sandbox care restricționează accesul la nivel de sistem. Sunt subiecte separate.

Reguli pentru fiecare zi

Totul se reduce la câteva obiceiuri:

  • în deny puneți ce este interzis în proiect indiferent de situație: un folder înghețat, .env, push;
  • în ask păstrați doar cazurile-limită, în care decizia vă aparține. Dacă puneți totul în ask, revine oboseala provocată de întrebări;
  • în allow treceți reguli restrânse pentru acțiuni repetate: o verificare anume, un script anume;
  • limitele proiectului merg în fișierul comun .claude/settings.json, preferințele personale în .claude/settings.local.json;
  • deschideți din când în când /permissions și eliminați regulile adăugate prin butonul "nu mai întreba";
  • după ce adăugați o regulă, verificați-o: cereți-i agentului să facă ceva interzis și asigurați-vă că refuză.
Puteți cere agentului să propună reguli

Descrieți-i agentului în cuvinte zonele proiectului: ce poate modifica liber, ce necesită o întrebare și unde nu are voie să intre. Cereți-i să propună un bloc permissions, apoi citiți JSON-ul înainte să-l salvați și puneți-vă aceleași întrebări ca în analiza de mai sus. E regula mai largă decât trebuie? Ajunge în fișierul potrivit?

Modul stabilește ritmul general de lucru, iar regulile indică unde să-l încetiniți. Împreună vă oferă ce nu poate oferi niciun mod singur: lucru rapid acolo unde greșeala costă puțin și o întrebare sau un refuz acolo unde costă mult.