Güvenlik modeli

aipager Claude Code'u senin yerine çalıştırır ve Telegram'dan yönetilir. Buradan iki soru çıkar:

GitHub'daki kaynak ↗Bu sayfa İngilizceden çevrildi; ikisi birbirini tutmazsa İngilizce sürüm geçerlidir. İngilizce
  1. Botu kim yönetebilir?
  2. Yönetildiğinde bot ne yapabilir?

Güven sınırı#

Botun açtığı her işleyici (mesajlar, dosyalar, sesli mesajlar, düğmeler), ~/.config/aipager/aipager.yaml içinde yapılandırılmış sohbetlerden kurulan bir python-telegram-bot sohbet filtresinden ya da (komutlar için) aipager'ın kendi yetkilendirmesindeki aynı kontrolden geçer. Tek istisna, yapılandırılmamış gruplardaki gönderenleri yalnızca kaydeder (aşağıda). Botla yalnızca yapılandırılmış sohbetler etkileşebilir. Başka bir sohbetten gelen hiçbir şey işlenmez ve bir oturuma ulaşmaz. Yapılandırılmamış bir özel sohbet tek bir yanıt alır: “Bu bot seninle konuşacak şekilde ayarlanmamış”. Yapılandırılmamış bir grupta bot asla yanıt vermez, ama orada ona kimin yazdığını (kişinin Telegram kimliği, kullanıcı adı ve adı, ayrıca grubun kimliği, adı ve türü) ~/.claude/aipager-pending-users.json dosyasına kaydeder, böylece aipager çalışırken aipager config yeni grubu ve oradaki kişileri bulabilir. Botu bir gruba herkes ekleyebilir, yani bu dosyaya bir satır da herkes ekleyebilir; bu hiçbir yetki vermez. Dosyayı yalnızca sen okuyabilirsin (izinler 0600), her yazımda baştan yazılır (asla yarım yazılmış kalmaz) ve 30 gündür görülmeyenleri çıkararak en fazla son 200 kişiyi tutar. Ekip modunda bunun üstüne rolleri olan bir izinli kişiler listesi gelir ve grupta yalnızca bota yönelik bir mesaj (bir komut, onun mesajına bir yanıt, bir anma ya da klavyesine bir dokunuş) işlenir, bot grupta yönetici olsun ya da olmasın (bkz. gruplar).

Yani dış dünyaya açık olan şunlardır:

  • Bot token'ı (gizli).
  • Sohbet kimliği (uzun bir tam sayı).

İkisi de sızarsa bir saldırgan aipager'ını yönetebilir. Yalnızca token sızarsa saldırgan senin sohbetinden bota gönderilen mesajları okuyabilir, ama aipager'ın çalıştıracağı komutlar gönderemez. Yalnızca sohbet kimliği sızarsa işe yarar bir şey olmaz: botun Telegram'la konuşabilmesi için token gerekir.

Gizli bilgiler#

Gizli bilgiNeredeİzinler
Bot token'ı~/.config/aipager/aipager.yamlvarsayılan 600
Sohbet kimliği (kimlikleri)aynı dosyavarsayılan 600

Token aipager günlüğüne girmez: onu taşıyan HTTP istek satırları günlüğe yazılmaz; hata mesajları, aipager doctor ve sihirbaz da bot token'ına benzeyen her şeyi gizler. Sohbet kimlikleri aipager günlüğünde görünür (örneğin sınırlarla ilgili satırlarda), bu yüzden aipager logs çıktısını kişisel say. İkisi de repoya girmez: yapılandırma reponun içinde değil, kullanıcının ~/.config klasöründedir. PyPI'a Trusted Publisher ile sürüm yayımlamak da gizli bilgilere asla dokunmaz; kimlik doğrulamayı OIDC yapar.

Token'ın ele geçirildiğinden şüpheleniyorsan onu @BotFather üzerinden iptal et (/revoke), yenisini oluştur ve aipager config komutunu yeniden çalıştır.

Claude kimlik bilgileri: onları gerçekte ne korur#

aipager, senin UNIX kullanıcın olarak Bash erişimi olan özerk bir ajan çalıştırır. Bu yüzden aipager'ın okuyabildiği her gizli bilgiyi, başlattığı ajan da okuyabilir. Bunu açıkça söylemek gerekir, çünkü yanlış türden korumaya sarılmak kolaydır.

~/.config/aipager/ dizini, Telegram'dan yönetilen bir oturumun içindeki dosyaları okumasını engelleyen safety.py yasak listesindedir. Bu bir yol korumasıdır ve burada hiçbir işe yaramaz: Claude kimlik bilgileri (CLAUDE_CODE_OAUTH_TOKEN ya da ANTHROPIC_API_KEY) bir yol üzerinden değil, başlatılan her oturumun süreç ortamına miras olarak gelir. Oturumun içinde echo $CLAUDE_CODE_OAUTH_TOKEN onları yazdırır, yasak listesi olsun ya da olmasın. Bir dosya yolu kuralı, bir ortam değişkeni için doğru türden koruma değildir.

Kimlik bilgileri nerede durur#

KurulumKaynakİzinler
systemd kullanıcı hizmetiLoadCredential=claude_oauth:%h/.config/aipager/daemon.env, $CREDENTIALS_DIRECTORY/claude_oauth konumundan okunur600 (daemon.env); systemd kimlik bilgilerini hizmetin kendi ortamının dışında tutar
macOS / Docker / systemd yok~/.config/aipager/daemon.env, doğrudan okunur600

İki yolu da aynı kod (aipager/daemon_secrets.py) ayrıştırır ve başlatılan oturuma, onları asla bir bash -c komut dizesine koymadan, alt sürecin env= tablosu üzerinden verir. /proc/PID/cmdline herkesçe okunabilir (0444); /proc/PID/environ ise 0400'dür (yalnızca sahibi).

LoadCredential= + 0600'ün gerçekte sağladığı: aynı bilgisayardaki diğer UNIX kullanıcıları kimlik bilgilerini okuyamaz ve bunlar asla systemctl show çıktısında, hizmet dosyasının bir yedeğinde ya da operatörün bir hata raporuna yapıştıracağı bir journalctl ekran görüntüsünde görünmez. Bu, aipager ile aipager'ın başlattığı ajan arasında bir sınır oluşturmaz: böyle bir sınır yoktur ve hiçbir dosya izni ayarı onu oluşturamaz, çünkü ajanın bütün işi aynı ortamda operatör gibi davranmaktır.

Gerçekten işe yarayan tek koruma#

Kimlik bilgilerinin kendisini sınırla. aipager'ı kendi etkileşimli claude girişin için kullandığın token'la değil, ayrı bir Anthropic hesabıyla ya da harcama sınırı olan bir API anahtarıyla çalıştır. aipager'ın kimlik bilgilerini iptal etmek bir insanı asla Claude hesabından çıkarmamalı; çıkarıyorsa bunlar aynı kimlik bilgileridir ve ikisi de sınırlı değildir. aipager doctor --fix, daemon.env dosyasını doldurmak için mevcut bir token'ı bulabilir, ama ona hangi token'ın verileceğine operatör karar verir ve bu belgede, çevredeki dosya izinlerinden daha önemli olan tek karar budur.

Tahmin etmeden girişi kontrol etmek#

aipager doctor (ve aipager her başladığında bir kez gelen tek satırlık bildirim) girişi asla kendi yazdığı bir dosya kontrolüyle değil, Claude Code'un kendi claude auth status komutuyla bildirir. Üç durum, göründükleri her yerde metin olarak ayrı kalır:

  • auth: <method> (<source>): giriş doğrulandı.
  • auth: none (not logged in): girişin olmadığı doğrulandı.
  • auth: unknown (...): denemenin kendisi başarısız oldu (zaman aşımı, program yok, çıktı ayrıştırılamıyor) ya da program, JSON çıktısının geldiği sürümden eski. Bu asla “giriş yapılmamış” olarak gösterilmez: aipager, emin olmadığı bir giriş kontrolü yüzünden bir oturum başlatmayı reddetmez. macOS Anahtar Zinciri ile giriş, yalnızca yenileme token'ı olan kimlik bilgileri ve dosyasız Max planı girişi hiçbir dosya kontrolüne görünmez; aksi halde tam olarak “giriş yapılmamış” gibi görünürlerdi.

Bir araç çağrısının çalışıp çalışmayacağına kim karar verir#

Bir araç çağrısının çalışıp çalışmayacağına iki ayrı kontrol karar verir ve şu sırayla çalışırlar:

  1. aipager'ın güvenlik kontrolü. Her araç çağrısından önce Claude Code, aipager'ın PreToolUse hook'unu çalıştırır. Telegram'dan başlatılan bir görev için hook, çağrıyı onu gönderenin rol kurallarına ve güvenlik alt sınırına (korunan yollar, komut kalıpları) bağlı tutar ve bunların yasakladığını reddeder: o zaman Claude Code, kendi kuralları ne derse desin, kimseye sormadan aracı reddeder. Terminalde yazılan bir mesaj bu kontrolle sınırlanmaz. Neyi kapsadığı aşağıda, kurallar ekipte nasıl uygulanır bölümünde.
  2. Claude Code'un kendi kuralları (~/.claude/settings.json, oturumun izin modu). Sormak gerektiğini söylerlerse Claude Code PermissionRequest çağırır ve aipager isteği Telegram'da gösterir (bkz. hooks). Dokunuşun Claude Code'a bir hook kararı olarak döner ya da 20 saniyelik bekleme dolduysa Claude Code'un kendi iletişim kutusuna yazılır. Claude Code'un kuralları çağrıyı reddederse Telegram'a hiç ulaşmaz.

Yani aipager, Claude Code'un izin vereceği bir çağrıyı reddedebilir; Claude Code sorduğunda ise aipager asla kendi kendine “evet” demez: izin her zaman bir insanın dokunuşudur. Üç şey, çağrıların bir insana sorulmadan çalışmasına izin verir:

  • Tam erişim modu, yöneticiler için (ve kişinin kendi özel sohbetinde o kişi için). Tam erişim modundaki bir oturum --dangerously-skip-permissions ile başlar: Claude Code hiçbir şey sormaz, bu yüzden aipager'ın güvenlik kontrolünün reddetmediği her çağrı dokunuş olmadan çalışır. Bir oturumu Tam erişim modunda yalnızca bir yönetici (owner ve admin rolleri ya da can_manage olan bir rol) başlatabilir, bir oturumu ona geçirebilir (/mode full, onaydan sonra) ya da bir oturuma onda devam ettirebilir; bir istisnayla: botla olan kendi özel sohbetinde, rolü mesaj gönderip Claude'u yanıtlayabilen bir kişi (can_prompt ve can_approve, yani user ama read_only değil), kendi oturumları için aynısını yapabilir (o sohbette /new !x1 ya da Tam erişim modu seçili “Yeni oturumlar”, /mode full, /resume), Telegram'da ve Mini App'te. Asla bir grupta ve asla başka birinin özel sohbetinde değil. Diğer herkes bunun yerine Otomatik modu alır ve yanıt bunu söyler. Tam erişim modu yalnızca Claude Code'un kendi isteklerini atlar: aipager'ın PreToolUse hook'u her çağrıya o kişinin rol kurallarını (güvenlik alt sınırı, klasör sınırı, yasak kuralları, kimlik bilgisi dosyaları) tıpkı Sor modunda ve Otomatik modda olduğu gibi uygulamaya devam eder; Claude Code'un bildirdiği mod onları asla gevşetmez. aipager'ın güvenlik kontrolü Tam erişim modunda da her çağrıda çalışır, ama sahibin kendi görevlerinde ve terminalde yazılan bir mesajda hiçbir şeyi reddetmez.
  • Otomatik mod, varsayılan. Otomatik moddaki bir oturum --permission-mode auto ile başlar: Claude Code'un kendi güvenlik denetimi her çağrıya bakar, güvenli olanları çalıştırır ve riskli olanları durdurur; bunlar o zaman Sor modundaki gibi Telegram'a bir istek olarak gelir. Sohbet /settings → Yeni oturumlar içinde başka bir şey seçmediyse her oturum Otomatik modda başlar. Bir oturumla işlem yapabilen herkes onu Sor modu ile Otomatik mod arasında geçirebilir (/mode); aipager bunu oturumda Shift+Tab'a basarak, yeniden başlatmadan yapar ve Tam erişim modunu Claude Code'un Shift+Tab döngüsüne ekleyecek bayrağı asla kullanmaz. Claude Code bir gün aipager'ın Tam erişim modunda başlatmadığı bir oturum için Tam erişim modu bildirirse aipager geleni gösterir, günlüğe bir uyarı yazar ve bu yüzden bir oturumu asla Tam erişim modunda başlatmaz ya da yeniden başlatmaz. Bilinen sınırlama: Claude Code'un bildirdiği mod, herhangi bir yerel sürecin yazabildiği hook soketi üzerinden gelir (bkz. ağ bağlantıları). Sahte bir mesaj, oturumun hangi modda gösterildiğini değiştirebilir; Sor modu ile Otomatik mod arasında bir geçiş onay beklerken de aipager'a Shift+Tab'a bir kez daha bastırabilir ve canlı oturum, Sor modu istenmişken Otomatik modda kalır (bir sonraki gerçek hook yine gerçek modu gösterir). Bir yeniden başlatmanın ya da devam ettirmenin verdiği bayrağı asla değiştirmez ve Tam erişim moduna asla uzanamaz: onu yalnızca başlatma bayrağı ayarlar. aipager, Tam erişim moduna dönebileceğini bildiği bir oturumda Shift+Tab'a basmaz: Tam erişim modunda başlatılmış olanda (terminalde Sor moduna ya da Otomatik moda geçirildikten sonra bile) ya da başladığından beri çalışan aipager'a Tam erişim modu bildirmiş olanda. Orada her mod değişikliği, yeni modun bayrağını veren ve Tam erişim modunun bayrağını kaldıran bir yeniden başlatmadır; Tam erişim modu hakkındaki sahte bir mesaj da bir değişikliği yalnızca bir yeniden başlatmaya çevirebilir. aipager bunu, terminalde Tam erişim modunu Shift+Tab döngüsüne ekleyen bir bayrakla (Tam erişim modunun bayrağının önündeki --allow-) başlatılmış bir oturum için ya da aipager onu öğrenmeden önce (aipager o sırada çalışmıyordu ya da o zamandan beri yeniden başladı) Tam erişim modundan çıkmış --dangerously-skip-permissions ile başlatılmış bir oturum için bilemez. Orada Sor modundan Otomatik moda geçiş Tam erişim modunda durabilir ve kart o zaman oturumun Tam erişim modunda olduğunu söyler. Modu Telegram'dan yönetici olmayan kişilerin değiştirebileceği terminal oturumları için bu bayrakları kullanma. Tam erişim modunun Telegram'dan çalışması için aipager her başlangıçta ~/.claude/settings.json içinde skipDangerousModePermissionPrompt ayarlar (yoksa Claude Code'un bu modda çalışmadan önceki uyarısı oturumu durdururdu); bu, uyarıyı elle başlattığın oturumlar için de kapatır. Aynı şekilde her oturumun başladığı klasörü ~/.claude.json içinde güvenilir olarak işaretler (o klasör ya da üstündeki bir klasör zaten güvenilir değilse), böylece Claude Code'un “Do you trust this folder?” sorusu Telegram'dan başlatılan bir oturumu durdurmaz: ilk mesaj bu soruya “No, exit” diye cevap verirdi. Güvenilir bir klasörün kendi .claude/ ayarları, .git/ hook'ları ve .mcp.json dosyası komut çalıştırabilir; bu yüzden can_manage yetkisi olmayan üyeler bu dosyaları asla yazamaz (policy.yaml rollerine shell'i geri vermedikçe). Claude Code bir klasörün güvenini, altındaki ve bir git reposunun içinde olmayan klasörlere de uygular; bir repo yine kendi sorusunu alır. Ev klasörü, orada bir oturum başladığında işaretlenir, çünkü Claude Code ev klasöründe verilen bir evet cevabını yalnızca o oturum için tutar. Bundan sonra Claude Code, ev klasörünün altında olup bir git reposunun içinde olmayan hiçbir klasörde bir şey sormaz, kendi başlattığın oturumlarda da. / ve ev klasörünün üstündeki klasörler asla işaretlenmez: bu, bilgisayardaki bu türden her klasöre ulaşırdı; bu yüzden bunlardan birinde başlatılan bir oturum soruda kalır. aipager başlarken hiçbir şeyi işaretlemez, yalnızca bir oturumun başlamak üzere olduğu klasörü işaretler. Yeni bir oturum aipager'ın çalıştığı klasörde (Linux ve macOS'ta aipager service install ile ve konteynerde ev klasörü) ya da ayarlıysa AIPAGER_WORK_DIR içinde başlar; o klasör / ya da ev klasörünün üstünde bir klasörse ve güvenilir değilse aipager günlüğü başlangıçta uyarır. Bu sürümden önceki sürümler aipager'ın klasörünü her başlangıçta işaretliyordu, bir macOS hizmeti için / da dahil (/ içinde çalışıyordu); aipager böyle bir kaydı senin oluşturduğun bir kayıttan ayırt edemez, bu yüzden ona dokunmaz. aipager, ~/.claude.json ve ~/.claude/settings.json dosyalarını tamamen okuyamadığında ya da aipager onları güncellerken çalışan bir Claude onları değiştirdiğinde onlara dokunmaz.
  • Hep izin ver, istekle birlikte önerilen “bir daha sorma” kuralını, tam olarak o seçeneğin Claude Code'un kendi iletişim kutusunda yapacağı gibi Claude Code'a geri verir.

Bir aracı herkese kapatmak için onu ~/.claude/settings.json içinde yasakla; bazı kişilere kapatmak için onların rol kurallarını policy.yaml içinde kullan (bkz. gruplar).

İstek ne gösteriyorsa çalışan odur. Bir izin isteği, Claude'un verdiği açıklamanın altında gerçek komutu ya da yolu gösterir. Unicode yön denetim karakterleri (U+202A-U+202E, U+2066-U+2069, U+200E, U+200F, U+061C), Telegram'ın, tarayıcının ya da telefonun onlardan sonraki metni çizdiği sırayı değiştirir, shell ise karakterleri sırasıyla çalıştırır; bu yüzden onlar yüzünden bir komut başka bir komut gibi okunabilir (“Trojan Source” hilesi, CVE-2021-42574). Her istekte, soruda, değişiklik önizlemesinde ve denetim kaydında bunlar görünür etiketlerle (⟨U+202E⟩) gösterilir ve istek, komutun göründüğünden farklı bir şey çalıştırabileceği konusunda uyarır. Diğer görünmez karakterler olduğu gibi kalır.

Kurallar ekipte nasıl uygulanır#

Ekip modunda aipager, dokunuşların altına kendi katmanını ekler: Telegram'dan gelen her mesaj, /tmp/claude-notes-<session>/ içine mesaj başına bir dosya olarak yazılan bir izin notu taşır (onu kimin gönderdiği ve rolünün neye izin verdiği). Claude bir mesajı aldığında yardımcı aipager-hook programı onu bu notlarla karşılaştırır ve gönderenin kurallarını PreToolUse kontrolünün okuduğu yere koyar. Geri kalan her şey şu özelliklere dayanır:

  • En sıkı olan kazanır. Claude tek bir görevde birden fazla kişiden mesaj alırsa (aipager bunun olmaması için mesajları bekletir, ama yine de olursa güvenli kalır), görev en sıkı birleşimle çalışır: sahibin mesajı yetkilerini asla başka birine ödünç veremez.
  • Süren bir görev asla genişlemez. Başka birinden gelen bir mesaj, süren görevin bitmesini bekler, sonra göndereninin kurallarıyla kendi görevi olarak çalışır. Bir mesaj yine de süren bir göreve katılırsa görev, ona katılan herkesin en sıkı kurallarını korur; terminalde yazılmış bir göreve katılan bir Telegram mesajı, o görevin geri kalanını göndereninin kurallarında tutar (sahibin mesajı hiçbir şeyi değiştirmez).
  • Rolün, işlem yaptığın sohbetteki roldür. Birden fazla sohbette bulunan bir kişinin (örneğin grupta user, kendi özel sohbetinde owner), grupta gönderdiği ya da dokunduğu her şey için rolü gruptaki rol, özel sohbette ise özel sohbetteki roldür; sohbetler aipager.yaml içinde hangi sırada olursa olsun.
  • Bilinmeyen, kısıtlı demektir. Kimseye bağlanamayan bir mesaj yerleşik alt sınırla çalışır (istisna yok, tüm yasak kuralları geçerli), ama asla sınırsız bir terminal mesajı olarak değil. Doğrudan terminalde yazdığın mesajlar sınırsız kalır; herhangi bir satırında Telegram etiketi taşıyan her şey kontrol edilir. Telegram'dan gelen her mesaj bu etiketi, tam olarak o mesajı gönderen kişinin adıyla taşır (oturumu en son yöneten kişinin değil); aipager'ın tanımadığı bir gönderen, örneğin mesajı beklerken aipager.yaml dosyasından çıkarılmış biri, çıplak bir [via Telegram] ve alt sınırı alır.
  • Slash komutları yönetici ister. Bir slash komutu Claude'a etiket olmadan olduğu gibi yazılır ve /deliver gibi bir komut ya da beceri, bütün bir görevi kendi metnine göre yürütür. Bu yüzden rolü rol kurallarını aşmayan bir üye (yerleşik user ve read_only, bypass_role_denies olmadan tanımladığın roller ve aipager'ın tanımadığı herkes) yalnızca aipager'ın “Komutlar” klavyesindeki komutları (artı /compact) ve model değişikliğini (/model <name>) gönderebilir; yazılan, /<name> ile bir oturuma gönderilen, bir dosya açıklaması, ilk /new mesajı ya da bir şablon olarak gelen diğer her slash komutu “Bu komut yalnızca yöneticiler için.” ve 🤷 ile reddedilir. Sahipler ve yöneticiler hepsini gönderebilir. Telegram'dan yine de Claude'a ulaşan bir slash komutu kontrol edilmeye devam eder: hook, görevin o komutu gönderen Telegram mesajını aldığını görür ve komutu o gönderenin kurallarına bağlı tutar. Terminalde yazdığın bir slash komutu sınırsız kalır; ancak aynı komut (herhangi bir argümanla) bu oturumda daha önce Telegram'dan gelmişse durum farklıdır: aipager senin kopyanı, Claude Code'un Telegram'dan geleni yeniden teslim etmesinden ayıramaz, bu yüzden seninki o zaman son Telegram görevinin kurallarıyla çalışır. Bu, oturumla birlikte biter.
  • Yeni bir gönderen getirmeyen bir mesaj görevin kurallarını korur. Bir Telegram görevi sürerken Claude Code, hiçbir Telegram mesajının açıklamadığı mesajları da bildirir: terminalde yazılıp görevin arkasında kuyruğa alınan bir mesaj (kuyruğa alındığı anda bildirilir), başka bir yerel Claude oturumundan gelen bir mesaj ya da bir sıkıştırmadan sonra yeniden teslim edilen aynı Telegram mesajı. Böyle bir mesaj bir Telegram göndereni eklemez, bu yüzden görev çalıştığı kuralları, hâlâ bekleyen herhangi bir mesajla sıkılaştırılmış ve asla gevşetilmemiş olarak korur. aipager'ın kimseye bağlayamadığı Telegram metnini taşıyan bir mesaj yine yerleşik alt sınıra düşer ve daha az yetkili bir gönderenden gelen bir mesaj görevi yine o gönderenin kurallarına indirir.

Kısıtlı bir kişiyi gerçekte ne tutar. Claude oturumu, aipager'ın yapılandırmasına (~/.config/aipager/aipager.yaml içindeki bot token'ı, ~/.config/aipager/daemon.env içindeki Claude kimlik bilgileri) ve görev başına kural dosyasına (/tmp/claude-policy-<session>.json) sahip olan aynı sistem kullanıcısı olarak çalışır. Bu kullanıcının bir shell'i ikisine de hiçbir kalıbın öngöremeyeceği yollarla ulaşabilir (sed -i … /tmp/*-policy-*.json, bir glob üzerinde for döngüsü, tek satırlık bir Python) ve kendi kurallarını sahibin kurallarıyla değiştirebilir. Bu yüzden komut kalıpları bir sınır değil, bir filtredir. Yerleşik kısıtlı rollere (user, read_only) ait bir görev ve aipager'ın kimseye bağlayamadığı bir görev için aipager şu kuralları uygular ve hiçbiri komut kalıplarına dayanmaz (neleri kapsamadıkları için aşağıdaki bilinen sınırlamalara bak):

  • Shell yok. Bash ve Claude Code'un kod çalıştırdığı başka herhangi bir aracı kullanamazlar (PowerShell, Monitor, REPL, Workflow, CronCreate ve RemoteTrigger mesaj zamanlayıcıları, …; liste safety.CODE_EXECUTION_TOOLS). Zamanlanmış bir mesaj Telegram etiketi olmadan, yani sınırsız gelirdi, bu yüzden bunlar da sayılır. Aynı nedenle SendMessage (bir mesajı, onu terminal mesajı gibi çalıştıracak başka bir yerel Claude oturumuna iletebilir) ve EnterWorktree/ExitWorktree (bir sonraki kuralın dayandığı oturum çalışma klasörünü taşırlar) da kullanamazlar.
  • Yazma projede kalır. Write, Edit, MultiEdit ve NotebookEdit yalnızca oturum klasörüne (Claude Code'un hook içeriğinde bildirdiği çalışma klasörü, asla araç çağrısındaki yol değil) ve bu oturumun Claude Code scratchpad'ine (/tmp/claude-<uid>/<project>/<session id>/ ya da bu belirlenemiyorsa /tmp/claude-<uid>/) yazar. Diğer her şey reddedilir: shell'inin başlangıç dosyaları, ~/.ssh, diğer projeler, aipager'ın /tmp içindeki dosyaları. Klasörün içinde .claude/, .git/ ve .mcp.json da reddedilir, çünkü her biri Claude Code'a ya da git'e bir komut çalıştırtır. Sembolik bağlantılar karardan önce çözülür. Klasörü ev klasörün, / ya da ev klasörünün üstündeki bir klasör olan bir oturumun proje klasörü yoktur: orada kısıtlı bir görev yalnızca kendi scratchpad'ine yazar, başka bir yere yazma ise “bu oturum ev klasöründe (ya da üstündeki bir klasörde) çalışıyor ve bu rol yalnızca bir proje klasörünün içine yazabilir” ile reddedilir. Kısıtlı üyeler orada takılmasın diye /new ve Mini App onların bu klasörlerde oturum başlatmasına izin vermez (aipager'ın kendi klasörü, yeni bir oturumun varsayılan klasörü, arka plan hizmeti altında senin ev klasörün); ev klasörünün içinde yeni bir klasör oluşturup orada başlayabilirler (gerçekten yeni olmalı: zaten sende olan bir klasör ya da başka programların kod yüklediği bin veya node_modules olmaz).
  • Üyeler kendi kök klasörlerinde kalır. can_manage olmayan bir rol (yerleşik user ve read_only), aipager config içinde ayarladığın sohbetin kök klasöründe çalışır (varsayılan ~/aipager-users/<label>; ~/aipager-users ve klasörün kendisi 0700 izinleriyle oluşturulur). /new, Devam ettir, Değiştir, Yeniden başlat, mod değişikliği ve Mini App böyle bir üyenin oturumunu yalnızca onun içinde başlatır ya da yeniden başlatır. Güvenlik hook'u, mesaj hangi yoldan gelirse gelsin (Telegram, Mini App, başka bir oturumun mesajı) bunu denetler: kök klasör görevin kural anlık görüntüsünde, oturumlar arası mesajların makbuzlarında ve sabitlenmiş ile zamanlanmış yetkilerde taşınır; bir görevi farklı kök klasörleri olan üyeler paylaştığında daha dar olan kazanır (iç içe olmayan iki tanesi yalnızca oturumun kendi klasörünü bırakır). Yazma, yalnızca oturum klasörü kök klasörün içindeyse oraya gider (onun dışındaki bir oturum, örneğin kök klasörlerden önce başlatılmış biri, çalışmaya devam eder ama görevleri yalnızca scratchpad'e yazar: “bu oturum bu rolün klasörünün dışında çalışıyor”), Read, LSP, Grep ve Glob ise oturumun scratchpad'i ve kendi yanıt dosyası dışında ev klasöründe kök klasörün dışındaki hiçbir şeye ulaşmaz (“bu rol ev klasöründe yalnızca kendi klasörünün içini okur”). Başka herhangi bir sohbetin kök klasörü, nerede olursa olsun, üye için korunan bir yoldur; /tmp/aipager-files/ altındaki diğer sohbetlerin yükleme klasörleri de öyle (Read, Grep, Glob ve yazma araçları için; Bash verilmiş bir rolde bunlardan birini adlandıran bir komut elden geldiğince reddedilir), sohbet başına klasörlerden önce bütün sohbetlerin ortak olarak oraya bıraktığı dosyalarla birlikte. Üyenin kendi sohbetinde yüklenen dosyalar okunabilir kalır. Ev klasörünün dışındaki klasörler (/usr, /etc, /srv) okunabilir kalır. bypass_role_denies ya da bypass_safety olan ama can_manage olmayan özel bir rol, kök klasörünün içinde her yere yazar ve arar; ev klasöründeki okuması da onun içinde kalır: sınırsız olanlar yalnızca sahipler ve yöneticilerdir. bypass_safety ile, klasörü kök klasörünün dışında olan bir oturumda user gibi yalnızca scratchpad'e yazar ve orada arar; araç çağrılarından biri reddedildiği anda görevin geri kalanı durur.
  • Arama projede kalır. Bir Grep ya da Glob yalnızca şunların hepsi sağlanırsa izinlidir: aradığı klasör (path değeri ya da yoksa oturum klasörü, sembolik bağlantılar çözülmüş olarak) oturum klasörünün içinde (ama yazmadaki gibi ev klasörün, / ya da ev klasörünün üstündeki bir klasör değil) ya da scratchpad'de; bu klasör korunan bir yol değil ve korunan bir yol içermiyor (ev klasöründe başlatılan bir oturum ~/.config/aipager dizinini içerir, bu yüzden en üstten arama yapamaz); her glob basit, göreli bir kalıp (başında /, ~, $ ya da sürücü harfi yok, .. yok, # (ripgrep için yorum) ya da ! (olumsuzlama) yok, \ kaçışı yok); ve başında / ya da ~ olmayan bir korunan yol kuralın yok (**/.env projenin herhangi bir yerinde olabilir, bu yüzden böyle bir kuralla her kısıtlı arama reddedilir). Diğer her şey reddedilir. Bu bilerek bir izin listesidir: üç inceleme turunun her biri, ripgrep'i ayrıştırma modelinin beklediği klasörün dışına çıkaran yeni bir glob yazımı buldu ve bunlardan biri bot token'ını okudu.
  • Dosya araçları korunan yollara uyar. Read, LSP ve yazma araçları, sembolik bağlantılar dahil, bir yolun gerçekte nereye çıktığını kontrol eder. Bir görevin okuyabileceği tek kontrol dosyası, daha eski bir mesaja yanıt verdiğinde aipager'ın mesajda adını verdiği, kendi oturumunun /tmp/claude-reply-<session>.txt dosyasıdır; diğer oturumların yanıt dosyaları ve bu dosyaya herhangi bir yazma yasak kalır. macOS'ta /tmp, /private/tmp demektir ve disk büyük-küçük harf ayırmaz, bu yüzden iki yazım ve her büyük-küçük harf biçimi tanınır.
  • Bozulan bir kontrol reddeder. Bir araç çağrısı hakkındaki karar bir hataya yol açarsa (yolda bir null bayt, bir hata) ya da hook karar verirken belleği tükenirse çağrı reddedilir; oturumun kuralları okunabilmiş ve sahip istisnası veriyorsa durum farklıdır. Eskiden böyle bir çağrı geçiriliyordu.

Kendi korunan yolların. policy.yaml içindeki safety: bölümü (deny_paths_no_access, deny_paths_no_write, deny_bash_patterns), yerleşik korunan yollara ve komut kalıplarına eklenir. Yöneticiler dahil owner dışındaki her rolün her görevinin aldığı alt sınıra dahildir ve dosya araçlarına, aramaya ve Bash komutlarına tam olarak yerleşik liste gibi uygulanır. aipager birleşik listeyi, güvenlik hook'unun yedek yolları için /tmp/claude-policy-.floor-<uid>.json dosyasına yazar (kendisi de korunan bir yoldur); bu dosya yoksa, okunamıyorsa ya da başka bir sistem kullanıcısına aitse hook yerleşik listeyi kullanır, asla daha azını değil. Yeniden başlatmadan yeniden yükleme ile yapılan bir değişiklik, yeniden yüklemeden sonra gönderilen mesajlara uygulanır; zaten süren bir göreve ya da zaten bekleyen bir mesaja değil. 0.7.20'den önce bölüm okunuyor ve aipager doctor --safety-check içinde gösteriliyordu, ama uygulanmıyordu.

aipager'ın kimseye bağlayamadığı görevler. Bağlanabileceği bir göndereni olmayan bir Telegram görevi, yerleşik user rolüne (policy.yaml içinde user rolüne eklenen ek kısıtlamalara değil) karşılık gelen alt sınırla artı senin safety: bölümünle çalışır: kod çalıştıran araç yok, sınırlı yazma ve arama, korunan yollar. Bu, izin notunun süresi dolmuş (24 saat sonra) ya da yazılamamış bir mesajda ve hiçbir notla eşleşmeyen Telegram metni taşıyan bir mesajda olur. Yeniden dene düğmesi, tekrarlanan mesajı aynı kişi gönderdiyse ona dokunan kişinin yetkileriyle çalışır, böylece sahibin kendi mesajındaki Yeniden dene Bash'i korur; başkasının mesajındaki ya da aipager'ın göndereni tanımadığı bir mesajdaki Yeniden dene ise kimsenin metni dokunanın yetkilerini ödünç almasın diye alt sınırla gider.

Korunan yolların dışında okuma, kök klasörün tutmadığı bir role (can_manage olan ama istisnaları olmayan özel bir rol) izinlidir: sistem kullanıcısının diğer projelerini okuyabilir. Yerleşik user ve read_only, ev klasöründe kendi kök klasörlerinin dışındaki hiçbir şeyi okumaz (yukarıda). Kimlik bilgisi dosyaların, bypass_role_denies olmayan her rol (yerleşik user ve read_only, tanımladığın roller ve alt sınır) için korunan yollardır: ~/.ssh, ~/.gnupg, ~/.aws, ~/.config/gh, ~/.git-credentials, ~/.netrc, ~/.docker/config.json, ~/.kube, ~/.config/gcloud, ~/.azure, ~/.password-store, ~/.pgpass, ~/.npmrc ve ~/.pypirc okunamaz, yazılamaz ve içlerinde arama yapılamaz. Bu, rolün varsayılan değeridir, bu yüzden rolün policy.yaml içindeki kendi deny_paths_no_access değeri onları o rol için değiştirir; süren göreve başka bir mesaj ya da terminalde yazılan bir mesaj katıldığında durum farklıdır: o andan görevin sonuna kadar yine onlara uyar (en sıkı kurallar kazanır). Başka bir yerdeki kimlik bilgisi dosyası (projedeki bir .env, başka bir klasördeki bir token) kapsanmaz: onu rolün deny_paths_no_access listesine ekle. Bunların hiçbiri sahipleri etkilemez. Yöneticilerin yazması sınırsızdır. Grep/Glob araçları korunan bir yola dokunmayan herhangi bir klasörde arama yapabilir: arama, aradığı klasör (path değeri ya da yoksa oturum klasörü; Glob için ayrıca kalıbının adını verdiği klasör, /home/you/.config/aipager/* örneğindeki gibi, ya da Claude Code'un o adı her derinlikte aradığı, joker karakter içermeyen bir kalıbın üstündeki klasör) sembolik bağlantılar çözüldükten sonra korunan bir klasör olduğunda, onun içinde olduğunda ya da onu içerdiğinde reddedilir. Bu yüzden ~, /, ev klasörünün üstündeki bir klasör ya da /tmp üzerinde Grep reddedilir (bunlar ~/.config/aipager, ~/.claude ya da aipager'ın /tmp/claude-* dosyalarını içerir), ama bir proje ya da /tmp/myproj üzerinde Grep reddedilmez. Başında / ya da ~ olmayan bir korunan yol kuralı (**/.env gibi) herhangi bir klasörde eşleşebilir, bu yüzden bir yöneticinin kurallarında (ya da owner dışındaki her rolün aldığı safety: bölümünde) böyle bir kural varken yöneticinin her araması, kısıtlı rollerdeki gibi reddedilir; aipager doctor, safety: bölümündeki böyle bir kural için uyarır. Yöneticilerin Bash'i vardır, bu yüzden kuralları elden geldiğince geçerli kalır (aşağıda).

Bilinen sınırlamalar. Şunlar kapsanmaz:

  • Hook'un kendisi karar vermeye başlamadan önce bozulursa (örneğin durum dosyasını okuyamazsa ya da başlarken belleği tükenirse) Claude Code bunu “izin ver” sayar. Kısıtlı bir kişi buna yol açamaz; karar sırasındaki her hata reddeder.
  • Dosya aracı olmayan ama dışarıya veri gönderebilen araçlar yola göre kontrol edilmez: WebFetch (görevin okuyabildiği her şeyi bir URL'e gönderebilir) ve Claude Code'un diğer teslim araçları. Bu senin için önemliyse onları policy.yaml içinde rol için yasakla. Sohbete dosya gönderen SendUserFile kontrol edilir (bkz. Claude'un gönderdiği dosyalar).
  • Kısıtlı bir görevin başlattığı bir arka plan ajanı görevin bitiminden sonra çalışmaya devam eder ve sonraki araç çağrıları oturumdaki en yeni mesaja göre değerlendirilir: sahipten ya da terminalden gelen daha sonraki bir mesaj kısıtlamalarını kaldırır.
  • can_manage ile ama iki istisna olmadan tanımladığın bir rol kök klasöre bağlı kalmaz: sohbetinin zaten çalıştığı herhangi bir proje klasöründe (önceki bir oturumun kullandığı klasör) başlayabilir, seninki dahil, ve diğer projelerini okuyabilir.
  • Hiçbir üyeye bağlanamayan bir görev (bilinmeyen bir gönderen, çıkarılmış bir üye, göndereni doğrulanamayan başka bir oturumdan gelen bir mesaj), kök klasörü olmayan kısıtlı alt sınırla çalışır. Okuma açısından bu alt sınır yerleşik user rolünden zayıftır: böyle bir görev, ev klasöründe korunan yol olmayan herhangi bir dosyayı (örneğin diğer projelerini) okuyabilir, oysa bir user görevi yalnızca kendi kök klasörünün içini okur. Böyle bir görev /tmp/aipager-files/ içinde bütün sohbetlerin yüklediği dosyaları da okuyabilir; bir user görevi ise yalnızca kendi sohbetininkileri okur. Yazması oturum klasörü ve scratchpad ile sınırlı kalır. Bir üyenin oturumundan gelen doğrulanmış bir mesaj o üyenin kök klasörünü taşır.
  • Kök klasör yalnızca dosya araçlarını tutar. Bash verdiğin özel bir rol shell üzerinden onun dışında okuyabilir (yerleşik user ve read_only rollerinin Bash'i yoktur). bypass_safety olan ama can_manage olmayan özel bir rol, dosya araçlarının yolları dışında her şey için istisnasını korur: ona hiçbir araç ve hiçbir komut kalıbı yasaklanmaz.
  • Başka bir üyenin kök klasörünü adlandıran bir ret nedeni, o klasörün yolunu Claude'a ve sohbette gösterir.
  • Kök klasörler geldiğinde (bir güncelleme) zaten süren bir üye görevinde, o üyenin bir sonraki mesajına kadar kök klasör yoktur.
  • Projenin içinde kısıtlı bir kişi, senin sonradan çalıştırdığın ya da okuduğun şeyleri değiştirebilir (kaynak kod, Makefile, package.json betikleri, conftest.py, görevlerinin yüklediği CLAUDE.md).

Bash'i olan bir rol (rolün yasak kurallarını aşan admin ya da policy.yaml dosyasının onu geri verdiği herhangi bir rol: Bash içeren allow_tools ya da değiştirilmiş bir deny_tools) yalnızca elden geldiğince çalışan kurallara bağlıdır: aşağıdaki komut kalıplarına; kararlı bir kişi onları atlatabilir. aipager doctor, bir üyedeki böyle her rol için bir kez uyarır. Bash'i yalnızca bu bilgisayarda bir shell ile güvenebileceğin birine ver.

Yerleşik komut kuralları. Sahibe ait olmayan, Bash'li her Telegram görevinin bağlı olduğu Bash kalıplarından biri claude sözcüğünü engeller: tek bir kuralla iç içe bir claude programını (herhangi bir yol, sarmalayıcı ya da bayrakla) ve ~/.claude dizinine her erişimi durdurur, ayrıca aynı öneki taşıyan aipager'ın /tmp/claude-* kontrol dosyalarının düz adlarını da yakalar (bu dosyalar için kalıp gerçek bir koruma değildir: glob ile yazım onu atlatır). Tek istisna Claude Code'un oluşturduğu scratchpad klasörü, /tmp/claude-<uid>/…: tam olarak bu klasör, yolun bütün bir parçası olarak hariç tutulur, bu yüzden oturumun scratchpad'inden çalışan komutlar durdurulmaz. Klasör tek bir oturuma değil sistem kullanıcısına aittir, bu yüzden Bash'li bir görev, tıpkı Read aracı gibi, oradaki diğer oturumların scratchpad'ini ve görev çıktılarını okuyabilir. Bir glob ya da bu klasörün bir benzeri (/tmp/claude-1*, claude-1000x), başka bir geçici klasör ve oradan ulaşılabilen her şey (…/../../home/you/.claude) engellenmeye devam eder. Sözcüğün diğer geçişleri (git log --grep=claude, claude-notes.md adlı bir dosya, pip show claude-agent-sdk) de bilerek engellenir: aynı sözcük programı, SDK'sını ve aipager'ın kontrol dosyalarını adlandırır ve bir kalıp bunları ayırt edemez. policy.yaml dosyasına eklediğin kurallar komutu, scratchpad dahil, tam olarak yazıldığı gibi görür.

Bash ile arama. Bazı Claude Code sürümlerinde Grep ya da Glob aracı yoktur (2.1.289 bunlardan biri) ve Claude o zaman yukarıdaki Grep/Glob kuralının geçerli olmadığı Bash üzerinden grep, rg ya da find ile arar. owner dışındaki her rol için komut kalıpları, ev klasörünün tamamında ya da / üzerinde özyinelemeli aramayı veya listelemeyi de yasaklar: grep -r (-R, --recursive, -d recurse, egrep, fgrep, rgrep), rg (ve rg --files), ag, ack (ve ack -f), find, fd, tree, du ve ls -R; klasör ~, ~user, $HOME, ${HOME} ya da "$HOME", /home, /home/<user> (ya da /home/$USER), /Users, /Users/<user>, /root ya da / ise (sonunda /, /. ya da /* olsun ya da olmasın) veya aipager'ın klasörlerinin bulunduğu ~/.config ya da ~/.local ise. Bu, cd x && sonrasında, bir pipe içinde, bash -c "..." içinde, xargs, env ya da timeout sonrasında ve LC_ALL=C gibi ayarlardan sonra da geçerlidir. Yanıt, proje klasörünün içinde aramayı önerir. Bir proje klasöründe arama (grep -rn x ~/proj, rg x src/, find . -name y), proje içinde ev klasörü yolunu ARAMA (grep -rn "$HOME" src: seçeneklerden sonraki ilk sözcük klasör değil, aranan metindir) ve özyinelemeli olmayan arama (grep x ~/.bashrc, ls ~) etkilenmez. Bu, her komut kalıbı gibi elden geldiğince çalışır: kalıp sözcükleri görür, shell'in onları nerede çalıştırdığını değil; bu yüzden ev klasöründen (ya da altından) çalıştırılan klasörsüz ya da . veya .. ile yapılan bir aramayı (cd ~ && grep -r x .), başka bir değişken ya da glob ile ulaşılan ev klasörünü, /home, /Users ve /root dışında tam olarak yazılmış bir ev klasörünü, \grep komutunu ve -e ya da -f ile biten bir sözcükten hemen sonra gelen bir klasörü görmez (grep ve rg'de -e/-f seçeneğinin verdiği metin sanılır, bu yüzden ag x -f ~ geçer). Hangi seçeneklerin ayrı bir değer aldığını da bilmez, bu yüzden rg -t py "$HOME" . ya da grep -rn -A 3 "/home/you" src, py ya da 3 değerini metin, ev klasörü yolunu ise klasör olarak okur ve reddedilir (-A3, --include=*.py yaz ya da seçeneği metinden sonra koy); bir seçenek grubunun içinde -e ile verilen bir ev klasörü yolu da öyle (grep -rne "/home" src; -r -n -e uygundur); başka bir komutun metninin içinde alıntılanan bir komut (echo "a; rg x ~") da reddedilir, du -sh ~ (yalnızca boyutlar) da.

Neden tek bir engelleme bütün görevi durdurur. Bir araç çağrısı engellendikten sonra aynı görevdeki sonraki her çağrı da bir sonraki mesaja kadar reddedilir. Bu olmasa ajan, yazımlardan biri kalıplardan sızana kadar aynı işlemi başka sözcüklerle (bir glob, başka bir komut, kodlanmış bir yol) tekrar ederdi. Görevi durdurmak ilk denemeyi pahalı kılar; kalıbı bir sınır yapmaz, çünkü denenen ilk yazım sızan yazım olabilir. Yanlış bir alarmın bedeli durdurulmuş tek bir görevdir, bu yüzden yukarıdaki kurallar dar tutuldu.

Bu notların taşıdığı kurallar, senin gördüğün haliyle, için bkz. gruplar → kurallar nasıl çalışır.

Claude'un gönderdiği dosyalar#

aipager'ın başlattığı her oturumda Claude Code'un SendUserFile aracı vardır (CLAUDE_CODE_ATTACHMENTS_BY_PATH=1); bu araç dosyaları okur ve oturumun sohbetine iletir (komutlar). PreToolUse hook'u, çağrının her dosyasını Claude Code onu okumadan önce denetler:

  1. Gönderim tabanı, her görev için, owner'ınki ve terminalde yazılmış bir mesaj dahil: aipager'ın yapılandırması ve durumu (~/.config/aipager/**, ~/.local/share/aipager/**, ~/.local/state/aipager/** ve /tmp içindeki denetim dosyaları), tüm ~/.claude/** ve ~/.claude.json* (Claude'un kimlik bilgileri ve hesabı), her kısıtlı rolün uzak tutulduğu kimlik bilgisi dosyaları (~/.ssh/**, ~/.gnupg/**, ~/.aws/**, ~/.git-credentials, ~/.netrc ve o listenin geri kalanı), /proc/**, /sys/**, /dev/** ve nerede olursa olsun gizli bilgiye benzeyen adlar (.env, .env.*, *.pem, *.key, id_rsa*, id_ed25519* ve diğer anahtar adları, *.p12, *.pfx, *.kdbx, *.jks, *.keystore, .pgpass, credentials, *credentials*.json). Yolun yazıldığı hâli ve gerçekte gittiği yer eşleştirilir, yani bunlardan birine giden sembolik bağ da reddedilir. Bazı zararsız dosyalar da bu adları taşır (bir Keynote *.key dosyası, bir .env.example) ve onlar da reddedilir.
  2. Dosyanın kendisi: sembolik bağlar çözüldükten sonra normal bir dosya, tek bir sabit bağla, boş değil, en çok 50 MB.
  3. Görevin kendi kuralları: görevin okuyamayacağı (Read) şeyler, ve bir üye için (can_manage olmayan, bir kök klasöre bağlı rol) her dosyanın, yazıldığı hâliyle ve gerçekte gittiği yerle, kök klasörün içinde olması gibi daha sıkı bir kural. Bir üyenin okumalarından farklı olarak, ev klasörünün dışındaki dosyalar (/tmp, /etc) için ve oturumun scratchpad'i için istisna yoktur.

Bir ret yumuşak bir rettir: Claude nedeni okur ("SendUserFile refused, nothing was sent: ... Tell the person which file could not be sent and why.") ve görev devam eder; engellenen bir araçta olduğu gibi oturum durdurulmaz. Başarısız olan bir denetim dosyayı reddeder, owner için de. Reddedilen her dosyanın denetim kaydında bir FileRefused kaydı olur.

aipager, bir dosya söz konusu olduğunda denetim soketinin sözüne güvenmez: her yerel süreç sokete yazabilir ve herhangi bir oturumun, çağrının ya da konuşma geçmişinin adını verebilir; üstelik tek başına bir araç çağrısının hook'u bile boşta duran bir oturumu çalışıyor gösterir. Bu yüzden bir çağrı yalnızca aipager'ın bir istemle başladığını gördüğü bir görev (Telegram'dan kendisinin yazdığı bir istem ya da bir UserPromptSubmit) ve o görevin arka plan işi sırasında sayılır; bu, oturum hiçbir iş çalışmadan boşta kalana kadar sürer. Bu başlangıçta aipager saati ve oturum için izlediği konuşma geçmişini not eder (aynı görevin sonraki bir UserPromptSubmit'i konuşma geçmişinin adını yeniden verir). aipager'ın yazdığı bir slash komutu görev başlatmaz (görev çalıştıran bir komut kendi UserPromptSubmit'ini gönderir), ve hiç başlamayan bir görev (oturum 15 saniye sonra hâlâ işsiz boşta) yeniden kapatılır. Claude Code bazı görevleri UserPromptSubmit olmadan başlatır: bir görev çalışırken gönderilen ve bir sonraki görev olarak aldığı bir mesaj, ve bir Stop hook'unun sürdürdüğü görev (/goal). Böyle bir görev, o mesajı aipager kendisi yazdıysa ya da not ettiği konuşma geçmişi son Stop'tan sonra görevin başladığını gösterdiği anda sayılır (bir dequeue kuyruk satırı ya da Claude Code'un yazdığı Stop hook feedback: satırı); o zamana kadar çağrıdan hiçbir şey okunmaz, en fazla 20 saniye. Dosya listesini denetlediği PreToolUse'dan, o kaçırıldıysa (yeniden başlatmadan sonra) PostToolUse'dan alır; asla Claude Code'un sonucundan almaz. Her çağrıyı yalnızca bir kez kopyalar: daha önce kopyaladığı bir çağrı kimliği bir daha asla kopyalanmaz ya da gönderilmez (oturum başına son 256 kimliği, yeniden başlatmadan sonra da saklar). Her dosyanın gerçek yolunu tek bir kez bulur ve dosyayı orada yeniden denetler (taban, dosya denetimleri ve oturumun kök klasörü), tam o yolu bağ izlemeden açar, açılan dosyanın denetlediği dosya olduğundan ve hâlâ o yolda durduğundan emin olur ve onu ~/.local/state/aipager/outbox/<chat>/ içine kopyalar (klasör 0700, dosya 0600); burası her kısıtlı görevin zaten uzak tutulduğu bir yerdir. Göndermeden önce çağrıyı, görev için not ettiği konuşma geçmişinde arar (bir alt ajanın çağrısı için, onun yanındaki kendi konuşma geçmişinde); bir araç çağrısının datagramının adını verdiği bir geçmişte asla aramaz: o kimliğe ve tam o dosyalara sahip bir SendUserFile tool_use'u içeren, aynı klasörden ve görevin başından önce olmayan bir zamanda yazılmış bir asistan satırı, ~/.claude/projects (ya da aipager'ın kendisi için ayarlandığı haliyle $CLAUDE_CONFIG_DIR/projects) altında, sahibi aipager'ın kendi işletim sistemi kullanıcısı olan bir .jsonl dosyasında. Claude Code konuşma geçmişini geç yazar, bu yüzden aipager çağrıyı en fazla 20 saniye bekler ve oturumun işi hâlâ sürüyorsa (bir arka plan ajanı, bir araç çağrısı) dosyaları saklayıp daha sonra yeniden bakar. Hiçbir şey çalışmazken de hâlâ bulamadığı bir çağrı gönderilmez ve kopyaları silinir; böyle bir görev çalışmıyorken ya da ikinci kez gelen bir çağrı hiç kopyalanmaz. Bunların her dosyası için denetim kaydına unverified nedenli bir FileFailed kaydı düşülür. Sohbet bunlar için bir satır (⚠️ report.pdf gönderilemedi: aipager, Claude'un bu dosyayı bu görevde gönderdiğini doğrulayamadı.) yalnızca Claude'un kendi konuşma geçmişi görev sırasında tam o çağrıyı gösterdiğinde alır, ve satır, geçmişteki o satırın listelediği dosyaların adını verir; böylece taklit bir çağrı sohbete ne satır ne de ad koyabilir. Aksi halde sohbete hiçbir şey gitmez. Yalnızca kopya gönderilir, yalnızca oturumun kendi sohbetine, görevin cevabından sonra, oturumun daha önceki dosyalarından sonra ve sonraki görevi bekletmeden; kopya gönderilince ya da bir gün sonra silinir.

Bu denetimlerin kapsamadığı şeyler: aipager'ın kendi işletim sistemi kullanıcısıyla çalışan bir süreç, soket kadar Claude'un konuşma geçmişlerini de yazabilir (bu dosyaları zaten kendisi okuyabilir). Sokete ulaşabilen başka bir kullanıcının süreci bir UserPromptSubmit de taklit edebilir; bu, bu denetimler için bir görev başlatır ve görevin konuşma geçmişinin adını verir. Ardından, gerçek bir SendUserFile çağrısının adını verdiği bir dosya, o andan sonra aynı klasörden o konuşma geçmişine yazılmışsa (örneğin tam o sırada başka bir oturumun yaptığı bir çağrı), aipager'ın bu dosyayı o oturumun sohbetine göndermesini sağlayabilir; bu her çağrı için bir kez olur. Bunun için o sürmekte olan çağrının kendi id'sini (tool_use_id) de göndermesi gerekir; başka bir kullanıcı bunu okuyamaz: aipager kullanıcısının ~/.claude altındaki konuşma geçmişlerindedir, ve hook bunu komut satırından değil girdisinden alır. Taklit edilmiş bir Stop bu denetimler için görevi bitirir, bu yüzden o görevin daha sonra gönderdiği dosyalar gönderilmez. aipager'ınkinden farklı bir $CLAUDE_CONFIG_DIR ile başlatılmış bir oturum ya da UserPromptSubmit'ini aipager'ın kaçırdığı bir görev (aipager yeniden başlarken terminalde yazılmış bir görev) dosya göndermez. Claude Code'un başka bir yolla hook olmadan başlattığı bir görev de dosya göndermez (bilinenler yukarıdaki ikisidir); Claude'un konuşma geçmişine göre orada istediği bir dosya yukarıdaki satırı alır. Soket, ayarlıysa diğer kullanıcıların ulaşamadığı $XDG_RUNTIME_DIR içindedir; ayarlı değilse /tmp içindedir.

Denetim kaydı#

Her İzin ver / Reddet dokunuşu ve AskUserQuestion için her yanıt, ~/.claude/aipager-audit.jsonl dosyasına bir JSON satırı ekler:

json
{
  "ts": "2026-05-18T15:42:11+00:00",
  "session": "claude-jim",
  "label": "jim",
  "action": "Allowed",
  "tool": "Bash",
  "summary": "ls -la /tmp",
  "user_id": 12345,
  "username": "alice",
  "denied": false
}

Alanlar (tam küme için bkz. aipager/audit.py):

  • ts: saniye hassasiyetinde ISO 8601 UTC zaman damgası.
  • session / label: iç ad ve okunaklı ad.
  • action: ne olduğu (Allowed, Denied, Allowed always, bir AskUserQuestion yanıtı, otomatik bir ret, …).
  • tool / summary: araç adı ve kısaltılmış girdi ya da sorunun metni.
  • user_id / username: kimin dokunduğu, ekip modunda kimin ne yaptığı görünsün diye; birden fazla sohbet yapılandırıldığında scope_label / scope_chat_id.
  • denied: dokunuşla ya da kuralla, her ret için true.

Yazma elden geldiğince yapılır. Disk dolarsa ya da ~/.claude/ yazılamaz hale gelirse aipager günlüğe bir WARNING yazar ve çalışmaya devam eder: sessiz kayıp yok, çökme yok. Bkz. aipager/audit.py.

Diskteki denetim kaydına yalnızca ekleme yapılır. Sohbetteki denetim yanıtıyla (karar başına, çalışma kartının altında bir Telegram mesajı) birlikte iki bağımsız kayıt sağlar.

Yetki sınırı#

aipager yetkilerini asla yükseltmez. sudo yok, setuid yok, doas yok. Yazdığı her dosya ev klasöründe, /tmp içinde (her aipager oturumunun kontrol dosyaları, indirmeler ve yeniden başlatma günlüğü) ya da kontrol soketinin klasöründe ($XDG_RUNTIME_DIR) durur; tam liste mimari sayfasında. Her alt süreç (claude, dtach, kurucular, claude update) aipager'ın kullanıcısı olarak çalışır.

Sesli mesaj desteğini Telegram'dan kurmak ([📦 Sesli mesajları kur]), aipager'ın sahibi olan kurucu üzerinden yapılır (uv tool install --reinstall aipager[voice], pipx install --force aipager[voice]), aksi halde bu desteğin paketlerini aipager'ın kendi Python'u ile kurar (<python> -m pip install): her zaman aipager'ın kendi ortamına, asla sistem Python'una değil.

[🔄 aipager'ı yeniden başlat] düğmesi, systemd hizmeti altında systemctl --user restart aipager.service komutunu ayrı, geçici bir kullanıcı hizmetinde zamanlar; macOS'ta launchctl kickstart -k çalıştırır; elle başlattığın bir aipager, eskisinin işini bitirmesini bekleyen ayrılmış bir kopyasını başlatır. Bir güncellemeden sonra kendini yalnızca systemd hizmeti yeniden başlatır (bkz. komutlar → güncelleme). Bunların hepsi aynı kullanıcı olarak çalışır; yetki yükseltme yok.

Ağ bağlantıları#

aipager loopback dışında hiçbir TCP portunu dinlemez. Mini App sunucusu yalnızca 127.0.0.1 adresine bağlanır (koda gömülü: bilerek bir host seçeneği yok) ve dışarıdan yalnızca aşağıda anlatılan yönetilen tünelle erişilebilir. Giden bağlantılar:

  • api.telegram.org adresine HTTPS uzun yoklama (Telegram bot yoklaması).
  • Mini App SDK betiği (telegram-web-app.js) için telegram.org adresine HTTPS; Mini App sunucusu başlarken bir kez indirilir ve en fazla günde bir yenilenir; ~/.local/share/aipager/webapp-sdk/ içinde önbelleğe alınır. aipager bu baytları sayfaya kendi kaynağından sunar ve onları asla çalıştırmaz. aipager bu betiği dağıtmaz: pakette yoktur ve aipager'ın kopyası olmadığında sayfa onu eskisi gibi doğrudan telegram.org adresinden yükler.
  • Açık olduğu sürece (varsayılan böyle) Cloudflare'e Mini App tüneli. Başlattığı cloudflared programı github.com/cloudflare/cloudflared sürümlerinden bir kez indirilir, sabitlenmiş bir SHA-256 ile doğrulanır ve ~/.local/share/aipager/cloudflared/ içinde önbelleğe alınır; PATH içindeki bir cloudflared asla kullanılmaz. Mini App için kendi URL'in varsa bunların hiçbiri olmaz (aşağıya bak).
  • Sürüm kontrolü, yalnızca biri Güncellemeleri kontrol et ya da Güncelle düğmesine dokunduğunda (/update, Mini App'teki “Güncellemeler”) ya da güncelleme yapabilen biri Mini App'in Ayarlar sekmesini açtığında (açık uygulama başına en fazla on dakikada bir): aipager için pypi.org ve Claude Code için, nasıl kurulduğuna bağlı olarak, downloads.claude.ai ya da registry.npmjs.org. Ardından güncelleme kurucuyu (PyPI ya da Homebrew ile konuşur) ve claude update komutunu çalıştırır. Komut satırındaki aipager update yalnızca kurucuyu çalıştırır.
  • Sesli mesaj desteğinin kurulumu, düğmesine dokunduğunda: kurucu paketleri PyPI'dan indirir ve ses modeli ilk kullanımda Hugging Face'ten (huggingface.co) indirilir.
  • raw.githubusercontent.com (rapor anahtarı dosyası) ve Sentry'nin alım ucuna HTTPS, yalnızca bir sorun raporu göndermeyi onayladığında: önizlemedeki rapor ve ondan kısa bir özet, başka hiçbir şey. Bkz. Sorun raporları.

Gelen:

  • $XDG_RUNTIME_DIR/aipager.sock konumundaki Unix datagram soketi ($XDG_RUNTIME_DIR ayarlı değilken /tmp/aipager.sock yedeğiyle). aipager başlarken bağlanır ve izinlerini chmod ile alır (aipager/dtach/hook_receiver.py). İzinler 0o666, böylece her yerel süreç ona hook olayları gönderebilir: hook'ları neyin çalıştıracağına zaten karar veren ~/.claude/settings.json dosyasına duyulan güvenin aynısı.

Bu, aipager'ın uzaktan saldırı yüzeyi olmadığı anlamına gelir. Ağdaki bir saldırgan, bilgisayarın kendisinde bir dayanağı olmadan ona ulaşamaz.

Claude'un metni ve Telegram'ın kendi indirmeleri. Telegram'ın sunucuları bir mesajdaki bazı adresleri kendiliğinden indirir: zengin bir mesajdaki resim, video ya da ses bloğunu ve bir bağlantı önizlemesinin arkasındaki sayfayı. Claude'un yanıtları, çalışma kartındaki notları, ajan açıklamaları ve araç argümanları Telegram'a Claude'un yazdığı gibi ulaşır; bu yüzden bir prompt injection, Claude'a bir gizli bilgiyi dışarı taşıyan bir adres yazdırabilir, üstelik ne bir araç çağrısı ne de bir izin isteği olmadan. aipager ilk yolu kapatır, ikincisini de Telegram'ın bunun için bir ayarı olduğu yerde:

  • Her zengin mesajda ![alt](url) biçiminde yazılmış bir resim, alt metniyle birlikte düz bir bağlantı olarak gönderilir; diğer her resim yazımı ve ham <img>, <video>, <audio>, <source>, <picture>, <figure>, <iframe>, <embed>, <object>, <tg-document>, <tg-collage>, <tg-slideshow>, <tg-button> ve <tg-button-row> etiketleri metin olarak gösterilir (aipager/bot/media_guard.py). Bir kod bloğunun içinde, örneğin bir HTML parçasında, bu fazladan bir \ ya da &lt; olarak görünür.
  • aipager'ın gönderdiği ya da düzenlediği her düz metin ve HTML mesajında (yanıtların ve kartların düz metin yedekleri dahil), kendi mesajlarında da bağlantı önizlemeleri kapalıdır. Mini App bağlantıları düğmedir ve Telegram düğmelerin arkasındaki sayfayı indirmez.

Telegram, zengin mesajlar için bir önizleme seçeneği belgelemiyor; Telegram'ın böyle bir mesaj için bağlantı önizlemesi oluşturup oluşturmadığı canlı hizmette kontrol edilmedi.

Mini App tüneli#

Mini App varsayılan olarak açıktır, bu yüzden standart bir kurulumda aipager bu tüneli kimseye sormadan açar. Bu bilinçli bir seçim (kimsenin bulamadığı bir “aç” seçeneği, var olmayan bir özellikti), ama yeni bir kurulumun internete çıktığı anlamına gelir. Onu aipager miniapp disable ile kapat ya da aipager.yaml içinde miniapp: altına enabled: false koy; açık bir false her zaman uygulanır. Dikkat: eksik ya da bozuk bir miniapp: bloğu artık KAPALI'ya değil, AÇIK'a döner.

Mini App (--url onun yerine geçmiyorsa) aipager'ın kendi loopback sunucusuna bakan yönetilen bir Cloudflare hızlı tüneli başlatır ve ona verilen genel https://*.trycloudflare.com adresini Telegram'ın menü düğmesi ve /app yanıtı olarak yayınlar.

Bu adres gizli değildir ve olması da gerekmez: Mini App'in sunduğu her istek Telegram'ın initData imzasıyla doğrulanır (bkz. yukarıdaki Güven sınırı) ve URL nasıl elde edilmiş olursa olsun onu bu kontrol korur. Tek bir sunucu adını bilmek, bir saldırgana trycloudflare.com alt alan adını rastgele tahmin ederek elde edemeyeceği hiçbir şey vermez: gerçek kapı imza kontrolüdür. Ona yayımlanmamış ama gizli de olmayan herhangi bir URL gibi davran: açık tutmak sorun değil, ama nedensiz yere herkese açık bir kanala yapıştırmak iyi olmaz.

Sunucu adı yalnızca bellekte tutulur: asla aipager.yaml dosyasına ya da ~/.config/aipager/ altında herhangi bir yere yazılmaz. Planlı bir yeniden başlatma (bir güncellemenin yeniden başlatması, Şimdi yeniden başlat, hizmet olmadan yerinde yeniden başlatma) tüneli çalışır durumda bırakır, böylece adres, menü düğmesi ve açık bir Mini App çalışmaya devam eder: bir sonraki aipager onu ancak aynı açılış olduğunu, aynı port olduğunu, sürecin o cloudflared olduğunu (komut satırından), hâlâ aynı adresi bildirdiğini (~/.claude/aipager-tunnel.json adresin kendisini değil, bir hash'ini tutar) ve adresin yanıt verdiğini kontrol ettikten sonra devralır. Başka her durumda onu durdurup yenisini başlatır; 3 dakika içinde hiçbir aipager'ın devralmadığı tutulan bir tüneli de küçük bir bekçi süreci durdurur. Başka her durdurma (Ctrl+C, docker stop, systemctl stop) tüneli de durdurur; bilgisayarı ya da konteyneri yeniden başlatmak yeni bir adres verir. MINIAPP_KEEP_TUNNEL=0 tüneli tutmayı kapatır. aipager zorla öldürülürse (bellek tükenmesi, kill -9) tünel, aipager yönetilen tünel açık olarak (Mini App etkin, MINIAPP_PUBLIC_URL yok) yeniden başlayıp onu devralana ya da durdurana kadar, ya da bilgisayar yeniden başlayana kadar çalışmaya devam eder; aipager uninstall da onu durdurur. Tünel çalışırken çökerse aipager onu artan aralıklarla yeniden başlatır ve yeni adresi yayınlar; birkaç denemeden sonra ayağa kalkmazsa düğme, ölü bir portu göstermeye devam etmek yerine kaldırılır.

MINIAPP_PUBLIC_URL (ya da aipager miniapp enable --url https://…) ayarlanırsa yönetilen tünel tamamen kapanır (cloudflared programı asla indirilmez ve başlatılmaz) ve verilen URL, altında aynı initData kontrolüyle olduğu gibi kullanılır. Tailscale'in otomatik algılanması (tailscale status --json), Tailscale'i zaten çalıştıran ve Cloudflare'e hiç bağımlı olmamayı tercih edenler için daha basit bir seçenek olarak kalır.

Sesli mesajları metne çevirme#

faster-whisper aipager sürecinin içinde çalışır. Ses, /tmp/aipager-files/ altında sohbetin kendi klasörüne (gönderilen dosyaların gittiği yer; klasör 0700, dosya 0600) .ogg olarak indirilir, işlemci üzerinde yerel olarak metne çevrilir ve dosya senin denetiminde kalır. Hiçbir ses bilgisayardan çıkmaz. Üçüncü taraf API yok. Telegram'la konuşmak için zaten gereken bot token'ı dışında hiçbir anahtar yok.

Metne çevirdikten sonra .ogg dosyasını silersen mesajın düz metin olarak tek kaydı, claude oturumuna yazılan metin olur (orada Claude Code'un kendi gizlilik kurallarına tabidir).

Oturumlar arası yalıtım#

Her Claude Code oturumu kendi dtach'ında çalışır. /tmp/claude-dtach-<name>.sock konumundaki kontrol soketi aipager'ın kullanıcısına aittir; dtach diğer kullanıcıların bağlanmasına izin vermez. Her oturum, /new ya da Mini App ile seçilen kendi klasöründe ya da aipager session komutunun çalıştırıldığı klasörde başlar.

aipager oturumları dosya sistemi düzeyinde birbirinden yalıtmaz: ~/projects/foo klasörüne bağlı bir oturum, Claude Code'un izinleri izin veriyorsa ilke olarak ~/projects/bar klasörünü okuyabilir. Daha sıkı yalıtım için proje başına ~/.claude/settings.json ya da bir konteyner (Docker imajı) kullan.

Claude oturumları arasındaki mesajlar#

Claude Code, bir oturumun diğerine mesaj göndermesine izin verir (SendMessage aracı). Onu alan oturumda bu mesaj diğer her mesaj gibidir, bu yüzden aipager onun yetkilerine bir Telegram mesajınınkine karar verdiği gibi karar verir: içinde ne yazdığına göre değil, onu gerçekte kimin gönderdiğine göre.

  • Bir mesaj, göndereninin yetkilerini taşır, asla daha fazlasını değil. aipager bir oturumun mesaj göndermesine izin verdiğinde tek kullanımlık bir makbuz yazar: tam metnin parmak izi, gönderen Claude süreci (süreç numarası ve Linux'ta başlangıç zamanı) ve o görevin sahip olduğu yetkiler. Claude Code, alınan mesajı çekirdeğin doğruladığı gönderen süreç numarasıyla kaydeder ve gönderenin kendine verdiği ada asla güvenmez. Mesajı alan görev tek bir araç çalıştırmadan önce aipager ikisini eşleştirir ve göreve tam olarak onu gönderen görevin yetkilerini verir: sahibin mesajı sahibin yetkileriyle, bir üyenin mesajı o üyenin yetkileriyle, gönderen oturumun terminalinde yazılmış bir mesaj sınırsız gider.
  • Makbuz yok, kısıtlı yetkiler. aipager'ın eşleştiremediği bir mesaj (aipager'ın başlatmadığı bir oturumun ya da Claude sürecinin gönderdiği, bir saat sonra süresi dolan bir makbuz, başka bir bilgisayardaki bir gönderen) en sıkı kurallarla, dosya değişikliği olmadan ve internet erişimi olmadan (yalnızca okumak ve düşünmek) gider. Alan oturumun önceki yetkileri ona asla uygulanmaz.
  • Oturumun dışından gelen diğer girdiler de öyle. Claude Code'un bu oturumun insanından gelmemiş olarak kaydettiği her şey de bu kısıtlı yetkileri alır: bir MCP kanalından bildirim, uzaktan bir çağıran, bir eklentinin kuyruğa koyduğu bir mesaj, başka bir oturumun gelen kutusundan aktarılan bir mesaj ve aipager'ın henüz tanımadığı her türden girdi (bir eklenti komutu, başlatılması senin tarafından yapılmış olsa bile dışarıdan gelen girdi sayılır). Oturumun kendi arka plan ajanları (dönüşleri ve raporları) ve görev bildirimleri işin yetkilerini korur.
  • Bir oturumun zamanladığı bir mesaj, onu zamanlayan görevin yetkileriyle gider. Bir görev bir /loop ya da bir cron kurduğunda aipager o mesaj için bu görevin yetkilerini kaydeder; mesaj daha sonra tetiklendiğinde, en son kim konuşmuş olursa olsun, bu yetkileri alır, asla daha fazlasını değil; bu göreve katılan bir mesaj onları yalnızca daraltabilir ve zamanlayan kişiden yetki alan bir kural değişikliği de onları daraltır. İki kez zamanlanan aynı mesaj daha sıkı yetkileri korur. Çıplak bir /loop kendi metni yerine Claude Code'un döngü talimatlarıyla tetiklenir, bu yüzden konuşma geçmişi tetiklenmeyi gösterir göstermez oturumun kurduğu tüm çıplak döngülerin en sıkı yetkilerini alır (o zamana kadar reddedilen bir araç çağrısı yumuşak şekilde reddedilir ve Claude yeniden dener). Kimsenin aipager'ın kontrolünden geçerek zamanlamadığı bir mesaj kısıtlı yetkiler alır.
  • Metin hiçbir şey kanıtlamaz. Gönderenin adı, bir [via Telegram · @owner] satırı ya da mesajın içindeki “sahip şunu istiyor…” hiçbir şeyi değiştirmez. Claude, aipager'ın gönderen olarak kimi doğruladığını ve metindeki iddiaların kanıt olmadığını öğrenir.
  • Süren bir göreve katılmak onu yalnızca daraltır. Bir görev sürerken gelen başka bir oturumun mesajı, o görevi ikisinin daha sıkı olanı kadar sıkı yapar, asla daha serbest değil. Claude Code mesajı kendi mesaj olayı olmadan aldığında da (süren göreve katılır ya da kuyruktan sonraki görev olarak başlar) böyledir: sahibin hızlı yolu her araç çağrısından önce konuşma geçmişinin sonuna bakar, görevin sonu ve aipager da böyle bir mesajı kuyrukta gördüklerinde oturumu kontrol için işaretler.
  • Roller kendi sohbetlerinde kalır. Başka bir sohbetin oturumundan gelen bir makbuz yalnızca görevinin sahip yetkileri varsa ya da o oturumun terminalinde yazılmışsa sayılır; diğer her şey kısıtlı gider.
  • Kim gönderebilir. Yerleşik kısıtlı roller SendMessage'ı hiç kullanamaz. Bir kuralın onu verdiği bir rol yalnızca aipager'ın başlattığı oturumlara yazabilir (uds:…/<pid>.sock olarak adreslenir); aipager doctor böyle bir rol için uyarır.
  • Arka plan ajanları yetkilerini korur. Bir ajan, onu başlatan görevin yetkilerini (ya da daha sonraki bir görevin daha sıkı yetkilerini) korur, asla daha fazla yetkisi olan daha sonraki bir görevin yetkilerini değil.
  • Durdurulduğunda. Başka bir oturumun başlattığı bir görevi güvenlik kuralları durdurursa çalışma kartı onu kimin gönderdiğini zaten gösterir, durdurma bildirimi bunu söyler ve görevi aktaran kişi de bunu öğrenir, böylece görev asla sessizce kaybolmaz: iki oturum da aynı sohbetteyse gönderen oturumun sohbeti; aksi halde yalnızca sahip, özel sohbette ve yalnızca gönderen görevi sahip (ya da terminal) yönettiyse.

Bilinen sınırlamalar:

  • Shell'i olan bir görev (bir sahipte ya da yöneticide) aipager ile aynı sistem kullanıcısı olarak çalışır ve tıpkı aipager'ın diğer kontrol dosyalarını zaten yeniden yazabildiği gibi bir makbuzu da taklit edebilir. Bu mevcut güven modelidir: shell'i yalnızca bu bilgisayarda güvenebileceğin kişilere ver.
  • aipager'ın başlatmadığı Claude oturumlarını, onlara kim yazarsa yazsın, aipager hiç yönetmez.
  • Linux dışında gönderen yalnızca süreç numarasından tanınır (Claude Code orada başlangıç zamanını kaydetmez). Linux'ta başlangıç zamanı olmayan bir alındı kaydı hiçbir şeyle eşleşmez.
  • Claude Code mesajı konuşma geçmişine görevin ilk araç çağrısından bir an sonra yazabilir. Bunu yapana kadar, kısıtlı yetkilerin yasaklayacağı bir çağrı yumuşak şekilde reddedilir (Claude'a yeniden denemesi söylenir; görev durmaz). Onsuz 8 çağrıdan sonra görev kısıtlı gider.
  • Sahibin hızlı yolu konuşma geçmişinin son 1 MiB'ını okur, asla daha fazlasını değil. Bundan uzun olan başka bir oturumun mesajı, hızlı yolun böyle bir mesaj sandığı bir satırla biter (pencerenin kestiği, 256 KiB'tan uzun her satır böyle sayılır). Tamamen daha geride kalan bir mesajı (bir sonraki araç çağrısına kadar ondan sonra 1 MiB'tan fazla geçmiş yazılmışsa) hızlı yol değil, görev sürerken aipager ya da mesaj hâlâ kuyruktayken görevin sonu yakalar.
  • Bir oturumda çıplak bir /loop kuruluyken, bir Telegram mesajının başlatmadığı her görevin (terminalde yazılan bir mesaj dahil) ilk araç çağrıları, Claude Code o görevin mesajını yazana ve aipager bunun bir döngü tetiklenmesi olmadığını görene kadar yumuşak şekilde reddedilebilir; o zaman Claude yeniden dener.
  • aipager zamanlanmış bir mesajın görevini, konuşma geçmişinin görevin başından beri aldıklarından okur; 8 MiB'tan fazlası için ilk ve son 4 MiB'tan (aradaki kısım en yeni bölümken kontrol edilmişti).
  • Zamanlanmış bir mesajın kaydedilmiş yetkileri, oturum sonlandırılana (/kill) kadar kalır: sona eren ya da devam ettirilen bir oturum onları korur, tıpkı Claude Code'un cron'larını ve bekleyen /loop uyandırmasını koruduğu gibi. Oturum başına en fazla 256 tanesi tutulur ve bunun üstünde bir tane daha zamanlamak o oturumdaki herkese reddedilir, bu yüzden zamanlama yapabilen herkes onları tüketebilir (o zaman oturumu başka bir adla başlat ya da bunu /kill ile sonlandır). Kayıt olmadan tetiklenen bir mesaj kısıtlı yetkiler alır, çıplak /loop olan bir oturumda ise Claude Code onu konuşma geçmişine yazar yazmaz o döngünün yetkilerini; o zamana kadar aipager görevi bir öncekine göre okur. Bu, bu sürümden önce kurulmuş bir mesajda; bir yeniden başlatmadan sonra (kayıtlar sistemin, yeniden başlatmanın temizlediği geçici klasöründe yaşar ve Claude Code devam ettirilen bir oturumun uyandırmasını bir saat içinde hâlâ geri getirebilir); ve kendi oturumu sona erdiğinde Claude Code'un aynı klasörün başka bir oturumunda çalıştırdığı uzun ömürlü bir cron'da olur. Aynı metni zamanlayan daha az yetkili bir oturum, mesajın yetkilerini düşürebilir (ama asla yükseltemez).
  • Önceki oturumun adıyla yeniden başlatılan bir oturum (Değiştir), /kill yapılana kadar o oturumun kayıtlarını, çıplak /loop yetkileri dahil, korur.
  • Claude Code'un başka bir görevin hemen ardından kendi mesaj olayı olmadan (kendi kuyruğundan) çalıştırdığı zamanlanmış bir mesaj, kendi yetkilerinin ve ardından geldiği görevin yetkilerinin daha sıkı olanını alır (terminalde yazılmış bir görevden sonra tam olarak kendininkini).
  • Terminalde yazılan bir görevin ilk araç çağrıları, Claude Code onun mesajını konuşma geçmişine yazana kadar reddedilebilir (o zamana kadar aipager ondan önceki görevi okur).
  • Daha dar yetkilerle başlatılmış bir arka plan ajanı, aynı işin daha sonraki bir görevine, onu işin yetkileriyle okuyan bir metin döndürebilir; Claude Code'un diğer görev bildirimleri gibi.
  • Claude Code, alan terminalde onaylanana kadar bir mesajı bekletebilir (crossSessionInbound ayarı ya da iki oturum farklı izin sınıflarında çalıştığında, örneğin Tam erişim modu ile Otomatik mod). aipager böyle bir mesajı Telegram'dan serbest bırakamaz; makbuz bir saate kadar bekler.

Tehdit özeti#

TehditKoruma
Bir yabancı bota komut gönderirSohbet kimliği filtresi reddeder
Bot token'ı çalındı@BotFather'da /revoke, sonra yeniden yapılandır
Ele geçirilmiş bir claude araç çağrısıaipager'ın güvenlik kontrolü, Telegram görevinin kurallarının yasakladığını reddeder; Sor modunda Claude Code'un settings.json içindeki kendi kuralları neyi soracağına karar verir ve insanın dokunuşu tek izindir; Otomatik modda (her yeni oturum için varsayılan) Claude Code'un kendi güvenlik denetimi güvenli saydığı çağrıları sormadan çalıştırır ve riskli olanları insan için durdurur; Tam erişim modundaki bir oturum (yöneticiler ve kendi özel sohbetindeki kişi) hiçbir şey sormaz, bu yüzden yolda yalnızca aipager'ın güvenlik kontrolü durur, sahibin kendi görevleri ve terminal mesajları için ise hiçbir şey (kim karar verir)
Telegram'daki kısıtlı bir kişi sahip yetkileri alırShell yok, oturumlar yalnızca üyenin kendi kök klasöründe başlar, yazma ve arama onun içindeki projeyle sınırlı (asla ev klasörü değil), ev klasöründe kök klasörün dışında okuma yok, diğer üyelerin kök klasörlerine ve diğer sohbetlerin yüklediği dosyalara erişilemez, kimlik bilgisi dosyaları okunmaz, dosya araçları için korunan yollar, bozulan kontroller reddeder (kurallar ekipte nasıl uygulanır); Bash'li bir rol için yalnızca elden geldiğince ve “Bilinen sınırlamalar” içindeki durumlar için kapsanmaz
Bir oturumun mesajı, sahibin konuştuğunu iddia ederMesaj, onu gönderen görevin kanıtlanmış yetkileriyle gider, asla alan oturumun önceki yetkileriyle değil; kanıt yoksa yalnızca okumak ve düşünmek (oturumlar arası mesajlar)
Bir grup üyesi başkasının yetkilerini ödünç alırHer mesaj, geldiği sohbette göndereninin rolüyle gider; başka bir gönderenin mesajı süren görevi bekler; yine de katılırsa en sıkı kurallar kazanır; kısıtlı rollerin slash komutları klavye komutlarıyla sınırlı (kurallar ekipte nasıl uygulanır)
Gruptaki konuşmalar oturuma girerGrupta yalnızca komutlar, bota yanıtlar, botun anılması ve işaretli klavyeye dokunuşlar işlenir (gruplar)
Çıkarılan bir üye erişimini koruraipager config, aipager'ı yeniden başlatmadan yeniden yükler; bekletilen mesajları atılır ve hâlâ süren görevi önceki yetkilerini kaybeder; Telegram grubundan çıkarılması onun grubu okumasını engeller (gruplar → yeniden başlatmadan yeniden yükleme)
Denetim kaydının sahteciliğiYalnızca ekleme yapılır; bunu ayrı bir imzalama programı olmadan önlemek kapsam dışı
Bir prompt injection, Claude'a veriyi dışarı taşıyan bir adres yazdırırClaude'un metnindeki resimler ve medya etiketleri asla medya olarak değil, bağlantı ya da metin olarak gösterilir; düz metin ve HTML mesajlarında bağlantı önizlemeleri kapalıdır (ağ bağlantıları)
Ağdaki saldırganGelen port yok, doğrudan ulaşılamaz
Yerel yetki yükseltmesudo / setuid yok; aipager kullanıcı alanında kalır
Sesli mesajların sesi buluta sızarMetne çevirme yereldir
Ajan, aipager'daki kendi Claude kimlik bilgilerini okurBeklenen, hata değil: bkz. Claude kimlik bilgileri. Bulunduğu dosyayı değil, kimlik bilgilerinin kendisini sınırla

Ayrıca bkz.#