IDE'de Agent ile Çok Adımlı İş: Tool Onayları, Terminal Komutları, Checkpoint'ler ve Bookstore'a Uçtan Uca Özellik Eklemek
Agent'ın 'tüm testler geçiyor' özeti, testin mi kodun mu değiştiğini söylemez: Bookstore'daki kurumsal minimum özelliğinde aynı kırmızı testi bir kez testi bir kez kodu değiştirerek yeşile çevirdik, ikisi de 14/14 geçti ve farkı yalnız git diff --stat gösterdi. Tool onayları, terminal kuralları, checkpoint sınırları, API, migration ve Angular.
Sürüm notu: Bu yazıdaki kodlar .NET 10, Entity Framework Core 10.0.15, xUnit.net v3 4.0.3, Angular 22.2 (TypeScript 6.0) ve Vitest 5.1 ile derlenip denenmiştir; testler SQL Server 2025 üzerinde çalıştırılmıştır. Agent'ın tool onayları, terminal kuralları ve checkpoint davranışı 15 Kasım 2026 itibarıyla Visual Studio 2026 (18.12) ve Visual Studio Code (VS Code) 1.146 dokümanlarından alınmıştır. Bu yazıda Copilot agent'ı çalıştırılmadı: özelliği agent'ın izleyeceği adımlarla elle ekledik ve her adımın gerçek çıktısını gösteriyoruz.
Önce Tahmin Et
Agent'a sitedeki serilerin ortak örnek uygulaması Bookstore'da (bir online kitapçı) kurumsal siparişler için "en az 20 kitap" kuralını eklemesini söyledin ve bütün komutları otomatik onaylayan modu açtın. Agent testleri yazdı, kodu yazdı, testleri çalıştırdı: biri kırmızı. Birkaç saniye sonra yeni bir değişiklik yaptı ve testleri yeniden çalıştırdı: hepsi yeşil. Özetinde "tüm testler geçiyor" yazıyor.
Tahminin ne? Kırmızı testi yeşile çeviren değişiklik kodda mıydı, testte mi? Özetten bunu anlayabilir misin? Diff'te neye bakarsan anlarsın? Aynı kırmızı testi iki farklı şekilde yeşile çevirip ikisini yan yana koyacağız.
Agent'ın Döngüsü
IDE'deki agent, chat'ten farklı olarak sonuca kadar çalışan bir döngü: hedefi alır, ilgili dosyaları arar ve okur, bir plan çıkarır, dosyaları düzenler, terminalde build ve test çalıştırır, çıktıyı okuyup hatayı düzeltir ve hedefe ulaşana ya da senden bir şey sorması gerekene kadar devam eder. Visual Studio dokümanı agent mode'u tam olarak böyle tanımlıyor: ask mode tek cevaptan sonra durur, agent mode durmaz. Dördüncü yazıdaki talimatlar (AGENTS.md'deki "her davranış değişikliği testle gelir, mevcut assertion'ı zayıflatma" kuralı dahil) bu döngünün her adımında context'te.
Görevi agent'a bu yazının özelliği için şöyle verirdik. Dördüncü yazıdaki new-endpoint prompt dosyasının mantığını izliyor: önce test, sonra kod, mevcut testlere dokunmamak, migration'ı uygulamamak:
Agent mode.
Add the institutional order minimum to Bookstore:
an order placed with an InstitutionCode needs at least 20 books in total across all lines.
1. Add integration tests first: 20 books across two lines is placed, 5 books is 400 with a ProblemDetails
message, an unknown code is 400. Run them and show that they fail.
2. Ordering must not read the Institutional tables; add IInstitutionService to the Institutional module.
3. Add Order.InstitutionId with a migration. Do not run dotnet ef database update.
4. Show the hint and disable checkout in the Angular cart below 20 books; add a Vitest spec.
5. Run dotnet test and npm test. Never change an existing assertion; if a test looks wrong, stop and ask.
Onaylar: Neyi Otomatik Çalıştırmalı
Agent dosya düzenlemenin yanında terminal komutu çalıştırıyor ve MCP (Model Context Protocol; agent'ın dış araçlara bağlandığı protokol) tool'larını çağırıyor. Bunların her biri için onay isteyip istememesi, çalışma hızı ile güvenlik arasındaki asıl ayar.
VS Code'un Copilot harness'ında üç izin seviyesi var: Manual permissions (varsayılan; tool, URL ve terminal onay ayarların uygulanır), Assisted permissions (her tool çağrısını bir model değerlendirir; doküman bunun hata yapabileceğini söylüyor) ve Allow all (onaysız çalışır). Autopilot ise bir izin seviyesi değil, ayrı bir mod: tool'ları onaylar, agent'ın sorduğu soruları da kendisi cevaplar ve görev bitene kadar devam eder. Allow all ve Autopilot ilk seçildiğinde bir uyarı penceresi çıkıyor. Oturum içinde /yolo ya da /autoApprove o oturum için onayları kaldırıyor; chat.tools.global.autoApprove ise bütün workspace'lerde kaldırıyor.
Manual seviyesinde terminal için kural yazmak mümkün. Bookstore'a eklediğimiz workspace ayarı:
"chat.tools.terminal.autoApprove": {
"/^dotnet (build|test)\\b/": true,
"/^npm (test|run build)\\b/": true,
"/^git (status|diff|log)\\b/": true,
"/^git push\\b/": false,
"/^dotnet ef database\\b/": false,
"rm": false,
"Remove-Item": false
}
/ ile başlayıp biten anahtarlar regular expression. true olan komut onaysız çalışır; false komutu engellemez, her seferinde onay ister ve true kurallarının ve oturum onaylarının önüne geçer. Zincirlenmiş bir komut (dotnet build && git push gibi) ancak bütün parçaları bir true kuralına uyup hiçbiri false kuralına uymuyorsa onaysız çalışır. Ne senin kurallarına ne de VS Code'un salt okuma komutları için yerleşik kurallarına uyan bir komut onaya düşer; dotnet ef migrations add bu yüzden her seferinde sorulur. Dokümanın en önemli cümlesi de şu: terminal otomatik onayı bir kolaylık, güvenlik sınırı değil. Gerçek sınır için VS Code'un agent sandbox'ı terminal komutlarının dosya sistemi ve ağ erişimini kısıtlıyor; 1.146'da macOS, Linux ve WSL (Windows Subsystem for Linux; Windows içinde Linux çalıştıran katman) için preview, Windows için deneysel ve Allow all ile Autopilot'ta da açık kalıyor.
Visual Studio'da agent, terminal komutundan ve yerleşik olmayan tool'lardan önce onay istiyor; onay penceresindeki Allow seçenekleriyle tool'u o oturum, o solution ya da her zaman için onaylayabiliyorsun. Bu seçimler Tools > Options > GitHub > Copilot > Tools altında sıfırlanıyor. 18.12'deki yeni Chat deneyiminde konuşma modu (Interactive ya da Autopilot) ile tool izni (Manual ya da Allow all) ayrı seçiliyor; Autopilot ile Manual birlikteyken otomatik onayı olmayan tool beklemek yerine reddediliyor. Microsoft Learn'deki bir not çok önemli: agent mode yalnız solution içindeki dosyalara dokunabiliyor ama terminal komutları Visual Studio process'inin yetkileriyle çalışıyor ve bu sınırın dışında.
Bookstore: Önce Test
Kural Requirements Analysis serisinden: kurumsal siparişte toplam en az 20 kitap. Testleri koddan önce yazdık; iki satıra dağılmış 20 kitap, 5 kitap ve bilinmeyen bir kurum kodu:
[Fact]
public async Task Institutional_order_with_twenty_books_across_lines_is_placed()
{
Guid cartId = await CreateCartAsync((Foundation, 12), (Middlemarch, 8));
HttpResponseMessage response = await client.PostAsJsonAsync("/api/orders",
new PlaceOrderRequest(cartId, "Barbara Liskov", "barbara@example.com", InstitutionCode: "RHS"), ct);
Assert.Equal(HttpStatusCode.Created, response.StatusCode);
}
[Fact]
public async Task Institutional_order_below_twenty_books_is_rejected()
{
Guid cartId = await CreateCartAsync((Emma, 5));
HttpResponseMessage response = await client.PostAsJsonAsync("/api/orders",
new PlaceOrderRequest(cartId, "Edsger Dijkstra", "edsger@example.com", InstitutionCode: "RHS"), ct);
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
ProblemDetails? problem = await response.Content.ReadFromJsonAsync<ProblemDetails>(ct);
Assert.Equal("Institutional orders need at least 20 books; this cart has 5.", problem?.Detail);
}
$ dotnet test
tests/Bookstore.Api.Tests/InstitutionalOrderTests.cs(23,80): error CS1739: The best overload for 'PlaceOrderRequest' does not have a parameter named 'InstitutionCode'
İlk kırmızı bir derleme hatası; beklenen bu, çünkü InstitutionCode henüz yok. Sonra kodu yazdık. Ordering module'ü kurumlar tablosunu doğrudan okumuyor; AGENTS.md'deki kurala uygun olarak Institutional module'üne bir IInstitutionService ekledik. OrderService'teki kontrol:
// Kurumsal Sipariş: kurum adına verilen siparişte toplam en az 20 kitap olmalı (Requirements Analysis serisi).
public const int InstitutionalMinimumQuantity = 20;
InstitutionInfo? institution = null;
if (!string.IsNullOrWhiteSpace(request.InstitutionCode))
{
institution = await institutions.FindByCodeAsync(request.InstitutionCode.Trim(), ct);
if (institution is null)
{
return new PlaceOrderOutcome.UnknownInstitution(request.InstitutionCode);
}
int quantity = cart.Items.Sum(i => i.Quantity);
if (quantity <= InstitutionalMinimumQuantity)
{
return new PlaceOrderOutcome.BelowInstitutionalMinimum(quantity);
}
}
Order'a eklenen InstitutionId için migration'ı araçla ürettik (dotnet ef migrations add AddOrderInstitution): bir nullable kolon, bir index ve Restrict davranışlı bir foreign key. Migration'ı veritabanına uygulayan dotnet ef database update kuralımızda false; bir agent bunu çalıştırmak istediğinde mutlaka soruluyor.
Kırmızı Testi Yeşile Çevirmenin İki Yolu
Dikkatli bakarsan yukarıdaki kodda bir hata var: <= yazılmış, yani tam 20 kitaplık sipariş de reddediliyor. Bu hatayı bilerek bıraktık ve testleri çalıştırdık:
$ dotnet test
...
failed Bookstore.Api.Tests.InstitutionalOrderTests.Institutional_order_with_twenty_books_across_lines_is_placed (13ms)
Expected: Created
Actual: BadRequest
Test run summary: Failed!
total: 14
failed: 1
succeeded: 13
skipped: 0
Testi yeşile çevirmenin iki yolu var. Birinci yol, Önce Tahmin Et'teki agent'ın yaptığı: testteki sepeti 21 kitaba çıkarmak.
$ git diff --stat
tests/Bookstore.Api.Tests/InstitutionalOrderTests.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
$ git diff
...
- Guid cartId = await CreateCartAsync((Foundation, 12), (Middlemarch, 8));
+ Guid cartId = await CreateCartAsync((Foundation, 12), (Middlemarch, 9));
$ dotnet test
...
Test run summary: Passed!
total: 14
failed: 0
succeeded: 14
skipped: 0
İkinci yol, kodu düzeltmek:
$ git diff --stat
src/Bookstore.Api/Ordering/OrderService.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
$ git diff
...
- if (quantity <= InstitutionalMinimumQuantity)
+ if (quantity < InstitutionalMinimumQuantity)
$ dotnet test
...
Test run summary: Passed!
total: 14
failed: 0
succeeded: 14
skipped: 0
İki sonuç da 14/14 yeşil, iki diff de tek satır. Özette ikisi de "testler geçiyor" diye görünür. Farkı yalnız diff'in hangi dosyada olduğu söylüyor: birincisi tests/ altında, ikincisi src/ altında. Birinci "düzeltme" iş kuralını değiştirdi: 20 kitaplık kurumsal sipariş artık reddediliyor ve bunu söyleyecek bir test kalmadı. Testin adı hâlâ "twenty books" diyor, verisi 21; review'da yakalanacak ipucu bu tutarsızlık. AI'ın kırmızı CI'ı nasıl yeşile çevirdiğini incelemeyi AI Destekli Geliştirme serisinin dördüncü yazısında anlatmıştık; Copilot'ta pratik karşılığı şu: agent'ın oturum sonunda git diff --stat çıktısında tests/ altındaki her değişiklik ayrı bir soru. Talimat dosyasındaki "mevcut assertion'ı zayıflatma" kuralı ve review talimatındaki "değişen assertion'a neden diye sor" maddesi bu yüzden var; ama talimat bir rica, son kontrol senin okuduğun diff.
Angular Tarafı
Kuralı API uyguluyor; istemci yalnız kullanıcıya erken söylüyor. Sepet sayfasına isteğe bağlı bir kurum kodu alanı, eksik adet için bir uyarı ve 20'nin altında devre dışı kalan bir sipariş düğmesi ekledik:
// OrderService.InstitutionalMinimumQuantity'nin kopyası; kuralı API uygular, istemci yalnız açıklar.
export const institutionalMinimumQuantity = 20;
protected readonly institutionCode = signal('');
protected readonly minimum = institutionalMinimumQuantity;
protected readonly missingForInstitution = computed(() =>
this.institutionCode().trim() ? Math.max(0, this.minimum - this.store.itemCount()) : 0);
<input #institutionBox name="institution" placeholder="Institution code (optional)"
data-testid="institution-code" (input)="institutionCode.set(institutionBox.value)" />
<button type="submit" [disabled]="missingForInstitution() > 0">Place order</button>
...
@if (missingForInstitution() > 0) {
<p class="hint" data-testid="institution-hint">
Institutional orders need at least {{ minimum }} books. Add {{ missingForInstitution() }} more.
</p>
}
Spec, sepette 5 kitap varken kurum kodu yazılınca uyarının "Add 15 more" dediğini ve düğmenin devre dışı olduğunu, kod boşken ise uyarının olmadığını kontrol ediyor:
it('explains the minimum and blocks checkout below 20 books', async () => {
const fixture = await render();
await typeCode(fixture, 'RHS');
const element = fixture.nativeElement as HTMLElement;
expect(element.querySelector('[data-testid="institution-hint"]')?.textContent).toContain('Add 15 more');
expect(element.querySelector<HTMLButtonElement>('button[type="submit"]')?.disabled).toBe(true);
});
$ npm test -- --watch=false
...
Test Files 2 passed (2)
Tests 3 passed (3)
Checkpoint, Keep/Undo ve Son Review
Agent'ın yaptığı değişikliği geri almak için iki mekanizma var. VS Code'da checkpoint'ler desteklenen oturumlarda varsayılan olarak açık (chat.checkpoints.enabled): her istekten önce etkilenen dosyaların bir kopyası alınıyor; önceki bir isteğin üstüne gelip Restore Checkpoint dediğinde dosyalar o ana dönüyor ve sonraki istekler geçmişten siliniyor. Copilot harness'ında bekleyen düzenlemeler bir çalışma kümesinde (working set) duruyor; tek bir değişikliği, bir dosyayı ya da hepsini Keep ya da Undo ile kabul edip geri alabiliyorsun. Visual Studio'da düzenlenen dosyalar Total changes listesinde; parça parça Keep ve Undo var, 18.6'dan beri bütün dosyaları tek sekmede gösteren özet diff görünümü de var. Önceki bir noktaya dönmek için checkpoint'in yanındaki Restore kullanılıyor; dokümana göre adım adım undo ve redo henüz yok.
Checkpoint'in sınırını bilmek şart. VS Code dokümanı açıkça söylüyor: checkpoint dosyaları ve chat geçmişini geri alır, ama tamamlanmış terminal komutlarını, ağ isteklerini, deploy'ları ve dış servislerdeki değişiklikleri geri almaz. Veritabanına uygulanmış bir migration da bu listede. Terminalde ya da script'le değiştirilen dosyalar ise çalışma kümesinde hiç görünmüyor; onları Source Control'den ya da git diff'ten review etmek gerekiyor. Bu yüzden agent'a başlamadan önce temiz bir commit almak, checkpoint'ten daha güvenilir bir geri dönüş noktası.
Özelliğin son hâlinde, dördüncü yazının tag'ine göre değişen dosyalar:
$ git diff --stat github-copilot/04
.vscode/settings.json | 9 +
.../20261114234727_AddOrderInstitution.Designer.cs | 1004 ++++++++++++++++++++
.../20261114234727_AddOrderInstitution.cs | 56 ++
.../Migrations/BookstoreContextModelSnapshot.cs | 10 +
.../Institutional/InstitutionService.cs | 20 +
.../Institutional/InstitutionalModule.cs | 3 +
src/Bookstore.Api/Ordering/Order.cs | 1 +
src/Bookstore.Api/Ordering/OrderService.cs | 24 +-
.../Ordering/OrderingConfiguration.cs | 2 +
src/Bookstore.Api/Ordering/OrderingContracts.cs | 3 +-
src/Bookstore.Api/Ordering/OrderingModule.cs | 7 +
src/Bookstore.Api/Program.cs | 3 +-
.../Bookstore.Api.Tests/InstitutionalOrderTests.cs | 65 ++
web/bookstore-web/src/app/cart/cart-page.html | 9 +-
web/bookstore-web/src/app/cart/cart-page.spec.ts | 54 ++
web/bookstore-web/src/app/cart/cart-page.ts | 10 +-
web/bookstore-web/src/app/cart/cart-store.ts | 6 +-
web/bookstore-web/src/app/core/api-models.ts | 3 +
18 files changed, 1280 insertions(+), 9 deletions(-)
1.280 satırın 1.004'ü üretilmiş migration designer dosyası; asıl review edilecek kısım yaklaşık 200 satır. İnsan review'unda bakacaklarımız: tests/ altında yalnız yeni dosya var mı, var olan bir assertion değişmiş mi? Migration'ın Up method'unda veri kaybı ya da beklenmeyen bir DropColumn var mı? Ordering başka bir module'ün tablosunu okuyor mu? Hata mesajı API'de ve istemcide aynı kuralı mı anlatıyor? Bu dört sorunun cevabı diff'te; agent'ın özetinde değil.
Üretimde Dikkat
Agent'ı izole et. Visual Studio'da terminal komutları IDE'nin yetkileriyle çalışıyor; VS Code'da sandbox Windows'ta henüz deneysel. Riskli işleri ayrı bir worktree'de, Dev Container'da ya da yetkisi kısıtlı bir ortamda çalıştırmak, yanlış bir komutun etkisini sınırlar.
Production'a dokunan hiçbir komut otomatik onaylanmamalı: git push, dotnet ef database update, deploy script'leri, bulut CLI'ları. Geliştirme makinesinde production connection string'i ya da geniş yetkili bir token bulunmamalı; agent'ın terminali onları görebilir.
Maliyeti izle. İlk yazıdaki hesapta gördüğümüz gibi her adım bütün konuşmayı yeniden gönderiyor; testleri tekrar tekrar çalıştırıp çıktısını okuyan uzun bir agent oturumu kredinin büyük kısmını harcar. Copilot CLI'daki --max-ai-credits gibi oturum sınırları bu yüzden var.
Sık Düşülen Tuzaklar
Her komutu otomatik onaylamak. rm, migration uygulama ve git push her zaman soru sormalı; terminal kuralları güvenlik sınırı değil.
Agent'ın özetine güvenmek. "Tüm testler geçiyor" cümlesi, testlerin değiştirilip değiştirilmediğini söylemez.
Kırmızı testi testi değiştirerek yeşillendiren agent'ı fark etmemek. git diff --stat'ta tests/ altındaki her değişikliği ayrı oku; test adıyla verisi tutarlı mı bak.
Checkpoint'in her şeyi geri aldığını sanmak. Uygulanmış migration'ı, gönderilmiş commit'i ve terminalde değişen dosyaları geri almaz.
Agent'ı kirli bir çalışma kopyasında başlatmak. Başlamadan commit al; geri dönüş noktası Git olsun.
Küçük Bir Deneme
★☆☆ Kendi projende chat.tools.terminal.autoApprove kurallarını yaz. Build ve test komutlarına izin ver; git push ve migration uygulamayı false yap. Bir hafta sonra hangi komutlar için en çok onay istendiğine bak ve kuralları buna göre düzelt.
★★☆ Bookstore'da <= hatasını geri koy ve agent'a "testleri yeşile çevir" de. Agent kodu mu düzeltti, testi mi? Oturum sonunda git diff --stat çıktısını ve agent'ın özetini karşılaştır.
★★★ Kurumsal Sipariş kuralının ikinci yarısını ekle: kurumsal siparişe yüzde 10 indirim. Önce testleri yaz (indirimli toplam, yuvarlama, 19 ve 20 kitap sınırı), sonra agent'a uygulat. Review'da her satırı Requirements Analysis serisindeki kuralla karşılaştır.
Bu yazıda agent yalnız IDE'nin yerleşik tool'larını kullandı. Bir sonraki yazıda onu genişletiyoruz: Bookstore için bir MCP server, GitHub ve Playwright MCP server'ları, custom agent'lar, agent skill'leri ve kuralları zorlayan hook'lar.