Manual modunda sıradan bir saatlik çalışma şöyle geçer: ajan projeyi okur, bir değişiklik önerir, testleri çalıştırmak için izin ister, sonra yine değişiklik ve yine testler gelir. Yirminci soruda neredeyse bakmadan "Yes" düğmesine basarsınız. Bu soruların arasında bir yerde, projede uzun zamandır kimsenin dokunmadığı ve dokunmaması gereken legacy/ klasöründe bir değişiklik de gözden kaçabilir.

Bu makalede, yalnızca kararın gerçekten size ait olduğu yerlerde soru sorulmasını sağlayacağız. Claude Code'da bunun için erişim kuralları bulunur: ayar dosyasındaki üç liste, ajanın neleri hemen yapabileceğini, neleri sorması gerektiğini ve neleri hiç yapmaması gerektiğini belirtir. Neden gerekli olduklarına, nasıl okunacaklarına ve muhtemelen zaten elinizde olan kurallar dosyasını nasıl düzenleyeceğinize bakalım.

Tek ayar her şeyi yönetiyor

Erişim modu, tüm oturumu yöneten tek bir düğme gibidir. İstediğiniz yöne çevirebilirsiniz, ama yalnızca bütünüyle.

Sıkı Manual modunda ajan her düzenlemeden, neredeyse her komuttan önce izin ister. Siz soruyu okuduğunuz sürece bu koruma işe yarar. Soru sayısı artınca insanlar okumayı bırakır ve koruma kâğıt üzerinde kalır.

Daha serbest acceptEdits modunda düzenlemeler sorulmadan yapılır; rm ve mv gibi dosya komutları da öyle. Kendi kodunuz için kullanışlıdır. Ancak mod klasörler arasında ayrım yapmaz: legacy/ içindeki değişiklik de projenin başka bir yerindeki gibi sessizce uygulanır.

CLAUDE.md dosyasına "legacy/ klasörüne dokunma" yazabilirsiniz. Ajan buna uymaya çalışır ama bu modele yönelik bir istektir, yasak değildir. Erişim kurallarını eylem gerçekleşmeden önce Claude Code denetler; CLAUDE.md dosyasındaki veya isteğinizdeki metin bu kuralları etkilemez.

Farklı eylemlerin hata maliyeti farklı, ama mod hepsine aynı yanıtı veriyor. Testleri sessizce çalıştırmak mantıklı. Başka bir modüldeki değişikliği görmek istersiniz. Dondurulmuş klasöre ise ajanın hiç girmemesi gerekir. Üç farklı eylem için üç farklı yanıt var, ama mod bunları tek başına sağlayamaz.

Üç liste

Kurallar tam da bu üç yanıtı sağlar:

  • allow - sormadan uygula. Gürültüyü keser: sık tekrarlanan ve güvenli işler artık dikkatinizi dağıtmaz;
  • ask - her zaman sor. Kararın size ait olduğu yerde soruyu korur; en serbest modda bile geçerlidir;
  • deny - uygulama. Ajan ret yanıtı alır, size soru bile gösterilmez. Bu da her modda geçerlidir.

Kurallar, örneğin projenin .claude/settings.json dosyası gibi bir ayar dosyasına yazılır. Girişteki proje için şöyle görünebilir:

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

Burada src/partner/ dikkatle değiştirdiğiniz başka bir modül, legacy/ projenin dondurulmuş bölümü, npm test ise ajanın bir görev sırasında defalarca çalıştırdığı kontroldür. İki yıldız, "klasörün içindeki her şey, hangi derinlikte olursa olsun" anlamına gelir.

Şimdi oturumda nelerin değiştiğine bakalım. Üç farklı durumda aynı beş eylem:

EylemKuralsız ManualKuralsız acceptEditsKurallı acceptEdits
src/ klasörünün geri kalanında düzenlemesorarsormazsormaz
src/partner/ içinde düzenlemesorarsormazsorar
legacy/ içinde düzenlemesorarsormazreddeder
npm testsorarsorarsormaz
git pushsorarsorarreddeder

Son sütuna bakın. Oturum hızlı modda ilerliyor: kendi kodunuz kesintisiz düzenleniyor, testler otomatik çalışıyor. Yalnızca gerçekten değişikliği görmek istediğiniz yer için bir soru kaldı. Kabul edilemez iki eylem de akşam ne kadar yorulduğunuza bağlı olmaktan çıktı.

Kuralların amacı tam olarak bu. Mesele ajana daha fazla izin vermek değil, izinleri hata maliyetine göre düzenlemek. Böylece daha serbest bir modda çalışırken önemli alanlardaki kontrolü koruyabilirsiniz.

Bir eylem aynı anda birden fazla kurala uyabilir. Bu yüzden Claude Code listeleri katı bir sırayla denetler:

Kuralların denetlenme sırası. Ajanın eylemi önce deny listesiyle karşılaştırılır: eşleşirse reddedilir. Eşleşmezse ask listesine bakılır: eşleşirse her modda soru sorulur. O da eşleşmezse allow listesine bakılır: eşleşirse eylem sormadan uygulanır. Hiçbir eşleşme yoksa kararı mod verir: Manual modunda ajan sorar, acceptEdits modunda düzenleme doğrudan yapılır.Ajanın eylemikomut, düzenleme, okumadeny ile eşleşti mi?ask ile eşleşti mi?allow ile eşleşti mi?Reteylem uygulanmazSoruher moddaSormadanhemen uygulanırEşleşme yok - kararı mod verirManual modunda ajan sorar, acceptEdits modunda düzenleme doğrudan yapılırevetevetevethayırhayırhayır
Yukarıdan aşağıya ilk eşleşme belirleyicidir

Şema yukarıdan aşağıya okunur ve her ajan eylemi bu kontrolden yeniden geçer. Bir kural eşleştiği anda denetim biter; daha spesifik bir kural öncelik kazanmaz. deny içinde Bash(git push *) varsa, allow içindeki hiçbir kural push komutuna izin veremez. Yasağı yanlışlıkla geçersiz kılamazsınız; iyi ki de öyle.

En alttaki dikdörtgeni ayrıca aklınızda tutun. Bir eylemin hiçbir listeyle eşleşmemesi, "izin verildi" demek değildir. Kararı mod verir: Manual modunda ajan sorar, acceptEdits modunda düzenleme doğrudan yapılır. Yani kurallar modu geçersiz kılmaz; adını koyduğunuz noktalarda onu netleştirir.

Bir kural nasıl okunur?

Neredeyse doğru yazılmış bir kural, hiç olmamasından daha kötüdür. Kural yoksa sınırın bulunmadığını bilirsiniz. Kural hatalıysa sınırın var olduğundan emin olursunuz ama o sınır düşündüğünüz şeyi korumaz.

Tüm kuralların biçimi aynıdır: araç adı ve parantez içinde hangi çağrının kastedildiği. Parantez yoksa kural aracın tüm çağrıları için geçerlidir; dolayısıyla deny içindeki Bash ajanın terminal erişimini tümüyle kaldırır.

Dosyalar

Dosyalar için iki araç gerekir: her türlü düzenleme için Edit, okuma için Read. Yol, .gitignore'daki gibi bir kalıpla yazılır: tek yıldız bir klasördeki her adı, iki yıldız iç içe tüm düzeyleri kapsar. Başında eğik çizgi olmayan yol, oturumun başlatıldığı klasöre göre değerlendirilir. Bu nedenle Claude Code'u projenin kökünden başlatın.

Sık yapılan bir hata Write(legacy/**) yazmaktır. Ajanın böyle bir aracı vardır ama Claude Code dosya kurallarını yalnızca Edit ve Read için denetler. Write kuralını kabul eder, başlangıçta bu konuda uyarır ve sonra onu hiç denetlemez. Oysa Edit, yeni dosya oluşturma dahil, yerleşik tüm dosya değiştirme yöntemlerini kapsar.

Bir de işinize yarayacak bir ayrıntı: deny içindeki Read(./.env) gibi bir okuma yasağı, ajanın bu dosyayı düzenlemesini de engeller.

Komutlar

Bash(...) kuralı komutun metnini karşılaştırır. Yıldız boşluklar dahil herhangi bir metnin yerini tutar. Kuralın eşleşip eşleşmeyeceğini üç ayrıntı belirler:

  • yıldız yoksa kural yalnızca harfiyen aynı komutla eşleşir;
  • yıldız alt komuttan sonra konur. Bash(git log *) yalnızca git log komutunu her türlü seçenekle geçirir; Bash(git *) ise push dahil her git komutunu geçirir;
  • yıldızdan önceki boşluk da kuralın parçasıdır: Bash(ls *), lsof ile eşleşmez, ancak Bash(ls*) eşleşir.
Komut kuralı metinle nasıl eşleşir? Bash(git log *) kuralında git log bölümü harfiyen karşılaştırılır; yıldız --oneline main kısmını kapsar, dolayısıyla kural yalnızca her türlü seçenekle git log komutunu geçirir. Bash(git *) kuralında yalnızca git harfiyen karşılaştırılır; yıldız push origin main kısmını kapsar, dolayısıyla push dahil her git komutu geçer.Bash(git log *)Bash(git *)yalnızca git log, her türlü seçeneklepush dahil her git komutugit log--oneline maingitpush origin mainyıldıza kadar: harfiyenyıldızın yerine: herhangi bir metin
Kuralın sınırını yıldızdan önceki metin belirler

Mavi bölüm komutla harfiyen karşılaştırılır; turuncu bölümü ise yıldız, içinde ne olursa olsun tümüyle kapsar. Bu yüzden kuralın kapsamını yıldızdan önce yazılanlar belirler. İlk kuralda bu bölüm git log; geçmişi görüntülemek dışında bir şeye izin vermez. İkincisinde yalnızca git var; yıldızdan sonra push, dal silme veya değişiklikleri sıfırlama gelebilir. Başkasının kuralını okurken önce şunu sorun: yıldızdan önce ne yazıyor?

KuralEşleşirEşleşmez
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 *)git push dahil tüm git komutları-
Edit(src/partner/**)src/partner/ içindeki herhangi bir dosyayı düzenlemesrc/app.js dosyasını düzenleme
Read(./.env)projenin kökündeki .env dosyasını okuma.env.example dosyasını okuma

a && b biçimindeki birleşik komutları Claude Code parçalara ayırır. allow ancak her parça kendi izniyle eşleşirse komutun tamamına izin verir. ask ve deny ise parçalardan en az biri eşleştiğinde devreye girer. Yani npm test izni, npm test && git push komutunun tamamını geçirmez.

Başka araçlar için de kurallar yazılabilir. Örneğin mcp__github__* tek bir MCP sunucusunun tüm araçlarını, WebFetch(domain:example.com) ise tek bir siteden sayfa yüklemeyi kapsar. Mantık aynıdır; burada ayrı ayrı incelemeyeceğiz.

Kurallar hangi dosyada tutulmalı?

Kuralı yanlış dosyaya koymak işleri sessizce bozabilir. Yasağı kişisel dosyanıza yazarsanız ekip arkadaşlarınızda bulunmaz; onların ajanı da legacy/ klasörüne rahatça girer. Kendinize uygun bir izni ortak dosyaya koyarsanız projeyi indiren herkese gider.

DosyaKimin kuralları?Git'e eklenir mi?
~/.claude/settings.jsonBu bilgisayardaki tüm projelerde sizin kurallarınızHayır, ev dizininizde bulunur
.claude/settings.jsonProjede çalışan herkes için ortakEvet, commit edilir
.claude/settings.local.jsonYalnızca bu projede sizin kurallarınızHayır

Bu üç dosyanın yanı sıra kurumunuz kendi ayar dosyasını dağıtabilir; bu dosyanın kuralları geçersiz kılınamaz. Eğitim projelerinde genellikle böyle bir dosya bulunmaz.

Farklı dosyalardaki listeler birbiriyle çakışmaz, birleşir: sizin dosyanızdaki allow, ortak dosyanın allow listesine eklenir. Denetim sırası herkes için aynıdır ve herhangi bir dosyadaki deny, başka bir dosyadaki allow kuralından üstündür. Kuralları buna göre dağıtın: legacy/, .env veya push gibi proje sınırlarını depoyla birlikte taşınacak ortak dosyaya koyun. Kendi çalışma biçiminize uygun kolaylıkları yerel dosyada tutun.

Ortak dosyanın bir koruma özelliği vardır. İçindeki allow kuralları, klasöre güvendiğinizi onayladıktan sonra etkinleşir: Claude Code projede ilk kez başlatıldığında bunu sorar ve dosyanın neleri yapmaya izin vereceğini gösterir. ask ve deny yalnızca kısıtlama getirdikleri için hemen uygulanır. Tüm terminal için izin içeren yabancı bir depo, siz onay vermeden hiçbir erişim kazanmaz.

Gerçekte hangi kuralların geçerli olduğunu iki komutla görebilirsiniz. /permissions tüm kuralları ve her birinin geldiği dosyayı gösterir; buradan kural ekleyebilir veya silebilirsiniz. /status çıktısındaki Setting sources satırı yüklenen dosyaları listeler. Claude Code dosyalardaki değişiklikleri yeniden başlatma olmadan alır. Ayar dosyası katı JSON biçimindedir: // ile yorum eklemek veya son öğeden sonra virgül koymak dosyayı bozar; Claude Code başlangıçta sizi uyarır.

Kendiliğinden yazılan dosya

Ajan bir komut için izin istediğinde "Yes, and don't ask again" seçerseniz Claude Code allow kuralını .claude/settings.local.json dosyasına yazar. Dosya henüz yoksa oluşturur ve commitlere eklenmemesini sağlar. Dosya düzenlemelerinde durum farklıdır: onay oturum sonuna kadar geçerlidir, dosyaya yazılmaz.

Gerçek bir settings.local.json dosyasını inceleyelim

Muhtemelen bu dosya sizde zaten var ve onu siz oluşturmadınız. Her "bir daha sorma" seçimi dosyaya bir satır ekledi; birkaç hafta sonra dosya ajana düşündüğünüzden daha fazla izin veriyor olabilir. İşte bir Python projesinde birkaç haftalık çalışma sırasında biriken gerçek bir bölüm:

{
  "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 *)"
    ]
  }
}

Çözümlemeyi okumadan önce kendiniz deneyin. Hangi satırları bırakır, hangilerini daraltır, hangilerini kaldırırdınız?

Bash(python3 *)
Dosyadaki en geniş kural bu. Herhangi bir betiği ve python3 -c üzerinden her türlü kodu çalıştırmaya izin verir. Python her şeyi yapabilir: dosyaları silebilir, ağa bağlanabilir, başka programları başlatabilir. Yani özünde, her şeyi sormadan çalıştırma iznidir. Kuralı, ortaya çıkmasına neden olan belirli betiğe daraltın; örneğin Bash(python3 scripts/build.py *).

Bash(PYTHONIOENCODING=utf-8 python3 *)
Bu, başına bir ortam değişkeni eklenmiş aynı komut. allow kuralı bu biçimi yalnızca değişken önceden bilinen güvenli değişkenlerden oluşan kısa listede yer alıyorsa geçirir. Listede yoksa Bash(python3 *) komutu kapsamaz; ajan ayrıca sorar ve düğmeye basmanız yeni bir kural kaydeder. Bu satır muhtemelen böyle oluştu. Bunu da belirli bir betiğe daraltabilirsiniz.

git status, git log, git diff, git show
Bu komutlar olağan biçimleriyle yalnızca okuma yapar; Claude Code da okuma komutlarını hiçbir kural gerekmeden ve soru sormadan çalıştırır. Satırlar zarar vermez ama pek bir şey de katmaz. Kaldırırsanız dosya daha kısa ve anlaşılır olur.

Bash(git branch *)
Zararsız görünüyor: dal listesini gösteriyor. Ancak kural metni karşılaştırır ve git branch -D feature da git branch ile başlar. Dal silme işlemi sorulmadan yapılır. Bu satırı kaldırmak daha iyi. Dal listesini gösterme sorusu rahatsız etmeye başlarsa yıldız kullanmadan tam Bash(git branch) komutuna izin verin.

git add ve git fetch
İlki değişiklikleri sonraki commit için hazırlar, ikincisi sunucudaki güncel geçmişi indirir ve çalışma dosyalarına dokunmaz. İkisini de kolayca geri alabilirsiniz; kalabilirler.

Bash(git commit *)
Ajan sormadan commit atar, yani siz diff'i okumadan önce. İşte tam da burada soru gerekli: commit, değişikliği onayladığınız andır. Bu satırı ask listesine taşıyın. Yalnızca silmek yetmez. Manual modunda ajan zaten sorar ama ask en serbest mod dahil her modda soruyu korur.

Dosyada olmayan kural
git push. Bu iyi; ancak kimsenin push için "bir daha sorma" düğmesine basmamış olmasına bağlı. Yasağı açıkça yazmak daha güvenlidir.

İncelemeden sonra ortaya çıkan düzenleme şöyle:

{
  "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 *)"
    ]
  }
}

On satırdan altısı kaldı ve her biri amaçlandığı işi yapıyor. Çalışırken soru sayısı neredeyse artmadı: derleme otomatik ilerliyor, ajan yalnızca commit öncesinde bir kez soruyor. Push yasağı tüm ekibi ilgilendiriyorsa, onu önceki bölümdeki kurala uygun olarak ortak .claude/settings.json dosyasına taşımak daha iyi olur.

Bir programın tamamına izin vermek

Bash(python3 *), Bash(node *), Bash(npm *) veya Bash(npx *) gibi kurallar tek bir araca izin veriyormuş gibi görünür. Aslında bu, aracın çalıştırabildiği her türlü koda izin vermektir. Programın tamamına değil, belirli bir betiğe veya komuta izin verin.

Kuralın yakalayamadıkları

Ajan bir ret yanıtı alır. Bu, ajan için sıradan bir araç yanıtıdır ve çalışmaya devam eder. Bazen aynı işi yapmanın başka bir yolunu arar. Bu noktada kuralın tam olarak neyi denetlediğini bilmek önemlidir.

Bash(...) kuralı çalıştırılacak programı değil, komut metnini karşılaştırır. Bu nedenle yasak, komutun alışılmış biçimini engeller ama olası tüm biçimlerini değil:

  • deny içindeki Bash(git push *), git -C . push komutunu durdurmaz. Komut aynı, yazımı farklı;
  • Bash(rm *), /bin/rm veya bash -c 'rm ...' komutlarını durdurmaz;
  • Read(...) yasağı, dosyayı kendi açan bir Python betiğini engellemez.

Bu yüzden kurallardan vazgeçmeniz gerekmez. Ajan komutu neredeyse her zaman alışılmış biçimiyle yazar ve deny tam da bu biçimi yakalar. Ancak kural aşılmaz bir duvar değildir; Claude Code belgeleri de bunu açıkça belirtir. Ajanın aşmanın yolunu aramasını önlemek için yasağı CLAUDE.md içinde sözcüklerle açıklayın: "legacy/ donduruldu; görev orada değişiklik gerektiriyorsa dur ve sor". Kural engeller, CLAUDE.md açıklar; birlikte kullanıldıklarında tek başlarına olduklarından daha etkilidirler.

Sınırın kesin olarak korunması gerekiyorsa başka mekanizmalar da vardır: her komutu çalıştırılmadan önce denetleyen bir hook ve erişimi sistem düzeyinde kısıtlayan bir sandbox. Bunlar ayrı konular.

Günlük kullanım kuralları

Birkaç alışkanlıkla özetleyelim:

  • deny listesine bu projede hiçbir koşulda yapılmaması gerekenleri koyun: dondurulmuş klasör, .env, push;
  • ask listesinde yalnızca kararın size ait olduğu sınır durumlar bulunsun. Her şey için ask kullanmak, o soru yorgunluğunu geri getirir;
  • allow listesi dar kapsamlı ve tekrarlanan işleri içersin: belirli bir kontrol, belirli bir betik;
  • proje sınırlarını ortak .claude/settings.json dosyasına, kişisel kolaylıkları .claude/settings.local.json dosyasına koyun;
  • arada bir /permissions komutunu açın ve "bir daha sorma" düğmesiyle biriken kuralları temizleyin;
  • yeni bir kural ekledikten sonra test edin: ajandan yasaklı eylemi yapmasını isteyin ve reddedildiğini doğrulayın.
Kuralları ajana yazdırabilirsiniz

Proje alanlarını ajana sözcüklerle anlatın: nerede serbestçe düzenleme yapılabilir, nerede izin istenmeli, hangi klasöre girilmemeli? permissions bloğu önermesini isteyin ve kaydetmeden önce JSON'u yukarıdaki incelemede kullandığınız sorularla gözden geçirin. Kural gerekenden geniş mi? Doğru dosyaya mı yazılacak?

Mod genel çalışma hızını belirler, kurallar bu hızın nerede düşeceğine karar verir. Birlikte, hiçbir modun tek başına sağlayamadığı şeyi sunarlar: hata maliyetinin düşük olduğu yerde hızlı çalışma, yüksek olduğu yerde soru veya ret.