Özet
Claude Code kaynak kodu sızıntısı, 31 Mart 2026 tarihinde 512.000 satırlık bir TypeScript kod tabanını ortaya çıkardı. Mimari, Claude API'sini çağıran, araç çağrılarını gönderen ve sonuçları geri besleyen bir while döngüsüne indirgeniyor. Kendi sürümünüzü Python, Anthropic SDK ve temel döngü için yaklaşık 200 satır kod kullanarak oluşturabilirsiniz. Bu kılavuz, her bir bileşeni ayrıntılarıyla anlatıyor ve bunları nasıl yeniden oluşturacağınızı gösteriyor.
Giriş
31 Mart 2026'da Anthropic, @anthropic-ai/claude-code npm paketinin 2.1.88 sürümünün içine 59.8 MB'lık bir kaynak haritası dosyası gönderdi. Kaynak haritaları, küçültülmüş JavaScript'i orijinal kaynağına döndüren hata ayıklama yapıtlarıdır. Anthropic'in derleme aracı (Bun'ın paketleyicisi) bunları varsayılan olarak ürettiği için, TypeScript kod tabanının tamamı kurtarılabilirdi.
Saatler içinde geliştiriciler, kodu onlarca GitHub deposuna yansıttı. Topluluk, ana aracı döngüsünden "gizli mod" ve sahte araç enjeksiyonu gibi gizli özelliklere kadar her modülü hızla inceledi.
Tepkiler ikiye ayrıldı. Bazıları Anthropic'in güvenlik uygulamalarını eleştirdi. Diğerleri ise mimariye hayran kaldı. Ancak en verimli yanıt, "Bunu kendim yapabilir miyim?" diye soran geliştiricilerden geldi.
Cevap evet. Temel desenler basittir. Bu rehber, her bir mimari katmanı hızlıca uygulamanız için örnek kod ve pratik açıklamalar sunar. Ayrıca, çok turlu API konuşmalarında hata ayıklamayı ham curl komutlarından çok daha kolay hale getiren Apidog ile özel aracınızın API etkileşimlerini nasıl test edeceğinizi de göstereceğiz.
Sızıntı, Claude Code'un mimarisi hakkında neyi ortaya çıkardı?
Kod tabanına bir bakış
Dahili olarak "Tengu" kod adlı Claude Code, yaklaşık 1.900 dosyadan oluşuyor. Modül organizasyonu şöyle ayrılıyor:
cli/ - Terminal UI (React + Ink)
tools/ - 40+ tool implementations
core/ - System prompts, permissions, constants
assistant/ - Agent orchestration
services/ - API calls, compaction, OAuth, telemetry
CLI'nin kendisi React + Ink ile yazılmış bir terminal uygulaması. Ancak, çalışan bir kodlama aracısı için React tabanlı bir terminal UI'ye ihtiyacınız yok. Basit bir REPL döngüsü yeterli.
Ana aracı döngüsü
Tüm karmaşıklığı çıkarınca, Claude Code'un çekirdeği bir while döngüsüne indirgeniyor. Temel akış:
- Claude API'ye mesaj gönder (sistem istemi + araç tanımları)
- Metin ve/veya
tool_useblokları içeren bir yanıt al - Her istenen aracı, ad-işleyici dağıtımı ile çalıştır
- Araç sonuçlarını mesaj listesine geri ekle
- Yanıt daha fazla araç çağrısı içeriyorsa, 1. adıma dön
- Yanıt araç çağrısı içermiyorsa, kullanıcıya döndür
Python’da minimal bir uygulama:
import anthropic
client = anthropic.Anthropic()
MODEL = "claude-sonnet-4-6"
def agent_loop(system_prompt: str, tools: list, messages: list) -> str:
"""The core agent loop - keep calling until no more tool use."""
while True:
response = client.messages.create(
model=MODEL,
max_tokens=16384,
system=system_prompt,
tools=tools,
messages=messages,
)
messages.append({"role": "assistant", "content": response.content})
if response.stop_reason != "tool_use":
return "".join(
block.text for block in response.content
if hasattr(block, "text")
)
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = execute_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": result,
})
messages.append({"role": "user", "content": tool_results})
Bu yaklaşık 30 satır. Geri kalan karmaşıklık araç tanımları, izinler ve bağlamdan geliyor.
Araç sistemini oluşturma
Neden özel araçlar tek bir bash komutundan daha iyidir?
Claude Code, dosya işlemleri için özel araçlar kullanıyor. Örneğin Read, Edit, Grep, Glob gibi araçlar bash yerine kendi tanımlı işlevlerle çalışıyor. Bunun üç sebebi:
- Yapılandırılmış çıktı: Araç yanıtları tutarlı ve ayrıştırılabilir.
-
Güvenlik: Ters tırnak ve
$()gibi riskli shell özellikleri engelleniyor. - Token verimliliği: Araç çıktıları gereksiz yere büyük olmaz, bağlamı israf etmez.
Temel araç seti
Basit bir aracı için şu araçlar yeterli:
TOOLS = [
{
"name": "read_file",
"description": "Read a file from the filesystem. Returns contents with line numbers.",
"input_schema": {
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "Absolute path to the file"
},
"offset": {
"type": "integer",
"description": "Line number to start reading from (0-indexed)"
},
"limit": {
"type": "integer",
"description": "Max lines to read. Defaults to 2000."
}
},
"required": ["file_path"]
}
},
{
"name": "write_file",
"description": "Write content to a file. Creates the file if it doesn't exist.",
"input_schema": {
"type": "object",
"properties": {
"file_path": {"type": "string", "description": "Absolute path"},
"content": {"type": "string", "description": "File content to write"}
},
"required": ["file_path", "content"]
}
},
{
"name": "edit_file",
"description": "Replace a specific string in a file. The old_string must be unique.",
"input_schema": {
"type": "object",
"properties": {
"file_path": {"type": "string", "description": "Absolute path"},
"old_string": {"type": "string", "description": "Text to find"},
"new_string": {"type": "string", "description": "Replacement text"}
},
"required": ["file_path", "old_string", "new_string"]
}
},
{
"name": "run_command",
"description": "Execute a shell command and return stdout/stderr.",
"input_schema": {
"type": "object",
"properties": {
"command": {"type": "string", "description": "Shell command to run"},
"timeout": {"type": "integer", "description": "Timeout in seconds. Default 120."}
},
"required": ["command"]
}
},
{
"name": "search_code",
"description": "Search for a regex pattern across files in a directory.",
"input_schema": {
"type": "object",
"properties": {
"pattern": {"type": "string", "description": "Regex pattern"},
"path": {"type": "string", "description": "Directory to search"},
"file_glob": {"type": "string", "description": "File pattern filter, e.g. '*.py'"}
},
"required": ["pattern"]
}
}
]
Araç işleyici dağıtımı
Araç fonksiyonlarını eşleştiren örnek bir dispatcher:
import subprocess
import os
import re
def execute_tool(name: str, params: dict) -> str:
"""Dispatch tool calls to their handlers."""
handlers = {
"read_file": handle_read_file,
"write_file": handle_write_file,
"edit_file": handle_edit_file,
"run_command": handle_run_command,
"search_code": handle_search_code,
}
handler = handlers.get(name)
if not handler:
return f"Error: Unknown tool '{name}'"
try:
return handler(params)
except Exception as e:
return f"Error: {str(e)}"
def handle_read_file(params: dict) -> str:
path = params["file_path"]
offset = params.get("offset", 0)
limit = params.get("limit", 2000)
with open(path, "r") as f:
lines = f.readlines()
selected = lines[offset:offset + limit]
numbered = [f"{i + offset + 1}\t{line}" for i, line in enumerate(selected)]
return "".join(numbered)
def handle_write_file(params: dict) -> str:
path = params["file_path"]
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w") as f:
f.write(params["content"])
return f"Successfully wrote to {path}"
def handle_edit_file(params: dict) -> str:
path = params["file_path"]
with open(path, "r") as f:
content = f.read()
old = params["old_string"]
if content.count(old) == 0:
return f"Error: '{old[:50]}...' not found in {path}"
if content.count(old) > 1:
return f"Error: '{old[:50]}...' matches {content.count(old)} locations. Be more specific."
new_content = content.replace(old, params["new_string"], 1)
with open(path, "w") as f:
f.write(new_content)
return f"Successfully edited {path}"
def handle_run_command(params: dict) -> str:
cmd = params["command"]
timeout = params.get("timeout", 120)
blocked = ["rm -rf /", "mkfs", "> /dev/"]
for pattern in blocked:
if pattern in cmd:
return f"Error: Blocked dangerous command pattern: {pattern}"
result = subprocess.run(
cmd, shell=True, capture_output=True, text=True,
timeout=timeout, cwd=os.getcwd()
)
output = ""
if result.stdout:
output += result.stdout
if result.stderr:
output += f"\nSTDERR:\n{result.stderr}"
if not output.strip():
output = f"Command completed with exit code {result.returncode}"
if len(output) > 30000:
output = output[:15000] + "\n\n... [truncated] ...\n\n" + output[-15000:]
return output
def handle_search_code(params: dict) -> str:
pattern = params["pattern"]
path = params.get("path", os.getcwd())
file_glob = params.get("file_glob", "")
cmd = ["grep", "-rn", "--include", file_glob, pattern, path] if file_glob else \
["grep", "-rn", pattern, path]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if not result.stdout.strip():
return f"No matches found for pattern: {pattern}"
lines = result.stdout.strip().split("\n")
if len(lines) > 50:
return "\n".join(lines[:50]) + f"\n\n... ({len(lines) - 50} more matches)"
return result.stdout
Bağlam yönetimi: zor sorun
Neden bağlam, istem mühendisliğinden daha önemlidir?
Claude Code, sistem isteminden çok bağlam yönetimine mühendislik harcıyor. Otomatik sıkıştırma ve yönerge yeniden enjeksiyonu ile uzun konuşmalarda bağlam kaybı önleniyor.
- Otomatik sıkıştırma: Bağlam penceresi sınırına yaklaşınca tetiklenir, konuşmayı özetler.
- CLAUDE.md yeniden enjeksiyonu: Her turda proje yönergelerini tekrar sistem istemine ekler.
Basit bir sıkıştırıcı oluşturma
def maybe_compact(messages: list, system_prompt: str, max_tokens: int = 180000) -> list:
"""Compact conversation when it gets too long."""
total_chars = sum(
len(str(m.get("content", ""))) for m in messages
)
estimated_tokens = total_chars // 4
if estimated_tokens < max_tokens * 0.85:
return messages
summary_response = client.messages.create(
model=MODEL,
max_tokens=4096,
system="Summarize this conversation. Keep all file paths, decisions made, errors encountered, and current task state. Be specific about what was changed and why.",
messages=messages,
)
summary_text = summary_response.content[0].text
compacted = [
{"role": "user", "content": f"[Conversation summary]\n{summary_text}"},
{"role": "assistant", "content": "I have the context from our previous conversation. What should I work on next?"},
]
compacted.extend(messages[-4:])
return compacted
Proje bağlamını yeniden enjekte etme
def build_system_prompt(project_dir: str) -> str:
"""Build system prompt with project context re-injection."""
base_prompt = """You are a coding assistant that helps with software engineering tasks.
You have access to tools for reading, writing, editing files, running commands, and searching code.
Always read files before modifying them. Prefer edit_file over write_file for existing files.
Keep responses concise. Focus on the code, not explanations."""
claude_md_path = os.path.join(project_dir, ".claude", "CLAUDE.md")
if os.path.exists(claude_md_path):
with open(claude_md_path, "r") as f:
project_context = f.read()
base_prompt += f"\n\n# Project guidelines\n{project_context}"
root_md = os.path.join(project_dir, "CLAUDE.md")
if os.path.exists(root_md):
with open(root_md, "r") as f:
root_context = f.read()
base_prompt += f"\n\n# Repository guidelines\n{root_context}"
return base_prompt
Üç katmanlı bellek sistemi
Sızdırılan kaynak, Claude Code'un üç katmanlı bir bellek mimarisi kullandığını ortaya çıkardı.
Katman 1: MEMORY.md (her zaman yüklü)
Kısa, dizin formatlı, her zaman sistem istemine eklenen bir dosya:
- [User preferences](memory/user-prefs.md) - prefers TypeScript, uses Vim keybindings
- [API conventions](memory/api-conventions.md) - REST with JSON:API spec, snake_case
- [Deploy process](memory/deploy.md) - uses GitHub Actions, deploys to AWS EKS
Katman 2: Konu dosyaları (talep üzerine yüklenir)
Dizin ilgisine göre yüklenen ayrıntılı bilgi dosyaları.
Katman 3: Oturum transkriptleri (aranır, asla okunmaz)
Toptan yüklenmeyen, sadece grep ile aranan oturum günlükleri.
Minimal bir bellek sistemi oluşturma
import json
MEMORY_DIR = ".agent/memory"
def load_memory_index() -> str:
"""Load the memory index for system prompt injection."""
index_path = os.path.join(MEMORY_DIR, "MEMORY.md")
if os.path.exists(index_path):
with open(index_path, "r") as f:
return f.read()
return ""
def save_memory(key: str, content: str, description: str):
"""Save a memory entry and update the index."""
os.makedirs(MEMORY_DIR, exist_ok=True)
filename = f"{key.replace(' ', '-').lower()}.md"
filepath = os.path.join(MEMORY_DIR, filename)
with open(filepath, "w") as f:
f.write(f"---\nname: {key}\ndescription: {description}\n---\n\n{content}")
index_path = os.path.join(MEMORY_DIR, "MEMORY.md")
index_lines = []
if os.path.exists(index_path):
with open(index_path, "r") as f:
index_lines = f.readlines()
new_entry = f"- [{key}]({filename}) - {description}\n"
updated = False
for i, line in enumerate(index_lines):
if filename in line:
index_lines[i] = new_entry
updated = True
break
if not updated:
index_lines.append(new_entry)
with open(index_path, "w") as f:
f.writelines(index_lines)
Araç listenize bir save_memory aracı ekleyerek oturumlar arası kalıcılık sağlayabilirsiniz.
Bir izin sistemi ekleme
Basit üç seviyeli bir izin sistemi için:
# Risk levels for operations
RISK_LEVELS = {
"read_file": "low",
"search_code": "low",
"edit_file": "medium",
"write_file": "medium",
"run_command": "high",
}
def check_permission(tool_name: str, params: dict, auto_approve_low: bool = True) -> bool:
"""Check if the user approves this tool call."""
risk = RISK_LEVELS.get(tool_name, "high")
if risk == "low" and auto_approve_low:
return True
print(f"\n--- Permission check ({risk.upper()} risk) ---")
print(f"Tool: {tool_name}")
for key, value in params.items():
display = str(value)[:200]
print(f" {key}: {display}")
response = input("Allow? [y/n/always]: ").strip().lower()
if response == "always":
RISK_LEVELS[tool_name] = "low"
return True
return response == "y"
Aracınızın API çağrılarını Apidog ile test etme
Bir kodlama aracısı geliştirirken Claude'a çok sayıda API çağrısı yapacaksınız. Özellikle araç çağrılarıyla çok turlu konuşmalarda hata ayıklamak için görsel ve tekrar oynatılabilir bir test ortamı gereklidir.
Apidog, aracınızın gönderdiği tam API isteklerini incelemenize ve test etmenize yardımcı olur. Şöyle kullanabilirsiniz:
API isteklerini yakalama ve yeniden oynatma
- Apidog'u açın ve yeni bir proje oluşturun.
- Anthropic Mesajlar API uç noktasını ekleyin:
POST https://api.anthropic.com/v1/messages - Sistem istemi, araç dizisi ve mesajlarınızı içeren istek gövdesini oluşturun.
- Yakalanan istekleri farklı parametrelerle yeniden oynatın.
Bu yöntemle, REPL'i tamamen çalıştırmadan tekil turları, araç çağrılarını ve hata durumlarını izole edebilirsiniz.
Çok turlu konuşmalarda hata ayıklama
- Her turdan sonra tam
messagesdizisini ortam değişkeni olarak saklayın. - Konuşmanın herhangi bir anından istekleri tekrar oynatın.
- Çalıştırmalar arasında araç sonuçlarını karşılaştırarak davranış değişimini analiz edin.
Araç şemalarını doğrulama
Araç tanımlarınız (API’ye ilettiğiniz JSON şemaları) modelin davranışını doğrudan etkiler. Yanlış şema modelin aracı atlamasına veya yanlış parametre göndermesine neden olur. Apidog'un JSON şema doğrulayıcısı ile, API’ye ulaşmadan önce hataları yakalayabilirsiniz.
Aracınızın API etkileşimlerinde hata ayıklamaya başlamak için Apidog'u indirin.
Hepsini bir araya getirme: eksiksiz REPL
Aşağıdaki gibi çalışan bir REPL ile tüm sistemi birleştirebilirsiniz:
#!/usr/bin/env python3
"""A minimal Claude Code-style coding agent."""
import anthropic
import os
import sys
client = anthropic.Anthropic()
MODEL = "claude-sonnet-4-6"
PROJECT_DIR = os.getcwd()
def main():
system_prompt = build_system_prompt(PROJECT_DIR)
memory = load_memory_index()
if memory:
system_prompt += f"\n\n# Memory\n{memory}"
messages = []
print("Coding agent ready. Type 'quit' to exit.\n")
while True:
user_input = input("> ").strip()
if user_input.lower() in ("quit", "exit"):
break
if not user_input:
continue
messages.append({"role": "user", "content": user_input})
messages = maybe_compact(messages, system_prompt)
current_system = build_system_prompt(PROJECT_DIR)
memory = load_memory_index()
if memory:
current_system += f"\n\n# Memory\n{memory}"
result = agent_loop(current_system, TOOLS, messages)
print(f"\n{result}\n")
if __name__ == "__main__":
main()
Bu kod, 300 satırdan az Python ile dosya okuma, kod düzenleme, komut çalıştırma, arama, bağlam yönetimi ve oturumlar arası bellek sağlar.
Sıradaki eklenecekler
Claude Code sızıntısında ortaya çıkan ve kendi aracınıza ekleyebileceğiniz ek özellikler:
Paralel çalışma için alt aracılar
Bağımsız görevler için alt aracılar (forked agents) oluşturun. Yeni bir agent_loop() başlatın, sonucu dize olarak döndürün.
Dosya okuma tekilleştirme
Okunan dosyaların değişip değişmediğini takip edin. Değişmediyse yeniden okumayı atlayın, modele "dosya son okumadan bu yana değişmedi" mesajı gönderin.
Çıktı kırpma ve örnekleme
Büyük araç çıktılarında (örneğin 10.000 satır grep sonucu) çıktıyı kırpın ve modele kaç sonucun atlandığını bildirin.
Dosya yeniden enjeksiyonu ile otomatik sıkıştırma
Sıkıştırmadan sonra yakın zamanda erişilen dosyaların içeriğini (örneğin dosya başına 5.000 token) tekrar sisteme enjekte edin.
Sızıntıdan öğrendiklerimiz
- Temel döngü basit: Aracı döngüsü ~30 satır kod. Karmaşıklık araçlarda ve bağlam yönetiminde.
- Özel araçlar bash'ten daha iyi: Yapılandırılmış araçlar, bash komutlarından daha iyi bilgi yoğunluğu sağlar.
- Belleğin katmanlara ihtiyacı var: Her zaman yüklü bir dizin, isteğe bağlı konu dosyaları ve sadece grep ile aranan transkriptler.
- Bağlam yönetimi asıl ürün: Otomatik sıkıştırma, proje yönergesi yeniden enjeksiyonu ve çıktı kırpma, uzun oturumları sürdürülebilir kılar.
- Ürün model değil, koşum takımıdır: Model zekayı, koşum takımı dosya erişimi, eylem ve belleği sağlar.
Çok turlu araç konuşmaları ve karmaşık istek/yanıt şemalarını test etmek için Apidog’u ücretsiz deneyin. API hata ayıklamasını ona bırakın, siz aracı mantığına odaklanın.
Sıkça Sorulan Sorular
Claude Code sızıntısındaki desenleri yasal olarak kullanabilir miyim?
Mimari desenler kamuya açık. Aracı döngüsü gibi desenler standart API belgelerinde de yer alıyor. Kodun tamamını kopyalamayın; mimariyi kendi kodunuzla uygulayın.
Kendin yap bir kodlama aracısı için hangi modeli kullanmalıyım?
Claude Sonnet 4.6, kodlama görevleri için iyi bir hız/yetenek dengesi sunar. Daha karmaşık işler için Claude Opus 4.6 tercih edilebilir. Basit işler için Claude Haiku 4.5 daha ucuzdur.
Kendi kodlama aracınızı çalıştırmak ne kadara mal olur?
Claude Sonnet 4.6 ile tipik bir oturum (30-50 tur) API ücretleri olarak 1-5 dolar arası tutar. Bağlam penceresi boyutu ana maliyet kalemidir. Sıkıştırma maliyetleri düşürür.
Claude Code neden terminal uygulaması için React kullanıyor?
Ink (terminaller için React), ekibin izin iletişim kutuları, akışlı çıktı ve araç çağrısı gösterimleri gibi karmaşık UI etkileşimleri için React’in bileşen modelini kullanmasını sağlar. DIY projede basit bir input() / print() REPL yeterli.
Temel döngüden sonra inşa edilecek en önemli özellik nedir?
İzin sistemi. Olmazsa model dosyaları silebilir veya rastgele komutlar çalıştırabilir. Küçük bir "önce onayla" kapısı bile kazara zararı engeller.
Claude Code, araç çağrılarından kaynaklanan hataları nasıl ele alıyor?
Araç hataları, tool_result mesajında metin olarak döndürülür. Model hatayı görür ve yeniden dener, farklı yaklaşım dener veya kullanıcıya sorar. Özel bir hata yönetimi yoktur.
Bunu Claude dışındaki modellerle kullanabilir miyim?
Evet. Fonksiyon çağrısını destekleyen GPT-4, Gemini, Llama gibi diğer modellerle de çalışır. API çağrı formatını uyarlamanız gerekir.
Aracının tehlikeli komutları çalıştırmasını nasıl engellerim?
rm -rf /, mkfs gibi tehlikeli desenleri engelleyin ve tüm run_command çağrıları için açık onay isteyin. Claude Code da her işlemi DÜŞÜK, ORTA, YÜKSEK risk olarak sınıflandırır.
Yukarıdaki adımları uygulayarak Claude Code tarzı bir aracı hızlıca inşa edebilir, Apidog ile her aşamada API etkileşimlerinizi görsel olarak test edip hata ayıklayabilirsiniz.

Top comments (0)