# Vibe Coder #4.2: Proje Kural Dosyaları – Anayasa Kökte, İç Tüzük Klasörde

> Dört kodlama ajanı da AGENTS.md okuyor ama aynı şekilde değil: biri CLAUDE.local.md görünce susuyor, biri alt klasöre inmiyor, biri yanlış yazılmış kuralı sessizce atıyor. Kural dosyası anayasa; kapıyı tutan ise izin kuralı ve kanca.

- Yazar: [Halit Yeşil](https://halityesil.com/hakkimda/)
- Yayın tarihi: 2026-10-13
- Dil: Türkçe
- Kaynak adres: https://halityesil.com/vibe-coder-4-2-agents-md-claude-md/
- İngilizce sürümü: https://halityesil.com/en/vibe-coder-4-2-agents-md-vs-claude-md.md
- Seri: [Vibe Coderin El Kitabı](https://halityesil.com/seri/vibe-coderin-el-kitabi/), bölüm 4.2
- Kategori: Vibe Coding
- Etiketler: AGENTS.md, AI Ajanları, Antigravity, Claude Code, CLAUDE.md, Codex, Cursor, Proje Kuralları, Vibe Coder
- Lisans: https://creativecommons.org/licenses/by-nc/4.0/
- Atıf: Halit Yeşil. “Vibe Coder #4.2: Proje Kural Dosyaları – Anayasa Kökte, İç Tüzük Klasörde”. halityesil.com, 2026-10-13. https://halityesil.com/vibe-coder-4-2-agents-md-claude-md/

---

[Bir önceki bölümde](https://halityesil.com/vibe-coder-4-1-mega-prompting/) şartnameyi konuştuk: her oturumda yeniden anlatmak yerine bir kez yazılıp bırakılan belge. Kapanışta da bir borç bırakmıştık: o belge diskte nerede duruyor, hangi araç onu ne zaman okuyor, iki dosya çeliştiğinde hangisi kazanıyor. Bu bölüm o borcu ödüyor. Konu **AGENTS.md**, `CLAUDE.md`, Cursor'un `.cursor/rules` klasörü ve Antigravity'nin kural dosyaları.

Metaforu baştan söyleyeyim, çünkü bütün yazı onun üstünde duruyor. Kökteki kural dosyası projenin anayasası. Alt klasörlerdeki ve dosya türüne bağlı kurallar iç tüzük. Ama anayasa kendini uygulamaz. Onu kapıda uygulatan ayrı bir bekçi var ve yazının son kısmı o bekçi hakkında.

## AGENTS.md nedir, neden tek başına yetmez?

AGENTS.md, kodlama ajanlarına projeyi anlatan düz bir Markdown dosyasıdır; kendi sitesinin tarifiyle "ajanlar için README". Format artık tek bir şirketin değil: [agents.md](https://agents.md/) sayfası formatın Linux Foundation altındaki Agentic AI Foundation tarafından yönetildiğini ve 60 binden fazla açık kaynak projede kullanıldığını yazıyor. Arkasında OpenAI, Google, Cursor, Amp ve Factory gibi şirketlerin ortak çalışması var.

4.1'de "dosya adı derdi büyük ölçüde bitti" demiştim, dört aracın dördü de bu dosyayı okuyabiliyor. Doğru. Ama "okuyabiliyor" ile "aynı şekilde okuyor" arasında koca bir boşluk var. Aynı anayasayı dört ayrı mahkeme dört ayrı usulle yorumluyor:

- **Ne zaman okuyor?** Oturum başında mı, ajan o klasöre girdiğinde mi?
- **Ne kadarını okuyor?** Bir yerde kesiyor mu, kestiğinde söylüyor mu?
- **Çakışınca kim kazanıyor?** Yakındaki mi, uzaktaki mi, yoksa hiçbiri?

Aşağıdaki her şey araçların kendi dokümanından, 11 Ekim 2026 itibarıyla.

## Dört aracın usul kanunu

### Claude Code: önce CLAUDE.md, yoksa AGENTS.md

[Claude Code](https://code.claude.com/docs/en/memory) `CLAUDE.md` dosyasını dört yerde arıyor: kurumun yönettiği politika dosyası, kullanıcının `~/.claude/CLAUDE.md` dosyası, projedeki `./CLAUDE.md` (ya da `./.claude/CLAUDE.md`) ve git'e girmeyen kişisel `CLAUDE.local.md`. Çalıştığınız dizin ve üstündeki dizinlerdeki dosyalar açılışta yükleniyor; alt klasördekiler ise Claude o klasördeki bir dosyayı okuduğunda, yazdığında ya da düzenlediğinde.

İki ayrıntı önemli. Birincisi, dosyalar birbirini ezmiyor, ucuca ekleniyor: kökten çalışma dizinine doğru sıralanıyor, yakın olan en son okunuyor. Doküman çelişki için şunu söylüyor: iki talimat birbiriyle çelişirse Claude birini keyfî olarak seçebilir. Yani "yakın olan kazanır" diye bir garanti yok.

İkincisi AGENTS.md. v2.1.277'den beri Claude Code onu doğrudan okuyor, ama bir şartla: çalışma dizininizde ya da üstünde `CLAUDE.md`, `.claude/CLAUDE.md` veya `CLAUDE.local.md` yoksa. **Gizli Hazine:** listedeki üçüncü dosya. Ekip AGENTS.md ile çalışıyor, siz de kendi notlarınız için git'e girmeyen bir `CLAUDE.local.md` açtınız. O andan itibaren Claude sizin makinenizde ekibin AGENTS.md dosyasını okumuyor. Doküman bunu açıkça yazıyor ve çözümünü de veriyor: "Project instructions" ayarını `claude-md-and-agents-md` yapmak.

İç tüzük tarafı `.claude/rules/` klasörü. Her dosyaya `paths` alanıyla bir dosya deseni verirseniz kural yalnızca o desene uyan dosyaya dokunulduğunda yükleniyor. `@dosya/yolu` ile içe aktarma da var, en fazla dört kademe derinliğe kadar. Önerilen boy dosya başına 200 satırın altı.

### Codex: kökten aşağı, en fazla dizin başına bir dosya

[Codex](https://learn.chatgpt.com/docs/agent-configuration/agents-md) önce `~/.codex` altında global dosyaya bakıyor: `AGENTS.override.md` varsa onu, yoksa `AGENTS.md`'yi alıyor. Sonra projenin kökünden çalışma dizinine doğru iniyor ve her dizinde en fazla bir dosya alıyor: önce `AGENTS.override.md`, sonra `AGENTS.md`, sonra ayarlarda tanımladığınız yedek adlar.

Sıralama kökten aşağı ve yakın olan sonra geldiği için öncekini geçersiz kılıyor. Dokümanın açıkça yazdığı bir kural daha var: Codex aramayı çalışma dizininde durduruyor. **Teknik Detay:** bu tarife göre Codex'i projenin kökünden başlatırsanız `api/AGENTS.md` dosyası zincire girmiyor, çünkü arama aşağı değil, kökten sizin bulunduğunuz yere kadar. Alt klasörün iç tüzüğü ancak oradan başlattığınızda yürürlüğe giriyor. Toplam boy varsayılan olarak 32 KiB ile sınırlı (`project_doc_max_bytes`); sınıra gelince sonraki dosyalar eklenmiyor.

Neyin yüklendiğini görmek için dokümanın önerdiği komut:

```bash
# Proje kökünde: Codex hangi talimatları gördüğünü öncelik sırasıyla saysın
codex --ask-for-approval never "Summarize the current instructions."
```

### Cursor: .mdc kuralları ve iç içe AGENTS.md

[Cursor](https://cursor.com/docs/context/rules) proje kurallarını `.cursor/rules` altında tutuyor ve uzantı konusunda katı: dosya `.mdc` olmalı, düz `.md` dosyası kural sistemi tarafından yok sayılıyor. Dört tür var: her zaman uygulanan, akıllıca uygulanan (açıklamaya bakıp ajan karar veriyor), belirli dosyalara uygulanan (`globs`) ve elle çağrılan. Önerilen boy 500 satırın altı.

AGENTS.md hem kökte hem alt klasörlerde destekleniyor; iç içe dosyalar üst dizinle birleştiriliyor, çakışmada daha özel olan öne geçiyor. Bir de kurumsal katman var: Team Rules → Project Rules → User Rules sırasıyla uygulanıyor ve çakışmada önce gelen kazanıyor. Yani Cursor'da şirketin kuralı sizin kişisel kuralınızı ezer, tersi olmaz.

Eski `.cursorrules` dosyasına gelince: Cursor'un eski doküman sayfası onu "hâlâ destekleniyor ama kullanımdan kaldırıldı" diye anıyordu, bugünkü kural sayfası ise adını hiç geçirmiyor. Yeni projede açmayın, eskisinde taşımayı takvime koyun.

### Antigravity: her klasörde, ama tetikleyicisiz kural yok

[Antigravity](https://www.antigravity.google/docs/rules) projenin herhangi bir alt klasöründe `AGENTS.md`, `GEMINI.md` ya da `.agents/rules/` klasörü kabul ediyor. Okunan veya düzenlenen dosyanın klasöründen çalışma alanının köküne doğru yukarı çıkıyor ve her seviyedeki kuralı yüklüyor. Kurallar birikiyor, birbirinin yerine geçmiyor; çakışmada daha özel dizin kuralı öncelikli. Global kurallar `~/.gemini/` altında.

`.agents/rules/` içindeki her dosya YAML ön bilgisinde bir `trigger` istiyor: `always_on`, `model_decision`, `glob` veya `manual`. **Acı Gerçek:** ön bilgisi olmayan ya da tetikleyicisi tanınmayan kuralı Antigravity sessizce atıyor. Dokümanın kendi örneği `alwaysOn`: tek harf büyük yazılınca kural hiç yüklenmiyor ve hata da vermiyor. Bütçe tarafında tek dosya 24.000 baytta kesiliyor; global ve `always_on` kurallar toplam 20.000 tokenlik bir bütçeyi paylaşıyor, taşanlar yalnızca işaretçiye düşürülüyor.

## Çakışınca kim kazanıyor?

Dört aracı yan yana koyunca tablo şöyle:

| | Okuduğu dosyalar | Alt klasör | Çakışmada | Sınır |
|---|---|---|---|---|
| Claude Code | CLAUDE.md, CLAUDE.local.md, `.claude/rules/`; CLAUDE.md yoksa AGENTS.md | O klasörde dosyaya dokununca | Hepsi eklenir, yakın olan son okunur; çelişkide seçim keyfî olabilir | Dosya başına 200 satır önerisi |
| Codex | AGENTS.override.md, AGENTS.md, yedek adlar | Yalnızca kökten çalışma dizinine kadar | Yakın olan sonra gelir, öncekini geçersiz kılar | Toplam 32 KiB |
| Cursor | `.cursor/rules/*.mdc`, AGENTS.md (kök ve alt klasör) | İç içe AGENTS.md birleşir | Özel olan öne geçer; Team → Project → User | Kural başına 500 satır önerisi |
| Antigravity | AGENTS.md, GEMINI.md, `.agents/rules/*.md` | Dosyanın klasöründen köke kadar | Birikir; özel dizin kuralı öncelikli | Dosya 24.000 bayt, always_on toplam 20.000 token |

AGENTS.md sitesinin kendi kuralı "düzenlenen dosyaya en yakın AGENTS.md kazanır, sohbetteki açık istek her şeyi ezer". Tabloya bakınca bunun araçların çoğunda tuttuğunu, birinde ise tutmadığını görüyorsunuz. Bundan çıkan pratik kural, **alt klasördeki dosyaya üsttekiyle çelişen kural yazmamak.** İç tüzük anayasayı daraltabilir, onunla kavga etmemeli. "Kökte `mysql` istemcisi kullanılır, `api/` altında yalnızca PDO" bir daraltma. "Kökte onay iste, `scripts/` altında isteme" bir çelişki ve dört araçtan biri bunu keyfî çözer.

## Anayasa kökte, iç tüzük klasörde

Benim önerdiğim düzen tek bir kaynak üzerine kurulu:

- **Kökte AGENTS.md**: ortam, yasaklar, onay kapıları, tuzaklar. 4.1'deki şartname buraya.
- **Claude Code için kökte CLAUDE.md**: tek satır `@AGENTS.md` ve altına yalnızca Claude'a özgü eklemeler. Windows'lu ekip arkadaşınız varsa sembolik bağlantı yerine bu.
- **Alt klasörde AGENTS.md**: o klasörün daraltmaları. Codex bunları yalnızca o klasörden başlatıldığında görüyor.
- **Dosya türüne bağlı kural gerekiyorsa** her araç kendi biçimiyle: `.claude/rules/*.md` (`paths`), `.cursor/rules/*.mdc` (`globs`), `.agents/rules/*.md` (`trigger: glob`). Bu tek yer gerçekten araç başına kopya istiyor; kısa tutun.

Bu dağılımın en tehlikeli yanı, hataların sessiz olması. Uzantısı yanlış bir Cursor kuralı, tetikleyicisi yanlış yazılmış bir Antigravity kuralı, 32 KiB'yi aşan bir Codex zinciri, yanlışlıkla açılmış bir `CLAUDE.local.md`: hiçbiri hata vermiyor. Ajan sadece o satırları görmüyor. O yüzden bunları elle aramak yerine küçük bir denetçi yazdım. Çerçeve yok, düz PHP 8.3:

```php
<?php

declare(strict_types=1);

/**
 * Kural dosyası denetimi: dört aracın sessizce yuttuğu durumları listeler.
 * Kullanım: php kural-denetimi.php /proje/yolu
 * Sınırlar araçların kendi dokümanlarından (Ekim 2026).
 */

$kok = rtrim($argv[1] ?? getcwd(), '/');
$uyarilar = [];

$dosyalar = new RecursiveIteratorIterator(
    new RecursiveCallbackFilterIterator(
        new RecursiveDirectoryIterator($kok, FilesystemIterator::SKIP_DOTS),
        fn (SplFileInfo $f) => !in_array($f->getFilename(), ['.git', 'vendor', 'node_modules'], true)
    )
);

foreach ($dosyalar as $dosya) {
    $yol = substr($dosya->getPathname(), strlen($kok) + 1);
    $ad = $dosya->getFilename();
    $bayt = $dosya->getSize();

    if ($ad === 'CLAUDE.md') {
        $satir = count(file($dosya->getPathname()));
        if ($satir > 200) {
            $uyarilar[] = "$yol: $satir satır. Claude Code dosya başına 200 satırın altını öneriyor.";
        }
    }

    if ((in_array($ad, ['AGENTS.md', 'GEMINI.md'], true) || str_contains($yol, '.agents/rules/')) && $bayt > 24000) {
        $uyarilar[] = "$yol: $bayt bayt. Antigravity 24.000 baytın sonrasını kesiyor.";
    }

    if (str_contains($yol, '.cursor/rules/') && $dosya->getExtension() === 'md') {
        $uyarilar[] = "$yol: Cursor .cursor/rules altında düz .md dosyasını yok sayıyor, uzantı .mdc olmalı.";
    }

    if (preg_match('#(^|/)\.agents/rules/[^/]+\.md$#', $yol)) {
        $bas = (string) file_get_contents($dosya->getPathname(), false, null, 0, 512);
        if (!preg_match('/^---\R.*?^trigger:\s*(always_on|model_decision|glob|manual)\s*$/ms', $bas)) {
            $uyarilar[] = "$yol: geçerli 'trigger' yok. Antigravity bu kuralı sessizce atıyor.";
        }
    }
}

// Codex kökten çalışma dizinine kadar AGENTS.md zincirini birleştirir; varsayılan tavan 32 KiB.
$zincir = 0;
foreach (glob($kok . '/{AGENTS.md,AGENTS.override.md}', GLOB_BRACE) ?: [] as $f) {
    $zincir += filesize($f);
}
if ($zincir > 32 * 1024) {
    $uyarilar[] = "Kök AGENTS dosyaları toplam $zincir bayt. Codex 32 KiB'de yüklemeyi durduruyor.";
}

// Claude Code: CLAUDE.local.md varsa AGENTS.md artık okunmuyor (varsayılan ayarda).
$claudeVar = is_file("$kok/CLAUDE.md") || is_file("$kok/.claude/CLAUDE.md");
if (is_file("$kok/AGENTS.md") && !$claudeVar && is_file("$kok/CLAUDE.local.md")) {
    $uyarilar[] = 'CLAUDE.local.md var, CLAUDE.md yok: Claude Code varsayılan ayarda AGENTS.md dosyanızı okumaz.';
}

echo $uyarilar === [] ? "Temiz.\n" : implode(PHP_EOL, $uyarilar) . PHP_EOL;
exit($uyarilar === [] ? 0 : 1);
```

Bilerek bozulmuş bir deneme klasöründe (40.000 baytlık AGENTS.md, yanında `CLAUDE.local.md`, `.cursor/rules/php.md`, `trigger: alwaysOn` yazılmış bir Antigravity kuralı, 250 satırlık `api/CLAUDE.md`) altı uyarının altısını da verdi ve 1 koduyla çıktı; temiz klasörde "Temiz." deyip 0 döndü. Çıkış kodu sayesinde CI'a da takılabiliyor. Kapsamı dar: Codex'in alt klasör zincirini değil yalnızca kökü topluyor, Claude Code'un üst dizinlerine çıkmıyor. Bir denetçi, hâkim değil.

## Anayasa kendini uygulamaz

4.1'de bir uyarı yapmıştık, burada somutlaştıralım. Claude Code dokümanı bu dosyaların zorlayıcı yapılandırma değil, bağlam olarak yüklendiğini söylüyor. "Onaysız silme yok" satırı anayasada yazılı; ajanın bunu okuyup uyması iyi niyete kalmış. Kapıda durduran bekçi ayrı ve her araçta adı farklı:

- **Claude Code**: `settings.json` içinde `permissions` kuralları (önce `deny`, sonra `ask`, sonra `allow` değerlendiriliyor) ve `PreToolUse` kancası.
- **Codex**: `~/.codex/rules/` altında Starlark ile yazılan `.rules` dosyaları; `allow`, `prompt`, `forbidden`. Doküman bunun deneysel olduğunu belirtiyor.
- **Cursor**: `.cursor/hooks.json` içinde `beforeShellExecution` kancası; `deny` dönerse ya da betik 2 koduyla çıkarsa komut çalışmıyor.
- **Antigravity**: izin ayarlarında Deny → Ask → Allow sırasıyla kurallar ve Default, Request Review, Turbo ön ayarları.

4.1'deki onay kapısının ("veriyi değiştirmeden önce say, söyle, bekle") kapıdaki karşılığı Claude Code tarafında şöyle bir kanca:

```bash
#!/bin/bash
# .claude/hooks/onay-kapisi.sh — Claude Code PreToolUse kancası.
# Veri silen SQL komutunu durdurur; gerekçeyi stderr ile Claude'a geri verir.
KOMUT=$(jq -r '.tool_input.command // empty')

if echo "$KOMUT" | grep -qiE '(DROP[[:space:]]+(TABLE|DATABASE)|TRUNCATE([[:space:]]+TABLE)?[[:space:]]+[a-z_]|DELETE[[:space:]]+FROM)'; then
  echo "Durduruldu: veri silen SQL komutu. Önce COUNT(*) ile etkilenecek kaydı söyle, onay bekle." >&2
  exit 2
fi

exit 0
```

Kancayı `.claude/settings.json` içinde `PreToolUse` olayına, `Bash` eşleştiricisiyle bağlıyorsunuz. Betiği örnek girdilerle denedim: `DELETE FROM` ve `TRUNCATE` 2 koduyla durdu, `SELECT COUNT(*)` geçti. İlk sürümümde desen düz `DROP` kelimesini arıyordu ve `git log | grep -i drop-shadow` komutunu da durdurdu. Kelimeyle avlanan kanca masum yolcuyu da çevirir. Claude Code dokümanı da aynı yere işaret ediyor: kancanın komut filtresi elinden gelenin en iyisini yapar, kesin izin ve yasak için izin sistemini kullanın.

Codex'te aynı fikrin karşılığı bir önek kuralı. `match` ve `not_match` örnekleri dosya yüklenirken doğrulanıyor; kural yanlış yazılmışsa hemen öğreniyorsunuz:

```python
# ~/.codex/rules/default.rules (Starlark)
prefix_rule(
    pattern = ["git", "push"],
    decision = "prompt",
    justification = "Uzak depoya göndermeden önce onay iste",
    match = ["git push origin main"],
    not_match = ["git status"],
)
```

Denemek için `codex execpolicy check --pretty --rules ~/.codex/rules/default.rules -- git push origin main` komutu hangi kararın verildiğini ve hangi kuralın eşleştiğini gösteriyor. Bu kuralı ve komutu Codex üzerinde ben çalıştırmadım; sözdizimi dokümandaki örnekten.

**Sonuç:** kural dosyasına "neden"i, kapıya "ne"yi yazın. Anayasa ajana neden durması gerektiğini anlatır; kanca durmadığı gün onu durdurur.

## Ne zaman işe yarar, ne zaman yaramaz?

**Yarar:** ekipte birden fazla araç kullanılıyorsa; monorepo'da klasörlerin kuralları gerçekten farklıysa; kökteki şartname 4.1'deki bütçeleri zorlamaya başladıysa.

**Yaramaz:** tek kişilik projede, tek araçla çalışıyorsanız kökte tek AGENTS.md yeter, iç tüzüğe gerek yok. Her klasöre dosya serpmek okunurluğu değil karmaşayı artırır; üç ay sonra hangi kuralın nereden geldiğini siz de bilemezsiniz.

[Araçları konuştuğumuz bölümde](https://halityesil.com/vibe-coder-3-1-ai-native-ide-dunyasi-cursor-windsurf-ve-ajanlarin-uyanisi/) "hangisini nasıl yazacağımız 4.2'nin konusu" demiştik; o hesap da burada kapandı. Bir sonraki bölümde, Vibe Coder #4.3: Iterative Development – Fili Dilim Dilim Yemek'te, bu kuralların altında işi nasıl küçük parçalara böleceğimize bakacağız. Serinin tamamı ve yayınlanan bölümlerin listesi [Vibe Coder El Kitabı](https://halityesil.com/vibe-coder-el-kitabi-sentaksin-olumu-orkestrasyonun-dogusu/) sayfasında.

Anayasayı yazmak kolay. Kapıya bekçi koymayan proje, anayasasını ajanın vicdanına emanet ediyor. Teknolojiyle kalın.
