Permission Mode'ları, Settings ve Sandbox: Claude Code'u Kontrollü Çalıştırmak
Claude Code'da neye izin verildiğini CLAUDE.md değil, Claude Code'un kendisinin uyguladığı permission kuralları belirler: deny her seviyede ve her modda kazanır, ama Bash kuralı programı değil komut metnini eşler. Altı permission mode, Auto mode classifier'ı, settings.json katmanları ve öncelik, allow/ask/deny sözdizimi, Bookstore'un ekip ayarları ve native Windows'ta olmayan sandbox.
Sürüm notu: Bu yazı Claude Code 2.1.325'i (13 Kasım 2026) anlatır; permission mode'ları, kural syntax'ı, ayar katmanları ve sandbox davranışı 15 Kasım 2026'da code.claude.com/docs'taki Permission modes, Configure permissions, Settings files and precedence ve Sandboxing sayfalarından kontrol edilmiştir. Bu yazıda resmî belgelerden yararlanılmıştır. Örnek ayar dosyaları yerelde JSON olarak ayrıştırılıp doğrulanmıştır.
Önce Tahmin Et
Emre, sitedeki serilerin ortak örnek uygulaması Bookstore'da (bir online kitapçı) Claude Code'un her komutta onay istemesinden sıkıldı. Ekibin commit'lediği .claude/settings.json'a "Bash(*)" ekledi, bağlantı bilgisini korumak için de Read(**/appsettings.Production.json) deny kuralı yazdı. Sonra session'ı Auto moda aldı ve rahatladı: "Artık her şey sormadan çalışıyor, gizli bilgi de güvende."
Tahminin ne? Auto modda Bash(*) kuralı hâlâ her komutu onaysız çalıştırır mı? Ve Claude grep -r ConnectionStrings . ya da dotnet user-secrets list çalıştırırsa o deny kuralı bağlantı bilgisinin context'e girmesini durdurur mu? İlk cevap Auto mode bölümünde, ikincisi kural yazımı bölümünde.
Önceki yazıda CLAUDE.md'nin Claude'un ne yapmaya çalışacağını şekillendirdiğini, ama neye izin verildiğini belirlemediğini görmüştük. Belgeler bunu tek cümleyle söylüyor: permission kuralları modelin değil, Claude Code'un kendisinin uyguladığı kurallardır. Bu yazı o katmanı anlatıyor. AI araçlarında secret ve prompt injection risklerinin araçtan bağımsız tarafı AI Destekli Geliştirme serisinin beşinci yazısında, derin güvenlik anlatımı da LLM Uygulama Güvenliği serisinde.
Altı Permission Mode
Permission mode, Claude'un hangi işlemleri sana sormadan yapacağını belirliyor. Belgelerdeki altı mod:
| Mod (ayar değeri) | Sormadan çalışan | Ne zaman |
|---|---|---|
Manual (default) | Yalnız okuma | Hassas iş, her adımı görmek istediğinde |
Accept edits (acceptEdits) | Okuma, dosya düzenleme, mkdir, touch, rm, mv, cp, sed gibi dosya komutları | Review ettiğin kod üzerinde hızlı ilerlerken |
Plan (plan) | Okuma ve keşif komutları; kaynak kodu düzenlemez | Değiştirmeden önce keşif ve plan (dördüncü yazı) |
Auto (auto) | Her şey, ama ayrı bir classifier modelin kontrolüyle | Uzun işler, onay yorgunluğunu azaltmak |
Don't ask (dontAsk) | Yalnız önceden izin verilen tool'lar; soru gerektiren her şey reddedilir | CI ve script'ler (onuncu yazı) |
Bypass permissions (bypassPermissions) | Her şey | Yalnız izole container ya da VM |
Etkileşimli session'da Shift+Tab modlar arasında döner: Auto'dan Manual'a, sonra Accept edits ve Plan. Bypass yalnız açılışta etkinleştirildiyse döngüye girer, Don't ask hiç girmez ve yalnız --permission-mode dontAsk ile seçilir. Durum çubuğunda ⏸ manual mode on ya da ⏵⏵ auto mode on gibi bir etiket aktif modu gösterir.
Session'ın hangi modda başlayacağı üç kaynaktan sırayla belirleniyor: --permission-mode bayrağı, ayar dosyalarındaki permissions.defaultMode, sonra yerleşik varsayılan. 2.1.283'ten beri yerleşik varsayılan, terminal ve Visual Studio Code'daki etkileşimli session'lar için Auto. İki istisna önemli: claude -p ve Agent SDK koşuları Manual başlıyor, yani onay gerektiren çağrılar reddediliyor; ve proje ayar dosyalarına (.claude/settings.json ya da .claude/settings.local.json) yazılan auto ya da bypassPermissions değeri dikkate alınmıyor. Bir repo'nun kendi kendine seni Bypass moduna alamaması bilinçli bir tasarım.
Bütün modlarda geçerli iki kural var. Deny kuralları Bypass dahil her modda engelliyor. Ve .git, .vscode, .claude, .mcp.json, .bashrc, .npmrc gibi korumalı yollara yazmak Manual ve Accept edits'te soruya dönüşüyor, Auto'da classifier'a gidiyor, Don't ask'te reddediliyor; yalnız Bypass sormadan yazıyor. Kök dizin, ev klasörü ya da çalışma dizini gibi kritik yolları silen rm ve rmdir komutları ise hiçbir allow kuralıyla otomatik onaylanmıyor.
Auto Mode Nasıl Karar Veriyor?
Auto modda her işlem çalışmadan önce ayrı bir classifier modelden geçiyor. Belgelerdeki varsayılan engel listesinde şunlar var: indirilen kodu çalıştırmak (curl | bash gibi), hassas veriyi dış bir adrese göndermek, production deploy'ları ve migration'ları, force push, commit edilmemiş değişiklikleri silen git reset --hard ve git clean -fd gibi komutlar, terraform destroy türü altyapı silme komutları, IAM (Identity and Access Management; bulutta kimin neye erişebileceğini yöneten servis) ya da repo yetkisi vermek ve kimsenin onaylamadığı bir pull request'i merge etmek. Varsayılan olarak izin verilenler arasında çalışma dizinindeki dosya işlemleri, lock dosyasında ya da manifest'te tanımlı bağımlılıkların kurulması, salt okuma HTTP istekleri ve üzerinde çalıştığın repo'nun branch'lerine push var; production gibi deploy hedefi adını taşıyan branch'ler hariç.
Classifier bir işlemi engellediğinde bildirim gösteriliyor ve işlem /permissions içindeki Recently blocked sekmesine düşüyor; oradan onaylarsan Claude tekrar deneyebilir. Arka arkaya 3 ya da toplam 20 engelden sonra Auto mode duraklıyor ve Claude Code tekrar sana sormaya başlıyor. Auto mode bütün planlarda var; Team ve Enterprise'da varsayılan açık ve yönetici managed settings'te permissions.disableAutoMode değerini "disable" yaparak kapatabiliyor. Anthropic API'de Opus 4.6 ve sonrası, Sonnet 4.6 ve sonrası, Haiku 5.5 ya da bir Fable modeli gerekiyor. Belgelerin uyarısı da açık: Auto mode soru sayısını azaltır, güvenliği garanti etmez.
Tahmindeki ilk sorunun cevabı burada. Auto moda girerken Claude Code geniş allow kurallarını devre dışı bırakıyor: Bash(*) ve PowerShell(*) gibi her şeyi kapsayan kurallar, Bash(python*) gibi joker karakterli yorumlayıcı kuralları, paket yöneticisinin script çalıştırma komutları ve subagent ile Monitor tool'u için yazılmış allow kuralları. Bash(npm test) gibi dar kurallar geçerli kalıyor; Auto'dan çıkınca düşürülen kurallar geri geliyor. Yani Emre'nin Bash(*) kuralı Auto modda hiçbir şeyi classifier'ın önünden geçirmiyor; Manual modda ise her komutu sormadan çalıştırıyor, ki bu daha da kötü.
settings.json Katmanları
Permission kuralları ve diğer ayarlar dört dosyadan okunuyor. Kullanıcı ayarları ~/.claude/settings.json (Windows'ta %USERPROFILE%\.claude\settings.json) bu makinedeki bütün projelerde senin için geçerli. Paylaşılan proje ayarları .claude/settings.json repo'ya commit'leniyor ve ekipteki herkese gidiyor. Proje local ayarları .claude/settings.local.json yalnız sana ve yalnız bu projeye ait; Claude Code bu dosyayı ilk yazdığında global git excludes dosyasına ekliyor, dosyayı elle oluşturduysan .gitignore'a eklemek sana kalıyor. Managed settings ise organizasyonun MDM (Mobile Device Management; şirket cihazlarını merkezden yöneten sistem) profili, sistem klasöründeki bir managed-settings.json ya da claude.ai yönetici konsolundan dağıttığı ayarlar.
Aynı anahtar birden fazla yerde varsa öncelik yukarıdan aşağıya şöyle: managed settings, komut satırında --settings ile verilen JSON, proje local, paylaşılan proje, kullanıcı. Ama permissions.allow gibi listeler birleşiyor, birbirini ezmiyor. Kurallar arasında da bir mutlak öncelik var: bir tool herhangi bir seviyede deny edildiyse başka hiçbir seviye ona izin veremiyor. Kullanıcı ayarındaki bir deny, projedeki allow'u bloke ediyor; managed bir deny'ı --allowedTools bile aşamıyor.
Ayar dosyaları katı JSON: yorum satırı ya da sondaki virgül bir sonraki açılışta Settings Error olarak raporlanıyor. Dosyanın başına $schema satırı eklemek Visual Studio Code'da otomatik tamamlama ve satır içi doğrulama sağlıyor. Hangi dosyaların yüklendiğini /status içindeki Setting sources satırı gösteriyor, reddedilen girdileri de terminalde claude doctor listeliyor. Bir prompt'ta "Yes, and don't ask again" seçtiğinde kaydedilen kural, repo'nun kökündeki .claude/settings.local.json dosyasına yazılıyor; yani bu seçenek ekibin değil, senin ayarını değiştiriyor.
Kural Yazımı: allow, ask, deny
Kurallar Tool ya da Tool(specifier) biçiminde. Değerlendirme sırası sabit: önce deny, sonra ask, sonra allow; ilk eşleşen sonucu belirliyor ve kuralın ne kadar özel olduğu bu sırayı değiştirmiyor. Bash(git *) deny'ı, Bash(git status) allow'unu da bloke eder. Bash kurallarında * boşluk dahil her metni karşılıyor ve yıldızdan önceki boşluk kuralın parçası: Bash(ls *) ls -la'yı eşler, lsof'u eşlemez; Bash(ls*) ikisini de eşler. Belgelerin önerisi yıldızı alt komuttan sonra koymak: Bash(git log *) yalnız git log'a, Bash(git *) bütün git komutlarına izin verir.
Claude Code shell operatörlerini tanıyor. &&, ||, ; ve | ile birleştirilmiş bir komut alt komutlara bölünüyor ve her alt komutun ayrı ayrı izinli olması gerekiyor; Bash(npm test *) izni npm test && curl ... komutunu onaylamıyor. timeout, nice, nohup gibi sarmalayıcılar eşleştirmeden önce soyuluyor; ama npx ve docker exec soyulmuyor, bu yüzden Bash(npx *) gibi bir kural arkasından gelen her komutu onaylar.
Belgelerin önemli bir uyarısı var: Bash kuralı, Claude'un yazdığı komut metnini eşliyor; aynı programı başka biçimde çağıran komutu değil. Bash(curl *) deny'ı /usr/bin/curl ya da sh -c 'curl ...' çağrısını durdurmuyor. Yani Bash deny kuralları Claude'un sık kullandığı biçimi engelliyor, programın etrafında bir güvenlik sınırı çizmiyor.
Dosya kuralları Read(...) ve Edit(...) ile yazılıyor ve gitignore syntax'ını kullanıyor. //path dosya sisteminin kökünden mutlak yol, ~/path ev klasöründen, /path ayarın tanımlandığı kaynağa göre (proje ayarında proje kökü), path ya da ./path çalışma dizinine göre. Tuzak tek eğik çizgide: /home/user/file mutlak yol değil. Windows yolları eşleştirmeden önce /c/Users/... biçimine çevriliyor. Bir Read deny'ı aynı yolda Edit ve Write'ı da engelliyor; .claudeignore diye bir dosya ise hiçbir şey yapmıyor.
Tahmindeki ikinci sorunun cevabı burada. Read ve Edit deny kuralları Claude'un kendi dosya tool'larına, Claude Code'un tanıdığı cat, head, tail, sed gibi Bash komutlarına ve > file gibi redirection'lara uygulanıyor. Dosyayı adıyla anmadan okuyan bir komuta (dosyayı içeren dizinden çalıştırılan grep -r pattern .) ya da dosyayı kendi içinde okuyan bir alt sürece uygulanmıyor. dotnet user-secrets list tam olarak böyle bir alt süreç. Bu yüzden Bookstore ayarlarında o komut ayrıca deny ediliyor ve asıl savunma başka yerde: geliştirici makinesinde production bağlantı bilgisi bulunmaması.
Bookstore: Ekip Ayarları ve Kişisel Ayarlar
Ekibin commit'lediği .claude/settings.json. Git for Windows'u olmayan makinelerde Claude komutları PowerShell tool'uyla çalıştırdığı için her Bash kuralının bir PowerShell karşılığı var; PowerShell kurallarında komut adı ve takma adlar büyük-küçük harf ayırmadan eşleşiyor:
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(dotnet build *)",
"Bash(dotnet test *)",
"Bash(npm test *)",
"Bash(npm run build *)",
"PowerShell(dotnet build *)",
"PowerShell(dotnet test *)",
"PowerShell(npm test *)",
"PowerShell(npm run build *)"
],
"ask": [
"Bash(dotnet ef database update *)",
"Bash(git push *)",
"PowerShell(dotnet ef database update *)",
"PowerShell(git push *)",
"Edit(/src/Bookstore.Api/Data/Migrations/**)"
],
"deny": [
"Read(**/.env)",
"Read(**/.env.*)",
"Read(**/appsettings.Production.json)",
"Bash(dotnet user-secrets *)",
"PowerShell(dotnet user-secrets *)"
]
}
}
Migration klasörü için deny değil ask kullandık. dotnet ef migrations add yeni dosyaları kendi alt süreciyle yazdığı için bu kurala takılmıyor; Claude'un mevcut bir migration'ı Edit tool'uyla değiştirmeye kalkması ise her seferinde sana soruluyor; belgelere göre eşleşen bir ask kuralı Auto modda da soru sorduruyor. Yeni ve eski migration dosyasını ayırt eden kesin bir engeli yedinci yazıda hook ile yazacağız. Proje ayarındaki allow kuralları ve ek dizinlerin bir de güven koşulu var: her ekip arkadaşı klasör için workspace trust penceresini onaylayana kadar uygulanmıyorlar. Deny ve ask kuralları ise kısıtladıkları için hemen geçerli.
Emre'nin kişisel .claude/settings.local.json dosyası. Local dosyada defaultMode olarak acceptEdits geçerli, auto ya da bypassPermissions değil:
{
"permissions": {
"defaultMode": "acceptEdits",
"allow": [
"Bash(docker start bookstore-sql)",
"PowerShell(docker start bookstore-sql)"
]
}
}
User-secrets ve bulut kimlik bilgileri repo'nun dışında, ev klasöründe duruyor; bu yüzden onları korumanın yeri kullanıcı ayarları. Proje dışı dosyaların okunması zaten onay gerektiriyor, ama açık bir deny Auto modda da kesin:
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"deny": [
"Read(~/AppData/Roaming/Microsoft/UserSecrets/**)",
"Read(~/.azure/**)",
"Read(~/.ssh/**)"
]
}
}
Sandbox: İşletim Sistemi Seviyesinde Sınır
Permission kuralları Claude Code'un hangi tool'u çağırabileceğini belirliyor; sandbox ise çalışan shell komutunun ve onun başlattığı süreçlerin dosya sistemi ve ağ erişimini işletim sistemi seviyesinde sınırlıyor. Bu, tahmindeki grep -r açığını da kapatan katman. Varsayılan olarak yazma çalışma dizini, kullanıcıya özel geçici klasör ve eklenen dizinlerle sınırlı; okuma ise makinenin büyük bölümüne açık, bu yüzden hassas klasörleri filesystem.denyRead ile kapatman gerekiyor. Ağ trafiği bir proxy'den geçiyor ve yalnız network.allowedDomains listesindeki adreslere izin veriliyor; liste boş başlıyor.
Windows kullanıcısı için kritik ayrıntı: sandbox macOS'ta yerleşik Seatbelt ile, Linux'ta ve WSL (Windows Subsystem for Linux; Windows içindeki Linux ortamı) 2'de bubblewrap ve socat ile çalışıyor; native Windows'ta desteklenmiyor ve komutlar sandbox'sız çalışıyor. Sandbox'a ihtiyacın varsa Claude Code'u WSL 2 içinde çalıştırman gerekiyor. Orada /sandbox komutuyla ya da ayarlarla açılıyor:
{
"sandbox": {
"enabled": true,
"filesystem": {
"denyRead": ["~/.azure", "~/.ssh"]
},
"network": {
"allowedDomains": ["api.nuget.org", "*.npmjs.org", "github.com"]
}
}
}
Sandbox yolları permission kurallarından farklı yazılıyor: mutlak ya da ev klasörüne göre yollar, // öneki yok. 2.1.325 ile bir davranış değişti: sandbox içinde çalışan Bash komutları artık varsayılan olarak normal permission akışından geçiyor; sandbox'lı komutların sormadan çalışmasını istiyorsan sandbox.autoAllowBashIfSandboxed değerini true yapman gerekiyor. Sandbox'ın kapsamadıkları da belli: Claude'un Read, Edit ve Write tool'ları, WebFetch, MCP (Model Context Protocol; dış araç ve veri kaynaklarına bağlanma protokolü) server'ları ve hook'lar sandbox dışında çalışıyor. Bir komut sandbox'ta başarısız olursa Claude onu sandbox dışında tekrar denemeyi isteyebilir; bu kaçış yolunu "allowUnsandboxedCommands": false kapatıyor.
Üretimde Dikkat
Bypass permissions'ı yalnız atılabilir bir container ya da VM'de kullan. Claude Code onu Linux ve macOS'ta root ya da sudo altında çalıştırmayı zaten reddediyor; şirket makinelerinde yönetici permissions.disableBypassPermissionsMode ile tamamen kapatabiliyor. Bir geliştirici bu anahtarı kendi kullanıcı ayarına yazarak kendini de kilitleyebiliyor.
Gözetimsiz çalışan bir session'ın bir prompt'ta takılıp beklemesini istemiyorsan, 2.1.319'dan beri permissions.denyInsteadOfPrompting soru gerektiren çağrıyı beklemek yerine reddediyor. Bu anahtar mevcut permission mode ile birlikte çalışıyor; Don't ask ayrı bir mod.
Ekipçe zorunlu olması gereken kuralları managed settings'e koy. allowManagedPermissionRulesOnly açıkken permission kuralları yalnız managed kaynaktan okunuyor. Ekip ayar dosyasını da kod gibi review et: .claude/settings.json'a eklenen tek bir allow satırı, ekipteki herkesin makinesinde sorulmadan çalışan bir komut demek.
Sık Düşülen Tuzaklar
Geniş allow kuralları. Bash(*) Manual modda her şeyi açar, Auto modda zaten düşürülür; iki durumda da istediğin şeyi yapmaz. Komut ailesini dar yaz.
Deny'ı tek savunma sanmak. Bash kuralı komut metnini eşler, programı değil; Read deny alt süreçleri durdurmaz. Hassas veriyi makineden uzak tut, gerekiyorsa sandbox ekle.
PowerShell kurallarını unutmak. Git for Windows olmayan bir makinede yalnız Bash(...) yazılmış bir ayar dosyası, Claude'un çalıştırdığı hiçbir komutu eşlemez.
Proje ayarına "defaultMode": "auto" yazıp çalışmasını beklemek. Proje ve local dosyalarda auto ve bypassPermissions yok sayılıyor; kendi varsayılanın için kullanıcı ayarını kullan.
Tek eğik çizgiyle mutlak yol yazmak. Read(/c/secrets/**) proje köküne göre çözülür; mutlak yol için // gerekir.
Küçük Bir Deneme
★☆☆ Bir session'da /status ile yüklenen ayar kaynaklarını, /permissions ile aktif kuralları ve her kuralın hangi dosyadan geldiğini listele. Beklemediğin bir kural var mı?
★★☆ Ekip ayar dosyasına Bash(git *) allow'u ile Bash(git push *) deny'ını ekle. git -C . push gibi bir çağrının neden deny'a takılmadığını belgelerdeki "What a Bash rule doesn't match" bölümüyle açıkla ve kuralı daraltarak düzelt.
★★★ WSL 2'de Claude Code'u sandbox açık çalıştır, network.allowedDomains'e yalnız NuGet ve npm adreslerini yaz. dotnet restore ve npm ci çalışırken başka bir adrese giden bir isteğin nasıl ele alındığını izle ve gördüğünü not et.
Kontrol katmanı yerinde olduğunda sıra günlük iş akışına geliyor. Dördüncü yazıda plan mode ile önce keşfedip planlamayı, Bookstore'a düşük stok bildirimi özelliğini adım adım eklemeyi, /goal ile tamamlanma koşulu vermeyi ve checkpoint'lerle context'i yönetmeyi göreceğiz.