Raporlama Modelin İşi Olmamalı: Claude Code Oturumlarını Organizasyon Şeması Gibi Yönetmek
Birden fazla Claude Code oturumunu tek elden yönettirmek istiyorsanız ilk kararınız şu olmalı: rapor, modelin hatırlamasına bırakılmaz. Asta "bitirince haber ver" demek işe yaramıyor, çünkü o talimat modelin bağlamında duruyor; bağlam sıkıştırıldığında, tükendiğinde ya da 400 satırlık bir test çıktısı tarafından bastırıldığında talimat da gidiyor. NestManager tam bu noktaya oturan bir Claude Code eklentisi: oturumları Executive, Manager ve Staff olmak üzere üç konumsal katmana yerleştiriyor, her üyenin raporunu harness'ın çalıştırdığı bir Stop hook'una bağlıyor ve takılan üyeyi sessizlik süresine bakmadan yakalamayı deniyor.
Aynı şeyi farklı projelerde defalarca denedik; her seferinde aynı biçimde çuvalladı. Bir noktada bunu prompt problemi saymayı bırakıp mimari problem olarak ele almaya başladık. Aşağıda ne bulduğumuzu, ne kurduğumuzu ve daha faydalısı, hiçbir birim testinin yakalayamayacağı altı harness davranışını anlatıyorum. Bunların dördü yalnızca gerçek bir oturum çalıştığında ortaya çıktı.
Astlar rapor vermiyor, amirler gözlemleyemiyor, arıza fark edilmiyor
Gözle görülen belirti astların rapor vermemesi. "Bitince haber ver" diyorsunuz, vermiyor. Ama bu, üç başarısızlıktan yalnızca birincisi ve en az ilginç olanı.
Astlar rapor vermiyor. Talimat modelin bağlamında yaşıyor. Bağlam sıkıştırılıyor, tükeniyor ya da görevin kendisi onu bastırıyor. İş bittiğinde "rapor et" talimatı 400 satırlık test çıktısının altında kalmış oluyor. Daha iyi cümle kurmak bunu düzeltmiyor, çünkü sorunun yeri bellek hiyerarşisi.
Amirler gözlemleyemiyor. Bir Claude Code oturumu yalnızca bir kullanıcı turu çalışırken iş yapar. Turlar arasında atıldır: yoklama yapmaz, beklemez, düşünmez. Yani rapor veren bir ast bile raporu alacak uyanık birini bulamaz. Mesaj, siz bir şey yazana kadar okunmayacak bir oturuma düşer.
Hiçbir şey arızayı fark etmiyor. İki oturum aynı dosyayı düzenler ve birbirinin üzerine sessizce yazar. Bir oturum görevin ortasında bağlamı tüketip ölür. Bir başkası döngüye girer. Dışarıdan bakınca üçü de, işi biraz uzun süren bir oturumla birebir aynı görünür.
Zamanınızı asıl yiyen üçüncü başarısızlık; "sen ona rapor vermesini söyle" yaklaşımı da onu tamamen görmezden geliyor.
Raporlama, modelin yaptığı bir iş olmaktan çıkarılıyor
Geri kalan her şeyi çözülebilir kılan kayma şuydu: rapor, modelin yaptığı bir şey olmamalı; modelin başına gelen bir şey olmalı.
Rapor, modelin onu yazıp göndermeyi seçmesine bağlıysa güvenilirliği modelin kalan bağlamı kadardır. Modelin denetiminden çıkardığınız anda güvenilirliği süreç yaşam döngüsü kadar olur.
Claude Code bunun için gereken kancayı zaten veriyor. Resmi hook belgelerinde tanımlanan Stop kancası, oturum bir turu bitirdiğinde harness tarafından çalıştırılıyor; modelin çağırdığı bir araç olmadığı için modelin hatırlamasına da ihtiyaç duymuyor. Bağlam tükenmiş olsun, süreç yarı yolda ölmüş olsun, kanca çalışıyor.
Bizim tarafımızda kayıt hooks.json içinde tek bir girdi: Stop olayına bağlanmış bir command kancası, komut olarak node ve argüman olarak ${CLAUDE_PLUGIN_ROOT}/hooks/stop-report.mjs. Zaman aşımını 15 saniyeye çektik; hook belgelerinde command tipi için verilen varsayılan 600 saniye ve tek satır rapor yazan bir betiğin bu kadar beklemesinin bir anlamı yok. Yük taşıyan fikir bundan ibaret, geri kalan her şey onun etrafına kurulmuş iskele. Durumun yaşadığı yer artık disk olduğu için bir amir kendi turunda astlarının en son ne dediğini okuyabiliyor.
NestManager oturumları bir organizasyon şeması gibi çalıştırıyor
NestManager, Claude Code oturumlarını bir kurum gibi işletiyor. Roller konumsal olarak atanıyor: kendi ekibini işe alan bir Staff üyesi, o alt ağaç için Manager oluyor.
- Executive — hedefi sizden alır, sonucu size döner.
- Manager — bir iş kolunun sahibidir, doğrudan astlarını her turda sınıflandırır.
- Staff — işi yapar, gerekirse kendi ekibini kurar.
Her üye tam olarak bir amire rapor veriyor ve yükseltme tek seferde bir basamak ilerliyor. Çakışan işi akranlar kendi aralarında çözüyor, çözemezlerse Manager'ı işin içine katıyorlar. Üç tasarım parçası ayrıca açıklamaya değer, çünkü her biri başka türlü de kararlaştırılabilecek bir tercihi kodluyor.
Durum, yalnızca sonuna eklenen bir olay günlüğü. Aynı dizine aynı anda on iki kadar işletim sistemi süreci yazıyor. Kilitlemek yerine her durum değişikliği tek satır olarak dosyanın sonuna ekleniyor. POSIX write tanımı — Open Group Base Specifications Issue 7, 2018 baskısı, IEEE Std 1003.1-2017 — O_APPEND bayrağı açıkken dosya konumunun her yazmadan önce dosya sonuna alınacağını ve konum değişikliğiyle yazma işlemi arasına başka bir dosya değişikliğinin giremeyeceğini söylüyor. Organizasyon şeması saklanmıyor; okuma anında günlük baştan sona işlenerek üretilen bir izdüşüm. Zorla öldürülen bir oturum hiçbir şeyi bozamıyor, en kötü ihtimalle geride bayat bir working kaydı bırakıyor. Takılma tespitinin varlık sebebi zaten tam olarak bu.
Amirler astlarının peşine düşüyor. Her amir her turda doğrudan astlarını sınıflandırıyor ve sabit bir merdivenden yükseltiyor: dürt, transkripti oku, yeniden ata. Ortadaki adım göründüğünden daha önemli. Uzun süren bir test koşusuyla sonsuz döngü dışarıdan ayırt edilemiyor; hangisi olduğunu anlamak için çıktının kendisini okumak gerekiyor. Sayaç yalnızca geçen süreyi bilir; o ayrımı yapabilmek için çıktıyı okuyan bir modele ihtiyaç var. Merdivenin asıl gerekçesi de burada: kovalama basamağı, sistemin astın kendi raporuna hiç bel bağlamak zorunda kalmaması için var. Ast raporunu kendi verirse yol kısalıyor, vermezse amir zaten peşine düşüyor ve sonuç değişmiyor.
Bütçeler zincirleniyor ve dolar cinsinden tanımlanıyor. Bu karara bir meslektaşımızdan itiraz geldi: abonelik kullanıcısı için dolar soyut, asıl hissedilen birim token. Yine de doları seçtik, iki nedenle. Birincisi, CLI referansında belgelenen --max-budget-usd, harness'ın gerçekten uyguladığı tek tavan; token tavanı ise bir JSON dosyasındaki, kimsenin uymak zorunda olmadığı bir sayı. Belgenin kaydını aynen aktarmak gerekiyor: bayrak print kipine özgü ve tavanın gerçekten uygulanması — tavan dolduğunda yeni alt ajan doğurmanın Budget limit reached ile düşmesi, çalışmayı sürdüren arka plan alt ajanlarının durdurulması — Claude Code v2.1.217 ve sonrasını gerektiriyor. Belgedeki örnek claude -p --max-budget-usd 5.00 "query" kadar sade. İkincisi, token'lar model katmanları arasında karşılaştırılabilir değil: aynı bir milyon token'ın maliyeti en ucuz modelle en yetenekli model arasında kabaca 10 kat oynuyor. Katman karıştırmak için var olan bir hiyerarşiyi token bütçesi sınırlayamıyor; bir Manager bütçenin rahatça içinde kalırken faturayı 10 katına çıkarabiliyor. Token'ı yine de gösterge olarak kaydediyoruz, ama zincirlenen kısıt dolar tarafında duruyor: varsayılan sözleşmede her üye devraldığı bütçenin yüzde 20'sini yedekte tutuyor, yani 10 dolarlık bir kol astlarına en fazla 8 dolar dağıtabiliyor.
Saatin göremediği durum
Takılma tespitinin çoğu, bir zaman aşımı sayacının işi. Bizim varsayılan sözleşmemizde de öyle: üyeler 5 dakikada bir hayat sinyali bırakıyor, 10 dakikalık sessizlik üyeyi quiet, 20 dakika stalled, 45 dakika lost yapıyor ve transkript okumaya geçmeden önce en fazla 2 dürtü gönderiliyor. Ama sistemdeki en acil durum bu eşiklerin hiçbirine takılmıyor: blocked raporu veren bir üye az önce konuşmuştur.
Son duyulma zaman damgası sıfır saniye önce, yani 10 dakikalık ilk eşiğin çok altında. Boşta kalma süresine bakan her kontrol onu kusursuz sağlıklı gösteriyor. Oysa o üye çalışmayı tamamen durdurmuş, yalnızca amirinin verebileceği bir kararı bekliyor ve hiçbir şey onu işaretlemeyecek, çünkü nezaketen takıldığını söylemiş durumda.
Bunu daha zor hataların hiçbirine gelmeden, kendi smoke testimizde bulduk. Bir ast blocked: beyond_capability raporu verdi, amirin durum görünümü onu OK diye listeledi. Sınıflandırma artık süreye bakmadan önce bildirilen duruma bakıyor: beyond_capability gelirse üye bir üst model katmanına yeniden atanıyor, diğer engel nedenlerinde amir transkripti okumaya çağrılıyor.
Sonra gerçek bir oturum çalıştırdık
O noktada 74 birim testimiz vardı ve hepsi yeşildi. CI matrisi Linux ve Windows üzerinde Node 18 ve Node 22 ile geçiyordu. Tasarım hem kâğıt üzerinde hem test paketinde tutarlıydı. Kendimize güveniyorduk.
Sonra önemsiz bir görevle tek bir gerçek arka plan oturumu başlattık — içinde "hello" yazan bir dosya üret — ve üst üste dört kez, dört ayrı nedenle başarısız olmasını izledik. Hiçbiri kodlama hatası değildi. Dördü de harness'ın bizim varsaydığımızdan farklı davranmasıydı ve dördü de sessizce başarısız oldu.
1. --session-id arka plan oturumlarında yok sayılıyor
Kimliği basit bir fikir üzerine kurmuştuk: ebeveyn, çocuğun session ID'sini önceden atar; böylece organizasyon şeması çocuk var olmadan önce yazılmış olur ve bir astın çalışıp da kayıtsız kaldığı bir aralık hiç oluşmaz. Deterministik ve temiz.
claude --bg --session-id <uuid> o UUID'yi kullanmıyor. Arka plan oturumu kendi kimliğini üretiyor.
Sonuç şu oldu: Stop hook harness'ın session ID'sine baktı, organizasyon şemasında eşleşen üyeyi bulamadı ve hiçbir rapor yazmadan döndü. Tek işi raporu garantilemek olan mekanizma, sessizce hiçbir şey yapan parça haline geldi.
Düzeltme: ebeveynin atadığı kimliği bir ortam değişkeniyle geçir ve onu esas al. Harness kimliğine yalnızca o değişken yoksa düş.
2. Arka plan oturumunda izin istemini yanıtlayacak kimse yok
Astımız brifingini kusursuz uyguladı. Görevini okudu, protokolü anladı ve ilk komutunu — nest inbox — tam talimattaki gibi çalıştırdı.
Sonra bir izin isteminde sonsuza kadar durdu. --permission-mode acceptEdits dosya düzenlemelerini kapsıyor, kabuk komutlarını kapsamıyor ve arka plan oturumuna "Evet"e tıklayacak bir insan bağlı değil.
Amirin gözünden bakıldığında bu, takılmış bir üyeden ayırt edilemiyor. Ast aslında her şeyi doğru yapıyor, gelemeyecek bir onayı bekliyor.
Düzeltme: CLI'yı doğuş anında --allowedTools ile önceden yetkilendir. Listeye her iki kabuk aracını da koymak gerekiyor; modelin hangisine uzanacağı platforma bağlı, Windows'ta PowerShell, diğerlerinde Bash.
3. --allowedTools değişken sayıda değer alıyor ve prompt'unuzu yutuyor
İzin kurallarını ekledikten sonra yeniden oturum açtık. Oturum başladı ve hemen şunu bildirdi: idle — send a prompt to start.
--allowedTools <tools...> variadic. Bir boole bayrağını geçtikten sonra da argüman yutmayı sürdürüyor. Yani claude --allowedTools "Bash(node:*)" --bg "<asıl prompt>" yazdığınızda prompt araç listesinin içine giriyor; oturum hiç talimatsız açılıyor ve hiç gelmeyecek bir girdiyi sabırla bekliyor.
Kendi değerini alan bir seçeneğe gelince argüman yutmayı bırakıyor, dolayısıyla claude --allowedTools "Bash(node:*)" --model haiku --bg "<asıl prompt>" çalışıyor. Biz artık izin kurallarını en başta, doğrudan --session-id öncesinde yazıyoruz; böylece doğruluk komutun geri kalanındaki argüman sırasına bağlı kalmıyor.
4. Arka plan oturumları düzenlemeden önce worktree istiyor
Dördüncü deneme. Oturum, bu arka plan oturumu için düzenleme yapmadan önce bir worktree'ye girmesi gerektiğini duyurdu. Bir tane açmayı denedi, deneme deposunda hiç commit olmadığı için başarısız oldu (Failed to resolve base branch "HEAD"), ardından git commit denedi — ki o da kimsenin veremeyeceği bir onay istiyordu.
Bunun bir kısmı test ortamımızın suçu. Ama altındaki olgu gerçek ve bilinmeye değer: arka plan oturumları yazma işlemleri için worktree yalıtımına yöneliyor. git-worktree belgesi komutun imzasını git worktree add <path> [<commit-ish>] olarak verir ve verilen yola bir commit-ish çıkarılacağını söyler; hiç commit'i olmayan bir depoda çıkarılacak bir şey yoktur. Yalıtım burada bir seçenekten çok varsayılana yakın duruyor.
Yoklayarak bulduğumuz iki davranış daha
--append-system-prompt-file yokladığımız sırada claude --help çıktısında görünmüyordu. Var olmadığı sonucuna varmak yerine denedik: bilinmeyen seçenek hatası yerine option '--append-system-prompt-file <file>' argument missing döndü, yani seçenek gerçekti. Bugün CLI referansında örneğiyle birlikte listeleniyor. Bu ayrıntı kulağa geldiğinden daha önemli: bir rol brifingi tırnaklar ve satır sonları içeren otuz satır kadar metin ve onu satır içi geçirmek Windows'ta üç ayrı biçimde bozuluyor. cmd.exe bir argümanın içinde satır sonu taşıyamıyor, tırnak kaçışı kabuktan kabuğa değişiyor ve Microsoft'un belgelediği üzere komut isteminde kullanılabilen dizenin üst sınırı 8191 karakter. Aynı belge ortam değişkenleri için Win32 sınırını 32.767 karakter olarak verir, ama komut isteminin kendi 8191 karakterlik sınırını aşan kalıtsal değişkenleri yok saydığını da ekler; metni ortam değişkenine taşımak da kurtarmıyor. Brifingi bir dosyaya yazıp yol geçmek üçünü birden aşıyor.
--plugin-dir doğan oturumlara ulaşmıyor. Bir eklentiyi klondan çalıştırmak yalnızca o oturuma uygulanıyor. Onun doğurduğu oturumlar hook'suz ve rol becerileri olmadan başlıyor; kendilerine hiç verilmemiş bir protokolü yok sayıyorlar. Kurulu bir eklentide bu sorun yok. Düzgün kurulumun önerilen yol olmasının ve yapılandırmanın klon durumu için açık bir iletme seçeneği taşımasının sebebi bu.
Yeşil test paketi de yetmedi
Bir hata daha var ve onu anlatmak gerekiyor, çünkü "canlı test yaparsan yeter" şeklindeki kolay çıkarımı kesiyor.
CI'ımız, yerel çalıştırmalarımızın hiç yakalamadığı bir hatayı yakaladı. Günlükteki olaylar milisaniye zaman damgasına göre sıralanıyordu ve eşitlik rastgele bir olay kimliğiyle bozuluyordu. Hızlı bir makinede bir olay salvosu düzenli olarak tek bir milisaniyeye düşüyor; yani dürt, dürt, rapor dizisi rapor, dürt, dürt olarak okunabiliyor ve az önce rapor vermiş bir üye hâlâ dürtülmemiş sayılıyordu. İzdüşüm deterministik değildi, her yüklemede farklı okunuyordu.
Windows'ta yerelde 74 test geçiyordu. Linux'ta CI iki kez kırmızıya döndü.
Zaman damgasının çözünürlüğünü artırmak yerine sıralamayı dosyanın kendisine bağladık. Sona ekleme atomik olduğu için dosyadaki fiziksel satır sırası, tüm süreçler genelinde yazma sırasının kendisi. Eşitliği satır indeksiyle bozunca sıralama hem deterministik hem nedensel olarak doğru hale geldi.
Güven, ucuz ve tekrarlanan yanlışlamadan geliyor
Buradan çıkan ders yapay zeka destekli geliştirmenin güvenilmezliği değil. Kod ucuz kısımdı ve büyük ölçüde doğruydu.
Ders, güvenin nereden geldiğiyle ilgili. Yeşil bir test paketi size sistemin modellediğiniz gibi davrandığını söyler; platforma dair modelinizin doğru olup olmadığı konusunda hiçbir şey söylemez. Anlattığım altı arızanın hepsi tam o boşlukta yaşıyordu. Birim testleri bunları yakalayamazdı, çünkü testler uygulamayla aynı yanlış varsayımları kodluyordu.
İşe yarayan şey, yanlışlamayı ucuzlatıp tekrar tekrar yapmak oldu. Her biri birkaç dakika süren ve en küçük modelde neredeyse hiçbir şeye mal olmayan dört canlı çalıştırma, 74 testin onayladığı dört mimari kusuru ortaya çıkardı.
Bir ajan platformunun üzerine bir şey inşa ediyorsanız bu döngü için açıkça bütçe ayırın. İlginç hatalar sizin kodunuzla, davranışını doğrulamak yerine çıkarsadığınız bir harness arasındaki dikişte duruyor.
Sekiz harness davranışının tamamını tasarım belgesinden ayrı olarak docs/harness-notes.md içine yazdık, çünkü bunlar projemizin tasarım kararlarından çok Claude Code'un olguları. Claude Code üzerine bir şey inşa ediyorsanız o dosya size projenin kendisinden daha çok iş görecektir.
NestManager MIT lisanslı ve GitHub'da: github.com/tecnonest/NestManager. Sürüm 0.1.0 ve 0.x kısmını ciddiye alın. Aynı duvarlara başka bir yönden çarpmış olanlardan gelecek issue ve katkılar özellikle kıymetli.
Sıkça Sorulan Sorular
Asta "bitince rapor ver" demek neden yetmiyor?
O talimat modelin bağlamında yaşıyor. Bağlam sıkıştırıldığında, tükendiğinde ya da 400 satırlık bir araç çıktısı tarafından bastırıldığında talimatla birlikte rapor da gidiyor. Stop kancasını ise harness çalıştırıyor: model hatırlamasa, bağlamı bitse veya süreç yarıda ölse bile kanca çalışıyor ve raporu dosyaya yazıyor. Bizim kaydımız node çalıştıran tek bir command kancası ve zaman aşımını 15 saniyeye çektik, belgelenmiş varsayılan 600 saniye. Böylece durumun yaşadığı yer disk oluyor ve amir, kendi turu çalıştığında astlarının en son ne dediğini okuyabiliyor.
blocked raporu veren bir ast neden takılma denetiminden kaçıyor?
Sessizliğe bakan denetimler son duyulma zaman damgasını ölçüyor. Bizim eşiklerimiz 10, 20 ve 45 dakikada sırasıyla quiet, stalled ve lost üretiyor; blocked raporu veren üyenin damgası sıfır saniye önce olduğu için hiçbirine ulaşmıyor ve her boşta kalma kontrolü onu sağlıklı görüyor. Oysa üye çalışmayı bırakmış ve yalnızca amirinin verebileceği bir kararı bekliyor. Bizim smoke testimizde blocked: beyond_capability diyen bir ast, amirin görünümünde OK olarak listelendi. Takılma denetiminin bildirilen durumu da okuması gerekiyor; geçen süre tek başına yeterli sinyal vermiyor.
Arka plan oturumu başlatırken hangi CLI bayrakları zorunlu?
Pratikte dördü. Kabuk araçlarını --allowedTools ile önceden yetkilendirin, yoksa oturum ilk komutta izin isteminde donuyor; listeye hem PowerShell hem Bash girmeli. --allowedTools variadic olduğu için onu her zaman kendi değerini alan bir seçenekten önce yazın, aksi halde prompt'unuzu yutuyor. Kimliği ortam değişkeniyle taşıyın, çünkü --bg ile verilen --session-id kullanılmıyor. Rol brifingini satır içi geçirmek yerine dosyaya yazıp --append-system-prompt-file ile verin; Windows'ta komut satırı 8191 karakterde bitiyor. Bayrakların belgelenmiş hali CLI referansında duruyor.
Bu yazının İngilizce sürümü Medium’da da yayımlandı. NestManager’ın kendisi github.com/tecnonest/NestManager adresinde.


