Warstwa wiedzy dla projektów klienckich, trzymana w repo i egzekwowana przez CI.
Jedno źródło prawdy (docs/DECISIONS.md), z którego generowany jest skrót aktywnych decyzji
wprost do CLAUDE.md. Rozjazd między nimi jest niemożliwy dłużej niż jeden PR, bo bramka CI
regeneruje i porównuje — tak jak check lockfile'a.
Dystrybucja dwiema ścieżkami z jednego repo: plugin Claude Code (skille + komendy dla zespołu)
oraz CLI uruchamiane wprost przez node (bramki w GitHub Actions, bez zależności
od Claude Code i bez menedżera pakietów — kit nie ma żadnych zależności).
- Skąd to się wzięło
- Model: źródło kontra derywata
- Co ręczne, co automatyczne — tabela zbiorcza
- Instalacja
- Jak powstaje dokumentacja — trzy ścieżki
- Routing dokumentów zespołowych
- Format wpisu DEC
- Status jest wyliczany, nie zapisywany
- Bramki CI
- Komendy CLI
- Rytm pracy i właściciel
- Czego repoBrain nie robi
- Rozwój kitu
Z audytu warstwy wiedzy w zakończonym projekcie klienckim: pięć równoległych magazynów, ręcznie utrzymywane kopie rozjechały się ze źródłem, a hook synchronizujący commitował cudzą pracę pod fałszywym komunikatem. Wspólna przyczyna wszystkich defektów była jedna — kopia utrzymywana ręcznie zawsze się rozjedzie. repoBrain zastępuje kopie derywatą.
Z tego wynika cały układ narzędzia:
- kopii się nie utrzymuje — kopię się generuje i porównuje w CI,
- statusu decyzji się nie zapisuje — status wynika z relacji między wpisami,
- automat nie pisze do repo bez człowieka — bo to była przyczyna defektu, nie jego lekarstwo.
To jest podział, z którego wynika wszystko poniżej.
┌─ ŹRÓDŁO (człowiek pisze, review w PR) ──────────────────────┐
│ │
│ docs/DECISIONS.md pełna treść decyzji │
│ Transcripts/*.md podsumowania spotkań (dowód) │
│ HYPOTHESES.md niepewności do rozstrzygnięcia │
│ docs/specs/ kontrakt implementacyjny │
│ │
└──────────────────────────┬───────────────────────────────────┘
│ knowledge.mjs index
▼
┌─ DERYWATA (maszyna generuje, NIKT nie edytuje ręcznie) ─────┐
│ │
│ CLAUDE.md → blok <!-- WYGENEROWANE:decyzje --> │
│ tabela aktywnych decyzji + lista odwróconych │
│ │
└──────────────────────────┬───────────────────────────────────┘
│ knowledge.mjs check (bramka index-fresh)
▼
rozjazd = czerwony PR, nie da się zmergować
Reguła pierwszeństwa, którą instalator dopisuje do CLAUDE.md:
docs/DECISIONS.md— pełna treść;Odwraca:/Zmienia:rozstrzygają aktualność- blok
WYGENEROWANE:decyzje— skrót aktywnych, zawsze zgodny z (1) docs/specs/— kontrakt implementacyjnyTranscripts/— materiał dowodowy, gdy 1–3 milczą
Wszystko poza tą listą to notatki robocze, nie źródło prawdy.
| Czynność | Kto | Kiedy |
|---|---|---|
| Napisanie wpisu DEC | człowiek (agent proponuje draft) | przy każdej decyzji zakresowej, kosztowej lub architektonicznej |
| Podsumowanie transkryptu | agent (/transcript-extract) |
po callu z klientem |
| Wybór, które drafty DEC zastosować | człowiek | krok 4 /transcript-extract |
Wybór Odwraca: vs Zmienia: |
człowiek | gdy decyzja dotyka wcześniejszej |
| Wyliczenie statusu (aktywna / odwrócona) | maszyna (lib/status.mjs) |
przy każdym index i check |
Wygenerowanie tabeli w CLAUDE.md |
maszyna (knowledge.mjs index) |
po każdej edycji DECISIONS.md |
Uruchomienie index |
człowiek (lokalnie, przed commitem) | po edycji DECISIONS.md |
Sprawdzenie, czy CLAUDE.md jest świeży |
maszyna (bramka index-fresh) |
każdy PR i push na main |
| Sprawdzenie kompletności wpisów | maszyna (bramka integrity) |
każdy PR i push na main |
| Przypomnienie „ta zmiana wymaga decyzji" | maszyna (bramka decision-required) |
PR ruszający ścieżki decyzyjne |
| Reakcja na czerwoną bramkę | człowiek | dopisuje wpis albo etykietę no-decision |
| Audyt dryfu systemowego | agent (/knowledge-audit) |
raz na sprint, uruchamiany ręcznie |
| Rozszerzenie ścieżek decyzyjnych | człowiek (właściciel) | gdy audyt pokaże, że furtka się normalizuje |
Zasada nadrzędna: żadne narzędzie w tym kicie nie zapisuje do docs/DECISIONS.md
bez jawnej akceptacji człowieka. Jedyny plik, który agent zapisuje samodzielnie, to
podsumowanie transkryptu w Transcripts/ — archiwum, nie źródło decyzji.
Sześć kroków, ~15 minut. Kroki 1–5 są obowiązkowe, krok 6 (plugin Claude Code) opcjonalny.
| Czego potrzebujesz | Po co | Jak sprawdzić |
|---|---|---|
| Node.js ≥ 20 | CLI używa node:test i natywnych ESM |
node --version |
| repo na GitHubie z włączonymi Actions | bramki biegną jako workflow | Settings → Actions |
| uprawnienia admina do repo | branch protection (krok 4) | Settings → Branches jest widoczne |
gh CLI (opcjonalnie) |
szybsze ustawienie branch protection | gh auth status |
Kit nie ma żadnych zależności — ani runtime'owych, ani deweloperskich. Uruchamia się
go wprost przez node, bez npm install i bez npx.
Dlaczego nie
npx github:…. Wcześniejsze wersje tej instrukcji używałynpx --yes github:monterail/repobrain#<SHA>. Ta droga wywala się w GitHub Actions błędemGitFetcher requires an Arborist constructor— to defekt npm 10.x, czyli dokładnie tej wersji, którąactions/setup-nodeinstaluje razem z node 20 i 22. Ponieważ kit nie ma zależności, npm był w tym łańcuchu wyłącznie pośrednikiem: usunięcie go naprawia błąd i skraca joba. Szczegóły w §13.
Workflow pinuje commit po pełnym SHA, nigdy po tagu. Tagi gita są mutowalne: każdy
z prawem pushu do repo kitu mógłby przesunąć v1.0.0 i wykonać dowolny kod — z flagą
--yes — w CI wszystkich projektów agencji.
git ls-remote https://github.com/monterail/repobrain.git main
# 85d7898f… refs/heads/main ← ten SHA wklejasz w krokach 2 i 3Zapisz go sobie — pojawi się w trzech miejscach. Dalej oznaczam go jako <SHA>.
Pobierz kit po ustalonym SHA i uruchom instalator w katalogu swojego projektu:
git clone https://github.com/monterail/repobrain.git ~/.repobrain
git -C ~/.repobrain checkout <SHA>
cd /ścieżka/do/projektu
node ~/.repobrain/bin/knowledge.mjs initCLI zawsze działa na bieżącym katalogu roboczym, niezależnie od tego, skąd uruchomiłeś plik — dlatego kit może mieszkać gdziekolwiek.
Z pluginem Claude Code równoważnie: /knowledge-init.
Instalator nigdy nie nadpisuje istniejących plików — raportuje, co dołożył (+),
a co pominął (=). Dzięki tej regule ten sam kod obsługuje repo puste i dwuletnie,
bez osobnego trybu „retrofit".
+ docs/DECISIONS.md
+ .github/workflows/knowledge.yml
~ CLAUDE.md (dopisano sekcję Źródła prawdy)
| Plik | Zawartość | Jeśli już istnieje |
|---|---|---|
docs/DECISIONS.md |
opis formatu + DEC-001 jako działający przykład |
pomijany w całości |
.github/workflows/knowledge.yml |
workflow ściągający kit przez actions/checkout z pinem po SHA |
pomijany w całości |
CLAUDE.md |
reguła pierwszeństwa + pusta para znaczników | dopisywany na końcu, nie nadpisywany |
Jeśli CLAUDE.md już zawiera znaczniki WYGENEROWANE:decyzje, instalator też ich nie
rusza — wypisze = CLAUDE.md (znaczniki już są, pominięto).
Transcripts/ i HYPOTHESES.md nie są scaffoldowane — powstają przy pierwszym
użyciu /transcript-extract. Pusty katalog to sierota, a sieroty to problem, który
kit ma likwidować.
Instalacja przerwana w połowie? Instalator wypisze, które pliki zdążyły powstać, i każe posprzątać ręcznie. Nie ma automatycznego rollbacku: kasowanie plików w cudzym repo jest gorszym domyślnym zachowaniem niż komunikat.
Instalator nie może ich zgadnąć. Dopóki tego nie zrobisz, część bramek jest wyłączona.
Otwórz .github/workflows/knowledge.yml i podmień trzy wartości:
# PRZED (prosto z instalatora)
- uses: actions/checkout@v4
with:
repository: monterail/repobrain
ref: <PELNY_SHA> # ①
path: .repobrain
…
- run: node .repobrain/bin/knowledge.mjs check
--paths 'docs/specs/**,**/pricing*' # ②
--client-names '<nazwiska klienta po przecinku, np. Kowalski, Nowak>' # ③
# PO (uzupełnione)
- uses: actions/checkout@v4
with:
repository: monterail/repobrain
ref: 85d7898f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d
path: .repobrain
…
- run: node .repobrain/bin/knowledge.mjs check
--paths 'docs/specs/**,docs/api-contract.md,**/pricing*'
--client-names 'Nowak, Wiśniewska'| # | Co | Konsekwencja pominięcia |
|---|---|---|
| ① | ref: → pełny SHA z kroku 1 |
checkout wywali się na nieistniejącej referencji |
| ② | --paths → ścieżki decyzyjne tego projektu |
bramka decision-required nie chroni niczego |
| ③ | --client-names → nazwiska osób decyzyjnych po stronie klienta |
integrity nigdy nie wymaga Źródło: dla decyzji klienta |
Nie zmieniaj kolejności kroków. Checkout projektu musi być pierwszy:
actions/checkoutdomyślnie czyści katalog docelowy przezgit clean -ffdx, więc odwrotna kolejność skasowałaby ściągnięty wcześniej kit.
Jak dobrać --paths. Zacznij wąsko: docs/specs/** i pliki cenowe. Nie dodawaj
katalogu migracji na starcie — większość migracji nie ma za sobą decyzji klienckiej,
a łapanie ich zamienia etykietę no-decision w odruch. Ścieżki rozszerza się później,
gdy audyt pokaże, że coś ważnego przechodzi bez wpisu. Składnia globów: * nie
przekracza /, ** przekracza.
Jak dobrać --client-names. Dopasowanie jest po podciągu, bez wielkości liter,
i celowo luźne — Nowak trafi też w Nowakowski. Kierunek błędu jest bezpieczny:
fałszywy alarm („wymagamy Źródło: tam, gdzie nie trzeba") jest tańszy niż przeoczona
decyzja klienta bez dowodu.
Bezpiecznik. Jeśli zostawisz niepodmieniony placeholder (<nazwiska klienta…>),
CLI potraktuje go jak brak flagi i głośno to wypisze:
ℹ reguła „decyzja klienta wymaga pola Źródło" jest wyłączona — --client-names zawiera
niepodmieniony placeholder z konfiguracji, traktowany jak brak flagi.
Cicha śmierć reguły przy zielonym CI jest gorsza niż jej brak. Z tego samego powodu CLI
odrzuca nieznane flagi — literówka --pahts zatrzymuje build, zamiast zostać zignorowana.
To jest warunek instalacji, nie zalecenie. Bez „require branches to be up to date"
dwa PR-y mogą dodać wpis o tym samym numerze DEC i auto-zmergować się (wstawiają tekst
w różnych miejscach pliku, więc git nie widzi konfliktu). Drugi merge czerwieni main,
a naprawa przez przenumerowanie unieważnia referencje zdążone już w Slacku i w polach
Odwraca:.
Przez UI: Settings → Branches → Add branch protection rule dla main:
- ✅ Require status checks to pass before merging
- ✅ Require branches to be up to date before merging ← to jest ten krytyczny
- w liście checków wybierz
knowledge
Przez gh CLI:
gh api -X PUT repos/OWNER/REPO/branches/main/protection --input - <<'JSON'
{
"required_status_checks": { "strict": true, "contexts": ["knowledge"] },
"enforce_admins": false,
"required_pull_request_reviews": null,
"restrictions": null
}
JSON"strict": true to dokładnie „require branches to be up to date".
node ~/.repobrain/bin/knowledge.mjs index✓ CLAUDE.md zaktualizowany — 1 aktywnych, 0 w historii
Zacommituj oba pliki razem — rozdzielenie ich na dwa commity da czerwoną bramkę
index-fresh na tym pierwszym:
git add docs/DECISIONS.md CLAUDE.md .github/workflows/knowledge.yml
git commit -m "chore: instalacja repoBrain"Uruchom bramki lokalnie, dokładnie tak, jak zrobi to CI:
node ~/.repobrain/bin/knowledge.mjs check \
--paths 'docs/specs/**' --client-names 'Nowak'✓ repoBrain — bramki zielone: integrity, index-fresh
(pominięte: decision-required (brak kontekstu PR))
Lokalnie decision-required zawsze jest pomijana — potrzebuje GITHUB_EVENT_PATH
i kontekstu pull requesta. To jest oczekiwane. Żeby sprawdzić ją naprawdę, zrób
próbny PR dotykający ścieżki decyzyjnej i zobacz, czy zapali się na czerwono.
Checklista po instalacji:
-
knowledge.mjs checklokalnie zielone - workflow przeszedł na pierwszym PR (zakładka Actions)
- w logu CI nie ma komunikatu o wyłączonej regule
--client-names - w logu CI bramka
decision-requiredjest w „zielonych", nie w „pominiętych" - próbny PR w
docs/specs/**bez wpisu DEC → czerwony - ten sam PR z etykietą
no-decision→ zielony (i build się retriggerował) -
mainma branch protection zestrict: true -
DECISIONS.mdma przypisanego właściciela (patrz §11)
Plugin daje zespołowi komendy /knowledge-init, /transcript-extract i skille
decisions-format, knowledge-audit. Nie jest wymagany — bramki CI działają
niezależnie od Claude Code, taki był niezmiennik architektoniczny.
Najprostsza droga dzisiaj: skopiuj zawartość .claude-plugin/ do katalogu .claude/
projektu docelowego i zacommituj — skille i komendy działają wtedy dla całego zespołu:
mkdir -p .claude/skills .claude/commands
cp -r ~/.repobrain/.claude-plugin/skills/* .claude/skills/
cp -r ~/.repobrain/.claude-plugin/commands/* .claude/commands/W skopiowanych plikach podmień <SCIEZKA_DO_KITU> na miejsce, w którym trzymasz kit
(np. ~/.repobrain) — komendy wołają to samo CLI, co Ty z ręki.
Repo nie ma jeszcze
.claude-plugin/marketplace.json, więc instalacja przez/plugin marketplace addnie zadziała. To znany brak, nie błąd konfiguracji po Twojej stronie.
Poprawka w repoBrain nie propaguje się sama — pin po SHA jest tego świadomym kosztem.
Żeby podnieść wersję w projekcie: weź nowy SHA (krok 1), podmień ref: w
.github/workflows/knowledge.yml, zrób PR. Zielony build na tym PR jest potwierdzeniem,
że nowa wersja nie psuje istniejących wpisów.
Lokalnie odśwież swoją kopię kitu do tego samego SHA:
git -C ~/.repobrain fetch && git -C ~/.repobrain checkout <NOWY_SHA>SHA w CI jest źródłem prawdy, kopia lokalna to wygoda. Jeśli się rozjadą, bramka
index-fresh to wyłapie — wygenerujesz blok starszą wersją, a CI porówna go z wynikiem
nowszej. Rozjazd nie przejdzie po cichu.
Główna ścieżka. Jedna komenda, cztery kroki, człowiek akceptuje każdy zapis do źródła.
surowy zapis (PDF / VTT, nazwa od dostawcy)
│
▼ /transcript-extract <ścieżka>
│
[1] podsumowanie → Transcripts/YYYY-MM-DD-slug.md ← JEDYNY automatyczny zapis
│ (kontekst, decyzje, zadania, otwarte pytania, cytaty)
│
[2] klasyfikacja pozycji wg TRWAŁOŚCI, nie wg typu treści:
│
├─ decyzja → draft wpisu DEC trwała, wersjonowana
├─ niepewność → HYPOTHESES.md do rozstrzygnięcia
├─ zadanie → lista do wklejenia w Jirę NIE do repo
└─ cytat → zostaje w podsumowaniu archiwum
│
[3] drafty DEC pokazane w odpowiedzi — NIE zapisane na dysk
│
[4] człowiek wybiera, co zastosować
│ → dopisanie na końcu docs/DECISIONS.md
│ → knowledge.mjs index
│ → commit obu plików
▼
Dlaczego zadania nie trafiają do repo. W transkrypcie decyzja i zadanie wyglądają
podobnie. Różni je cykl życia: decyzja obowiązuje, aż ktoś ją odwróci; zadanie umiera
po wykonaniu. Zadania w docs/ zamieniają się w listy TODO, których nikt nie zamyka.
Niepewność ma bezpiecznik. Komenda ma zakaz zmyślania — cokolwiek niejasne oznacza
[verify]. To jeden z placeholderów blokujących CI, więc niepewność wyciągnięta
z transkryptu fizycznie nie przejdzie do merge'a.
PR rusza docs/specs/** albo **/pricing*
│
├─ PR rusza też docs/DECISIONS.md? → zielono, przechodzi
├─ PR ma etykietę `no-decision`? → zielono, przechodzi (furtka)
└─ ani jedno, ani drugie → CZERWONO, merge zablokowany
│
▼
człowiek dopisuje wpis DEC albo świadomie
oznacza PR etykietą `no-decision`
Bramka nie pisze wpisu — tylko nie pozwala przejść dalej bez decyzji człowieka.
Etykieta no-decision jest legalną furtką (nie każda zmiana specyfikacji to decyzja
projektowa), ale jej użycia są liczone przez /knowledge-audit.
Decyzja, która nie wyszła ani z transkryptu, ani z PR-a — np. ustalenie na Slacku.
Piszesz wpis wprost do docs/DECISIONS.md. Skill decisions-format ładuje się w Claude Code
automatycznie, gdy piszesz lub edytujesz wpis, i pilnuje formatu, zanim zrobi to CI.
Po każdej ścieżce ten sam finał:
node ~/.repobrain/bin/knowledge.mjs index
git add docs/DECISIONS.md CLAUDE.md && git commitŻeby nie przepisywać ścieżki po każdej edycji, dodaj alias w projekcie —
w package.json:
"scripts": { "knowledge:index": "node ~/.repobrain/bin/knowledge.mjs index" }albo w Makefile, jeśli projekt nie jest nodowy:
knowledge-index:
node ~/.repobrain/bin/knowledge.mjs indexZespół produkuje więcej niż transkrypty z callów: BA papers, notatki z refinementów, dokumentację architektury, research. Ta sekcja mówi, gdzie każda z tych rzeczy ma żyć.
Czy ta rzecz obowiązuje, dopóki ktoś jej nie odwróci?
┌─ TAK ──────────────▶ wpis DEC w docs/DECISIONS.md
│
czy obowiązuje ├─ NIE, ale jest dowodem, skąd wzięła się decyzja
aż do odwrócenia? │ ▶ Transcripts/YYYY-MM-DD-slug.md
│
├─ NIE, to kontrakt: co dokładnie budujemy
│ ▶ docs/specs/
│
├─ NIE, to niepewność do rozstrzygnięcia
│ ▶ HYPOTHESES.md
│
└─ NIE, po prostu się przyda
▶ zwykłe docs/, bez ceremonii
Kryterium to cykl życia, nie typ dokumentu. Decyzja i zadanie wyglądają w notatce podobnie; różni je to, że decyzja obowiązuje aż ktoś ją odwróci, a zadanie umiera po wykonaniu.
| Dokument | Gdzie | Dlaczego |
|---|---|---|
| BA paper definiujący co budujemy | docs/specs/ + wpis DEC na rozstrzygnięcia sporne |
kontrakt implementacyjny — poziom 3 reguły pierwszeństwa |
| BA paper analityczny (opcje, porównania, research) | zwykłe docs/; wynik → wpis DEC |
zestarzeje się w chwili, gdy decyzja zapadnie |
| Notatki z refinementu | Transcripts/YYYY-MM-DD-refinement-slug.md, Typ: wewnętrzne |
ten sam cykl życia co transkrypt: dowód, upstream decyzji |
| Warsztat discovery | Transcripts/…, Typ: discovery |
jw. |
| Ustalenia z dostawcą | Transcripts/…, Typ: vendor |
jw. |
| Otwarte pytania z refinementu | HYPOTHESES.md |
mają zostać rozstrzygnięte, nie zarchiwizowane |
| Ustalenia „to jest w cenie / to change request" | wpis DEC ze Scope: |
dokładnie to, przed czym Scope: chroni w sporze |
| Decyzja architektoniczna (ADR-owa) | wpis DEC — nie osobny ADR | dublowanie magazynów to defekt, który kit likwiduje |
| Estymaty, harmonogram | poza repo (Jira) — konsekwencje → pole Konsekwencje: we wpisie DEC |
przeterminowują się szybciej niż PR |
| Action items z dowolnego spotkania | Jira — nie repo | listy TODO w docs/ to listy, których nikt nie zamyka |
| Runbook, onboarding, README modułu | zwykłe docs/ |
nikt nie musi pilnować ich świeżości |
1. Transcripts/ nie jest tylko dla klienta. Szablon podsumowania ma pole Typ:
z czterema wartościami — klient / wewnętrzne / discovery / vendor. Refinement to
wewnętrzne, warsztat BA to discovery. Katalog trzyma podsumowania dowolnego
spotkania, nie tylko rozmów z klientem.
2. /transcript-extract przyjmuje każdy plik. Notatki z refinementu, zrzut z Miro,
podsumowanie z Confluence — komenda robi z nich podsumowanie w ustandaryzowanym formacie
i proponuje drafty DEC. Nie musi to być stenogram.
3. Źródło: może wskazywać na cokolwiek w repo. Bramka integrity sprawdza
wyłącznie, czy plik istnieje — nie wymusza prefiksu Transcripts/. BA paper jest
legalnym materiałem dowodowym:
**Źródło:** docs/specs/ba-model-rozliczen.mdBA paper na dwadzieścia stron może nieść trzy decyzje i siedemnaście opisów. Proces
nie archiwizuje papera jako „wiedzy" — wyciąga z niego trzy wpisy DEC i zostawia
paper jako dowód, na który te wpisy wskazują przez Źródło:.
Dlatego nie ma i nie powinno być „bramki na kompletność dokumentacji projektowej":
mierzyłaby objętość, nie wiedzę. Jedyne, co repoBrain sprawdza w dokumentacji poza
DECISIONS.md, to czy zmiana w ścieżce decyzyjnej ma za sobą decyzję.
Zapisane świadomie, żeby nie budować fałszywego poczucia pokrycia:
Dryf specyfikacji względem decyzji. DEC-039 zmienia zachowanie billingu,
docs/specs/billing.md dalej opisuje stare — i nic tego nie łapie. Bramki pilnują
świeżości bloku w CLAUDE.md, nie świeżości speców. Spec pozostaje ręczną kopią wiedzy,
czyli dokładnie tą kategorią, którą kit likwiduje w jednym miejscu i toleruje w drugim.
Obejście proceduralne: przy wpisie DEC wypełniaj Konsekwencje: na tyle konkretnie,
żeby review PR-a zobaczył, który spec wymaga aktualizacji.
Sprzężenie wsteczne działa tylko dla Transcripts/. /knowledge-audit sprawdza,
czy podsumowanie z sekcją „Decyzje" ma na siebie wskazujący wpis DEC. BA paper
z decyzjami, z którego nikt nie zrobił wpisów, nie zostanie zgłoszony — audyt nie
zagląda poza Transcripts/.
## DEC-NNN — YYYY-MM-DD
**Odwraca:** DEC-XXX (opcjonalne — XXX przestaje obowiązywać w całości)
**Zmienia:** DEC-XXX (opcjonalne — XXX obowiązuje dalej, ten wpis doprecyzowuje fragment)
**Obszar:** tag, tag (opcjonalne)
**Scope:** w cenie (opcjonalne — w cenie | change request | do wyceny)
**Źródło:** Transcripts/YYYY-MM-DD-slug.md (opcjonalne; wymagane dla decyzji klienta)
**Temat:** jedno zdanie
**Kontekst:** dlaczego temat w ogóle się pojawił
**Decyzja:** co ustalono
**Konsekwencje:** co to zmienia w kodzie, kosztach, harmonogramie
**Podjął:** kto i gdzie- Wymagane pola:
Temat,Kontekst,Decyzja,Konsekwencje,Podjął. - Data ściśle
YYYY-MM-DDz zerami wiodącymi. Separator-,–lub—. Scope:przyjmuje wyłącznie:w cenie,change request,do wyceny.- Każdy nagłówek
##w pliku musi być kompletnym wpisem DEC — nie ma cichego pomijania. (Dlatego nagłówki sekcji opisowych w szablonie są poziomu###.) Odwraca:iZmienia:wykluczają się wzajemnie — wpis ma co najwyżej jedną relację.- Relacja musi wskazywać na wpis wcześniejszy wg pary (data, numer ID).
- Nigdy nie dopisuj pola
Status:— patrz §8.
- Nowe wpisy dopisuj na końcu pliku — równoległe PR-y dają wtedy konflikt tekstowy zamiast cichego auto-merge z tym samym numerem DEC.
- Zmiana merytoryczna = nowy wpis. Edycja korygująca (literówka, data, dopisanie
Źródło:) jest dozwolona w miejscu.
[data] [uzupełnij] [TBD] [verify] TODO
Te ciągi blokują cały plik. Nie używaj ich jako roboczych znaczników. Jeśli czegoś jeszcze nie wiadomo — lepiej nie commitować wpisu wcale niż commitować niepełny.
Uwaga: od pierwszego wpisu DEC w dół placeholdery są wykrywane także wewnątrz bloków kodu. Blok kodu nie może być furtką do niekompletnego wpisu. W preambule (sekcja opisująca format, przed pierwszym wpisem) bloki kodu są ignorowane — tam to dokumentacja.
Nie ma pola Status:. Gdyby było, ktoś musiałby je zaktualizować przy dodaniu nowego
wpisu — i tego właśnie nikt nigdy nie robi. Zamiast tego nowy wpis deklaruje relację
do starego, a status wynika z grafu.
| Sytuacja | Pole | Efekt w indeksie |
|---|---|---|
| Poprzednia decyzja przestaje obowiązywać w całości | Odwraca: |
stary wpis ląduje w sekcji „Odwrócone (historia)" |
| Poprzednia obowiązuje dalej, doprecyzowujesz fragment | Zmienia: |
stary wpis zostaje aktywny, z adnotacją (zmienione przez DEC-XXX) |
| Temat niezwiązany z niczym wcześniejszym | żadne | zwykły aktywny wpis |
Przy wątpliwości zadaj pytanie: czy po tej zmianie ktokolwiek nadal działa według
starego wpisu? Jeśli tak — Zmienia:.
Dodatkowe reguły grafu, których pilnuje lib/status.mjs:
- wpis odwrócony nie może dalej „zmieniać" celu — jego doprecyzowanie umiera razem z nim,
- nie można
Zmienia:wpisu, który został już odwrócony (błąd, blokuje CI), - wpis z błędem walidacji (duplikat ID, obie relacje, cel z przyszłości) nie wnosi krawędzi do grafu — zostaje widoczny, ale jego relacje są ignorowane, żeby jeden zepsuty wpis nie zafałszował całego indeksu.
<!-- WYGENEROWANE:decyzje — nie edytuj. Uruchom: npx … index -->
| DEC | Data | Obszar | Temat |
|-----|------|--------|-------|
| DEC-012 | 2026-06-02 | api | Webhooki idempotentne po kluczu zdarzenia |
| DEC-007 | 2026-05-14 | billing | Faktury korygujące poza MVP *(zmienione przez DEC-011)* |
**Odwrócone (historia):**
- DEC-004 (2026-04-21) — odwrócony przez DEC-009
<!-- /WYGENEROWANE:decyzje -->Najnowsze pierwsze. Generator nigdy nie dopisuje bloku na końcu pliku — jeśli
znaczników nie ma, odmawia i każe uruchomić init. Blok, który ktoś przesunął albo
zduplikował, kończy się błędem „napraw ręcznie", nie cichym nadpisaniem.
Treść znacznika jest dopasowywana dosłownie, więc zdanie „Uruchom: npx … index" zostaje w nim mimo zmiany sposobu uruchamiania (§4). Podmiana tego napisu zerwałaby parowanie znaczników w każdej istniejącej instalacji — koszt nieproporcjonalny do kosmetycznego zysku. Aktualne polecenie to
node <kit>/bin/knowledge.mjs index.
Workflow .github/workflows/knowledge.yml odpala się na pull_request
(typy opened, synchronize, reopened, labeled, unlabeled) i na push do main.
Typy
labeled/unlabeledsą obowiązkowe — bez nich dodanie etykietyno-decisionnie retriggeruje builda i PR zostaje czerwony mimo poprawnej reakcji.
| Bramka | Co sprawdza | Kiedy blokuje | Jak naprawić |
|---|---|---|---|
integrity |
kompletność wpisów, poprawność relacji, placeholdery, istnienie plików z Źródło:, Źródło: dla decyzji klienta |
zawsze | popraw wpis w DECISIONS.md |
index-fresh |
czy blok w CLAUDE.md = regeneracja z DECISIONS.md |
zawsze | knowledge.mjs index i zacommituj |
decision-required |
czy PR ruszający ścieżki decyzyjne dotyka DECISIONS.md |
tylko w kontekście PR i tylko gdy podano --paths |
dopisz wpis DEC albo etykietę no-decision |
Bramki pominięte są wypisywane w logu, np.:
✓ repoBrain — bramki zielone: integrity, index-fresh (pominięte: decision-required (brak --paths — żadna ścieżka nie jest chroniona))
To celowe: „wszystko zielone" nie może znaczyć „bramka nigdy nie pobiegła". Z tego samego
powodu CLI odrzuca nieznane flagi (literówka --pahts zamiast --paths byłaby cicho
zignorowana) i traktuje niepodmieniony placeholder w --client-names jak brak flagi,
komunikując to wprost.
Bramki łapią pojedyncze zdarzenia. Audyt łapie dryf systemowy — rzeczy, których blokowanie dawałoby fałszywe alarmy:
- Zgubione decyzje — transkrypt z sekcją „Decyzje", na który żaden DEC nie wskazuje
przez
Źródło:. Ostrzeżenie, nie błąd: nie każda decyzja z callu zasługuje na wpis. - Użycia furtki — liczba PR-ów z etykietą
no-decisionz ostatnich 30 dni. Rosnąca oznacza, że ścieżki decyzyjne są za szerokie albo bramka jest obchodzona. To jedyna obrona przed cichym znormalizowaniem furtki. - Dokumenty bez odsyłaczy — pliki w
docs/, do których nic w repo nie linkuje. - Martwe linki wewnętrzne — świadomie poza CI, bo ścieżki względne dawałyby fałszywe alarmy.
Pole Źródło: domyka pętlę w obie strony: w przód integrity blokuje wpis wskazujący
na nieistniejący transkrypt; wstecz audyt ostrzega, że coś z rozmowy wypadło.
node <ścieżka-do-kitu>/bin/knowledge.mjs <init|index|check> [flagi]Zero zależności, więc żadnego npm install ani npx — wystarczy node ≥ 20
i katalog z kitem sklonowany po ustalonym SHA. CLI zawsze operuje na bieżącym
katalogu roboczym, nie na katalogu kitu.
| Komenda | Flagi | Działanie |
|---|---|---|
init |
— | tworzy docs/DECISIONS.md, workflow, dopisuje sekcję do CLAUDE.md. Nigdy nie nadpisuje. |
index |
— | regeneruje blok w CLAUDE.md. Idempotentne — bez zmian wypisuje „już aktualny". |
check |
--paths, --client-names |
uruchamia bramki. Wypisuje wszystkie błędy naraz, nie pierwszy. |
Kody wyjścia: 0 sukces, 1 błąd walidacji lub bramki, 2 nieznana komenda.
Komendy Claude Code (plugin): /knowledge-init, /transcript-extract <plik>.
Skille ładowane automatycznie: decisions-format, knowledge-audit.
DECISIONS.md ma przypisanego właściciela — domyślnie PM projektu. Audyt poprzedniego
projektu sformułował prawo „każdy magazyn wymaga właściciela i tempa aktualizacji";
spec bez tego przydziału powtarzałby błąd, który opisuje.
| Kiedy | Kto | Co |
|---|---|---|
| po każdym callu z klientem | właściciel | /transcript-extract, akceptacja draftów |
| przy każdym PR w ścieżkach decyzyjnych | autor PR-a | wpis DEC albo świadoma etykieta |
po każdej edycji DECISIONS.md |
autor | knowledge.mjs index, commit obu plików |
| raz na sprint | właściciel | /knowledge-audit, przegląd użyć furtki |
| gdy furtka rośnie | właściciel | zawężenie albo rozszerzenie ścieżek decyzyjnych |
Zielone CI nie znaczy zdrowy second brain. Bramki pilnują świeżości derywaty przy zmianach kodu. Decyzja z calla, która nie dotyka żadnej ścieżki decyzyjnej („klient potwierdził, że pakiet premium zawiera X"), nie ma żadnej bramki — jej jedyną drogą do repo jest człowiek. Dlatego rola jest przypisana, a nie dorozumiana.
Świadome granice, żeby nie budować oczekiwań, których kit nie spełnia:
- Nie pilnuje, czy źródło opisuje rzeczywistość. Gwarancja dotyczy dryfu kopii,
nie dryfu wiedzy.
Odwraca:deklaruje ten sam człowiek, który wcześniej zapominał zaktualizowaćStatus:. Zysk jest realny, ale mniejszy niż brzmi: nowy wpis to lepszy moment na przypomnienie niż powrót do starego, a jedno miejsce zapisu bije dwa. - Nie zapisuje niczego automatycznie do
DECISIONS.md. Bez auto-commitu w CI, bez hooka pre-commit. Automat piszący do repo bez człowieka jest przyczyną defektu, który naprawiamy. - Nie generuje listy plików w
docs/. Problem sierot to brak kuracji, nie brak listy; automatyczna lista tols -Rw markdownie. Zamiast tego/knowledge-auditraportuje dokumenty, do których nic nie linkuje. - Nie parsuje surowych PDF-ów w CI. To zadanie dla agenta z człowiekiem w pętli.
- Nie migruje istniejących repo. Instalator nie nadpisuje, więc retrofit jest możliwy później, ale konwersja formatu starych wpisów nie jest zbudowana ani przetestowana.
- Nie działa offline. Workflow ściąga kod kitu z GitHuba przez
actions/checkout. Ryzyko rezydualne zapisane świadomie: przy awarii GitHuba merge'e stają, acontinue-on-error: truedodane pod presją deadline'u ma tendencję do pozostawania na zawsze.
bin/knowledge.mjs CLI — jedyne miejsce znające filesystem, argv i zmienne CI
lib/parse.mjs Markdown → obiekty DEC
lib/status.mjs derywacja statusu z grafu relacji
lib/render.mjs render bloku + wstrzyknięcie między znaczniki
lib/integrity.mjs placeholdery, istnienie źródeł, decyzje klienta
lib/gates.mjs trzy bramki CI
lib/fences.mjs maska bloków kodu
lib/init.mjs plan instalacji (czysta funkcja)
templates/ szablony kopiowane przez `init`
.claude-plugin/ komendy i skille pluginu Claude Code
Pierwotna instrukcja instalacji używała npx --yes github:monterail/repobrain#<SHA>.
W GitHub Actions ta droga wywala się zawsze:
npm error GitFetcher requires an Arborist constructor to pack a tarball
To defekt npm 10.x — czyli dokładnie tej wersji, którą actions/setup-node instaluje
razem z node 20 i 22. Nie zależy od wersji node'a, więc podniesienie node'a nie pomaga.
Na maszynach z npm ≥ 11 to samo polecenie działa i dlatego błąd przeszedł
przez weryfikację przy projektowaniu: wykonalność sprawdzono lokalnie, choć jedynym
środowiskiem, w którym to polecenie miało realnie biec, było CI.
Poprawka usuwa przyczynę zamiast obchodzić objaw: kit nie ma żadnych zależności,
więc npm nie miał tu nic do zrobienia — był czystym pośrednikiem między git clone
a node. Workflow ściąga go teraz przez actions/checkout z tym samym pinem po SHA
i uruchamia bezpośrednio. Pin i jego gwarancje zostają bez zmian, znika jedno ogniwo
i kilkanaście sekund joba.
Lekcja ogólniejsza: weryfikacja wykonana w innym środowisku niż docelowe nie jest weryfikacją. Zgłoszone przez użytkownika, 2026-07-29.
Niezmiennik architektoniczny: lib/ nie może zależeć ani od API Claude Code,
ani od API GitHub Actions. Naruszenie wyłączyłoby kit w CI — czyli w jedynym miejscu,
gdzie egzekwowanie realnie następuje. Dlatego wszystko w lib/ to czyste funkcje:
tekst na wejściu, obiekty i tablica błędów na wyjściu.
npm test # node:test, zero zależności, bez mocków i plików tymczasowychProjekt: docs/design/2026-07-28-repobrain-design.md ·
plan implementacji: docs/plans/2026-07-28-repobrain-implementation.md