Przejdź do głównej zawartości

Plan: zapisz intent.md

Etap planowania w cyklu AI-native zamienia pomysł, ticket albo sygnał z produkcji w commitowany intent.md: problem, oczekiwany wynik, ograniczenia i otwarte pytania, zapisane słowami zgłaszającego. Agent przeprowadza wywiad ze zgłaszającym i pisze plik, ale zatrzymuje się przed jakimkolwiek projektem i kodem. Product owner akceptuje plik, zatwierdzając pull request, który go dodaje.

Ta strona jest dla dewelopera albo product ownera, który spisuje intencję, i dla tech leada, który odpowiada za kolejną bramkę (akceptację przed designem). Oto sytuacja, którą rozwiązuje. Support przekazuje do zespołu „klienci chcą powiadomień”, deweloper wkleja to agentowi, a w piątek działa funkcja e-mailowa, o którą nikt nie prosił. Klienci chcieli powiadomień w aplikacji i tylko o komentarzach do własnych dokumentów. Nigdzie nie było to zapisane.

Tradycyjnie: pomysł przechodzi przez backlog, user stories i spotkania refinementowe, zanim ktokolwiek zacznie nad nim pracować. Przy każdym przekazaniu zmienia się właściciel, więc to, co dociera do inżynierów, jest oddalone o kilka kroków od tego, co zgłaszający miał na myśli.

AI-native: zgłaszający omawia pomysł z agentem, który zadaje pytania analityka, a wynik trafia do repozytorium jako intent.md w ramach tej samej sesji pracy. Agenci od designu, budowy i review czytają ten jeden plik.

  • Szablon i wypełniony przykład intent.md oraz zasadę, co do niego nie wchodzi.
  • Trzy prompty do skopiowania: wywiad ze zgłaszającym, szkic intencji z ticketu i kodu oraz atak na szkic w świeżej sesji.
  • Skill capture-intent do commitowania, dzięki któremu każdy zgłaszający przechodzi ten sam wywiad w Claude Code, Codeksie i Cursorze.
  • Kontrolę kształtu w CI i bramkę w CODEOWNERS, więc nikt nie sprawdza struktury ręcznie, a żadna intencja nie zostanie przyjęta bez zatwierdzenia product ownera.
  • Sposób wyjścia z każdej typowej awarii tego etapu.
  • Miejsce na intencje. Trzymaj katalog intent/ w repozytorium produktu, po jednym podkatalogu na zmianę: intent/notifications/intent.md. Etap designu zapisuje obok niego spec.md. Osobne repozytorium intencji opłaca się dopiero wtedy, gdy jedna intencja obejmuje wiele repozytoriów; ten wybór oraz alternatywy w Jirze czy Linearze opisuje łańcuch artefaktów.
  • Szablon. Zacommituj intent/TEMPLATE.md z następnej sekcji.
  • Wskazana osoba akceptująca. Jeden product owner na obszar, wpisany do CODEOWNERS (zobacz sekcję o weryfikacji).
  • Ścieżka dla osób, które nie używają gita. Product manager albo inżynier supportu może przeprowadzić wywiad w claude.ai lub Claude Cowork, a potem dodać plik jako pull request przez edytor webowy GitHuba. Może też zacommitować go za nich inżynier. Liczy się plik, a nie narzędzie, którego użył zgłaszający.

To pierwszy etap cyklu AI-native, więc nie wymaga żadnego wcześniejszego.

intent.md mówi, co jest potrzebne i dlaczego. Nigdy nie mówi jak. Nazwy tabel, endpointy, biblioteki i ścieżki plików należą do spec.md i plan.md, gdzie decyduje o nich ktoś, kto przeczytał kod. Szablon jest ten sam, którego używa łańcuch artefaktów:

# Intent: INTENT_TITLE
Author: AUTHOR_NAME (TEAM). Status: draft | accepted. Ticket: TICKET_ID
## Problem
WHAT_IS_BROKEN_OR_MISSING
## Proposed outcome
WHAT_BETTER_LOOKS_LIKE
## Affected users and systems
USERS_AND_SYSTEMS
## Constraints
CONSTRAINTS
## Open questions
OPEN_QUESTIONS

Tak wygląda przykład z powiadomieniami po 20-minutowym wywiadzie. Zwróć uwagę, o czym agentowi nie wolno było zdecydować:

# Intent: Tell document owners when a teammate comments
Author: Maria Nowak (Support). Status: draft. Ticket: SUP-412
## Problem
Document owners miss comments on their documents. Support gets about ten
tickets a week that read "I didn't know anyone had replied". Owners only
see comments when they reopen the document.
## Proposed outcome
An owner learns about a new comment on their document within a minute,
without opening it, and can turn this off. Success: those support tickets
stop.
## Affected users and systems
Document owners on all plans. The comments feature and the account
settings screen. Commenters see no change.
## Constraints
In-app first. Email is out of scope for this change (originator preference:
customers asked for in-app). Must respect the existing "do not disturb"
setting. No new third-party service without a security review.
## Open questions
- Should owners hear about replies inside a thread they already follow?
(Product owner to decide.)
- What volume do the largest workspaces generate per hour? (Data team.)
SekcjaJest dobra, gdySygnał ostrzegawczy
ProblemMówi, kto dziś czego nie może zrobić, słowami zgłaszającegoOpisuje funkcję („dodaj tabelę notifications”)
Proposed outcomeTester mógłby zaobserwować, że to się dzieje„Lepiej”, „szybciej” albo „usprawnić” bez zdarzenia czy liczby
Affected users and systemsWymienia użytkowników i istniejące systemy, także tych, dla których nic się nie zmieniaPusta albo „wszyscy”
ConstraintsWymienia terminy, regulacje, budżety i systemy, których nie wolno zmieniaćDecyzja projektowa podana jako ograniczenie bez słowa „preference”
Open questionsKażde pytanie wskazuje, kto może na nie odpowiedziećPusta przy czymkolwiek większym niż drobna poprawka: agent zgadywał

intent.md pomijasz tylko przy zmianach, których nikt spoza zespołu nie zauważy: literówka, podbicie zależności, refaktoryzacja bez zmiany zachowania. Wszystko, co może zauważyć użytkownik albo inny system, dostaje intencję, nawet jeśli wydaje się drobne.

  1. Zacznij od tego, co masz. Wystarczy pomysł, ticket, e-mail od klienta albo zrzut ekranu. Zgłaszający nie musi mówić ustrukturyzowanym językiem; strukturę tworzy wywiad.

  2. Przeprowadź wywiad. Agent zadaje jedno pytanie naraz i proponuje odpowiedź, więc zgłaszający reaguje, zamiast pisać od zera. Wszystko, na co nie ma odpowiedzi, trafia do Open questions zamiast do zgadywania.

    Gdy inżynier zaczyna od ticketu, agent może najpierw przeczytać ticket i kod, a na wywiad przyjść ze szkicem i krótszą listą pytań.

  3. Popraw szkic jako zgłaszający. Zgłaszający czyta plik, który jest krótki, i poprawia wszystko, co agent źle zrozumiał. To przejście należy do zgłaszającego, a nie do inżyniera, który prowadził sesję.

  4. Zaatakuj szkic w świeżej sesji. Nowa sesja nie ma założeń z wywiadu, więc czyta plik tak, jak przeczyta go agent od designu.

  5. Otwórz pull request i pozwól product ownerowi go zaakceptować. Pull request zawiera tylko intent/notifications/intent.md. Product owner komentuje, prosi o zmiany albo zatwierdza. Przed zatwierdzeniem product owner (albo autor, na jego prośbę) zmienia Status: draft na Status: accepted w tym samym pull requeście. Scalenie po tym zatwierdzeniu jest akceptacją i wysyła intencję do etapu Design: napisz spec.md. Zamknięcie pull requesta to zapisane odrzucenie.

Jak poprowadzić wywiad w Claude Code, Codeksie i Cursorze?

Dział zatytułowany „Jak poprowadzić wywiad w Claude Code, Codeksie i Cursorze?”

Wywiad wygląda tak samo w każdym narzędziu. Różni się tylko sposób, w jaki powstrzymujesz agenta przed edycją kodu produktu, gdy zadaje pytania.

  • Uruchom sesję w trybie tylko do odczytu poleceniem claude --permission-mode plan albo przełącz się przez Shift+Tab lub /plan. Od v2.1.283 (kanał latest) sesje interaktywne startują w trybie auto, więc przełącz się świadomie.
  • Tryb planowania blokuje wszystkie edycje, także intent.md. Gdy Claude przedstawi plan zapisania intent.md, wybierz Yes, manually approve edits; potem zatwierdź zapis do intent/notifications/intent.md i odrzuć każdy inny plik.
  • Product owner bez terminala może uruchomić ten sam prompt w claude.ai lub Claude Cowork, a potem otworzyć pull request w edytorze webowym GitHuba.

Zrób z wywiadu skill, który dostaje każdy zgłaszający

Dział zatytułowany „Zrób z wywiadu skill, który dostaje każdy zgłaszający”

Prompt wklejany z wiki się rozjeżdża: każdy przycina go po swojemu. Skill w repozytorium daje każdemu zgłaszającemu ten sam wywiad i ten sam szablon. Zacommituj go jako capture-intent/SKILL.md w katalogu skilli każdego narzędzia (.claude/skills/ dla Claude Code, .agents/skills/ dla Codeksa i Cursora; etap designu wymienia te lokalizacje i pokazuje, jak trzymać jedną kopię źródłową):

---
name: capture-intent
description: Use when someone describes an idea, ticket, bug report, or incident and wants it written up as intent.md, or asks to capture intent before design. Interviews the originator and writes intent/FEATURE/intent.md from intent/TEMPLATE.md. Never designs or writes code.
---
# Capture intent
1. Ask one question at a time and give your recommended answer with each.
2. Cover, in order: the problem today and for whom, how often it happens,
an observable outcome, constraints, and what is out of scope.
3. If the codebase can answer a question, read the code instead of asking.
Do not edit any file while reading.
4. Stop asking when every template section has content or a named open question.
5. Write intent/FEATURE/intent.md from intent/TEMPLATE.md with Status: draft.
Keep the originator's words in Problem.
6. Never name tables, endpoints, libraries, or files. A design idea the
originator insists on goes under Constraints, marked "originator preference".
7. Every unanswered question goes under Open questions with who can answer it.

Wywołaj go po nazwie, gdy chcesz mieć pewność, że się załaduje: /capture-intent w Claude Code i Cursorze, $capture-intent w Codeksie. Budowanie własnych skilli opisuje, jak przetestować skill, zanim zespół zacznie na nim polegać.

Gdy tickety przychodzą szybciej, niż ktokolwiek zdąży przepytać ich autorów, niech pierwszy szkic napisze zadanie headless, a pytania z wywiadu trafią do pull requesta. Autor odpowiada tam, a agent poprawia plik.

Okno terminala
# Terminal albo zadanie CI. TICKET.md zawiera wyeksportowaną treść ticketu i nigdy nie trafia do commita.
FEATURE=notifications
PROMPT="Use the capture-intent skill. Read TICKET.md and the code it refers to. \
Write intent/$FEATURE/intent.md with Status: draft. Do not ask questions: \
put every question under Open questions with who can answer it."
# Przed startem agenta: pobierz commit bazowy i skrypt kontroli z zaufanej bazy.
# Oba zostają w pamięci tej powłoki, gdzie agent nie może ich zmienić.
BASE_SHA=$(git rev-parse origin/main) || exit 1
CHECK=$(git show "$BASE_SHA:scripts/check-intent.sh") && [ -n "$CHECK" ] || exit 1
# Claude Code: headless, edycje plików akceptowane, bez interaktywnych pytań
claude -p "$PROMPT" --permission-mode acceptEdits
# albo Codex: headless, sandbox ograniczony do workspace'u
codex exec -s workspace-write "$PROMPT"
# Zadanie nie commituje zmian: zaindeksuj je bez ticketu, żeby kontrola kształtu je zobaczyła
git add -A -- . ':!TICKET.md'
printf '%s\n' "$CHECK" | REQUIRE_INTENT=1 RANGE="--cached $BASE_SHA" sh

Treść ticketu pochodzi spoza zespołu, więc traktuj ją jak każde niezaufane wejście: uruchamiaj zadanie bez poświadczeń do wdrożeń i sekretów produkcyjnych, a kontrola kształtu opisana niżej niech oblewa każdy przebieg, który dotknął pliku poza intent/. Uruchamiaj skrypt kontroli w wersji z origin/main, nigdy kopię z workspace’u: agent może edytować każdy plik w workspace’ie, także scripts/check-intent.sh, a skrypt przepisany na exit 0 przepuści wszystko. Dlatego zadanie wczytuje skrypt i commit bazowy, zanim agent wystartuje, i kończy się błędem, gdy w bazie nie ma skryptu kontroli. Zadanie nie commituje zmian, więc przed kontrolą zaindeksuj jego wynik, jak w dwóch ostatnich liniach; kontrola czytająca tylko historię commitów nie zobaczyłaby żadnych zmian i przeszłaby bez błędu. REQUIRE_INTENT=1 sprawia, że w razie wątpliwości kontrola oblewa: przebieg, który nie zapisał intent.md, a zmienił src/ albo .github/, kończy się błędem, zamiast przejść jako zmiana bez intencji, a gdy skrypt nie może porównać zmian z gałęzią bazową, zwraca błąd, a nie sukces. Specyfikacja ścieżki ':!TICKET.md' zostawia wyeksportowany ticket poza indeksem, więc kontrola nie zgłasza go jako zbędnego pliku. Incydent produkcyjny przechodzi tę samą ścieżkę, poprzedzony agentem triażu działającym tylko do odczytu; opisuje to Maintain: zamknij pętlę.

Jak sprawdzić intent.md bez czytania go linijka po linijce?

Dział zatytułowany „Jak sprawdzić intent.md bez czytania go linijka po linijce?”

Intencja jest krótka i czytają ją zgłaszający oraz product owner. Nikt więcej nie powinien. Podziel sprawdzanie na trzy części: skrypt sprawdza kształt, przegląd w świeżej sesji sprawdza treść, a product owner podejmuje jedyną decyzję, która wymaga człowieka.

Kontrola kształtu. Zapisz ją jako scripts/check-intent.sh. Uruchamiaj ją w CI przy każdym pull requeście; kończy się od razu, jeśli pull request nie zmienia pliku intent/*/intent.md, więc pull requesty z designu i budowy, które dodają spec.md i plan.md do tego samego katalogu, przechodzą bez przeszkód. Uruchamiaj ją też po zadaniu headless, w wersji z bazy, jak pokazano wyżej, ze zmienną RANGE wskazującą zaindeksowane zmiany i z REQUIRE_INTENT=1, żeby przebieg bez intent.md oblał kontrolę:

scripts/check-intent.sh
# W CI pull requesta porównuje gałąź z jej merge base (domyślnie).
# CI: pobierz repozytorium z fetch-depth: 0 (albo git fetch origin main), żeby origin/main...HEAD dało się rozwiązać.
# Po zadaniu headless zaindeksuj jego wynik i uruchom:
# REQUIRE_INTENT=1 RANGE="--cached $BASE_SHA" sh, z tym plikiem z bazy na stdin
BASE=origin/main
RANGE=${RANGE:-"$BASE...HEAD"}
status=0
# Bezpieczna porażka: zakres, którego git nie rozwiąże, to błąd, a nie „brak zmian”.
changed=$(git diff --name-only $RANGE) || { echo "git diff $RANGE failed"; exit 2; }
intents=$(printf '%s\n' "$changed" | grep '^intent/.*/intent\.md$')
if [ -z "$intents" ]; then
# Zadanie headless musi wytworzyć intent.md; wszystko inne, co zmieniło, oblewa kontrolę.
if [ -n "$REQUIRE_INTENT" ]; then
[ -n "$changed" ] && printf '%s\n' "$changed"
echo "No intent/*/intent.md changed"; exit 1
fi
# Pull requesty bez zmian w intent.md (specyfikacja i budowa) przechodzą.
exit 0
fi
# Pull request z intencją zmienia wyłącznie pliki intent.md.
if printf '%s\n' "$changed" | grep -v -e '^intent/.*/intent\.md$' -e '^$'; then
echo "Files above are not intent.md files"; status=1
fi
for f in $(git diff --name-only --diff-filter=AM $RANGE -- 'intent/*/intent.md'); do
grep -Eq '^Author: .+Status: (draft|accepted)' "$f" || { echo "$f: no Author/Status line"; status=1; }
for s in '## Problem' '## Proposed outcome' '## Affected users and systems' '## Constraints' '## Open questions'; do
grep -qx "$s" "$f" || { echo "$f: missing section $s"; status=1; }
done
# Bloki kodu i ścieżki źródeł należą do spec.md albo plan.md.
if grep -nE '^`{3}|(src|app|lib)/[A-Za-z0-9_./-]+\.(ts|tsx|js|py|go|rb|php|ex)' "$f"; then
echo "$f: code or file paths above belong in spec.md or plan.md"; status=1
fi
done
exit $status

Kontrola treści. Wklej tabelę z przeglądu w świeżej sesji do pull requesta. Werdykt NOT READY wraca do zgłaszającego, a nie do product ownera.

Bramka ludzka. Nic nie zostanie scalone bez zatwierdzenia product ownera. Wpisz go do CODEOWNERS i włącz „Require review from Code Owners” w regule ochrony gałęzi domyślnej. To czyni zatwierdzenie obowiązkowym, ale po nim scalić może każdy z prawem zapisu; jeśli samo scalenie ma należeć do product ownera, ogranicz też, kto może pushować do gałęzi (ruleset albo opcja „Restrict who can push to matching branches”). Minimalny CODEOWNERS:

# .github/CODEOWNERS
/intent/**/intent.md @acme/product-owners
/intent/billing/**/intent.md @acme/billing-product

Wzorce pasują tylko do intent.md, więc spec.md i plan.md z tego samego katalogu przechodzą przez własnych właścicieli, a nie przez product ownerów.

Wskaźniki. Dwie liczby z historii gita pokazują, czy etap działa; obie definiuje strona Metryki AI-native SDLC:

  • Wyprzedzający: czas od pierwszego zgłoszenia (daty utworzenia ticketu albo pierwszego commita na gałęzi) do scalonego intent.md. Gdy etap działa, mierzy się go w godzinach albo dniach, nie w tygodniach.
  • Opóźniony: odsetek intencji przyjętych do designu zamiast zamkniętych oraz to, jak często intent.md zmienia się jeszcze po pierwszym commicie spec.md dla tej samej zmiany. Późne edycje intencji oznaczają, że wywiad coś przeoczył.

Co się psuje, gdy intencję zapisuje agent, i jak to naprawić

Dział zatytułowany „Co się psuje, gdy intencję zapisuje agent, i jak to naprawić”

Intencja zawiera rozwiązanie. Problem brzmi „dodaj tabelę notifications”, a Proposed outcome opisuje ekran ustawień. Kontrola kształtu łapie ścieżki plików, a przegląd w świeżej sesji (punkt 1) resztę. Przenieś każdy pomysł projektowy do Constraints jako preferencję zgłaszającego albo go usuń, a wynik przepisz tak, żeby tester mógł go zaobserwować.

Open questions jest puste przy prawdziwej funkcji. Agent zapełnił każdą lukę wiarygodnym domysłem, a domysły wyglądają teraz jak wymagania. Uruchom ponownie przegląd w świeżej sesji i poproś, żeby każde niepoparte stwierdzenie zamienił w pytanie. Jeśli w skillu brakuje zdania „anything I cannot answer goes under Open questions”, dopisz je.

Inżynier napisał intencję sam. Plik czyta się dobrze, ale opisuje to, co zbudowałby inżynier, a nie to, czego potrzebuje zgłaszający. Odeślij pull request do zgłaszającego na krok 3. Autor pull requesta jest widoczny w gicie, więc ten wzorzec widać w historii.

Wywiad się nie kończy. Po czterdziestu pytaniach zgłaszający się poddaje. Każ agentowi skończyć, gdy każda sekcja szablonu ma treść albo nazwane otwarte pytanie, co mówi już krok 4 skilla, a pozostałe pytania przenieś do pliku.

Jedna intencja ukrywa trzy zmiany. „Powiadomienia, podsumowania i usługa push na telefony” w jednym pliku dają specyfikację, której nikt nie zaakceptuje. Przegląd w świeżej sesji (punkt 5) proponuje podział. Akceptuj jedną intencję na każdy wynik, który da się wdrożyć niezależnie.

Intencja żyje poza repozytorium. Leży w wątku na czacie, na slajdzie albo w portalu, którego agent nie przeczyta, a sesja designu startuje od parafrazy. Trzymaj plik w gicie. Jeśli istniejący system, na przykład Jira, musi zostać rejestrem, powiąż oba tak, jak opisuje łańcuch artefaktów.

Claude Code nie może zapisać pliku w trybie planowania. Tryb planowania blokuje każdą edycję. Gdy Claude przedstawi plan, wybierz Yes, manually approve edits; potem każda edycja pyta osobno, więc zatwierdź zapis do intent.md i odrzuć każdy inny plik.

Intencja zmienia się po powstaniu specyfikacji. Ktoś w trakcie budowy edytuje intent.md, żeby pasował do tego, co zbudowano. Zamrażaj zaakceptowane intencje: zmiana intencji to nowy pull request z własną akceptacją, który odsyła specyfikację z powrotem do designu. Te edycje liczy wskaźnik opóźniony opisany wyżej.