W poprzednim wpisie poznaliśmy trzy poziomy konfiguracji Copilota i wiemy już gdzie co ustawiać. Teraz czas na konkret – jak pisać instrukcje które faktycznie działają. Bo to jest właśnie ta umiejętność która oddziela Copilota który generuje generyczny kod od Copilota który generuje kod jakbyś go napisał sam.
Instrukcje to nie magia. To zwykły Markdown z naturalnym językiem. Ale – i to jest ważne – nie każdy tekst działa tak samo dobrze. Jest spora różnica między instrukcją która "mówi" Copilotowi coś istotnego a instrukcją która jest tam bo "wypadało coś napisać". W tym wpisie pokażę Ci jak tę różnicę zobaczyć i jak pisać instrukcje które robią robotę.
Zanim zaczniesz pisać, warto wiedzieć że instrukcje w ekosystemie Copilota mają kilka wariantów – różnią się zakresem i miejscem przechowywania:
🔍 Rodzaje instrukcji i ich zakres
Rodzaj
Plik
Zakres
Kiedy używać
GLOBAL
.github/copilot-instructions.md
Całe repozytorium
Stack, architektura, zasady ogólne projektu
PATH
.github/instructions/*.instructions.md
Pliki pasujące do glob pattern
Zasady per język, per warstwa, per typ pliku
PERSONAL
Ustawienia konta GitHub / VS Code
Wszystkie repozytoria danego użytkownika
Osobiste preferencje stylu, języka odpowiedzi
ORG
Ustawienia GitHub Organization
Wszystkie repozytoria organizacji
Polityki compliance, standardy firmowe
Priorytet gdy kilka instrukcji jest aktywnych jednocześnie: Personal → Repo-wide → Org-level. Wszystkie jednak trafiają do kontekstu – Copilot stara się uwzględnić każdą z nich.
W tym wpisie skupiamy się na dwóch najważniejszych z perspektywy codziennej pracy w teamie: GLOBAL i PATH.
Co powinna zawierać dobra instrukcja globalna?
GitHub w swoim blogu technicznym wyróżnia pięć elementów które powinny znaleźć się w każdym pliku copilot-instructions.md. Nie są to sztywne wymogi – to rekomendacje, które w praktyce znacząco podnoszą jakość sugestii Copilota.
1
Opis projektu – co budujesz
Krótkie zdanie o tym czym jest aplikacja. Copilot bez tego kontekstu generuje kod "w próżni" – z kontekstem rozumie domenę i dobiera nazwy, typy i logikę spójnie z tym co już istnieje.
2
Stack technologiczny – czego używasz
Język, framework, wersja, biblioteki. Bez tego Copilot może zaproponować Moq zamiast NSubstitute, Maven zamiast Gradle, albo jQuery zamiast Vanilla JS. Konkretne nazwy z wersjami są kluczowe.
3
Zasady kodowania – jak piszecie kod
Konwencje nazewnictwa, wzorce których używacie, rzeczy których unikacie. To jest najczęściej pomijana sekcja – i jednocześnie ta która robi największą różnicę w jakości PR-ów.
4
Struktura projektu – gdzie co jest
Główne katalogi i ich przeznaczenie. Agent szukający gdzie wstawić nowy handler będzie działał szybciej i trafniej gdy wie że handlery są w Application/[Feature]/Commands/.
5
Zasoby i narzędzia – z czego korzystać
Skrypty build, komendy testów, narzędzia diagnostyczne. Agent który wie jak uruchomić testy sam je odpali po zmianie i zweryfikuje poprawność – bez pytania Cię o komendę.
⚠️ Długość ma znaczenie – ale w drugą stronę niż myślisz
Naturalną pokusą jest wrzucenie do instrukcji wszystkiego co wiesz o projekcie. To błąd. Bardzo długi plik instrukcji ma dwa negatywne efekty: zajmuje cenną przestrzeń okna kontekstu przy każdej sesji, a Copilot może pomijać instrukcje zbyt daleko od początku pliku.
Reguła praktyczna: trzymaj się dwóch stron A4. Jeśli masz więcej – przenieś szczegóły do plików *.instructions.md z odpowiednim scopem, a w głównym pliku zostaw tylko esencję.
Instrukcje path-specific z frontmatter
Gdy projekt rośnie, jeden globalny plik zaczyna być niewystarczający. Zasady dla kodu C# są inne niż dla testów, a zasady dla infrastruktury inne niż dla warstwy API. Do tego właśnie służą pliki *.instructions.md z frontmatter applyTo.
---
applyTo: "**/*.cs"
description: "Zasady dla kodu C# w tym projekcie"
---
Treść instrukcji...
Pole applyTo przyjmuje glob pattern – takie same jak w .gitignore. Instrukcja jest włączana do kontekstu automatycznie gdy Copilot pracuje na pliku pasującym do wzorca. Możesz też użyć excludeAgent jeśli chcesz żeby dana instrukcja nie była stosowana przez konkretnego agenta:
---
applyTo: "**/*.cs"
excludeAgent: "copilot-review"
description: "Zasady dla generowania kodu (nie dla code review)"
---
🌟 Przykład: kompletny zestaw instrukcji dla projektu .NET
Każdy plik jest mały i skupiony na jednym aspekcie. Copilot dostaje tylko te instrukcje które są odpowiednie dla aktualnie edytowanego pliku – bez szumu z innych warstw projektu.
Czego instrukcje NIE potrafią
Zanim przejdziemy do przykładów "przed/po", jedna ważna rzecz którą trzeba powiedzieć wprost: instrukcje mają ograniczenia. Copilot to system probabilistyczny – ta sama instrukcja nie zawsze da identyczny wynik. Warto wiedzieć co nie działa żeby nie tracić czasu na pisanie instrukcji które nie przyniosą efektu.
⚠️ Te typy instrukcji prawdopodobnie nie zadziałają
Odwołania do zewnętrznych zasobów:"Przestrzegaj zasad z styleguide.md w repo my-org/my-repo" – Copilot nie pobiera zewnętrznych plików przez instrukcję. Potrzebne zasady przepisz bezpośrednio.
Ograniczenia długości odpowiedzi:"Odpowiadaj zawsze w mniej niż 1000 znaków" – działa nieprzewidywalnie, zależy od złożoności zadania.
Polecenia narzędziowe:"Używaj @terminal gdy odpowiadasz na pytania o Git" – takie dyrektywy nie są przetwarzane przez instrukcje.
Styl konwersacji:"Odpowiadaj jak przyjazny kolega, używaj nieformalnego języka" – możesz spróbować w instrukcjach osobistych, ale nie oczekuj konsekwencji.
Ogólna zasada: instrukcje działają najlepiej gdy są konkretne, techniczne i sprawdzalne. "Używaj xUnit zamiast NUnit" – działa. "Bądź pomocny" – nie robi żadnej różnicy.
Przed i po – przykłady złych i dobrych instrukcji
To jest sekcja którą chciałem dodać od siebie – bo różnica między złą a dobrą instrukcją często nie jest oczywista na pierwszy rzut oka. Cztery konkretne przykłady z komentarzem co dokładnie zmieniliśmy i dlaczego to ma znaczenie.
Nie używaj `var` gdy typ nie
wynika wprost z prawej strony
przypisania.
Metody publiczne mają XML
doc comments.
Nie umieszczaj logiki biznesowej
w kontrolerach – tylko wywołania
przez MediatR.
Maksymalna długość metody: 30 linii.
Jeśli dłuższa – wyodrębnij
prywatną metodę pomocniczą.
🔎 Co zmieniliśmy i dlaczego
"Dobry kod" i "najlepsze praktyki" to pojęcia które Copilot interpretuje według ogólnej wiedzy z internetu – nie według Twoich standardów. Każda z czterech reguł w wersji "po" jest sprawdzalna: albo jest var albo go nie ma. Albo jest XML doc comment albo go nie ma. Albo logika jest w kontrolerze albo jej tam nie ma. Copilot może weryfikować takie reguły mechanicznie. Nie może weryfikować "czytelności".
Przykład 2 – Brak kontekstu stacku
❌ Przed – zła instrukcja
To jest projekt .NET.
Używamy testów jednostkowych.
Mamy warstwową architekturę.
Wersja "przed" mówi Copilotowi że to .NET – ale nie mówi który .NET, jakie biblioteki, jaka architektura warstwowa. Efekt: Copilot może zaproponować Moq zamiast NSubstitute, ADO.NET zamiast EF Core, albo wrzucić logikę do warstwy Infrastructure zamiast Application. Wersja "po" daje konkretne nazwy z wersjami – i Copilot wie dokładnie czego użyć bez zgadywania.
Przykład 3 – Zakaz bez alternatywy vs zakaz z kontekstem
❌ Przed – zła instrukcja
Nie używaj async void.
Nie używaj static classes.
Nie używaj Thread.Sleep.
Nie używaj magic numbers.
✅ Po – dobra instrukcja
// zamiast: async void Handler()
// użyj: async Task Handler()
// Powód: async void nie propaguje
// wyjątków do callera.
// zamiast: Thread.Sleep(1000)
// użyj: await Task.Delay(1000,
// cancellationToken)
// Powód: Sleep blokuje wątek;
// Delay go zwalnia.
// zamiast: if (retries > 3)
// użyj: if (retries > MaxRetryCount)
// gdzie MaxRetryCount to stała
// w klasie konfiguracyjnej.
🔎 Co zmieniliśmy i dlaczego
Lista zakazów bez alternatywy i bez uzasadnienia to słaby kontekst. Copilot wie że ma unikać async void – ale co wygenerować zamiast? Wersja "po" daje konkretne pary przed/po z komentarzem dlaczego. To jest też doskonały materiał onboardingowy dla nowych developerów – instrukcja przestaje być tylko dla Copilota a staje się żywą dokumentacją decyzji technicznych.
Przykład 4 – Jeden wielki plik vs właściwy podział
❌ Przed – jeden wielki plik globalny
## Zasady ogólne
[30 linii zasad ogólnych]
## Zasady dla testów
[25 linii o xUnit, AAA,
FluentAssertions...]
## Zasady dla migracji EF
[20 linii o naming, rollback...]
## Zasady dla kontrolerów
[20 linii o routingu...]
## Zasady dla DTOs
[15 linii o record types...]
## Zasady dla logowania
[20 linii o Serilog...]
# Razem: ~130 linii w jednym pliku
# Ładuje się przy każdej sesji.
✅ Po – podział na scopowane pliki
# copilot-instructions.md (~30 ln)
# Stack + architektura + TOP 5 zasad
# + struktura katalogów
# + komendy build i test
# tests.instructions.md
# applyTo: **/*Tests.cs
# [25 linii – TYLKO o testach]
# migrations.instructions.md
# applyTo: **/Migrations/*.cs
# [20 linii – TYLKO o migracjach]
# api.instructions.md
# applyTo: **/Controllers/*.cs
# [20 linii – TYLKO o API]
# Każdy plik jest mały i skupiony.
# Copilot dostaje tylko instrukcje
# relevantne do aktualnego pliku.
🔎 Co zmieniliśmy i dlaczego
130-liniowy plik globalny ma dwa problemy. Po pierwsze, zajmuje dużo miejsca w oknie kontekstu przy każdej sesji – niezależnie od tego czy pracujesz przy testach czy przy migracjach. Po drugie, instrukcje z dołu pliku mają mniejszą szansę być wzięte pod uwagę niż te z góry. Podzielony zestaw plików z applyTo sprawia że przy pracy nad kontrolerem Copilot dostaje zasady dla kontrolerów – nie zasady dla testów i migracji. Precyzja rośnie, szum spada.
Jak Copilot może sam wygenerować instrukcje?
Dobra wiadomość jeśli masz projekt bez żadnych instrukcji i nie wiesz od czego zacząć – możesz poprosić Copilota o pomoc w ich napisaniu. GitHub oficjalnie rekomenduje taki prompt w trybie agentycznym:
🔍 Prompt do automatycznego wygenerowania instrukcji
@workspace Wygeneruj plik copilot-instructions.md dla tego repozytorium
na podstawie aktualnego kodu. Plik powinien zawierać:
- opis co robi aplikacja
- stack technologiczny z wersjami
- zasady kodowania które obserwujesz w projekcie
- strukturę katalogów
- komendy build i test
Instrukcje mają być zwięzłe – maksymalnie 2 strony A4.
Copilot przeskanuje codebase i wygeneruje propozycję. Traktuj to jako punkt startowy do edycji – nie jako gotowy produkt. Warto uzupełnić o rzeczy których nie wywnioskuje z kodu: decyzje architektoniczne, powody dla których coś jest tak a nie inaczej.
Analogicznie możesz poprosić o przegląd istniejącego pliku:
@workspace Przejrzyj nasz .github/copilot-instructions.md
i zaproponuj ulepszenia. Szukaj: zbyt ogólnych reguł,
brakujących sekcji, rzeczy które można skonkretyzować.
To jest iteracyjny proces. Nie musisz mieć idealnego pliku od razu – zacznij od czegoś, sprawdź jak Copilot reaguje, dodawaj reguły gdy widzisz że generuje coś niezgodnego z Twoimi oczekiwaniami.
Jak sprawdzić czy instrukcje są używane?
Często pojawia się pytanie: "Mam plik, ale nie wiem czy Copilot go czyta". Jest prosta metoda weryfikacji:
Otwórz Copilot Chat w VS Code i zadaj dowolne pytanie.
Po otrzymaniu odpowiedzi rozwiń sekcję References (referencje) nad treścią odpowiedzi w panelu chatu.
Jeśli plik .github/copilot-instructions.md widnieje na liście – instrukcje zostały dołączone do zapytania. Możesz kliknąć w link i otworzyć plik bezpośrednio.
⚠️ Jeśli instrukcje nie są używane – sprawdź to ustawienie
Dołączanie instrukcji może być wyłączone. Otwórz Ctrl+, → wpisz "instruction file" i upewnij się że checkbox przy Code Generation: Use Instruction Files jest zaznaczony. Wyłączenie tego ustawienia obowiązuje tylko dla Ciebie – nie wpływa na innych użytkowników w teamie.
Podsumowanie
Instrukcje to najprostszy i najskuteczniejszy sposób na podniesienie jakości sugestii Copilota. Ale działają tylko gdy są napisane z myślą o tym czego Copilot naprawdę potrzebuje – nie o tym co wygląda dobrze w dokumencie.
✅ Cztery rodzaje instrukcji – global, path-specific, personal, org. Zacznij od global, uzupełnij path-specific gdy projekt rośnie.
✅ Pięć sekcji dobrej instrukcji globalnej: opis projektu, stack z wersjami, zasady kodowania, struktura katalogów, zasoby i narzędzia.
✅ Dwie strony A4 maksimum dla pliku globalnego. Resztę do plików z applyTo.
✅ Konkretne reguły wygrywają z ogólnikami – "używaj xUnit, NSubstitute, FluentAssertions" działa; "pisz dobre testy" nie robi różnicy.
✅ Pary przed/po z uzasadnieniem – lepsza wskazówka dla Copilota i dokumentacja decyzji technicznych dla całego teamu.
✅ Iteracja – wygeneruj z Copilotem, edytuj, obserwuj efekty, doprecyzowuj. Weryfikuj przez References w Copilot Chat.
W kolejnym wpisie przechodzimy do tworzenia skutecznych Skills – samowystarczalnych zdolności które możesz pakować, współdzielić z teamem i uruchamiać na żądanie lub automatycznie przez agenty.