Özet ve karar
Claude Code'a sürekli yazdığın dört iş farklı dosyalara aittir. Release kontrol listesi bir skill'dir. Asla bozulmaması gereken kural bir PreToolUse hook'udur. Çok sayıda dosya okuyan denetim bir subagent'tır. Claude'un göremediği veri bir MCP sunucusudur.
Dördünü de 34 testli bir fatura API'si olan gerçek bir repoda çalıştırdık ve her seferinde önce yanlış seçimi yaptık. Yanlış seçimler ekranda başarısız oldu:
- CLAUDE.md'deki kontrol listesi, her turda /context'e bir
Memory files: 210 tokenssatırı ekledi. - İlk hook çalıştı, uyarısını yazdı ve yazma işlemi geçti (unitPrice 8000'den 12000'e).
- Doğrudan çalıştırılan denetim thread'i doldurdu: Messages 19.3k token, adı verilen subagent ile 7.2k.
- Docs sunucusu olmadan Claude şunu cevapladı: "I couldn't find that setting... I won't guess one."
Karar: türü docs tablosundan seç, sonra dosyanın sadece var olmasını değil cevap vermesini sağla. Yalnızca loglayan bir hook, yerini aldığı CLAUDE.md satırı gibi tavsiye niteliğindedir. Dördü arasında yalnızca hook asla sormaz.
Aşağıdaki dosyaları kopyala, commit et ve en çok yeniden yazdığın olanla başla.
Kaynaklı sentez
Oturumun ilk kelimenden önce neyi yüklediği. Başlangıçtaki /context okumamız 26.2k/1m token gösterdi; ne bellek satırı vardı ne MCP satırı. Eklediğin her iş bu tabloya ya bir satır koyar ya da koymaz. Önce onu oku, sonra ona göre ölç.
CLAUDE.md kuralı bir ricadır, hook zorunluluktur. Docs, CLAUDE.md'deki ya da bir skill'deki "never edit .env" gibi bir talimatın bir rica, düzenlemeyi engelleyen bir PreToolUse hook'unun ise zorunluluk olduğunu söylüyor s1. Memory sayfası CLAUDE.md'yi zorunluluk değil bağlam olarak tanımlıyor s8. Hacker News'te bir thread aynı şeyi hook tarafından bildirdi: 0 koduyla çıkan bir hook hiçbir şeyi engellemez s10.
Tetikleyici tablosu hangi dosyanın gerektiğini söyler. Bir prosedürü üçüncü kez yapıştırmak skill demektir. Sohbeti dolduran çıktı subagent demektir. Claude'un göremediği bir sekme MCP sunucusu demektir. Her seferinde olması gereken bir şey hook demektir s1.
İş 1, release kontrol listesi, bir skill'dir.
- CLAUDE.md içinde büyüyen bir prosedürün yeri bir skill'dir ve gövdesi yalnızca kullanıldığında yüklenir s3.
- Bizim çalıştırmamızda CLAUDE.md'ye yapıştırılan kontrol listesi bir
Memory files: 210 tokenssatırı ekledi.disable-model-invocation: trueile bir skill olarak /context başlangıç değerine döndü. /releasealtı adım çalıştırdı (34 test, 0.4.0'dan 0.4.1'e, tag v0.4.1). Ayrıcagit commit -amkomutunun izlenmeyen dosyaları atladığını yakaladı ve önce yeni changelog'u stage etti.
İş 2, bozulmaması gereken kural, bir hook'tur ve garanti döndürdüğü cevaptır.
- Çıktısız 0 kodu karar yokluğudur. 2 kodu engeller. Deny JSON'u da engeller s2.
- İlk hook'umuz logladı, 0 koduyla çıktı ve yazma işlemi geçti (unitPrice 8000'den 12000'e). Claude'un cevabı hook'tan hiç söz etmedi.
- Aynı hook deny JSON'unu döndürünce düzenlemeyi şu mesajla reddetti:
PreToolUse:Edit hook error: Stored data is never edited by hand: write a migration in src/store/migrations.ts (README § Conventions).Sonra Claude sordu: aşalım mı, yoksa migration mı yazalım. - Docs, korumalı dosyalar için bir PreToolUse tarifi yayımlıyor s23.
- Sınır: bu hook Edit ve Write'ı izliyor. Shell'i de kapsa ya da shell'i izin listenin dışında tut.
onFailure: "block", başarısız bir hook'un geçirmek yerine engellemesini sağlar. v2.1.295'te geldi s2 s15.
İş 3, taşıran denetim, bir subagent'tır.
- Subagent kör başlar ve bir özet döndürür s4.
- Doğrudan çalıştırınca Messages 19.3k okundu. Adı verilen subagent ile 7.2k.
- Yalnızca agent dosyası 2 çalıştırmanın 0'ında delege etti. Prompt'ta adını yazmak delege ettirdi. Dosya onu var eder, prompt'un Claude'a kullandırır.
- Dosyada
model:değerini sabitle. Fatura değişmedi: okuma yine gerçekleşiyor, sadece senin pencerende değil.
İş 4, Claude'un ulaşamadığı veri, bir MCP sunucusudur.
claude mcp add --scope projectkomutu.mcp.jsonyazar ve araç araması yalnızca araç adlarını yükler s5.- Claude Code'un kendi docs'u için,
search_claude_code_docsvequery_docs_filesystem_claude_code_docsaraçlarıyla, ücretsiz ve girişsiz bir HTTP sunucusu var s24. - Onsuz Claude şunu cevapladı: "I couldn't find that setting... I won't guess one." Onunla Claude
"onFailure": "block"cevabını verdi, v2.1.295'te eklendi, bizim kurulumumuz ise 2.1.294'tü. - Modelin zaten bildiği bir kütüphane için docs sunucusu bizde hiçbir şeyi değiştirmedi. Modelin sahip olamayacağı şeyi bağla.
Saha raporları. Bir Reddit thread'i, Claude'un CLAUDE.md'deki bir "MUST use agent" satırını yok saydığını bildirdi s9. Bunu bir ölçüm olarak değil, bir rapor olarak aktarıyoruz. Anthropic'in mühendislik yazıları aynı ayrımı ele alıyor s6 s7.
Kod
Çalıştırmadan dört dosya ve iki yardımcı. Yollar, her birinin reponda nerede durduğunu gösteriyor.
1. Release skill'i, .claude/skills/release/SKILL.md içinde. /release yaz. disable-model-invocation: true başlatmayı sana bırakır; commit ve tag atan bir iş için istenen de budur.
SKILL.md
---
name: release
description: Cut a patch release of ledgerly (typecheck, tests, version bump, changelog line, commit, tag).
disable-model-invocation: true
---
Run these steps in order and stop at the first failure:
1. `pnpm typecheck` must exit 0.
2. `pnpm test` must pass.
3. Bump the patch version in `package.json` (e.g. 0.4.0 -> 0.4.1).
4. Add one line at the top of `CHANGELOG.md` (create it if missing): `## vX.Y.Z - YYYY-MM-DD` followed by a one-line summary of the commits since the last tag.
5. `git commit -am "release vX.Y.Z"`
6. `git tag vX.Y.Z`. Never push.
2. Protect-data hook'u, .claude/settings.json içinde. Claude'un okuduğu bir gerekçeyle deny kararını döndürür. PATH'inde jq gerekir ve satır içine sığar, yani hook'un kendi script dosyasına ihtiyacı yoktur. data/.*\.json$ desenini ve gerekçeyi kendi kuralına göre değiştir.
settings.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -c 'if (.tool_input.file_path // \"\") | test(\"data/.*\\\\.json$\") then {hookSpecificOutput: {hookEventName: \"PreToolUse\", permissionDecision: \"deny\", permissionDecisionReason: \"Stored data is never edited by hand: write a migration in src/store/migrations.ts (README § Conventions).\"}} else empty end'"
}
]
}
]
}
}
3. Conventions auditor, .claude/agents/conventions-auditor.md içinde. Araçlar salt okunur olanlarla sınırlı ve model sabitlenmiş. Kurallar listesini README'ne göre düzenle.
conventions-auditor.md
---
name: conventions-auditor
description: Use when asked to audit the code against the README conventions
model: sonnet
tools: Read, Grep, Glob
---
You audit ledgerly's source against README § Conventions:
- Money is always an integer number of cents. Never floats.
- Domain functions return new objects; they never mutate their input.
- Validation failures throw `ValidationError` (400), missing records `NotFoundError` (404), illegal state transitions `ConflictError` (409).
- A change of stored shape bumps `schemaVersion` and adds a migration in `src/store/migrations.ts`.
Read every file under `src/`. Return only the findings: one line per violation as `file:line - convention - what is wrong`, then borderline cases the same way, then one line with the count of files read. No file contents, no summary of clean files.
conventions-auditor.md on GitHub
4. MCP yapılandırması, reponun kökünde .mcp.json olarak kaydedilir. claude mcp add --transport http claude-docs --scope project https://code.claude.com/docs/mcp komutunun yazdığı dosya budur. Claude Code, bir proje sunucusunu bir sonraki oturumunda onaylayana kadar beklemede olarak listeler.
mcp.json
{
"mcpServers": {
"claude-docs": {
"type": "http",
"url": "https://code.claude.com/docs/mcp"
}
}
}
Yardımcılar. ctx.sh, /context komutunu başsız bir oturumda çalıştırır ve token satırlarını yazdırır; böylece öncesini ve sonrasını karşılaştırabilirsin. mcp-probe.sh, bir HTTP MCP adresine initialize ve tools/list gönderir; sunucuyu eklemeden önce cevap verdiğini kontrol edersin.
ctx.sh
#!/usr/bin/env bash
# Usage: ctx.sh <step> -> runs "/context" through run-session.sh, writes context-<step>.txt (honours STRICT_MCP / EXTRA_ALLOW)
C="$(cd "$(dirname "$0")" && pwd)"
"$C/run-session.sh" "$C/out/context-$1.json" "/context" >/dev/null
python3 -c "import json,sys;d=json.load(open(sys.argv[1]));print(d['result'])" "$C/out/context-$1.json" > "$C/context-$1.txt"
grep -E '^\*\*Tokens|^\| (System prompt|System tools|MCP tools|Memory files|Skills|Custom agents|Messages) ' "$C/context-$1.txt"
mcp-probe.sh
#!/usr/bin/env bash
# Usage: mcp-probe.sh <url> [tools/call json params] -> initialize + notifications/initialized + tools/list (+ optional tools/call) over streamable HTTP
U="$1"; H=$(mktemp)
curl -s -D "$H" -m 30 -X POST "$U" -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}'
echo; SID=$(grep -i '^mcp-session-id:' "$H" | tr -d '\r' | cut -d' ' -f2); echo "session-id: ${SID:-none}"
HS=(-H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream'); [ -n "$SID" ] && HS+=(-H "Mcp-Session-Id: $SID")
curl -s -m 30 -X POST "$U" "${HS[@]}" -d '{"jsonrpc":"2.0","method":"notifications/initialized"}' >/dev/null
curl -s -m 30 -X POST "$U" "${HS[@]}" -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'; echo
[ -n "${2:-}" ] && { curl -s -m 90 -X POST "$U" "${HS[@]}" -d "{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"tools/call\",\"params\":$2}"; echo; }
rm -f "$H"
Pazartesi bunu yap
- Yeni bir oturum aç ve /context çalıştır. Toplamı not et. Bu senin başlangıç değerin.
- En çok yapıştırdığın kontrol listesini seç. Onu
.claude/skills/<name>/SKILL.mdiçine taşı, commit ya da tag atıyorsadisable-model-invocation: trueekle ve/<name>ile çalıştır. - Asla bozulmaması gereken tek kuralı al ve
permissionDecision: "deny"döndüren ya da 2 koduyla çıkan bir PreToolUse hook'una koy. Claude'dan kuralı çiğnemesini iste ve düzenlemenin reddedildiğini kontrol et. - Hook'un yalnızca logluyorsa onu değiştir. 0 koduyla çıkan bir hook hiçbir şeyi engellemez.
- Çok dosya okuyan bir işi, sabitlenmiş bir
model:ile.claude/agents/<name>.mdiçine taşı. Claude kendiliğinden seçene kadar prompt'unda adını yaz. - Claude'un yakın zamanda senin için tahmin ettiği bir bilgiyi kontrol et. Modelden daha yeniyse
claude mcp add --transport http <name> --scope project <url>ile bir docs sunucusu ekle ve.mcp.jsondosyasını commit et. - Bir ayara güvenmeden önce Claude Code sürümünü kontrol et.
onFailure: "block"için 2.1.295 gerekir. -
git add -A && git statusçalıştır ve yeni dosyaları commit et. Bizim çalıştırmamızda tam olarak dört tane çıktı.
Daha ileri
Seçim kartı. Tek sayfa. Bunlar docs satırları s1, üzerlerine dört işimiz yazılmış. Bu paketin kahramanı yukarıdaki dört dosya artı bu kart.
| Tür | Ne yapar | Ne zaman kullan | Bizim işimiz | Bizim dosyamız |
|---|---|---|---|---|
| CLAUDE.md | Her konuşmada yüklenen kalıcı bağlam | Claude'un iki kez yanlış yaptığı bir kural | Bir prosedür değil, bir satır | yok |
| Skill | Claude'un kullanabildiği talimatlar ve iş akışları | Aynı kılavuzu üçüncü kez yapıştırıyorsun | Release kontrol listesi | .claude/skills/release/SKILL.md |
| Hook | Olaylarla tetiklenen bir script | Sormadan, her seferinde olmasını istiyorsun | Saklanan veriyi asla elle düzenleme | .claude/settings.json |
| Subagent | Özetlenmiş sonuç döndüren yalıtılmış context | Yan bir iş konuşmanı dolduruyor | Kural denetimi | .claude/agents/conventions-auditor.md |
| MCP | Dış servislere bağlanır | Claude'un göremediği bir sekmeden sürekli veri kopyalıyorsun | Claude Code docs'u | .mcp.json |
| Plugin | Dördünü tek kurulabilir pakette toplar | İkinci bir repoda aynı kurulum gerekiyor | Kullanılmadı | yok |
Kart türü belirler, kaliteyi değil. Yalnızca loglayan bir hook, adını yazmadığın bir subagent ve modelin bildiği docs için bir sunucu, her biri doğru türdeydi ve başarısız oldu. Türü seç, sonra dosyanın cevap vermesini sağla.
Bunlara ne zaman başvurma.
- Claude'un sürekli yanlış yaptığı bir kural CLAUDE.md'de bir satır olarak kalır, prosedür olarak değil.
- İleri geri yönlendirdiğin, geçmişinin görünür olduğu bir iş ana thread'de kalır, subagent'ta değil.
- Modelin zaten bildiği bir kütüphane için docs sunucusu context'e mal olur ve hiçbir şeyi değiştirmez.
pnpm testzaten sahip olduğun bir CLI'dır. Bu bir MCP işi değil.
Plugin'ler. Plugin, dördünü birlikte taşıyan kutudur. Başka bir repo aynı kurulumu gerektirdiğinde ona başvur.
Skill artı MCP. Docs bunları eşleştiriyor: sunucu bağlantıyı sağlar, skill Claude'a onu iyi kullanmayı öğretir.
context: fork ile skill. Bir skill, çatallanmış bir subagent içinde çalışabilir; böylece okuması senin pencerenin dışında kalır. Güvenmeden önce tek bir işte dene.
Command dışındaki hook türleri. Command, kullandığımız türdü. Hooks başvuru kılavuzu http ve prompt hook'ları dahil başka işleyici türlerini listeler. Kural aynı: hook'un döndürdüğü karar verir ve sessiz bir hook hiçbir şeye karar vermez.
MCP karşı CLI. MCP sunucularının context'i yediğine dair açık bir tartışma var; bir yazı önce CLI'ı savunuyor s11, bir başkası MCP sunucularının context maliyetini ele alıyor s12. Bizim kuralımız: bir CLI işi zaten yapıyorsa onu kullan. MCP'yi CLI'ı olmayan şey için kullan. Araç araması artık yalnızca adları yüklüyor, bu yüzden karar vermeden önce kendi kurulumunda /context ile ölç s5.
Skill'leri kısa ve doğrulanmış tut. İş başına bir kısa skill, gerçek bir çalıştırmayla kontrol edilmiş. SkillsBench makalesine s13 ve skill'lerin kullanılana kadar neden az maliyetli olduğuna dair bir uygulayıcı görüşüne bak s14.
SSS
Hook'um çalıştı ama düzenleme neden yine geçti? Bir hook yalnızca komutunun döndürdüğüyle karar verir. Çıktısız 0 kodu karar yokluğudur s2. Deny JSON'unu döndür ya da 2 koduyla çık.
Bir subagent'ım varken Claude neden dosyaları kendisi okuyor? Bizim çalıştırmamızda yalnızca agent dosyası 2 çalıştırmanın 0'ında delege etti. Prompt'ta adını yaz, örneğin "use the conventions auditor subagent".
Hook, Claude'un yapabildiği her şeyi kapsıyor mu? Hayır. Bizimki Edit ve Write ile eşleşiyor. Claude sonraki bir çalıştırmada değişikliği shell üzerinden yapmayı önerdi, bu yüzden shell'i kapsa ya da izin listenin dışında tut.
Kullandığım her kütüphane için bir MCP sunucusu eklemeli miyim? Hayır. Model kütüphaneyi zaten biliyorsa sunucu hiçbir şeyi değiştirmez ve context'e mal olur. Modelden daha yeni ya da diskinin dışındaki veri için ekle ve kurulu sürümünü özelliği ekleyen sürümle karşılaştır.
Bunların hepsini commit edebilir miyim?
Evet. Skill, ayar dosyası, agent dosyası ve .mcp.json repoda durur, yani repoyu klonlayan herkes onları alır. Proje MCP sunucusunu bir sonraki oturumunda bir kez onayla.
AIDive