Skip to main content
Glama
radthenone
by radthenone
README.md
# Instruction Kit — MCP z instrukcjami projektów

Centralne repo MD + serwer MCP. Projekty wybierają Stack **per Tier** (`backend`/`web`/`mobile` w `.ai/project.profile.yaml`) + overlay.

## Szybki start

Trzy kroki cyklu życia kita w projekcie. Szczegóły każdego kroku są niżej.

### Krok 1 — Instalacja

```bash
uv tool install git+https://github.com/radthenone/ai-instruction-kit-mcp
cd /m/projects/moja-appka                  # repo aplikacji
kit-ai install
```

Bez `@` instalujesz gałąź domyślną (`master`). Nowsze, jeszcze nie wydane zmiany są na
`dev` — wtedy dopisz ref, np. `…/ai-instruction-kit-mcp@dev`.

### Krok 2 — Konfiguracja

Zrestartuj IDE / CLI, potem w kliencie AI:

```text
/kit-project-begin      # pierwszy raz: pytania o Stack, karta Profilu i .ai/project.md
/kit-project-edit "…"   # później: jedna zmiana, np. "zmień web na angular"
```

`/kit-project-begin` proponuje odpowiedzi wykryte w repo, a `/kit-project-edit` zmienia jedną
odpowiedź bez całego wywiadu ([pełny opis](#slash-commands--konwencja-nazw)). Po zapisie
zrestartuj klienta.

### Krok 3 — Update

```bash
uv tool upgrade guides-mcp                 # nowa wersja kita
kit-ai reload                              # odśwież pliki kita w projekcie
kit-ai status                              # w agencie: check_kit_status
kit-ai doctor                              # ścieżki i komendy w regułach vs repo
```

## Szczegóły instalacji

Jedna komenda robi instalację i update. Bootstrap jest idempotentny: pliki generowane (agenci, komendy,
hooki, `mcp.json`) nadpisuje świeżą kopią, a pliki z Twoją treścią (`AGENTS.md`,
`.ai/project.md`) zostawia w spokoju. `BUGBOT.md` odświeża z szablonu, ale blok
`<!-- project:rules -->` z regułami projektu przechodzi bez zmian — szczegóły w sekcji
[Bootstrap](#bootstrap).

**Wymagania:** `uv` w `PATH`, `bash` (Windows: Git for Windows), `node` (dla hooków),
opcjonalnie `npx` (skille zewnętrzne).

### 1. Instalacja / update w projekcie — `kit-ai`

Bez klona kita — `kit-ai` jako narzędzie uv (ref po `@`: branch, tag albo commit):

```bash
uv tool install git+https://github.com/radthenone/ai-instruction-kit-mcp          # master
uv tool install git+https://github.com/radthenone/ai-instruction-kit-mcp@dev      # albo gałąź dev
cd /m/projects/moja-appka                  # repo aplikacji
kit-ai install                             # bez ścieżki = bieżący katalog
kit-ai reload | kit-ai status | kit-ai doctor | kit-ai remove [--dry-run]
kit-ai labels [--apply]                    # brakujące etykiety GitHuba (bez --apply = plan)

# jednorazowo, bez instalowania narzędzia:
uvx --from git+https://github.com/radthenone/ai-instruction-kit-mcp kit-ai install
```

Wybrany ref trafia do `mcp.json` projektu (np. `uvx --from git+…@dev`), a commit kita do
stampu — `kit-ai status` porównuje go z commitem zainstalowanego narzędzia. Update:
`uv tool upgrade guides-mcp` (albo `uv tool install --force git+…@<inny-ref>`) +
`kit-ai reload`. Instalacja z lokalnej ścieżki (`uv tool install .`) nie zna commitu —
`status` mówi wtedy „nieznany commit”.

`install` pyta o dwie rzeczy (`Język [pl/en] (pl)`, `Klienci (…) (all)`) — flagi `--language`
i `--clients` pomijają pytania, bez TTY pytań nie ma wcale. Zakłada `.ai/project.profile.yaml`
(`backend/web/mobile: none` = sam core) i `.ai/project.md`, robi Bootstrap, a na końcu
wypisuje JSON serwera MCP i gdzie leży per klient. Repo z kitem `install` odrzuca — wtedy
`reload`.

Jedyna konfiguracja to Profil (ADR-0007): język, klienci, Stacki per Tier, `codegen:`.
Zmiana czegokolwiek = edycja `.ai/project.profile.yaml` + `kit-ai reload`. `reload` nie
rusza `.ai/project.md`; repo ze starą konfiguracją (stamp z `--preset`, brak Profilu) dostaje
Profil core + none i nowy `mcp.json`.

| Klucz Profilu | Kiedy zmienić |
| --- | --- |
| `clients:` | `claude` \| `codex` \| `vscode` (= GitHub Copilot) \| `cursor` \| `kiro` \| `kilo` \| `antigravity` \| `opencode` \| `all`. Pliki klientów **spoza** listy są sprzątane przy `reload` |
| `backend`/`web`/`mobile` | Stack per Tier (puste Tiery = sam core) |
| `language:` | `pl` \| `en` — język prozy. Tytuły issue/PR/branch zawsze EN |
| `codegen:` | `orval` (default) \| `none` \| `graphql` |

Niskopoziomowo to samo robi `scripts/bootstrap-project.sh "$APP" --from "$KIT" --clients … --language …`
(dodatkowo `--with-overlay`, `--with-plugins`, `--keep-unselected-clients`). `--preset`,
`--profile`, `--with-profile` i `--codegen` zostały usunięte — skrypt odmawia i odsyła do `kit-ai reload`.

### 2. Po instalacji (kroki, których skrypt nie zrobi za Ciebie)

`kit-ai install` kończy się blokiem „Dalej” (Superpowers + `/kit-project-begin`). Pełna
lista poniżej — rób tylko to, czego jeszcze nie masz, i tylko dla klientów z `clients:`.
Wszystko poza 2.5 robisz **raz na maszynę**, nie per projekt.

Komendy są te same w Git Bash (Windows) i na Linuksie, chyba że wiersz mówi inaczej.
Różnice Windows zebrane są w [2.4](#24-windows-git-bash-vs-linux).

#### 2.1. rtk — sprawdź, czy jest

```bash
rtk --version && rtk gain        # oba muszą zadziałać; "command not found" = brak rtk
```

`rtk gain` nie działa, a `rtk --version` tak → masz inne narzędzie o tej nazwie
(`reachingforthejack/rtk`), nie Rust Token Killer. Brak rtk niczego nie psuje — agenci
wykonują wtedy komendy bez prefiksu (`core:tooling-rtk`).

Instalacja:

```bash
# Linux / macOS
curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh
# Windows (winget działa też z Git Bash)
winget install rtk-ai.rtk
```

Hook, który przepisuje komendy na `rtk …` poza modelem — po jednym na klienta:

| Klient | Komenda | Uwagi |
| --- | --- | --- |
| Claude Code | `rtk init -g --auto-patch` | Hook kita `rtk-check.mjs` przypomina przy starcie sesji, gdy go brak |
| Codex | `rtk init -g --codex` | Potem `/hooks` w TUI Codexa i zaufaj hookowi — bez tego jest pomijany |
| OpenCode | `rtk init -g --opencode` | |
| VS Code (Copilot) | — | Hook przychodzi z kita: `.github/hooks/rtk-rewrite.json`. Nie odpalaj `rtk init --copilot` — nadpisze `.github/copilot-instructions.md` |
| Antigravity | `rtk init -g --agent antigravity` | |

Po `rtk init` zrestartuj klienta. Weryfikacja: `rtk init --show`.

#### 2.2. Pluginy i skille zewnętrzne — per klient

Kolejność bez znaczenia; wszystkie są opcjonalne poza Superpowers (warstwa 3 w
`AGENTS.md`). `npx skills` przyjmuje `-a claude-code|codex|opencode|github-copilot|antigravity`
i dla klientów poza Claude instaluje do `.agents/skills/` (dodaj `-g`, żeby globalnie).
Wyjątek: Antigravity CLI (`agy`) **nie czyta** globalnego `~/.agents/skills/`, gdzie `-g`
kładzie skille — globalnie widzi tylko `~/.gemini/config/skills/`
([antigravity-cli#103](https://github.com/google-antigravity/antigravity-cli/issues/103)).

**Superpowers** ([obra/superpowers](https://github.com/obra/superpowers))

| Klient | Komenda |
| --- | --- |
| Claude Code | Proponuje się sam przy otwarciu repo (bootstrap wpisuje go do `.claude/settings.json`). Gdy pytanie nie padło: `/plugin marketplace add obra/superpowers-marketplace`, potem `/plugin install superpowers@superpowers-marketplace` |
| Codex | W TUI: `/plugins` → `superpowers` → *Install Plugin* |
| OpenCode | Napisz agentowi: `Fetch and follow instructions from https://raw.githubusercontent.com/obra/superpowers/refs/heads/main/.opencode/INSTALL.md` |
| VS Code (Copilot) | Tylko Copilot CLI: `copilot plugin marketplace add obra/superpowers-marketplace` + `copilot plugin install superpowers@superpowers-marketplace` |
| Antigravity | `agy plugin install https://github.com/obra/superpowers` |

**Skille Matta Pococka** ([mattpocock/skills](https://github.com/mattpocock/skills), [aihero.dev/skills](https://www.aihero.dev/skills)) — `/grill-me`, `/tdd`

| Klient | Komenda |
| --- | --- |
| Claude Code | `/plugin install mattpocock-skills` |
| Codex, OpenCode, VS Code | `npx skills@latest add mattpocock/skills -a <id>` (albo `bootstrap-project.sh --with-plugins`) |
| Antigravity — per projekt | `npx skills@latest add mattpocock/skills -a antigravity -s '*' -y` → `.agents/skills/` w repo |
| Antigravity — globalnie | `npx skills@latest add mattpocock/skills -g -a antigravity -s '*' -y`, potem skopiuj skille Matta z `~/.agents/skills/` do `~/.gemini/config/skills/` i zrestartuj `agy`. `agy plugin install` **nie działa** — skille Matta leżą w `skills/<kategoria>/<nazwa>`, agy szuka tylko `skills/<nazwa>` |

**Caveman** ([JuliusBrussee/caveman](https://github.com/JuliusBrussee/caveman))

| Klient | Komenda |
| --- | --- |
| Claude Code | `claude plugin marketplace add JuliusBrussee/caveman && claude plugin install caveman@caveman` |
| Codex | `npx skills add JuliusBrussee/caveman -a codex` |
| OpenCode | `npx -y github:JuliusBrussee/caveman -- --only opencode` |
| VS Code (Copilot) | `npx -y github:JuliusBrussee/caveman -- --only copilot --with-init` |
| Antigravity | `npx skills add JuliusBrussee/caveman -a antigravity` (bez trybu always-on) |

**Ponytail** ([DietrichGebert/ponytail](https://github.com/DietrichGebert/ponytail))

| Klient | Komenda |
| --- | --- |
| Claude Code | `/plugin marketplace add DietrichGebert/ponytail`, potem **osobną wiadomością** `/plugin install ponytail@ponytail` |
| Codex | `codex plugin marketplace add DietrichGebert/ponytail` + `codex plugin add ponytail@ponytail`, potem zaufaj hookom w `/hooks` |
| OpenCode | Klon repo + w `opencode.json`: `{ "plugin": ["<ścieżka-do-klona>/.opencode/plugins/ponytail.mjs"] }` |
| VS Code (Copilot) | Tylko Copilot CLI: `copilot plugin marketplace add DietrichGebert/ponytail` + `copilot plugin install ponytail@ponytail` |
| Antigravity | `agy plugin install https://github.com/DietrichGebert/ponytail` |

**Context7** ([upstash/context7](https://github.com/upstash/context7)) — docs bibliotek (MCP)

Najprościej `npx ctx7 setup --claude` / `--opencode` (OAuth + klucz API + konfiguracja).
Reszta ręcznie — serwer zdalny `https://mcp.context7.com/mcp`, nagłówek
`Authorization: Bearer <KLUCZ>` ([wszystkie klienty](https://context7.com/docs/resources/all-clients)):

| Klient | Gdzie | Wpis |
| --- | --- | --- |
| Claude Code | CLI | `claude mcp add --scope user --header "Authorization: Bearer KLUCZ" --transport http context7 https://mcp.context7.com/mcp` |
| Codex | `~/.codex/config.toml` | `[mcp_servers.context7]` + `url = "https://mcp.context7.com/mcp"` + `http_headers = { "Authorization" = "Bearer KLUCZ" }` |
| OpenCode | `opencode.json` | `"mcp": { "context7": { "type": "remote", "url": "https://mcp.context7.com/mcp", "headers": { "Authorization": "Bearer KLUCZ" } } }` |
| VS Code | `mcp.json` | `"servers": { "context7": { "type": "http", "url": "https://mcp.context7.com/mcp", "headers": { "Authorization": "Bearer KLUCZ" } } }` |
| Antigravity | `~/.gemini/antigravity/mcp_config.json` | `"mcpServers": { "context7": { "serverUrl": "https://mcp.context7.com/mcp", "headers": { "Authorization": "Bearer KLUCZ" } } }` |

**CodeGraph** ([@colbymchenry/codegraph](https://www.npmjs.com/package/@colbymchenry/codegraph)) — graf kodu (MCP + CLI, nie skill)

```bash
npm i -g @colbymchenry/codegraph
codegraph install --target claude,codex,opencode,copilot-vscode,antigravity --location global
codegraph init -i        # w każdym repo — buduje indeks .codegraph/
```

Zostaw w `--target` tylko swoich klientów. `codegraph install --print-config <id>` pokazuje
wpis bez zapisu.

**GitHub MCP** ([github/github-mcp-server](https://github.com/github/github-mcp-server)) — issues/PR z poziomu agenta

Serwer zdalny `https://api.githubcopilot.com/mcp/`. Poza VS Code (OAuth) potrzebny PAT
([github.com/settings/tokens](https://github.com/settings/tokens), scope `repo`, `read:org`, `read:user`)
w zmiennej środowiskowej, nie w pliku w repo:

| Klient | Komenda / wpis |
| --- | --- |
| Claude Code | `/plugin install github@claude-plugins-official` albo `claude mcp add github --transport http https://api.githubcopilot.com/mcp/ -H "Authorization: Bearer $GITHUB_PAT"` |
| Codex | `codex mcp add github --url https://api.githubcopilot.com/mcp/ --bearer-token-env-var GITHUB_PAT_TOKEN` |
| OpenCode | `"mcp": { "github": { "type": "remote", "url": "https://api.githubcopilot.com/mcp/", "oauth": false, "headers": { "Authorization": "Bearer {env:GITHUB_PERSONAL_ACCESS_TOKEN}" } } }` |
| VS Code | `"servers": { "github": { "type": "http", "url": "https://api.githubcopilot.com/mcp/" } }` — logowanie OAuth przy pierwszym użyciu |
| Antigravity | `~/.gemini/antigravity/mcp_config.json`: `"mcpServers": { "github": { "serverUrl": "https://api.githubcopilot.com/mcp/", "headers": { "Authorization": "Bearer <PAT>" } } }` |

#### 2.3. Gdzie co ląduje

`.agents/skills/` jest wspólny dla Codexa, OpenCode, Copilota i Antigravity — skill dodany
przez `npx skills -a codex` zobaczą też pozostali. Kit ignoruje ten katalog w `.gitignore`,
więc na nowej maszynie instalację powtarzasz.

Globalnie Antigravity CLI czyta tylko `~/.gemini/config/skills/` — `npx skills update`
odświeża `~/.agents/skills/`, więc po aktualizacji skopiuj skille ponownie.

#### 2.4. Windows (Git Bash) vs Linux

- `npx skills` domyślnie robi symlinki, a te na Windowsie wymagają Developer Mode albo
  admina. Bez tego dodaj `--copy`.
- Lokalny (stdio) serwer MCP odpalany przez `npx` uruchamiaj na Windowsie jako
  `cmd /c npx …`. Serwery zdalne (Context7, GitHub wyżej) tego nie potrzebują.
- Pełny instalator Caveman: na Windowsie `install.ps1`, nie `install.sh` — hooki i tak
  wołają wersje PowerShell.
- Hooki Ponytail i Caveman (Claude, Codex) potrzebują `node` w PATH powłoki
  **nieinteraktywnej** — przy nvm to częsta pułapka.
- Zmienne z tokenami: Git Bash / Linux `export GITHUB_PAT_TOKEN=…`, PowerShell
  `$env:GITHUB_PAT_TOKEN = "…"`. Klient musi wystartować już z ustawioną zmienną.

#### 2.5. Konfiguracja projektu

`/kit-project-begin` — patrz [Krok 2](#krok-2--konfiguracja).

Hooka `pre-push` kit już nie dostarcza (guardraile siedzą w hookach klientów);
istniejący `git-hooks/pre-push` w Twoim repo zostaje nietknięty.

**Zrestartuj IDE / CLI.** MCP i komendy ładują się przy starcie — bez restartu
zobaczysz stan sprzed bootstrapu.

### 3. Weryfikacja

```bash
# MCP odpowiada i widzi właściwy kit
#   w Claude Code: poproś o wywołanie narzędzia check_kit_status
#   oczekiwane: "Kit status: aktualny"

# hooki działają (powinno wypisać "deny")
printf '%s' '{"tool_input":{"command":"git reset --hard HEAD"}}' \
  | node .claude/hooks/git-guard.mjs

# konfiguracja AI wchodzi do repo, lokalny stan nie
git status --short -uall .claude .codex .github/prompts
```

#### Doctor — reguły projektu vs drzewo repo

`kit-ai reload` kończy się raportem `doctor:`, `kit-ai status` i MCP `check_kit_status`
dokładają go do swojego wyniku, a `kit-ai doctor` uruchamia samą kontrolę. Doctor czyta
`BUGBOT.md`, `.ai/project.md`, `AGENTS.md` i `CODING_STANDARDS.md` (w repo kita także
komendy w `templates/shared/agents/*`). Linie `AGENTS.md` / `BUGBOT.md` skopiowane bez
zmian z szablonu kita są pomijane — to treść kita, nie reguły projektu:

- ścieżki w backtickach — brak w drzewie = `OSTRZEŻENIE` z plikiem i numerem linii;
  globy (`**/auth/**`) i placeholdery (`<N>`) są pomijane. Ścieżka może być od roota
  repo, względem katalogów z `## Ścieżki` (i ich `src/` / `app/`) albo gołą nazwą
  (`server.py`, `ui/`) szukaną w całym drzewie;
- **zakres Tieru** — ścieżka w sekcji z nagłówkiem Tieru (`## Backend`,
  `## Frontend (web / mobile)`) albo w linii z prefiksem `backend:` / `web:` / `mobile:`
  liczy się tylko wewnątrz katalogu tego Tieru (klucz `backend:` / `web:` / `mobile:`
  w `## Ścieżki`). Plik, który leży wyłącznie w innym Tierze, daje `stale-path`. Prefiks
  linii wygrywa z nagłówkiem; ścieżka pełna od roota repo i sekcja bez Tieru — bez
  zawężania;
- klucze `## Ścieżki` w overlayu (`backend:`, `web:`, `routes-web:` …) — katalog albo plik
  musi istnieć;
- komendy `/nazwa` — muszą mieć agenta, komendę albo skill u któregoś klienta
  z `clients:`; komendy innych warstw (Matt, Superpowers, Cursor) są pomijane;
- pakiety workspace'ów Bun/npm, pnpm i uv, których overlay nie opisuje — `INFO`, nie
  ostrzeżenie.

```text
doctor: 1 ostrzeżenie, 1 informacja
doctor: OSTRZEŻENIE BUGBOT.md:12 — ścieżka `src/auth/` nie istnieje
doctor: INFO .ai/project.md — katalog `packages/ui/` z workspace'u nie jest opisany w `.ai/project.md`
```

Klasy zgłoszeń (pole `kind`):

| `kind` | Poziom | Co znaczy |
|--------|--------|-----------|
| `stale-path` | ostrzeżenie | ścieżka w regule albo klucz `## Ścieżki` wskazuje coś, czego nie ma (z `suggestion`, gdy w drzewie jest dokładnie jeden kandydat) |
| `negated-path-exists` | ostrzeżenie | overlay pisze, że ścieżki nie ma („brak `x/`”, „nie istnieje”), a ona istnieje |
| `stale-kit-content` | ostrzeżenie | `AGENTS.md` / `BUGBOT.md` ma linie ze starej wersji szablonu kita — do odświeżenia |
| `stale-project-brief` | ostrzeżenie | blok `kit:brief` w `AGENTS.md` nie odpowiada bieżącemu Profilowi i overlayowi — `kit-ai reload` go odświeży |
| `uncertain-migration` | ostrzeżenie | `AGENTS.md` / `BUGBOT.md` bez bloku projektu, migracji reload nie zastosował sam — `value` niesie propozycję treści bloku; zgłoszenia per linia z szablonowej części pliku są wyciszone |
| `missing-path-key` | ostrzeżenie | brak klucza w `## Ścieżki`, a reguła szablonu `BUGBOT.md` używa domyślnej ścieżki, której nie ma w repo (`ui` / `api-generated` domyślnie pod `web:`); kilku kandydatów w drzewie → lista w komunikacie zamiast propozycji |
| `missing-command` | ostrzeżenie | komenda `/nazwa` bez agenta, komendy ani skilla u klientów z `clients:` |
| `undescribed-package` | info | pakiet workspace'u bez opisu w `.ai/project.md` |
| `invalid-clients` | info | nieprawidłowe `clients:` w Profilu — doctor sprawdza jak `all` |
| `path-candidates` | info | tylko z `--verbose`: ścieżka pasuje do kilku miejsc — lista kandydatów |

```bash
kit-ai doctor            # linie doctor:, kod wyjścia 0
kit-ai doctor --json     # {"warnings", "infos", "findings": [{kind, file, line, value, suggestion, …}]}
kit-ai doctor --verbose  # + INFO `path-candidates`, gdy ścieżka pasuje do >1 miejsca
```

Bez `--verbose` ścieżka pasująca do kilku miejsc przechodzi po cichu (jak dotąd);
z flagą każde takie trafienie dostaje linię `INFO` z listą kandydatów, w obrębie zakresu
Tieru. `--verbose` łączy się z `--json`.

`OSTRZEŻENIE` znaczy, że reguła review albo wpis overlayu wskazuje coś, czego w repo nie
ma — po cichu przestaje działać. `INFO` to porządki w overlayu. Doctor **nigdy nie
blokuje** reloadu: raport i tak wychodzi, a kod wyjścia to 0.

**Naprawa — tryb C** `/kit-project-edit "napraw zgłoszenia doctora"`: proponuje poprawki
w overlayu, w bloku `project:rules` w `BUGBOT.md` i w bloku `project:agents` w `AGENTS.md`
(przestarzała treść kita), pokazuje jeden podgląd na całą partię i zapisuje po
akceptacji. Ścieżki w szablonowych częściach `BUGBOT.md` / `AGENTS.md` i w
`CODING_STANDARDS.md` wymagają ręcznej decyzji (reload nadpisałby szablon).

**Po reloadzie** (`kit-ai reload`, MCP `reload_workspace`) ostrzeżenia do naprawy trafiają
do pliku stanu `.ai/.kit-doctor.json` (ten sam format co `kit-ai doctor --json`); czysty
przebieg plik usuwa, `--dry-run` go nie dotyka. Raport kończy linia
`doctor: N do naprawy → /kit-project-edit "napraw zgłoszenia doctora"`, a MCP
`reload_workspace` każe agentowi od razu uruchomić tryb C na tej partii — bez czekania na
prośbę (auto-start). Tryb C bierze partię z pliku stanu albo z `kit-ai doctor --json`.

### 4. Kiedy aktualizować

Narzędzie MCP `check_kit_status` porównuje commit kita zapisany przy bootstrapie
(`.ai/.kit-bootstrap.json`) z aktualnym `HEAD` i mówi, co się zmieniło. Rozdziela dwie
rzeczy: pliki, które **re-bootstrap wciągnie sam** (w tym `BUGBOT.md` — odświeżany
z szablonu), i te wymagające **ręcznego przeniesienia** (`AGENTS.md`, `.ai/project.md` —
kopiowane tylko gdy brak, żeby nie zdeptać Twojej treści). Gdy pokaże zmiany: `kit-ai reload`
(z terminala to samo pokazuje `kit-ai status`).

### 5. Zanim odpalisz update na repo z pracą w toku

Bootstrap nadpisuje `.claude/{agents,commands,hooks}/`, `.codex/`, `.github/prompts/`,
`copilot-instructions.md` i pliki MCP. Jeśli edytowałeś je ręcznie — `git diff` najpierw.
Nie chcesz oglądać planu na sucho? Z poziomu agenta:

```text
reload_workspace()                  # dry run — lista plików nowych/nadpisanych/usuniętych
reload_workspace(dry_run=False)     # odświeżenie z Profilu (= kit-ai reload)
```

**Etykiety GitHuba.** Agenci kita używają tylko istniejących etykiet: `type: *`, kategorii
`bug` / `enhancement` (słownik `/triage`), `scope: *` według Tierów i etykiet stanu
(`needs-triage`, `needs-info`, `ready-for-agent`, `ready-for-human`, `wontfix` — nazwy
z `docs/agents/triage-labels.md` projektu, jeśli jest). Zestaw leży w
`templates/shared/labels.tsv`; brakujące zakłada `ensure_labels(dry_run=False)` albo
`kit-ai labels --apply` (istniejących nie zmienia). `/kit-project-begin` proponuje to po
reloadzie.
Etykiety `design: layout` / `design: tokens` dochodzą tylko przy Tierze web/mobile **i**
`claude` w `clients:` — sesję designu robi człowiek w Claude Code (opis:
`docs/agents/design-handoff.md`, instalowany przy tych samych warunkach). Treść agentów tylko
dla takich projektów siedzi w blokach `<!-- clients: claude -->…<!-- /clients -->`; bootstrap
zostawia je (bez znaczników) albo wycina według `clients:`.

**Gdzie żyje konfiguracja AI po instalacji:** wszystko poza `.claude/settings.local.json`
i `.agents/skills/` idzie do repo — bootstrap wstawia do `.gitignore` sekcję między
markerami `# >>> instruction-kit >>>`. Szczegóły: sekcja „`.gitignore`" niżej.

**Gdzie czytać / zmieniać konfigurację:**


| Co                                           | Gdzie pisać                                             |
| -------------------------------------------- | ------------------------------------------------------- |
| Argumenty MCP (`--language`, `--clients`, `--workspace`, …) | ten README (sekcja niżej) + szablony `templates/*/mcp*` |
| Stack per Tier i fork                       | [profil z Tierami](#profil-z-tierami-backendwebmobile)              |
| Kanon agentów / reguł (niezależny od IDE)    | [`templates/shared/`](templates/shared/README.md)       |
| Multi-client design                          | [design](docs/specs/2026-08-05-multi-client-templates-design.md) |
| Szczegóły jednego produktu                   | `.ai/project.md` w **repo aplikacji** (Taskfile, porty, Docker)  |
| Inny zestaw modułów niż Tiery              | `include:` w `.ai/project.profile.yaml` (routing wg tagów)         |
| Docelowy kontrakt `--overlays` | [design overlays](docs/specs/2026-08-05-mcp-profile-architecture-overlays-design.md) |
| Cursor `/compact` (alias Summarize)          | `templates/cursor/skills/compact/` → `.cursor/skills/` (nie Claude/Codex) |
| Skille kita (wszyscy klienci)                | `templates/shared/skills/` → sekcja „Skille kita” niżej |


## Struktura `docs/`

```text
docs/
├── adr/     — decyzje architektoniczne (format Nygarda)
├── agents/  — kontrakt issue trackera, etykiety triage, docs domenowe
├── specs/   — projekty przed implementacją
└── plans/   — plany implementacyjne
```

> `docs/specs/` i `docs/plans/` nazywały się wcześniej `docs/superpowers/{specs,plans}`. Zmiana jest celowa: Superpowers i `mattpocock/skills` to zewnętrzne biblioteki, z których kit **korzysta** — ich nazwa nie powinna strukturyzować drzewa docs tego repo.

## Konfiguracja projektu — argumenty `guides-mcp`

Wszystkie flagi serwera MCP wpisujesz w `args` klienta (Cursor: `.cursor/mcp.json`). Kolejność: najpierw `--from` / nazwa pakietu (`guides-mcp`), potem flagi poniżej.

### Warstwy (co gdzie należy)


| Warstwa                           | Mechanizm                                             | Przykład                 |
| --------------------------------- | ----------------------------------------------------- | ------------------------ |
| Stack backendu                    | Tier `backend` w profilu                              | `django`, `fastapi`, `flask`, `none` |
| Stack webu                        | Tier `web` w profilu                                  | `react`, `angular`, `expo`, `none` |
| Stack mobile                      | Tier `mobile` w profilu                               | `expo`, `react-native`, `none` |
| Powtarzalny wariant               | `--tag` / facety (**planowane**, niezaimplementowane) | `physical`, `digital`    |
| Fakty jednego repo                | `.ai/project.md` + `--workspace`                      | porty, Taskfile          |
| Inny zestaw modułów niż Tiery     | `include:` w profilu (routing wg tagów)               | `capability:payments`    |


Nie mieszaj: nazwa produktu ≠ Stack; porty ≠ tag.

### Flagi (aktualne)

```json
{
  "mcpServers": {
    "project-guides": {
      "command": "uvx",
      "args": [
        "--from", "git+https://github.com/radthenone/ai-instruction-kit-mcp.git",
        "guides-mcp",
        "--language", "pl",
        "--clients", "all",
        "--workspace", "${workspaceFolder}"
      ]
    }
  }
}
```


| Flaga              | Wymagana? | Rola                                                                                                                                               | Gdzie / jak zmieniać                                     |
| ------------------ | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| `--from SOURCE`    | przy `uvx` | Źródło zdalne kita: `git+https://…@ref`. Dla lokalnego klonu bootstrap generuje zamiast tego `uv run --project <ścieżka>` — patrz „Lokalny klon" niżej | `.cursor/mcp.json` (i odpowiedniki innych klientów)      |
| `--language pl|en` | nie       | Język **prozy** (odpowiedzi, docstringi, body issue/PR, commity). **Tytuły** issue/PR/branch zawsze EN. Domyślnie: `language:` w profilu albo `pl` | `language:` w Profilu + `kit-ai reload`; env `GUIDES_LANGUAGE` |
| `--clients LIST`   | nie       | Metadane IDE: `all` \| `cursor` \| `claude` \| `codex` \| `vscode` \| `kiro` \| `kilo` \| `antigravity` \| `opencode` (lista; alias `copilot`→`vscode`). **Nie** zmienia treści bundle | mcp.json / bootstrap `--clients` (default `all`); env `GUIDES_CLIENTS`; tool `get_clients` |
| `--kit-root PATH`  | nie       | Klon kita, z którego serwer czyta `manifest.yaml` / `modules/`. Bez niej root jest wykrywany automatycznie — a przy `uvx --from <katalog>` wykrywa się kopia z cache `uv` zamiast klonu | mcp.json — bootstrap dodaje sam przy źródle lokalnym; env `GUIDES_KIT_ROOT` |
| `--workspace PATH` | zalecane  | Root aplikacji — stąd profil `.ai/project.profile.yaml` i overlay `.ai/project.md`                                                                                                        | mcp.json; Cursor/VS: `${workspaceFolder}`                |
| `--overlay PATH`   | nie       | Extra MD (można wielokrotnie)                                                                                                                      | mcp.json — rzadko; zwykle wystarczy workspace            |


Stare konfiguracje klienta z `--preset` / `--profile` / `--codegen` nadal startują serwer, ale
te flagi są ignorowane, a bundle i indeks niosą ostrzeżenie o migracji — `kit-ai reload`
przepisze `mcp.json`. Bootstrap zapisuje tylko `--language` i `--clients` (z Profilu).

**Język:** MCP tool `get_language`. Priorytet: `--language` / `GUIDES_LANGUAGE` → `language:` w YAML profilu → `pl`. Moduł w bundle: `core:language-pl` albo `core:language-en`.

**Klienci AI:** MCP tool `get_clients` — tylko metadane instalacji; treść `get_bundle` jest identyczna dla każdego klienta.

**Codegen (Orval):** wyłącznie `codegen:` w `.ai/project.profile.yaml` (`orval` \| `none` \| `graphql`, domyślnie `orval`; ADR-0007), odczyt przez MCP tool `get_codegen`. Bez pary backend + klient (web/mobile) efektywny codegen to zawsze `none`. Reviewery FE/BE to honorują (przy `orval` wymagają regeneracji klienta po zmianie API; `graphql` → moduł `arch:api-contract:graphql` zamiast REST).

## Profil z Tierami (backend/web/mobile)

```yaml
# .ai/project.profile.yaml w repo aplikacji
name: moja-appka
language: pl
clients: claude,codex

backend: django      # none | django | django-html | fastapi | flask
web: react            # none | react | react@legacy | angular | angular@rxjs | expo
mobile: none           # none | expo | react-native

codegen: orval        # orval | none | graphql (bez pary backend + klient: zawsze none)

capabilities:
  - auth
  - payments

decisions:
  database: postgres
  auth: jwt
```

Bundle liczone są z Tierów: `get_bundle backend` zawiera Stack z Tieru `backend`, pusty profil daje sam core. Nierozpoznana wartość Tieru nie wywraca serwera — ląduje w „Nierozpoznanych decyzjach" w `get_index` (ADR-0004). Stare klucze `stacks:` / `patterns:` czytane są nadal.

### Model tiers agentów (`models:` / `agents:`)

Każdy agent kita ma w template `model-tier:` (`light` / `standard` / `heavy`; osobny klucz
od `tier:` Stacku). Profil mapuje tier na model per klient:

```yaml
models:                  # ręcznie; reload tego bloku nie rusza
  claude:
    light: haiku
    standard: sonnet
    heavy: opus
  opencode:
    light: anthropic/claude-haiku-5-5

agents:                  # synchronizuje reload
  light: git-start,git-commit,git-end,git-check,cleanup
  standard: create-task,create-skill
  heavy: night-run,review-edge
```

- Brak klienta albo tieru w `models:` = brak pola `model` (agent dziedziczy model sesji).
  Bez `models:` pliki agentów są takie jak przed tą funkcją.
- `agents:` przy reloadzie: blok powstaje, gdy go nie ma; brakujący agenci kita trafiają
  do tieru z template; agenta już przypisanego reload nie przenosi (Profil wygrywa);
  nazwy spoza kita znikają. Każde dopisanie (`+ agents.<tier>: <agent>`) i usunięcie (`-`)
  jest w wyjściu reloadu. Reload przepisuje tylko blok `agents:` — komentarze w nim giną.
- Nieznany tier (w `models:` albo `agents:`), tier bez modelu, agent w dwóch tierach i zapis
  w jednej linii (`models: {…}`) przerywają reload z opisem błędu. Oba bloki pisz z wcięciami,
  jak wyżej; `agents:` obejmuje wszystkich agentów kita, także Tierów Stacku spoza Profilu.
- `models.claude.takeover` (obok tierów, nie tier agenta): model przejęcia ticketu nocnego, gdy
  wykonawca `/headless` zwróci limit (kod 75, #257). Tylko alias Claude Code: `haiku`, `sonnet`,
  `opus`, `fable`; inny zapis przerywa reload. Brak klucza = model sesji.

| Klient | Wspiera `model` | Plik | Format nazwy modelu | Przykład |
|--------|-----------------|------|---------------------|----------|
| Claude Code | tak | `.claude/agents/<agent>.md` | alias (`haiku`/`sonnet`/`opus`) albo pełne id | `models.claude.light: haiku` |
| opencode | tak | `.opencode/command/<agent>.md` | `provider/model` | `models.opencode.light: anthropic/claude-haiku-5-5` |
| Cursor, Codex, VS Code, Kiro, Kilo, Antigravity | nie — pole pomijane | — | — | — |

Komendy `/nazwa` Claude (`.claude/commands/`) zostają bez `model:` — działają w sesji głównej.

### Katalog pytań o projekt (`list_questions`)

`manifest.yaml` → `questions:` trzyma pytania o projekt (Tiery, warianty, `codegen`, Docker,
Taskfile, CI/CD, monorepo, capability-provider, webhooki, ścieżki per Tier) z opcjami,
domyślnymi (`defaults:` zależne od Profilu, np. `django-html` → web/mobile `none`),
warunkiem `when:` i sygnałami `detect:` (`glob` + opcjonalny regex `pattern` w treści pliku).
Narzędzie MCP `list_questions` zwraca katalog z warunkami ocenionymi na bieżącym Profilu —
sygnały sprawdza agent w plikach repo, Python niczego nie skanuje. Odpowiedź ląduje tam, gdzie
wskazuje `sets:` (klucz Profilu albo `paths.<tier>` → `## Ścieżki` w `.ai/project.md`), a pytania
tak/nie dopisują `include:` / `patterns:` z `on_yes:`.

Moduły układu katalogów (`stack:frontend:*`) nie wchodzą do Bundli — `layouts:` w manifeście
wybiera podpowiedź drzewka dla kombinacji web/mobile (np. `web: react` + `mobile: expo` →
`react-expo-split`), `web: expo` + `mobile: react-native` daje ostrzeżenie, brak drzewka →
domyślne ścieżki (`backend/`, `frontend/web/`, `frontend/mobile/`; Expo unified: `frontend/`).

### Tagi / facety (planowane — jeszcze nie w CLI)

Gdy wiele projektów dzieli **ten sam** powtarzalny wariant instrukcji (np. sklep fizyczny vs cyfrowy), zamiast mnożyć presety `shop-jewelry` / `shop-tokens`:

1. W `manifest.yaml` → `mappings.tiers.<tier>` dopisać dozwolone Stacki (np. `fulfillment` nie — Tiery to backend/web/mobile; nowy wymiar trafia do `decisions` albo `capabilities`).
2. W mcp.json dodać np. `"--tag", "physical"` albo `"--facet", "fulfillment=physical"` (docelowa składnia przy implementacji).
3. Resolver dołoży wtedy dodatkowe MD z `modules/` — bez lokalnego forka, jeśli zestawy capabilities są te same.

**Teraz:** różnice jubiler vs tokeny → `.ai/project.md`. Tagi włączaj dopiero gdy wariant wraca w ≥2–3 projektach.

Szkic (nie działa jeszcze):

```json
"args": [
  "--from", "…",
  "guides-mcp",
  "--tag", "physical",
  "--tag", "b2c",
  "--workspace", "${workspaceFolder}"
]
```



### Bootstrap

```bash
# Generyczny — profil z Tierami + --language pl
./scripts/bootstrap-project.sh /sciezka/do/projektu \
  --from /absolutna/sciezka/do/ai-instruction-kit-mcp \
  --with-overlay

# Tylko Cursor
./scripts/bootstrap-project.sh /sciezka/do/projektu \
  --clients cursor \
  --from /absolutna/sciezka/do/ai-instruction-kit-mcp

# Proza EN, wszyscy klienci AI (Stacki potem w .ai/project.profile.yaml)
./scripts/bootstrap-project.sh /sciezka/do/moj-sklep \
  --language en \
  --clients all \
  --from /absolutna/sciezka/do/ai-instruction-kit-mcp
```

**Agenci per Tier:** agenci z `tier:` we frontmatterze (`templates/shared/agents/`) trafiają do klienta tylko przy wybranym Tierze — `tier: backend` (`review-backend`, `teacher-backend`, `subagent-backend`) gdy `backend ≠ none`, `tier: client` (`review-frontend`, `teacher-frontend`, `subagent-frontend`, `review-ui`) gdy `web` lub `mobile ≠ none`. Tier zmieniony na `none` + `kit-ai reload` = ich pliki znikają u wszystkich klientów. Agenci nie zakładają Stacka — biorą go z `get_bundle`. `BUGBOT.md` dostaje sekcje (`<!-- tier:backend -->`, `<!-- tier:client -->`) tylko wybranych Tierów.

**`BUGBOT.md` i reguły projektu:** każdy reload renderuje `BUGBOT.md` oraz `.cursor/BUGBOT.md` z bieżącego szablonu — poprawki ścieżek i reguł kita docierają do repo same, także gdy masz własne reguły. Własne reguły wpisuj **wyłącznie** między `<!-- project:rules -->` i `<!-- /project:rules -->`: ten blok przechodzi przez reload bajt w bajt, a reszta pliku jest brana z szablonu. Plik dostosowany przed wprowadzeniem bloku jest migrowany: bootstrap dopasowuje go do najbliższej wersji `templates/cursor/BUGBOT.md` z historii gita kita i przenosi dopisane linie do bloku, a w wyniku reloadu wypisuje ich listę. Gdy migracja jest niepewna (brak historii — np. kit z koła, albo za duży diff), plik zostaje bez zmian, a reload wypisuje instrukcję ręcznego przeniesienia.

Zapisuje m.in. MCP per klient (`--language`, `--clients`, `--workspace`), agents z `templates/shared/agents`, `BUGBOT.md` w root (wszyscy klienci) + `.cursor/BUGBOT.md` (natywny Cursor BugBot), skill Cursor `/compact`, hooki `gate-*` (Cursor), stamp `.ai/.kit-bootstrap.json` (patrz "Update kita w projekcie"). Wymaga **Python 3** (`python3` albo `python` z major==3).

**Declarative sync klientów:** domyślnie bootstrap **usuwa** kitowe pliki klientów spoza `--clients` (np. przełączenie z `--clients all` na `--clients claude` sprząta `.cursor/`, `.codex/` itd. wygenerowane przy poprzednim bootstrapie). Flaga `--keep-unselected-clients` wyłącza to sprzątanie — zostają pliki wszystkich klientów kiedykolwiek bootstrapowanych.

Sprzątanie kasuje **wyłącznie pliki kita, po nazwie** — listę bierze z przebiegu tych samych funkcji instalacji w pustym katalogu. Własne agenty, komendy, hooki i skille w `.claude/`, `.opencode/`, `.codex/`, `.github/prompts/` itd. zostają; katalog znika tylko, gdy po kicie jest pusty. Plik użytkownika o nazwie identycznej z plikiem kita (np. własny `.claude/agents/git-start.md`) zostanie usunięty razem z kitowymi.

**`kit-ai remove [ścieżka] [--dry-run]`** — odinstalowanie: pliki kita wszystkich klientów, konfiguracje MCP, wpisy kita w `.claude/settings.json`, sekcja `# >>> instruction-kit >>>` w `.gitignore`, Profil i stamp (także stara konfiguracja z presetem). Pliki tworzone raz (`AGENTS.md`, `.gitattributes`) znikają tylko, gdy są identyczne z bieżącym szablonem kita — zmienione przez Ciebie zostają. `BUGBOT.md` znika, gdy jest nietkniętym renderem: blok `project:rules` bez własnych reguł liczy się jak pusty, ale plik z regułami projektu zostaje. Zawsze zostają `.ai/project.md`, `CONTEXT.md`, `docs/adr/` i Twoje pliki. Kit nie robi kopii, więc nic nie przywraca. `--dry-run` pokazuje listę bez usuwania.

### `.gitignore` — co z tego wersjonować

Bootstrap wstawia do `.gitignore` repo aplikacji sekcję między markerami
`# >>> instruction-kit >>>` i `# <<< instruction-kit <<<`. Przy kolejnych przebiegach
podmienia ją w całości, więc wpisy się nie duplikują, a reguły spoza markerów zostają
nietknięte. Źródło: `templates/gitignore-kit.txt`.

Zasada: **konfiguracja AI jest częścią repo.** Hooki bezpieczeństwa, agenci i komendy mają
działać u każdego, kto sklonuje projekt — nie tylko na maszynie, gdzie odpalono bootstrap.
Poza gitem zostaje lokalny stan klienta, to, co i tak żyje globalnie, oraz pliki, które
bootstrap renderuje **ze ścieżką tej maszyny**:

| Wersjonowane | Ignorowane |
| --- | --- |
| `.claude/{agents,commands,hooks,skills}/`, `.claude/settings.json` | `.claude/settings.local.json` (uprawnienia per maszyna) |
| `.codex/skills/` | `.codex/config.toml` (MCP), reszta `.codex/` (stan sesji) |
| `.github/prompts/`, `.github/copilot-instructions.md`, `.github/hooks/` | `.vscode/mcp.json` (MCP) |
| `AGENTS.md`, `BUGBOT.md`, `.ai/project.md` | `.mcp.json`, `.cursor/mcp.json`, `.kiro/settings/mcp.json`, `.kilocode/mcp.json`, `.agents/mcp_config.json`, `opencode.json` (MCP), `.ai/.kit-bootstrap.json` (stamp) |
| — | `.agents/skills/`, `skills-lock.json` (skille z `npx skills add` — instalowane globalnie w `~/.agents/skills/`, kopia w repo zaraz rozjedzie się z globalną) |

**Konfigi MCP i stamp są per maszyna, nie per repo.** Przy `--from <lokalny klon>` bootstrap
wpisuje do nich absolutną ścieżkę klona (`uv run --project`, `--kit-root`), a dla Codex
i opencode absolutny `--workspace`. Zacommitowane z Windowsa (`M:/projects/…`) na Linuksie
dają `CONNECTION_CLOSED` bez czytelnego powodu. Każdy odbiornik — PC, laptop, serwer —
odpala `kit-ai reload` u siebie; język i klienci są w zacommitowanym Profilu, więc nic
więcej nie trzeba pamiętać.

Repo zbootstrapowane wcześniej mają te pliki w indeksie — sam wpis w `.gitignore` ich nie
odśledzi. Bootstrap wykrywa to i wypisuje gotową komendę (pliki zostają na dysku):

```bash
git -C "$APP" rm --cached .mcp.json .vscode/mcp.json .codex/config.toml .ai/.kit-bootstrap.json
```

Typowy `.gitignore` ma `.claude/` wpisane hurtem — wtedy hooki i komendy nigdy nie trafiają
do repo, a bootstrap trzeba powtarzać na każdej maszynie. Reguły kita są w formie „ignoruj
katalog, odwróć dla plików kita", bo git nie wchodzi do zignorowanego katalogu i sam wyjątek
na plik by nie wystarczył.

### Bootstrap bez klona kita — narzędzie MCP `bootstrap_workspace`

Jeśli projekt ma już podłączony serwer MCP `project-guides`, kita nie trzeba klonować ani ręcznie odpalać skryptu — serwer ma szablony pod ręką i uruchamia ten sam `bootstrap-project.sh` u siebie. Poproś agenta o wywołanie narzędzia:

```text
bootstrap_workspace()                          # dry run — tylko lista plików
bootstrap_workspace(dry_run=False)             # instalacja
bootstrap_workspace(clients="claude", with_overlay=True, dry_run=False)
```

Odświeżenie z Profilu (= `kit-ai reload`, łącznie z migracją starej konfiguracji) robi `reload_workspace()` / `reload_workspace(dry_run=False)`.

Argumenty `bootstrap_workspace` (`clients`, `language`, `with_overlay`, `keep_unselected_clients`) odpowiadają flagom skryptu; pominięte biorą wartość z parametrów startowych serwera MCP. Cel zapisu to `--workspace` / `GUIDES_WORKSPACE` — **bez niego narzędzie odmawia**, zamiast zapisywać do katalogu, z którego przypadkiem wystartował proces serwera.

`dry_run=True` jest domyślne i nic nie zapisuje: skrypt leci na kopii kitowej powierzchni repo w katalogu tymczasowym, a raport pokazuje pliki nowe, nadpisane i **usunięte** przez sprzątanie klientów spoza `--clients`. Plan pochodzi więc z faktycznego przebiegu skryptu, nie z drugiej listy ścieżek w Pythonie.

> **Uwaga na bramki.** Hooki kita (`PreToolUse`) łapią `Bash`, `PowerShell` i `Edit|Write|MultiEdit|NotebookEdit` — nie nazwy narzędzi MCP. To jedyne zapisujące narzędzie tego serwera i hooki go **nie zatrzymają**; `dry_run=True` jako domyślka plus wymóg jawnego `dry_run=False` są tu całą ochroną. Reszta narzędzi serwera pozostaje tylko do odczytu.

## MCP w innych klientach (multi-client)

Kanon treści: `templates/shared/{agents,rules}`. Adaptery IDE trzymają tylko format MCP / ścieżki natywne. Bootstrap `--clients` instaluje wybrane pakiety (default `all`).


| Klient                   | Id `--clients` | Plik MCP w aplikacji              | Klucz top-level                  | Szablon                          |
| ------------------------ | -------------- | --------------------------------- | -------------------------------- | -------------------------------- |
| Cursor                   | `cursor`       | `.cursor/mcp.json`                | `mcpServers`                     | `templates/cursor/mcp.json`      |
| Claude Code              | `claude`       | `.mcp.json` (root)                | `mcpServers`                     | `templates/claude/mcp.json`      |
| Codex CLI                | `codex`        | `.codex/config.toml`              | `[mcp_servers.x]` (TOML)         | `templates/codex/config.toml`    |
| GitHub Copilot (VS Code) | `vscode` (alias `copilot`) | `.vscode/mcp.json`     | `servers` (**nie** `mcpServers`) | `templates/vscode/mcp.json`      |
| Kiro                     | `kiro`         | `.kiro/settings/mcp.json`         | `mcpServers`                     | `templates/kiro/settings/mcp.json` |
| Kilo                     | `kilo`         | `.kilocode/mcp.json`              | `mcpServers`                     | `templates/kilo/mcp.json`        |
| Antigravity              | `antigravity`  | `.agents/mcp_config.json`         | `mcpServers`                     | `templates/antigravity/mcp_config.json` |
| opencode                 | `opencode`     | `opencode.json` (root)            | `mcp` (`type: "local"`)          | `templates/opencode/opencode.json` |


Zmienna dla `--workspace`:


| Klient          | Zmienna                                     |
| --------------- | ------------------------------------------- |
| Cursor, VS Code, Kiro, Kilo, Antigravity | `${workspaceFolder}`             |
| Claude Code     | `${CLAUDE_PROJECT_DIR:-.}`                  |
| Codex CLI, opencode | ścieżka absolutna (brak stabilnej zmiennej) |




## Instalacja per klient (krok po kroku)

Wspólne dla wszystkich: `git clone` / masz kita lokalnie → uruchom `bootstrap-project.sh` w **repo aplikacji** (nie w repo kita) z `--from` wskazującym na kita → zrestartuj IDE.

```bash
./scripts/bootstrap-project.sh /sciezka/do/mojej-appki \
  --from /m/projects/ai-instruction-kit-mcp \
  --clients cursor \
  --with-overlay
```

| Klient | `--clients` | Wymaga poza kitem | Extra config po bootstrapie |
| --- | --- | --- | --- |
| Cursor | `cursor` | Cursor IDE | Ustaw `--from` w `.cursor/mcp.json` jeśli nie `uvx`-owalny git remote. Hooki (`gate-*`) działają od razu — wymagają `bash` w PATH (Windows: Git Bash) |
| Claude Code | `claude` | `claude` CLI albo desktop app | `.mcp.json` w root — Claude Code czyta go automatycznie po `cd` do repo. `.claude/commands/*.md` = prawdziwe `/nazwa`, `.claude/agents/*.md` = subagenty (Task tool) |
| Codex CLI | `codex` | `codex` CLI | `.codex/config.toml` wymaga absolutnej ścieżki w `--workspace` (brak `${workspaceFolder}`) — bootstrap wypełnia sam z `TARGET` |
| GitHub Copilot (VS Code) | `vscode` (alias `copilot`) | VS Code + rozszerzenie GitHub Copilot Chat | `.vscode/mcp.json` (`servers`, nie `mcpServers`) + `.github/prompts/*.prompt.md` (Copilot Chat `/nazwa`) + `.github/copilot-instructions.md` + `.github/hooks/rtk-rewrite.json` (`rtk hook copilot` — jedyny klient bez trybu globalnego rtk, więc hook idzie z kita) + `.github/hooks/kit-guards.json` (guardy kita: git-guard, server-guard, sensitive-files-guard). Wymaga `node` w PATH i w VS Code ustawienia `chat.promptFiles: true` (część wersji ma to domyślnie) |
| Kiro | `kiro` | Kiro IDE | `.kiro/settings/mcp.json` + `.kiro/steering/instruction-kit.md` + `.kiro/agents/` — format agentów kopiowany 1:1, **niezweryfikowany na żywym Kiro** |
| Kilo Code | `kilo` | rozszerzenie Kilo Code | `.kilocode/mcp.json` + `.kilocode/workflows/*.md` (`/nazwa`, `$ARGUMENTS` wspierane) |
| Google Antigravity | `antigravity` | Antigravity IDE / CLI (`agy`) | `.agents/mcp_config.json` + `.agents/skills/<nazwa>/SKILL.md` (agenty jako natywne skille) + `.agents/hooks.json` (guardy kita: git-guard, server-guard, sensitive-files-guard) |
| opencode | `opencode` | `opencode` CLI | `opencode.json` w root (klucz `mcp`, `type: "local"`, `command` jako tablica) + `.opencode/command/*.md` (`/nazwa`, `$ARGUMENTS`) |

Wiele klientów naraz: `--clients cursor,claude` albo `--clients all`. Każdy klient dostaje **ten sam** `--language`/`--workspace` — różni się tylko format pliku MCP i ścieżka komend.

Po bootstrapie zawsze: **zrestartuj IDE/CLI** (MCP i komendy ładują się przy starcie), potem sprawdź że MCP wstał (np. `get_bundle` / lista narzędzi w kliencie).

## Czego kit **nie robi** / brakujące komendy

Świadome braki — nie zgłaszaj jako bug, tylko sprawdź czy potrzebujesz obejścia niżej:

| Brak | Status | Obejście |
| --- | --- | --- |
| `--tag` / facety wariantów | Zaprojektowane, **nie w CLI** | Różnice trzymaj w `.ai/project.md` dopóki wariant nie powtórzy się w ≥2–3 projektach |
| `--profile` / `--preset` / `--codegen` | Usunięte (serwer je ignoruje, bootstrap odmawia) | Profil zawsze `.ai/project.profile.yaml` w `--workspace`; migracja przez `kit-ai reload` |
| `/compact` poza Cursorem | Nie istnieje dla Claude/Codex/inne | To alias Cursor UI Summarize; Claude Code ma **wbudowane** `/compact` — nie koliduj, nie kopiuj |
| Natywna weryfikacja formatu VS Code/Kilo/Antigravity/opencode | Oparta o dokumentację (sierpień 2026), **nie testowana na żywych klientach** | Jeśli `/nazwa` nie działa w Twoim kliencie, zgłoś i popraw `scripts/render_agent_commands.py` |
| Auto-instalacja Superpowers/Autopilot | Niemożliwa ze skryptu (marketplace pluginów Claude/Cursor, wymaga interaktywnego `/plugin install`) | `--with-plugins` wypisze dokładne komendy/kroki, patrz niżej |

## Pluginy zewnętrzne — schemat użycia (4 warstwy)

Kit **nie** bundluje tych pluginów w `guides-mcp` (różna dystrybucja: MCP vs Claude/Cursor plugin marketplace vs npx skill). Pełna tabela warstw i priorytet źródeł: `AGENTS.md`.

```text
1. Fundament   — ten kit (MCP + /git-* + /review-*)     → instaluje bootstrap
2. Proces      — mattpocock/skills (/grill-me, /tdd)     → npx skills@latest add mattpocock/skills
3. Meta/izolacja — Superpowers (worktree, finishing…)     → Claude Code: /plugin marketplace add obra/superpowers-marketplace
                                                              /plugin install superpowers@superpowers-marketplace
4. PR → green  — Autopilot (Cursor)                       → Cursor: Settings → Extensions/Skills → Autopilot
```

Nie mieszaj warstw: kit = prawda o stacku i nazwach branchy, Matt = proces feature, Superpowers = sesja/worktree/finisz, Autopilot = dociąganie PR.

**Auto-instalacja przy bootstrapie:** `--with-plugins` (best-effort, opt-in — nic nie instaluje się bez tej flagi):

```bash
./scripts/bootstrap-project.sh ../moj-projekt \
  --clients claude \
  --from /m/projects/ai-instruction-kit-mcp \
  --with-plugins
```

Co robi: odpala `npx skills@latest add mattpocock/skills` w `TARGET` (wymaga `npx`/Node.js w PATH; best-effort — błąd nie przerywa bootstrapu), i wypisuje gotowe komendy do Superpowers/Autopilot (te dwa wymagają interaktywnego kroku w kliencie, nie da się ich odpalić z bash). TDD: jeden path na feature — domyślnie Matt `/tdd`, nie mieszaj z Superpowers TDD.

## Katalog modułów

```text
modules/
  core/              repo-first, workflow, typing, code-review, language-*, tooling-rtk
  architecture/      platforms, CI/CD, API (REST/GraphQL), security, testing, i18n,
                     taskfile, docker-structure, …
  stacks/
    django-drf/      (+ django/, fastapi/, flask/ layouts)
    expo-router/
    frontend/        warianty Expo/React (macierz web/mobile — design)
  capabilities/      auth (+ allauth/jwt/custom warianty), files, payments (+ expo-stripe gdy Tier expo), …
  patterns/          capability-provider, providers-and-settings, gateway, webhooks, …
  infra/             database, cache, queue, storage, tasks, search, vps-lightweight (auto na VPS)
templates/
  shared/            kanon agents + rules (źródło prawdy)
  cursor|claude|…    adaptery MCP / format IDE
```



## Sloty infrastruktury (`decisions`)

```yaml
decisions:
  database: postgres      # → infra:database:postgres
  cache: redis            # → infra:cache:redis
  queue: redis            # → infra:queue:redis  (lub rabbitmq)
  storage: s3             # → infra:storage:s3
  tasks: celery           # → infra:tasks:celery
  search: postgres        # → infra:search:postgres (lub meilisearch)
```

Moduły infra trafiają automatycznie do bundle `infra` i `devops`.

**Dodanie nowej technologii nie wymaga Pythona** (ADR-0001). Trzy kroki:

1. Napisz `modules/infra/queue/kafka.md`.
2. Zarejestruj go w `manifest.yaml` → `modules:`.
3. Dopisz wartość w `manifest.yaml` → `mappings.slots.queue.kafka`.

Nierozpoznana Decyzja (literówka `postgress`, technologia bez modułu) **nie wywraca
serwera** — ląduje w sekcji „Nierozpoznane decyzje" w `get_index` (ADR-0004).

## Lekki tryb VPS (`infra:vps-lightweight`)

Agenci na słabym VPS-ie (np. 1 vCPU, 4,5 GB RAM, bez swapu, LXC) nie mogą zachowywać
się jak na maszynie dewelopera — pełny `docker compose up`, `next dev` czy e2e
potrafią zabić produkcję obok przez OOM.

- Wykrywanie bez nazw hostów: Linux, brak CI/WSL, małe zasoby (CPU ≤ 2, RAM ≤ 8 GB,
  brak swapu) i sygnał serwerowy (wirtualizacja z `systemd-detect-virt` albo brak
  desktopu). Nadpisanie: `KIT_HOST_PROFILE=vps|local` (alias `GUIDES_HOST_PROFILE`).
  CI zawsze dostaje `local` — pełna weryfikacja należy do CI.
- `get_bundle` na takim hoście dokleja `infra:vps-lightweight` do **każdego**
  bundle'a (też `backend`/`frontend`/`architecture`); `get_index` pokazuje
  `- Host: vps|local`. Bez hooka blokującego — tylko reguła tekstowa, żeby nie
  zatrzymać celowego deployu.
- Moduł operuje kategoriami (kontenery, dev serwery, buildy, e2e vs lint/typecheck/
  unit in-memory), nie zakłada Django/React/Next ani innego stacku.
- Podział Twojego repo dopisz w overlay (`.ai/project.md`), np. `task lint` lekkie
  vs `task test:e2e` ciężkie — jedna zmiana przez `/kit-project-edit`.

## Wariant auth (`decisions.auth`)

```yaml
decisions:
  auth: custom      # default — brak enforced pakietu, opisz w .ai/project.md
  # auth: allauth   # → capability:auth:allauth (django-allauth headless)
  # auth: jwt       # → capability:auth:jwt (djangorestframework-simplejwt)
```

Inny mechanizm niż infra: nie tworzy osobnego bundle'a — dokleja się zaraz po
`capability:auth` wszędzie tam, gdzie ten moduł już jest wypisany w bundle
(`capabilities: [auth]` albo `include:` z ID modułu — routing wg tagów).
W manifeście to `mappings.variants.auth` (Wariant = wstaw po module bazowym),
w odróżnieniu od `mappings.substitutions.codegen` (Substytucja = podmień moduł bazowy).

## Słownik i decyzje

| Plik                       | Rola                                                                      |
| -------------------------- | ------------------------------------------------------------------------- |
| [`CONTEXT.md`](CONTEXT.md) | Ubiquitous language kita — Bundle, Preset, Slot, Wariant, Alias, Overlay… |
| [`docs/adr/`](docs/adr/)   | Decyzje architektoniczne z uzasadnieniem (dlaczego tak, a nie inaczej)    |

Nazwy z `CONTEXT.md` obowiązują w kodzie, docstringach i review. Zanim zaproponujesz
zmianę architektury, sprawdź `docs/adr/` — część rzeczy już rozstrzygnięto.

## Bundle'e MCP


| Bundle         | Zastosowanie                                |
| -------------- | ------------------------------------------- |
| `backend`      | Stack z Tieru backend, capabilities BE      |
| `frontend`     | Stacki z Tierów web i mobile, UI/UX         |
| `payments`     | Stripe, webhooks                            |
| `architecture` | monorepo, kontrakt API, capability-provider |
| `infra`        | postgres, redis, queue, s3, celery          |
| `devops`       | CI/CD + infra                               |
| `full`         | wszystko + infra                            |




## Bootstrap w projekcie docelowym

W **repo aplikacji** uruchom `scripts/bootstrap-project.sh` albo skopiuj z `templates/`:


| Plik                                | Rola                                                                    | Wymagany?            |
| ----------------------------------- | ----------------------------------------------------------------------- | -------------------- |
| `.cursor/mcp.json`                  | uvx → `--language` + `--clients` + `--workspace`; **per maszyna, poza gitem** | tak (Cursor)        |
| `.mcp.json` / `.codex/` / `.vscode/` / … | MCP per klient z `--clients`; **per maszyna, poza gitem**  | wg wybranego klienta |
| `.ai/project.md`                    | Overlay — Taskfile, Docker, porty           | zalecany             |

| `.ai/project.profile.yaml`          | Tiery (backend/web/mobile) + `codegen:` — jedyna konfiguracja kita                                              | **tak** |
| `.cursor/rules/use-guides.mdc`      | Bootstrap MCP                                                           | tak                  |
| `.cursor/rules/code-review.mdc`     | Review przed pushem                                                     | tak                  |
| `.cursor/rules/git-branch-pr.mdc`   | `/git-start`+`/git-check`+`/git-commit`+`/git-end`, issue#, chronione main/master/dev | tak                  |
| `.cursor/BUGBOT.md`                 | Reguły Bugbota                                                          | tak                  |
| `.cursor/hooks.json` + `hooks/invoke-hook.js` + `hooks/*.mjs` | Guardy: git-guard + sensitive-files (adapter → node) | tak                  |
| `AGENTS.md`                         | Cienki — odsyła do MCP                                                  | tak                  |
| `.cursor/agents/*.md`               | Subagenty `/review-*`, `/subagent-*`, `/git-*`                          | zalecany             |
| `.cursor/skills/compact/`           | **Tylko Cursor:** `/compact` = alias UI Summarize (nie Claude/Codex)    | zalecany (Cursor)    |


W projekcie docelowym **nie** duplikuj `modules/` — wystarczy profil z Tierami + opcjonalny overlay.

## Update kita w projekcie

Komendy update: [Szybki start, krok 3](#krok-3--update). Poniżej to, co update robi z plikami,
i lokalny klon kita.

Bootstrap to **jednorazowy stempel**, nie sync. Cztery różne zachowania:

| Co | Przy ponownym `bootstrap-project.sh` |
| --- | --- |
| `.claude/agents/`, `.cursor/agents/`, `.claude/commands/`, `mcp.json`/`config.toml` | **Zawsze nadpisane** świeżą kopią z kita — traktuj jak wygenerowany kod, nie edytuj ręcznie. `mcp.json`/`config.toml` i stamp dodatkowo **nie są wersjonowane** (ścieżka maszyny) — patrz „`.gitignore` — co z tego wersjonować” |
| `BUGBOT.md`, `.cursor/BUGBOT.md` | **Renderowane na nowo z szablonu** (sekcje Tierów według Profilu). Blok `<!-- project:rules -->` przechodzi bez zmian — tam wpisuj własne reguły projektu. Plik sprzed wprowadzenia bloku jest migrowany po historii szablonu; niepewna migracja = plik bez zmian + ostrzeżenie |
| `AGENTS.md`, `.ai/project.md` | Kopiowane **tylko jeśli brak** — bootstrap nigdy więcej ich nie tyka, update ręczny. `check_kit_status` wypisuje je w osobnej sekcji „wymagają ręcznego przeniesienia", żeby nie obiecywać nadpisania, którego nie zrobi |
| `modules/*.md` (treść instrukcji) | **W ogóle nie kopiowane** — MCP czyta je z `--kit-root` przy każdym `get_bundle`/`get_overlay`. Aktualne bez re-bootstrapu **pod warunkiem**, że serwer wie, gdzie jest klon — patrz niżej |

### Lokalny klon: `uv run --project`, nie `uvx --from`

`uvx --from <katalog>` **nie** czyta kita z tego katalogu w czasie działania. uv buduje koło,
w którym `manifest.yaml` i `modules/` lądują jako `guides/_data`
(`force-include` w `pyproject.toml`), i cache'uje je pod **wersję pakietu**. Wersja nie rośnie
przy zwykłej edycji modułu ani kodu serwera, więc klient dostaje kopię sprzed builda.
Do tego `find_kit_root()` woli `_data` od repo, więc `check_kit_status` traci historię gita.

Objaw: poprawiasz `modules/…`, restartujesz klienta, a `get_bundle` wciąż zwraca starą treść.
Bez komunikatu błędu. To samo dotyczy poprawek w `src/guides/` — serwer nadal biegnie na
starym kodzie.

Dlatego przy źródle lokalnym bootstrap generuje:

```json
"command": "uv",
"args": ["run", "--project", "/sciezka/do/klona", "guides-mcp", …,
         "--kit-root", "/sciezka/do/klona", …]
```

Pakiet ma układ `src/`, więc `uv run` instaluje go jako editable — `_data` w ogóle nie
powstaje, a kod i moduły czytane są wprost z klonu. `--kit-root` nie jest wtedy konieczny,
ale zostaje: nazywa klon wprost, zamiast pozwalać serwerowi go wnioskować.

Przy źródle zdalnym (`git+https://…`) nic się nie zmienia — zostaje `uvx --from`, bo klonu
nie ma, a `_data` z koła jest jedyną i aktualną kopią.

Projekty zbootstrapowane przed tą zmianą mają w `mcp.json` stare `uvx --from` albo
`uv run --directory` — wystarczy `kit-ai reload`.

Skąd wiedzieć **kiedy** re-bootstrapować (bez ciągłego czytania plików kita — tanie, jedno porównanie commitów):

```text
MCP tool: check_kit_status
```

Bootstrap zapisuje `.ai/.kit-bootstrap.json` (commit kita w momencie bootstrapu). `check_kit_status`
porównuje go z aktualnym `HEAD` kita (`git rev-parse` + `git diff --name-only` tylko na ścieżkach
które bootstrap faktycznie kopiuje) i zwraca: aktualny / zmienił się (+ lista plików) / brak stampu
(stary bootstrap sprzed tej funkcji) / brak lokalnej historii git (gdy `--from` to zdalny URL, nie
lokalny klon). Zero kosztu tokenów na nawigację plików — jedno wywołanie tool, agent woła je kiedy
chce sprawdzić stan (np. na początku sesji), nie w pętli.

Gdy pokaże zmiany: `bootstrap-project.sh` ponownie z tymi samymi flagami co poprzednio.

## Slash commands — konwencja nazw


| Prefiks       | Rola                                                 | Przykłady                                                                                                                                          |
| ------------- | ---------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/compact`    | **Cursor only** — alias UI Summarize w tym projekcie | `/compact`                                                                                                                                         |
| `/git-*`      | Start / sync issue / commit / PR                   | `/git-start`, `/git-check`, `/git-commit`, `/git-end`                                                                                               |
| `/create-task` | Pomysł → ocena na tle repo → issue (bez brancha)   | `/create-task`, `/create-task "eksport CSV"`; flagi: `/create-task --help`                                                                          |
| `/create-skill` | Pomysł na skill → skill czy agent → issue (bez brancha) | `/create-skill`, `/create-skill "konwencje migracji"`; flagi: `/create-skill --help`                                                            |
| `/kit-project-begin` | Konfiguracja projektu po `kit-ai install` | `/kit-project-begin`, `/kit-project-begin --yes` |
| `/kit-project-edit` | Jedna zmiana konfiguracji / odstępstwo od modułu / naprawa doctora | `/kit-project-edit "zmień web na angular"`, `/kit-project-edit "nie zgadzam się z …"`, `/kit-project-edit "napraw zgłoszenia doctora"` |
| `/review-*`   | Review tylko do odczytu, raport                      | `/review-backend`, `/review-frontend`, `/review-architecture`, `/review-ui`, `/review-edge`, `/review-tests`, `/review-bugbot`, `/review-security` |
| `/subagent-*` | Praca w dwóch oknach (wymiana raportów)              | `/subagent-backend`, `/subagent-frontend`                                                                                                          |
| `/night-run`  | Nocna praca na liście issue (`/goal` opcjonalny)     | `/goal Wykonaj #150–#157 wg /night-run …`                                                                                                          |




### `/compact` (wyłącznie Cursor)

Skill: `templates/cursor/skills/compact/SKILL.md` → **tylko** `.cursor/skills/compact/`.

Bootstrap **nie** kopiuje tego do Claude / Codex. Nie nadpisuje ani nie „tłumaczy” ich wbudowanego `/compact`.

- **Po co:** w Cursorze jedna komenda `/compact` zamiast szukania UI **Summarize**.
- **Nie** jest wspólną konwencją kita cross-tool.
- **Nie** mylić z `/handoff` (plik + nowy chat).

```text
/compact
```



### `/git-start`, `/git-check`, `/git-commit`, `/git-end` + Superpowers + Autopilot

Wymaga `gh` + `git`. Konwencja: `feat/42-add-cart-coupon`. Pełne zasady: `.cursor/rules/git-branch-pr.mdc`.

#### Podział ról (czytelnie)


| Krok                     | Narzędzie                                                                  | Uwagi                                        |
| ------------------------ | -------------------------------------------------------------------------- | -------------------------------------------- |
| Scope / TDD              | Matt `/grill-me`, `/tdd`                                                   | `/grill-me` tylko przy niejasnym scope; nie mieszać z Superpowers TDD |
| Issue + branch           | `/git-start` (kit)                                                         | Numeracja issue, Conventional name           |
| Sync issue ↔ diff        | `/git-check` (kit)                                                         | Gdy tytuł/body rozjechały się z plikami      |
| Commit(y)                | `/git-commit` (kit)                                                        | Conventional; `--one` / `--split` / `--dry-run` |
| Izolacja (opc.)          | Superpowers `using-git-worktrees`                                          | Na branchu z `/git-start`, nie zamiast niego |
| Review przed pushem      | `/review-bugbot` + **minimalny** stack (`/review-backend` i/lub `/review-frontend`) | Nie wszystkie `/review-*` naraz; format: Severity\|Location\|Finding\|Fix |
| Push + PR                | `/git-end` **lub** Superpowers `finishing-a-development-branch` → opcja PR | Jedno z dwóch. `/git-end` = push + PR (`Closes #N`); **bez** merge; brudne tree → najpierw `/git-commit` |
| CI / komentarze aż green | **Autopilot**                                                              | Po istniejącym PR; bez auto-merge            |
| Merge                    | Ty / `gh pr merge`                                                         | Gdy green → GitHub zamyka issue (`Closes #N`) |


```text
Krótko:   /git-start → kod → [/git-check] → /git-commit → /review-bugbot → /git-end → [Autopilot]
Długo:    [/grill-me] → /git-start → worktree → kod → [/git-check] → /git-commit → finishing| /git-end → Autopilot → merge
```


| Komenda kit  | Co robi                                                                                 |
| ------------ | --------------------------------------------------------------------------------------- |
| `/create-task` | Ocena pomysłu na tle repo → karta issue → utworzenie po akceptacji; `--dry-run` / `--quick` / `--split` / `--no-assign` / `--parent #N`. **Nie** zakłada brancha |
| `/create-skill` | Rozstrzyga skill vs agent, potem karta issue z nazwą, `description` i kryterium odpalenia; `--dry-run` / `--quick` / `--no-assign` / `--parent #N`. **Nie** pisze `SKILL.md` |
| `/kit-project-begin` | Pytania z MCP `list_questions` z propozycjami wykrytymi w repo (zawsze z wolną odpowiedzią) → karta Profilu i `.ai/project.md` → zapis → `reload_workspace`. `--yes` = same propozycje |
| `/kit-project-edit` | (A) jedna odpowiedź: Stack per Tier, codegen, klienci, język, sekcja `project.md` → podgląd → zapis → reload; (B) spór z modułem → grillowanie → `## Odstępstwa od modułów` w `.ai/project.md`; (C) naprawa zgłoszeń doctora → podgląd poprawek w overlayu i bloku `project:rules`; zmiana dla wszystkich projektów → szkic `/create-task` w repo kita. **Nigdy** nie edytuje `modules/` |
| `/git-start` | `#N` / opis / **puste = auto-diff** / `--help` (ręcznie: `gh issue create` / `develop`) |
| `/git-check` | Dopasuj tytuł (EN) i body (język MCP) issue do realnego diffa; `--dry-run`              |
| `/git-commit` | Conventional Commit(s) z diffa; `--one` (jeden) / `--split` / `--dry-run`; odpala pre-commit |
| `/git-end`   | Push + PR z `Closes #N` w body; `--help`; alias `/git-pr`. **Nie** merguje i **nie** zamyka issue od razu — issue zamyka się **po merge** PR |
| `/compact`   | **Cursor only** — skrót czatu (alias UI Summarize); nie Claude/Codex                     |


```text
/git-start --help
/git-start feat add cart coupon
/git-start fix #108 login returns 500
/git-start                    # auto z lokalnego diffa
# … praca zmieniła scope …
/git-check
/git-commit                   # lub --one / --split / --dry-run
# … review …
/git-end --help
/git-end
```

Ręczny odpowiednik:

```bash
gh issue create --title "Add cart coupon" --body "…"
gh issue develop 42 --name feat/42-add-cart-coupon --base dev --checkout
# … praca …
git push -u origin HEAD
gh pr create --base dev --title "feat: add cart coupon" --body "Closes #42"
```

UI: GitHub Issue → Development → **Create a branch** (potem nazwij spójnie `typ/N-slug`).


| Slash                                | Plik szablonu                                    |
| ------------------------------------ | ------------------------------------------------ |
| `/create-task`                       | `templates/shared/agents/create-task.md`         |
| `/create-skill`                      | `templates/shared/agents/create-skill.md`        |
| `/kit-project-begin`                 | `templates/shared/agents/kit-project-begin.md`   |
| `/kit-project-edit`                  | `templates/shared/agents/kit-project-edit.md`    |
| `/git-start`                         | `templates/shared/agents/git-start.md`           |
| `/git-check`                         | `templates/shared/agents/git-check.md`           |
| `/git-commit`                        | `templates/shared/agents/git-commit.md`          |
| `/git-end`                           | `templates/shared/agents/git-end.md`             |
| `/compact` (Cursor)                  | `templates/cursor/skills/compact/SKILL.md`       |
| `/review-architecture`               | `templates/shared/agents/review-architecture.md` |
| `/review-backend`                    | `templates/shared/agents/review-backend.md`      |
| `/review-frontend`                   | `templates/shared/agents/review-frontend.md`     |
| `/review-ui`                         | `templates/shared/agents/review-ui.md`           |
| `/review-edge`                       | `templates/shared/agents/review-edge.md`         |
| `/review-tests`                      | `templates/shared/agents/review-tests.md`        |
| `/review-bugbot`                     | `templates/shared/agents/review-bugbot.md` (manualny odpowiednik natywnego Cursor BugBot — stosuje reguły z `BUGBOT.md` ręcznie, dla klientów bez tej usługi) |
| `/cleanup`                           | `templates/shared/agents/cleanup.md` (znajdź i usuń zbędne scratch/testowe pliki zostawione po weryfikacji — pyta o potwierdzenie) |
| `/subagent-backend`                  | `templates/shared/agents/subagent-backend.md`    |
| `/subagent-frontend`                 | `templates/shared/agents/subagent-frontend.md`   |
| `/teacher-backend`                   | `templates/shared/agents/teacher-backend.md`     |
| `/teacher-frontend`                  | `templates/shared/agents/teacher-frontend.md`    |
| `/teacher-architecture`              | `templates/shared/agents/teacher-architecture.md` |
| `/teacher-agent`                     | `templates/shared/agents/teacher-agent.md`       |
| `/review-security`                   | `templates/shared/agents/review-security.md`      |

### Git worktree (.ai/worktree.mjs)

Zarządzanie worktree przez jedną metodę kita (`node .ai/worktree.mjs …`): przenosi pliki z `.gitignore` (w tym konfiguracje MCP i `.env`) oraz zależności bez doinstalowywania czegokolwiek na VPS.

#### Konfiguracja (`.ai/project.profile.yaml`)

Opcjonalna sekcja w profilu projektu:

```yaml
worktree:
  copy: [ ... ]      # pliki/katalogi kopiowane z głównego checkoutu (bez nadpisywania istniejących)
  link: [ ... ]      # symlink do głównego checkoutu (np. frontend/node_modules); bez domyślnych wpisów
  setup: [ ... ]     # komendy uruchamiane w worktree po copy/link; domyślnie pusta
  venv: auto         # auto | overlay | none (domyślnie auto)
```

Gdy brak sekcji `copy`, skrypt kopiuje istniejące wpisy `MACHINE_FILES` (pliki MCP i stampy kita) + `.env` + `.claude/settings.local.json`.
Polecenia w `setup:` przed uruchomieniem są weryfikowane przez `server-guard.mjs` (na VPS niebezpieczne komendy, np. instalacja paczek, są pomijane).

#### Overlay venv i ograniczenia

Dla Pythona tryb `venv: auto` (oraz `overlay`) tworzy lekki overlay venv bazujący na głównym `.venv`:
- `python -m venv --without-pip` interpreterem z głównego venv (identyczna wersja),
- plik `_kit_worktree.pth` w `site-packages` przekierowuje pakiety instalowane w trybie editable (`-e`) z prefiksem głównego repozytorium na ścieżkę worktree, a następnie dopisuje `site-packages` głównego venv,
- **Ograniczenia**: metadane paczek i entry pointy pochodzą z głównego venv; overlay venv nie posiada wygenerowanych console scripts w `bin/` (testy i komendy uruchamiaj przez `python -m …` lub `uv run --no-sync python -m …`); editable instalowane przez import hook (`import __editable___..._finder`) nie są przekierowywane (ostrzeżenie w logu).

#### Zasady zależności i uprawnień

- **Linkowane zależności są tylko do odczytu**: `node_modules` czy współdzielony `site-packages` nie powinny być modyfikowane z poziomu worktree (postinstall, ensurepip czy instalacja paczek zmieniają środowisko główne).
- **Pliki konfiguracyjne MCP**: kopiowane pliki wskazują ścieżkę `--workspace` głównego checkoutu (jest to zamierzone i bezpieczne).
- **Server guard w worktree**: działa w worktree tylko wtedy, gdy projekt commituje pliki hooków kita (np. `.cursor/hooks/`, `.claude/hooks/`). Doctor **nie** sprawdza obecności hooków w repozytorium; przed założeniem worktree zweryfikuj ręcznie, np. `git ls-files .cursor/hooks .claude/hooks`.


### `/teacher-*` — tryb nauki (przed kodem, nie po)

`/review-*` sprawdza **gotowy diff** i zwraca tabelę findingów. `/teacher-*` działa **zanim** napiszesz kod: bierze Twoją koncepcję (albo bieżący diff, gdy nie podasz argumentu), tłumaczy o co w problemie naprawdę chodzi, pokazuje max 3 opcje z kosztami, wskazuje **jedną** rekomendację i zostawia Ci zadanie do zrobienia samodzielnie.

| Komenda | Zakres |
| --- | --- |
| `/teacher-backend` | Django/DRF (opc. FastAPI, Flask+Pydantic): warstwy, modele, migracje, transakcje, Celery, ACL, pytest, uv/ruff |
| `/teacher-frontend` | React, React Native/Expo Router (opc. Angular): stan serwera vs klienta, granice komponentów, re-rendery, web/native, typy TS, RTL/Playwright |
| `/teacher-architecture` | granice FE/BE, kontrakt API, kiedy **nie** dzielić, infra (Postgres/Redis/Celery/S3), Docker+Taskfile, odwracalność decyzji, ADR |
| `/teacher-agent` | praca z samymi agentami: skille, worktree i izolacja zadań, delegacja do subagentów, autonomia (`/goal` vs `/loop`), pisanie promptów, jak spiąć `/git-*` i `/review-*` w jeden flow |

Kontrakt tych agentów: `readonly` — **nie edytują plików**, nie dają gotowca do wklejenia (szkic ≤ 20 linii), nazywają wzorce po imieniu i mówią wprost, gdy koncepcja jest zła. Czytają `get_bundle` + `get_overlay`, więc uczą na Twoim stacku i Twoim kodzie, nie na `Foo/Bar`.

```
/teacher-backend czy walidację ceny dać do serializera czy do serwisu
/teacher-frontend                 # bez argumentu → uczy o tym, co masz w git diff
/teacher-architecture czy dodać Redisa pod cache koszyka
```

### `/night-run` — lista issue przez noc

Za dnia grillujesz issue (kryteria akceptacji, relacje blocked-by). W nocy `/night-run` działa sam (wznawia go heartbeat `CronCreate`, `/goal` opcjonalny) i daje procedurę: na każdy ticket `/git-start` → test-first → szybkie bramki → `/git-commit` → review na diffie → `/git-end` → CI → merge → jeden raport na PR i zamknięcie issue. Problem zamiast pytania kończy się komentarzem `needs-human` z pytaniami Q1/Q2 na issue i agent idzie dalej. Pełna procedura: `templates/shared/agents/night-run.md`.

Agent jest **orkiestratorem w głównej sesji** (w Claude przez Skill, nie jako subagent). Sam nie czyta kodu: na ticket odpala świeżego subagenta ticketu, a review robi osobny świeży subagent na samym `git diff` (albo — przy skillach review z argumentów — orkiestrator przez Skill, biorąc od skilla tylko tabelę findingów). Dzięki temu żaden kontekst nie puchnie do 200k, a każda tura nie czyta go od nowa. Niczego nie dopisujesz do overlay:

- **Gałąź bazowa:** `dev`, jeśli `origin/dev` istnieje i nie jest w tyle za gałęzią domyślną; inaczej gałąź domyślna repo. Porzucony `dev` nie przejmie nocy.
- **Plik kontekstu nocy** (`~/.cache/night-run-<repo>-<data>/context.md`): mapa aplikacji, konwencje, pułapki toolchainu z pamięci projektu i overlay. Po każdym tickecie orkiestrator dopisuje, co doszło (modele, serwisy, endpointy). Subagent czyta ten plik zamiast AGENTS.md, BUGBOT.md i wszystkich ADR-ów. Katalog w `~/.cache` przeżywa restart hosta (`/tmp` po restarcie kontenera znika). Commit po każdym zielonym kroku, a deny guarda (`server-guard:` / `git-guard:` w powodzie) to reguła, nie awaria — nie obchodzisz jej i nie liczysz do prób naprawy. Na VPS (bundle z `infra:vps-lightweight`) kroki odrzucane przez guard idą jako „tylko CI”, a brak checków CI = brak merge.
- **Bramki jakości:** kroki `run:` z `.github/workflows/*.yml` + sekcja kontroli z `.ai/project.md` (i `codegen:`). Lokalnie tylko szybkie (lint, typecheck, `makemigrations --check`, testy dotknięte ticketem); pełny zestaw testów tylko w CI.
- **Model subagenta ticketu:** `model: <nazwa>` w tekście celu; brak → model sesji.
- **Koszt:** po każdym tickecie snippet `python3` liczy z transkryptów subagentów tury, tokeny (input / cache_creation / cache_read / output), maks. kontekst i czas. Wynik trafia do `NIGHT-RUN REPORT`.
- Wybrana baza, bramki, model i każde założenie trafiają do `NIGHT-RUN REPORT`.

Bez `/goal`, z wykonawcą headless i wskazanym review:

```text
/night-run #150 #151 /headless opencode --timeout 90 "implementacja i testy" /review-edge /review-bugbot
```

`/headless` zastępuje implementację w subagencie ticketu (subagent pilnuje wrappera, sprawdza raport i commituje resztę); skille review uruchamia orkiestrator przez Skill, nieznany skill albo wykonawca (spoza `clients:` lub równy hostowi) zatrzymuje noc na starcie jako needs-human, a klient bez `/headless` wraca do implementacji subagentem. Wykonawca i review każdego ticketu trafiają do `NIGHT-RUN REPORT`.

Pod `/goal` sędzia widzi tylko transkrypt, więc warunek żąda dowodów w rozmowie:

```text
/goal Wykonaj issue #150–#157 wg /night-run, model: sonnet. Koniec, gdy w transkrypcie jest
NIGHT-RUN REPORT, w którym każdy ticket ma: MERGED (wynik gh pr view --json state)
albo needs-human (link do komentarza), albo jest wpis "night-run halted".
```

Uwagi dopisujesz za warunkiem („#155 bez PDF”, „bez merge, same PR-y”, „model: sonnet”) — polecenia z celu mają pierwszeństwo przed procedurą. W Claude `model:` przyjmuje tylko aliasy (`sonnet`, `opus`, `haiku`, `fable`); konkretną wersję modelu wybierasz dla całej sesji: `claude --model <id>`.

#### Pomiar kosztu ticketu na różnych modelach

Tańszy token nie znaczy tańszy ticket: mocniejszy model może zrobić mniej tur i mniej poprawek, a koszt nocy to głównie ponowne czytanie kontekstu (cache_read). Porównanie robisz tak:

1. Wybierz **jeden** ticket średniej wielkości (kilka kryteriów akceptacji, jedna aplikacja backendu), bez decyzji o pieniądzach i zgodach, żeby needs-human nie zepsuł porównania. Zapisz commit bazowy: `git rev-parse origin/<BASE>`.
2. Na każdy model osobny worktree z tego commitu i osobna sesja z dokładnym id modelu:
   ```bash
   git worktree add ../measure-<model> <commit>
   cd ../measure-<model> && claude -p --model <id> "/night-run #<N>, bez merge"
   ```
3. PR służy tylko do pomiaru: po zebraniu wyników `gh pr close <PR> --delete-branch` i `git worktree remove ../measure-<model>`.
4. Metryki: snippet z sekcji „Pomiar kosztu ticketu” w agencie, uruchomiony na transkryptach sesji i jej subagentów (`~/.claude/projects/<projekt>/<sesja>.jsonl` i `…/<sesja>/subagents/*.jsonl`). Koszt liczysz **osobno** dla input, cache_creation, cache_read i output według aktualnego cennika, nie jedną stawką.
5. Jakość: CI zielone za pierwszym razem (t/n), liczba rund poprawek, potwierdzone findingi review, needs-human (t/n).
6. Limit: ile ticketów mieści się w jednym oknie limitu sesji. Okno nie jest publiczne, więc szacujesz: zużycie na ticket w stosunku do zużycia skumulowanego w chwili HTTP 429 we wcześniejszym przebiegu.

Wynik (tabela + rekomendacja modelu domyślnego) trafia do issue pomiaru; zmiana domyślnego modelu to jedna linijka w agencie.


Bootstrap (`--clients`) kopiuje/renderuje shared agents do natywnych ścieżek każdego klienta. Format i mechanizm różnią się per klient:

- **Cursor**: `.cursor/agents/` — natywne slash commands, działa 1:1.
- **Claude Code**: `.claude/agents/` (subagenty, wywołanie przez Task/Agent tool) **oraz** `.claude/commands/` (prawdziwe slash commands `/git-start` itd. — `$ARGUMENTS` wstrzyknięty automatycznie przy kopiowaniu).
- **Codex**: agenty instalowane jako natywne skille w `.codex/skills/<nazwa>/` (renderowane z `templates/shared/agents/*.md` przez `scripts/install_shared_skills.py`). Custom prompts (`.codex/agents/*.toml`) zostały wycofane w Codex CLI — Codex sam ładuje SKILL.md, gdy `description` pasuje do sytuacji.
- **Kiro**: `.kiro/agents/` — kopiowane 1:1, format niezweryfikowany na żywym Kiro.
- **VS Code/Copilot**: `scripts/render_agent_commands.py vscode` → `.github/prompts/*.prompt.md` (wywołanie `/nazwa` w Copilot Chat).
- **Kilo**: `scripts/render_agent_commands.py kilo` → `.kilocode/workflows/*.md` (wywołanie `/nazwa`, `$ARGUMENTS` wspierane).
- **Antigravity**: agenty jako natywne skille w `.agents/skills/<nazwa>/` (`agy` nie zna workflow — patrz `install_agent_skills.py`).
- **opencode**: `scripts/render_agent_commands.py opencode` → `.opencode/command/*.md` (wywołanie `/nazwa`, `$ARGUMENTS` wspierane).
  Guardy kita: plugin `.opencode/plugins/kit-guards.js` + `.opencode/hooks/` (sekcja „Guardrails”).
  Model: projektowy `opencode.json` dostaje przy install i reload `model` z globalnego configu
  OpenCode, tylko gdy projekt nie ma własnego `model`. Katalog jak w OpenCode:
  `$XDG_CONFIG_HOME/opencode/` albo `~/.config/opencode/` (na Windows `%USERPROFILE%\.config\opencode\`);
  pliki `config.json`, `opencode.json`, `opencode.jsonc` (komentarze dozwolone), ostatni z `model`
  wygrywa. Kolejność: `model` w projektowym `opencode.json` → globalny config → domyślny model
  OpenCode. Nadpisanie: wpisz `model` w projektowym `opencode.json` — reload go nie rusza. Kopia
  nie śledzi późniejszych zmian globalnego configu; żeby ją odświeżyć, usuń `model` z projektu
  i zrób reload. Inne pola globalnego configu (provider, agent) nie są kopiowane.
  Do tego `/goal` i `/loop` jak w Claude Code: `templates/opencode/command/{goal,loop}.md` + plugin `.opencode/plugins/kit-loop.js`, który po `session.execution.succeeded` wysyła kolejną turę. Stop: `<promise>DONE</promise>` w odpowiedzi, Esc, `/goal clear` / `/loop stop`, limit tur (goal 25, loop 10, `max=N`); `/loop 5m <zadanie>` powtarza co interwał.

Formaty VS Code/Kilo/Antigravity/opencode oparte o publiczną dokumentację tych klientów (sierpień 2026) — nie testowane na żywych instalacjach; jeśli coś nie zadziała, zgłoś różnicę i popraw `scripts/render_agent_commands.py`.

Po skopiowaniu/wyrenderowaniu **zrestartuj** okno IDE — agenty/komendy ładują się przy starcie.

### Wywołanie

```text
/git-start feat #42 cart coupon   # lub bez # — utworzy issue
/git-check                        # gdy diff rozjechał się z opisem issue
/git-commit                       # Conventional Commit(s)
/review-backend przejrzyj zmiany w backend/apps/products/
/git-end
```

```text
/subagent-backend przejrzyj zmiany…   # potem wklej raport do /subagent-frontend w drugim oknie
```



## Skille kita — wspólne źródło

Skill to wiedza, którą model ładuje **sam**, gdy `description` pasuje do sytuacji —
w odróżnieniu od agenta (`/nazwa`), którego ktoś musi wywołać. Jedno źródło:
**`templates/shared/skills/<nazwa>/SKILL.md`** (+ opcjonalne `references/`, `scripts/`,
`assets/`). Rozkłada je `scripts/install_shared_skills.py`.

| Klient | Gdzie ląduje | Jak działa |
|--------|--------------|------------|
| claude | `.claude/skills/` | natywnie, z zasobami |
| cursor | `.cursor/skills/` | natywnie, z zasobami (obok Cursor-only `/compact`) |
| antigravity | `.agents/skills/` | natywnie, z zasobami |
| codex | `.codex/skills/` | natywnie, z zasobami |
| vscode | `.github/prompts/` | degradacja: komenda `/nazwa` |
| kiro | `.kiro/agents/` | degradacja: komenda `/nazwa` |
| kilo | `.kilocode/workflows/` | degradacja: komenda `/nazwa` |
| opencode | `.opencode/command/` | degradacja: komenda `/nazwa` |

**Degradacja kosztuje dwie rzeczy:** skill przestaje odpalać się sam (trzeba wpisać
`/nazwa`) i gubi wszystko poza `SKILL.md`, bo komenda to jeden plik. Instalator mówi
o gubionych katalogach na stderr. Skill, którego sens leży w `scripts/`, będzie
w pięciu na osiem klientów wydmuszką — wtedy to prawdopodobnie powinien być agent.

`.claude/skills/` i `.agents/skills/` dzielisz ze skillami spoza kita (`npx skills add`),
więc odznaczenie klienta kasuje tam **tylko** katalogi o nazwach ze wspólnego źródła,
nigdy całego katalogu skilli.

Nowy skill zakładasz przez **`/create-skill`** (issue), a piszesz według skilla
`skill-authoring` — to on trzyma zasady frontmatter, sufity długości i kryteria odpalania.

## `/headless` — zadanie dla innego klienta

Z dowolnego klienta kitu (host) zlecasz zadanie innemu klientowi uruchomionemu bez
interfejsu (wykonawca). Host czeka, wrapper sprząta procesy, host streszcza wynik.

```text
/headless <wykonawca> [--model <id>] [--timeout <min>] [--heartbeat <min>] "<treść>"
```

| Flaga | Znaczenie |
|-------|-----------|
| `--model <id>` | Model sesji wykonawcy w jego formacie (`haiku`, `anthropic/claude-haiku-5-5`) |
| `--timeout <min>` | Limit w minutach, domyślnie 60; po nim drzewo procesów jest zabijane (kod `124`) |
| `--heartbeat <min>` | Co ile minut linia stanu `[headless] ♥` w wyjściu i logu, domyślnie 10 |

Inna flaga = błąd z listą dozwolonych. Treść idzie do wykonawcy słowo w słowo, plus stała
stopka: na branchu `typ/<N>-slug` linia „Ticket #N: przeczytaj `gh issue view N --comments`”
(branch bez numeru — bez tej linii), katalog runu na logi testów i pliki robocze, zakaz
`git stash` / `git checkout` / `git reset` (porównanie z bazą przez
`git worktree add --detach <katalog runu>/base <ref>` i `git worktree remove` na końcu),
plan 5–10 kroków przy tickecie z więcej niż 3 kryteriami albo więcej niż jedną aplikacją,
test-first z lokalnym commitem po każdym zielonym kroku, lokalnie tylko testy dotknięte
zmianą i szybkie bramki (pełny zestaw robi CI), na VPS `uv run --no-sync`, maks. 2 próby
naprawy tego samego błędu, raport `## Zmiany` / `## Testy` / `## Problemy`. Dlatego
`/headless <wykonawca> "implementacja i testy"` na branchu ticketu wystarcza.
W logu runu linia `[headless] ticket #N`.
Push i PR robi host (`/git-end`) po review commitów.

**Log i heartbeat.** Wrapper przechwytuje wyjście wykonawcy, przepuszcza je dalej i zapisuje
do `.ai/headless-runs/<start>-<wykonawca>/headless.log` (katalog sam się ignoruje w gicie; przy starcie kasuje runy poza 5 najnowszymi);
ścieżka logu to pierwsza linia wyjścia. Co `--heartbeat` minut dopisuje
`[headless] ♥ <min> min | pliki: <git status --short> | commity: <od startu> | ostatnio: <linia>`,
a po dwóch interwałach bez wyjścia — `[headless] możliwe zacięcie: brak wyjścia od X min`
(bez zabijania; to robi `--timeout`). Liczy to Node, nie model — zero tokenów. Podgląd na żywo
w osobnym terminalu: `tail -f <log>`; agent czyta stan jedną linią:
`grep '^\[headless\]' <log> | tail -1`.

**Raport końcowy** — zawsze, także po timeoucie (`124`) i po SIGINT / SIGTERM / SIGHUP wrappera (nie po SIGKILL): `git status
--short`, commity wykonawcy od startu (`git log <start>..HEAD --oneline`), nowe wpisy
`git stash list` z ostrzeżeniem `UWAGA` (bez auto-`pop` — konflikt) i ostatnie 20 linii
wykonawcy. Agent `/headless` przenosi ostrzeżenie o stashu do raportu dla użytkownika.

**Reguły.** Wykonawca musi być w `clients:` Profilu, mieć tryb headless z guardami kita
i być **inny niż host** — `/headless <host>` z tego samego hosta kończy się błędem z listą
dozwolonych wykonawców.

| Wykonawca | Komenda | Model | Treść |
|-----------|---------|-------|-------|
| `claude` | `claude -p --permission-mode bypassPermissions` | `--model` | stdin |
| `opencode` | `opencode2 run --standalone --auto` (bez `opencode2` w PATH: `opencode run …`) | `--model provider/model` | argument |
| `antigravity` (alias `gemini`) | `agy -p "<treść>" --dangerously-skip-permissions --model … [--effort …]` (agy 1.4.8) | `--model` → `.agents/agy.json` → `gemini-3.8-flash-medium`; `--effort` tylko z `.agents/agy.json` | argument |

**Fallback przy limicie.** Limit dostawcy albo brak binarki u wykonawcy → wrapper przekazuje
tę samą treść 1:1 pozostałym z `FALLBACK_ORDER` (`opencode`, `antigravity`), jeśli są
w `clients:` i nie są hostem; zastępca bierze swój domyślny model. Limit u ostatniego →
kod `75` i zadanie przejmuje host (agent `/headless`, krok 2). Z Claude:
`/headless opencode "…"` → `gemini` → Claude sam; `/headless gemini "…"` → `opencode` → Claude sam.
Limit rozpoznaje tekst w ogonie wyjścia; agy po błędzie dodatkowo `agy -p "/quota"` — grupa
`Gemini Models` na 0% = limit, reset z najwcześniejszego wyczerpanego wiersza.

**`.agents/agy.json`** — agy nie ma projektowego configu z modelem (tylko globalny
`~/.gemini/antigravity-cli/settings.json`), więc wrapper czyta ten plik (gitignored):
`{"model": "gemini-3.8-flash-high"}` albo `{"model": "gemini-3.8-flash", "effort": "high"}`.
Poziom siedzi w sufiksie nazwy (`agy models`) albo w `effort` przy nazwie bazowej — nie oba:
agy odrzuca `--effort` niezgodny z sufiksem.

Wszyscy wykonawcy mają edycje i bash bez pytań. Guardy kita (git-guard, sensitive-files-guard)
działają u `claude` i `opencode`: hooki Claude Code i plugin `kit-guards.js` w OpenCode (#166).
U `antigravity` hooki `.agents/hooks.json` działają mimo `--dangerously-skip-permissions`
(deny git-guard sprawdzone na agy 1.4.8). Nowy wykonawca
= wiersz w `EXECUTORS` w `templates/shared/headless/headless.mjs` i w `HEADLESS_EXECUTORS`
w `scripts/bootstrap-project.sh`; opcjonalnie alias w `EXECUTOR_ALIASES` i miejsce w `FALLBACK_ORDER`.

Codex ma guardy kitowe przez PreToolUse (`node "$(git rev-parse --show-toplevel)/.codex/hooks/invoke-hook.js"
<guard>.mjs --to codex`, #199) — nie jest jeszcze wykonawcą headless (patrz `EXECUTORS` w `headless.mjs`),
ale może być **hostem** i wywoływać `claude` lub `opencode` jako wykonawcę.
Codex odpala projektowy `.codex/hooks.json` dopiero po zaufaniu hookom repo (`/hooks` w Codexie);
bez tego guardy leżą na dysku, ale nie działają.
VS Code (Copilot) ma guardy kitowe przez `.github/hooks/kit-guards.json`
(`node .github/hooks/invoke-hook.js <guard>.mjs --to copilot`, #200) — nie jest wykonawcą
ani hostem headless w instalacji kita, ale jego agent mode egzekwuje tę samą politykę.
Cursor (`cursor-agent -p`) ma tryb headless, ale nie jest wykonawcą kita (patrz `EXECUTORS`
w `headless.mjs`) — może natomiast być **hostem** (macierz niżej). Antigravity jest wykonawcą
(`agy -p`), ma guardy kitowe przez `.agents/hooks.json`
(`node hooks/invoke-hook.js <guard>.mjs --to antigravity`, #201). Kiro i Kilo — bez trybu
headless w instalacji kita.

**Macierz host × wykonawca** (przy kliencie w `clients:`; wykonawca = klient z guardami
kita i wpisem w `EXECUTORS`):

| Host \ wykonawca | `claude` | `opencode` | `gemini` (`antigravity`) |
|------------------|----------|------------|--------------------------|
| Claude Code | — (sam siebie) | tak | tak |
| OpenCode | tak | — (sam siebie) | tak |
| Antigravity | tak | tak | — (sam siebie) |
| Codex, Cursor, VS Code, Kiro, Kilo | tak | tak | tak |

**Instalacja.** Agent `/headless` trafia do każdego klienta z `--clients`, gdy lista zawiera
co najmniej dwóch wykonawców (dziś: `claude`, `opencode` i `antigravity`; `all` też). Bootstrap wpisuje w plik
agenta id hosta, a wrapper kładzie w `.ai/headless.mjs`. Mniej niż dwóch wykonawców
= agent i wrapper znikają przy reload.

**Model — trzy warstwy:**

| Warstwa | Skąd model |
|---------|------------|
| Agent `/headless` u hosta | `models.<host>.light` w Profilu (#168), bez mapowania — model sesji hosta |
| Sesja wykonawcy | `--model` → projektowy config wykonawcy (`model` w `opencode.json`, #167; `.agents/agy.json` dla agy) → domyślny model wykonawcy. Wrapper podaje tylko `--model`; resztę rozstrzyga CLI wykonawcy. W linked worktree config z głównego checkoutu idzie jako `OPENCODE_CONFIG`, a raport mówi `CONFIG=main-checkout`/`CONFIG=missing` (#300) |
| Agenci kitu wołani w sesji wykonawcy | `models.<wykonawca>.<tier>` w Profilu, bez mapowania — model sesji wykonawcy |

**Sprzątanie procesów.** Wrapper uruchamia wykonawcę we własnej grupie procesów (Unix)
i po zakończeniu, błędzie albo timeoucie zabija całe drzewo — z LSP i serwerami MCP
(Windows: `taskkill /T /F /PID` na wykonawcy i na potomkach zebranych w trakcie przez
`Get-CimInstance Win32_Process` co 5 s — Windows nie ma grup procesów, a po wyjściu rodzica
`/T` nie widzi już dzieci). OpenCode leci z `--standalone`, żeby jego serwer był procesem
potomnym, a nie usługą w tle. Proces żyjący krócej niż 5 s może umknąć snapshotowi.
Zabicie samego wrappera (SIGINT / SIGTERM / SIGHUP — np. koniec sesji hosta) też sprząta
drzewo wykonawcy. Na Windows shim `.cmd` z npm (`opencode2.cmd`) wrapper zamienia na
binarkę `.exe`, którą shim wskazuje (`"%dp0%\…\x.exe"`), i uruchamia ją bez powłoki. Shim
bez `.exe` jest odrzucany: `cmd.exe` rozbiłby wieloliniową treść w argumencie. Nazwa binarki
działa jak nazwa wykonawcy (`/headless opencode2` = `/headless opencode`). Sesje wykonawców zostają na
dysku (historia `claude` i `opencode`); wrapper ich nie usuwa.

## Guardrails — bezpieczeństwo

Jedno źródło polityki: **`templates/shared/guards/`**. Bootstrap kopiuje je do katalogu
hooków wybranego klienta (`--clients`), więc Claude Code, Cursor, OpenCode, Codex, VS Code
(Copilot) i Antigravity egzekwują dokładnie te same reguły.

| Guard | Klient | Zachowanie |
|-------|--------|------------|
| `git-guard.mjs` | Claude, Cursor, OpenCode, Codex, VS Code (Copilot), Antigravity | **deny**: `git reset --hard`, `git clean -f`, force push i zwykły push na `main`/`master`/`dev` (`--force` / `-f` / `--force-with-lease` / plus-refspec), `git branch -D`, `git checkout .` / `checkout --`, rekursywne `rm` na szerokiej ścieżce (`~`, `/`, `..`, katalogi domowe), mutacja / `sed -i` / redirect do `~/.ssh`, `/etc`, `C:\Windows`, `Program Files`, `~/.claude/settings*.json`. Reszta **allow** — także `git stash`, `git restore`, `find -delete`, `rm -rf` w repo |
| `sensitive-files-guard.mjs` | Claude, Cursor, OpenCode, Codex, VS Code (Copilot), Antigravity (tylko narzędzia plikowe — bez Basha) | **deny** odczyt i zapis sekretów (`.env*` poza `.env.example|sample|template`, `*.pem|key|p12|pfx`, `id_rsa*`, `id_ed25519*`, `.netrc`, `credentials.json`, `.git/objects|refs|hooks`); **deny** oczywisty odczyt sekretu przez Bash — komenda czytająca (`cat`, `head`, `tail`, `less`, `more`, `bat`, `grep`, `rg`, `sed`, `awk`, `xxd`, `base64`, `strings`, `source`/`.`, `rtk read`, `rtk grep`) z argumentem będącym ścieżką sekretu; segmenty po `;`/`&`/`&&`/`||`/`|`, prefiksy `sudo`/`env`/`rtk` (z opcjami, `rtk proxy`, `VAR=1`; i powłoka z `-c`), podstawienia `$(...)`; pierwszy argument `grep`/`rg`/`sed`/`awk` to wzorzec, a cel przekierowania (`> .env`) to zapis — przechodzą; Bash pilnują wszyscy poza Antigravity; **deny** ręczną edycję lockfile (`package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, `bun.lockb`, `bun.lock`, `uv.lock`, `poetry.lock`, `Pipfile.lock`, `Cargo.lock`) — odczyt lockfile wolny |
| `server-guard.mjs` | Claude, Cursor, OpenCode, Codex, VS Code (Copilot), Antigravity | Tylko VPS (decyzja w runtime): **deny** kontenery (`docker`/`podman`, poza `ps`/`images`/`logs` bez `-f`), instalację paczek w każdym ekosystemie (`uv`/`pip`/`bun`/`npm`/`pnpm`/`yarn`/`cargo`/`go`/`apt`/`corepack`), pobieranie przez launchery (`npx`/`bunx`/`pnpm dlx`/`yarn dlx`/`uvx`, poza trybem offline), buildy (`next`/`nuxt`/`astro`/`vite`/`webpack`/`tsup`/`cargo`/`turbo run build`, `expo`, `eas`), e2e (`playwright`/`cypress`/`maestro`, narzędzia Playwright MCP), `pytest -n`; wrappery `task`/`bun|npm|pnpm|yarn run` rozwijane przy `reload`. Na PC i w CI **allow** |
| `bash-guard.mjs` | Claude | Tylko Windows: **deny** `pwsh` / `powershell` / `cmd` uruchamiane z narzędzia Bash — agent używa Git Basha. Narzędzie PowerShell nie jest blokowane |
| `linters-guard.mjs` | Claude | PostToolUse po Edit/Write: format → lint edytowanego pliku (ruff, prettier, eslint, shellcheck, hadolint, yamllint), tylko gdy repo ma config danego narzędzia; wynik wraca do modelu jako `additionalContext`, nigdy nie blokuje |
| `rtk-check.mjs` | Claude | SessionStart: brak `rtk` w PATH lub hooka `rtk hook claude` w `~/.claude/settings.json` → instrukcja `rtk init -g --auto-patch` dla użytkownika; kit sam nic w `~/.claude` nie zmienia |
| `rtk-rewrite.json` | Copilot | `.github/hooks/`: PreToolUse → `rtk hook copilot` przepisuje komendy bash na `rtk <cmd>`. Copilot nie ma globalnego trybu rtk, stąd per-repo z kita. Pozostali klienci (Claude, Cursor, Codex, OpenCode) mają rtk globalnie per maszyna — instrukcja w `modules/core/tooling-rtk.md` |
| `kit-guards.json` | Copilot | `.github/hooks/`: PreToolUse → `node .github/hooks/invoke-hook.js <guard>.mjs --to copilot` dla git-guard, server-guard i sensitive-files-guard. VS Code czyta PascalCase `PreToolUse` i `hookSpecificOutput.permissionDecision`; dla Copilot CLI zakładamy ten sam plik i top-level `permissionDecision` (niezweryfikowane). `deny` blokuje wywołanie, `allow` = pusty stdout (brak opinii, natywne potwierdzenia VS Code zostają) |
| `.agents/hooks.json` | Antigravity | `.agents/hooks/`: PreToolUse (nazwany hook `kit-guards`) → `node hooks/invoke-hook.js <guard>.mjs --to antigravity`. Matchery: `run_command` → git-guard + server-guard; `call_mcp_tool\|^mcp_` → server-guard; `^(view_file\|write_to_file\|replace_file_content\|multi_replace_file_content\|edit_file)$` → sensitive-files-guard. Plik dzielimy z użytkownikiem — `antigravity_hooks.py` scala i prune'uje tylko klucz `kit-guards`. `deny` blokuje wywołanie, `allow` tylko deleguje (nie auto-approve'uje) |

**Zero `ask`** (ADR 0006): Guard odpowiada `allow` albo `deny`. W auto mode `ask` z hooka
blokuje tak samo jak prompt, więc bramka, która pyta, nie jest automatyczna. Model dostaje
`permissionDecisionReason` i sam dobiera bezpieczną alternatywę. Git odzyska wszystko
w repo; poza repo pilnujemy tylko katalogów systemowych i sekretów — resztę gate'uje
natywna permission klienta (`cwd` + `additionalDirectories`).

**Granica sensitive-files-guarda pod Bash (#231).** Guard blokuje **oczywiste**
odczyty sekretów — komenda czytająca z jawną ścieżką sekretu, w tym forma po
przepisaniu przez RTK (`cat .env` → `rtk read .env`, `grep KEY .env` → `rtk grep
KEY .env`). Nie jest piaskownicą: `python -c "open('.env')"`, `grep -r KEY .` ani
zapis sekretu przez Bash (`echo X > .env`, `tee .env`) przechodzą. Świadomie poza
zakresem jest też każda inna komenda ze ścieżką sekretu (`cp .env.example .env`,
`ls -la .env`, `rm .env`, `git check-ignore .env`). Parser jest tekstowy
(split po `;`/`&`/`&&`/`||`/`|` + prefiksy), a nie AST — upgrade ścieżką wspólnego
parsera z server-guardem dopiero przy realnym omijaku, nie przez doklejanie wzorców.

**Jeden dialekt, adapter na brzegu.** Skrypty polityki mówią wyłącznie kontraktem
Claude Code (`hookSpecificOutput.permissionDecision`). Cursor (`permission`), OpenCode
(`{ tool, input }` → `{ decision, reason }`), Copilot (nazwy narzędzi runtime, `tool_input`
jako string) i Antigravity (`{ toolCall: { name, args } }` → `{ decision, reason }`) mają
własne kształty, więc `invoke-hook.js` tłumaczy — i to jedyne miejsce w kicie, które
wie o różnicy między klientami.

| Klient | Wywołanie | Kontrakt |
|--------|-----------|----------|
| Claude Code | `node .claude/hooks/<guard>.mjs` | natywny, bez adaptera |
| Cursor | `node .cursor/hooks/invoke-hook.js <guard>.mjs --to cursor [--tool Read\|Write]` | tłumaczony przez adapter |
| OpenCode | plugin `.opencode/plugins/kit-guards.js` → `node .opencode/hooks/invoke-hook.js <guard>.mjs --to opencode --tool Bash\|Read\|Edit\|Write` | tłumaczony przez adapter |
| Codex | `node "$(git rev-parse --show-toplevel)/.codex/hooks/invoke-hook.js" <guard>.mjs --to codex` | tłumaczony przez adapter; wyjście jak Claude Code (`hookSpecificOutput.permissionDecision`) |
| Copilot (VS Code + CLI) | `node .github/hooks/invoke-hook.js <guard>.mjs --to copilot` | tłumaczony przez adapter; deny = top-level `permissionDecision` + `hookSpecificOutput`, allow = pusty stdout |
| Antigravity | `node hooks/invoke-hook.js <guard>.mjs --to antigravity` (cwd = katalog `hooks.json`, czyli `.agents/`) | tłumaczony przez adapter; wyjście `{ decision, reason }` (allow = `{"decision":"allow"}`) |

Cursor: `beforeShellExecution` → git-guard + sensitive-files-guard, `beforeReadFile` →
sensitive-files-guard (`--tool Read`), `preToolUse` z matcherem `Write` → sensitive-files-guard
(`--tool Write`).
`--tool` dopisuje `tool_name`, którego payload Cursora nie niesie. Wszystkie wpisy mają
`failClosed: true` — padnięty Guard (brak JSON) blokuje akcję, a nieczytelny payload
daje **deny**. `invoke-hook.js` po wypisaniu JSON **zawsze kończy exit 0** (niezerowy
exit ukrywa payload przy failClosed).

OpenCode (`--clients opencode`): bootstrap kładzie `git-guard.mjs`, `sensitive-files-guard.mjs`
i `invoke-hook.js` w `.opencode/hooks/` oraz plugin V2 `.opencode/plugins/kit-guards.js`.
Plugin podpina się pod `tool.execute.before`: `shell` (dawniej `bash`) → git-guard +
server-guard + sensitive-files-guard, `read` /
`edit` / `write` / `multiedit` → sensitive-files-guard, `patch` → sensitive-files-guard dla każdego
pliku z `patchText` (także celu `Move to`). Nazwy i pola narzędzi sprawdzone na opencode 2.0.24.
Działa niezależnie od `permission` w `opencode.json`, także przy `allow` na bash i edycje. Przy
deny narzędzie kończy się błędem, a model widzi `Zablokowane przez guard kita — <powód z guarda>`
i dobiera inną drogę. Awaria guarda, timeout (10 s) albo wejście bez oczekiwanego pola
(`command`, `path`) = deny. `grep` i `glob` nie są pilnowane — tak samo jak w Claude Code.

Codex (`--clients codex`): bootstrap kładzie guardy, `invoke-hook.js` i `server-guard.json`
w `.codex/hooks/` oraz `.codex/hooks.json` (PreToolUse). Powłoka (`Bash` / `shell` /
`local_shell` / `exec_command`, `command` jako string albo argv) → git-guard + server-guard +
sensitive-files-guard;
Playwright MCP → server-guard; `apply_patch` i `Read|Edit|Write|…` → sensitive-files-guard,
dla `apply_patch` po kolei na każdej ścieżce z nagłówków `*** Add|Update|Delete File:` /
`*** Move to:` (patch bez ścieżek = deny). Ścieżka hooka liczona od roota repo
(`git rev-parse --show-toplevel`), więc sesja z podkatalogu też jest pilnowana. Nazwy narzędzi
i pola payloadu nie są sprawdzone na żywym Codexie — adapter przyjmuje warianty wyżej.
Bootstrap nadpisuje `.codex/hooks.json` (`cp`) — własne wpisy dopisz po każdym reloadzie.
Wymaga `node` w PATH (OpenCode działa na Bunie, guardy na Node). Tylko API pluginów V2 (`export default { id, setup }`, jak `kit-loop.js`); `bash-guard`,
`linters-guard` i `rtk-check` zostają tylko w Claude Code.

Copilot (`--clients vscode`): bootstrap kładzie guardy, `invoke-hook.js` i `server-guard.json`
w `.github/hooks/` oraz plik `kit-guards.json` (PreToolUse, obok hooka `rtk-rewrite.json`
z #67). Plik używa PascalCase `PreToolUse`, który czyta VS Code; że ten sam plik i kształt czyta
Copilot CLI — zakładamy, niezweryfikowane. Adapter `--to copilot` sprowadza nazwy narzędzi
(Copilot CLI: `bash` / `view` / `create` / `edit`; VS Code: `run_in_terminal`,
`create_and_run_task`, `read_file`, `create_file`, `replace_string_in_file`) do nazw Claude
i parsuje `tool_input` (string JSON, `filePath`/`path`); `apply_patch` i
`multi_replace_string_in_file` idą przez guard ścieżka po ścieżce. Narzędzie plikowe bez
ścieżki = deny. Narzędzia MCP VS Code (`mcp_<server>_<tool>`) server-guard rozpoznaje jak
`mcp__…`. Trzy guardy (git-guard, server-guard, sensitive-files-guard) biegną jako osobne
wpisy `PreToolUse` bez `matcher` (native VS Code go nie zna). Deny wychodzi jako nadzbiór
(top-level `permissionDecision` + `hookSpecificOutput`); allow to pusty stdout — jawne
`allow` w VS Code auto-approve'owałoby każde narzędzie i wyłączało natywne potwierdzenia.
Timeout hooka (`timeout: 5`) przepuszcza wywołanie (fail-open). Znana luka: `grep_search`
i `file_search` nie są mapowane — sensitive-files-guard ich nie widzi. Najbardziej restrykcyjna
decyzja wygrywa — `deny` blokuje wywołanie w agent mode. Wymaga `node` w PATH.
`bash-guard` / `linters-guard` / `rtk-check` zostają w Claude Code — Copilot ma jedno
narzędzie powłoki, więc nie ma czego rozdzielać.

Antigravity (`--clients antigravity`): bootstrap kładzie guardy, `invoke-hook.js` i
`server-guard.json` w `.agents/hooks/` oraz workspace'owy `.agents/hooks.json` (nazwany hook
`kit-guards`, PreToolUse). Plik dzielimy z użytkownikiem — `scripts/antigravity_hooks.py`
scala przy install i prune'uje przy odznaczeniu wyłącznie klucz `kit-guards`, więc własne
hooki zostają (nieparsowalny plik → `.bak` i wpis kita od zera). Komendy hooków startują
z katalogu, w którym leży `hooks.json`, stąd `node hooks/invoke-hook.js … --to antigravity`.
Adapter sprowadza narzędzia runtime (`run_command` z `CommandLine`, `view_file`
z `AbsolutePath`, `write_to_file` / `replace_file_content` / `multi_replace_file_content` /
`edit_file` z `TargetFile`, MCP jednym narzędziem `call_mcp_tool` z `ServerName` / `ToolName` /
`Arguments` → `mcp__<server>__<tool>`) do nazw i pól, które znają guardy; brak pola, którego
guard potrzebuje, = deny. Sprawdzone na żywej sesji `agy` 1.3.0: `allow` nie omija polityki
uprawnień Antigravity (w `-p` komenda i MCP dalej wymagają reguły `permissions.allow`),
pusta decyzja i awaria hooka (exit ≠ 0) = deny, deny działa też z
`--dangerously-skip-permissions`. Zachowanie przy przekroczeniu `timeout: 10` niesprawdzone.
Znana luka: `grep_search`, `find_by_name` i `list_dir` nie są mapowane — sensitive-files-guard
ich nie widzi. Tak samo `view_file_outline` i `view_code_item` (w `agy` 1.3.0 niedostępne
w środowisku narzędzi, argumentów nie dało się podejrzeć) — matcher plikowy jest zakotwiczony
`^(...)$`, więc ich nie łapie. Pozostałe nazwy zapisu z binarki (`create_file`, `write_file`,
`delete_file`) też poza mapą, bo nie pojawiły się w żywych payloadach. Wymaga `node` w PATH. Sprawdzone na `agy` 1.3.0 — `/hooks` listuje hook
`kit-guards`; `bash-guard` / `linters-guard` / `rtk-check` zostają w Claude Code.

Guardy są w `.mjs` i idą przez `node` — bez basha, więc bez wykrywania Git Basha na
Windows i bez otwartych okien konsoli.

## Server guard (VPS) — twarda blokada ciężkich komend

Po incydencie z 2026-10-15 (restart VPS po `uv run` bez `--no-sync`, ADR 0009)
sama reguła tekstowa z `infra:vps-lightweight` nie wystarcza — subagent pod
night-run nie czyta overlayu tak uważnie jak sesja interaktywna. Dlatego kit ma
twardy guard `templates/shared/guards/server-guard.mjs`: na VPS odrzuca tylko
komendy, które mogą zawiesić serwer albo uderzyć w inne usługi na nim. Reszta
pracy (edycja, git, lint, typecheck, testy) przechodzi.

**Kiedy guard jest aktywny.** Decyzja zapada w momencie wywołania, nie przy
instalacji — Profil i `.claude/settings.json` są commitowane i wspólne dla PC
i VPS. Kolejność: `server.guard: off` w Profilu → allow; `KIT_HOST_PROFILE` /
`GUIDES_HOST_PROFILE` = `vps` / `local` → wymuszenie (tylko gdy heurystyka się
myli; normalnie niczego nie eksportujesz); heurystyka 1:1 z `host_profile.py`
(Linux, nie CI, nie WSL, CPU ≤ 2, RAM ≤ 8 GB, swap 0, wirtualizacja albo brak
desktopu) → aktywny; w pozostałych przypadkach → allow. Na PC i w CI ten sam
zainstalowany guard przepuszcza wszystko.

**Gdzie guard działa, a gdzie nie.** Zakres jest per host i rozstrzyga się w
runtime, tym samym plikiem hooka:

- **Aktywny:** mały linuksowy VPS albo kontener serwerowy (heurystyka wyżej:
  CPU ≤ 2, RAM ≤ 8 GB, swap 0, wirtualizacja albo brak desktopu).
- **Nieaktywny:** Windows (także Git Bash i PowerShell), macOS, WSL, Codespaces /
  devcontainer i CI — ten sam zainstalowany guard przepuszcza tam wszystko.

Nic nie ustawia się per projekt: ten sam zacommitowany guard działa identycznie
w repo kita i w projektach aplikacyjnych na obu maszynach — na
PC nie blokuje, na VPS blokuje. Osobnej konfiguracji „tylko lokalnie” nie ma.

**Korekta heurystyki per maszyna.** Gdy heurystyka pomyli się w którąkolwiek
stronę, wymuś profil zmienną środowiskową na **tej maszynie** — nie w repo:

```sh
# Linux / VPS: ~/.profile albo ~/.bashrc (dotyczy tylko tego hosta)
export KIT_HOST_PROFILE=local   # PC, który heurystyka fałszywie uznała za VPS
export KIT_HOST_PROFILE=vps     # VPS, którego heurystyka nie rozpoznała
```

```powershell
# Windows (PowerShell): trwała zmienna użytkownika, nowe powłoki ją widzą
setx KIT_HOST_PROFILE local
```

Nie używaj do tego `server.guard: off` w Profilu: Profil jest commitowany, więc
wyłączyłby guard **także na VPS**. `server.guard: off` ma sens tylko w repo, które
nigdy nie trafia na VPS.

**Wdrożenie nowej wersji guarda w projekcie.** Guardy jadą z bootstrapem/`reload`,
nie osobno:

1. Zaktualizuj klon kita (`git pull`).
2. W projekcie uruchom `kit-ai reload` — podmienia pliki hooków i renderuje
   `server-guard.json` na nowo.
3. Zacommituj zmienione pliki hooków w projekcie (`.claude/hooks/…`, `.codex/…`
   itd.) — to one jadą na VPS po `git pull`.

**Domyślne deny kita** (każde z powodem i alternatywą; `allow` wygrywa z `deny`):

| Kategoria | Deny | Allow (świadomie) | Powód / alternatywa |
|---|---|---|---|
| Kontenery | `docker`, `docker-compose`, `docker compose`, `podman` — każda podkomenda poza allow obok (także `stop`, `rm`, `down`, `kill`, `restart`, `prune`, `compose config`) | `ps`, `images`, `inspect`, `logs` bez `-f`, `version`, `info`, `compose ps` | budowanie i uruchamianie kontenerów tylko w CI; na hoście działają cudze kontenery |
| Paczki | `uv sync`, `uv add`, `uv remove`, `uv lock`, `uv pip install` / `uv pip sync`, `uv tool install`, `pip install` (także `pip3.12`), `uv run` bez `--no-sync`, `uv run --with` / `--with-requirements` (także z `--no-sync`), `bun install` / `add` / `remove` / `i` / `a` / `update`, `npm install` / `ci` / `add` / `it` / `update` / `up`, `pnpm install` / `add` / `remove` / `update`, `yarn install` / `add` / `remove` / `upgrade`, goły `yarn` | `uv run --no-sync …`, `uvx --offline …` / `UV_OFFLINE=1` | instalacja kompiluje zależności natywne; lockfile zmienia się na PC albo w CI |
| Inne ekosystemy | `cargo install`, `go install`, `apt install` / `apt-get install` (także po `sudo`), `corepack enable` | `cargo check` | instalacja na serwerze — zależności zmieniają się na PC albo w CI |
| CLI instalujące paczki | `shadcn init` / `shadcn add` (także przez `bunx` / `npx` / `pnpm dlx`), `expo install` | — | CLI samo dopisuje zależności; instalacja tylko na PC albo w CI |
| Buildy | `next build`, `nuxt build`, `astro build`, `vite build`, `tsup`, `webpack`, `cargo build`, `expo prebuild`, `expo export`, `eas build --local`, `turbo run build` | `tsc --noEmit`, `turbo run lint` / `typecheck` | buildy produkcyjne tylko w CI |
| Launchery JS | `npx`, `bunx`, `pnpm dlx`, `yarn dlx` — domyślnie pobierają paczkę | `npx --no <bin>`, `bunx --no-install <bin>` (uruchamiają tylko to, co już jest w `node_modules/.bin`) | pobieranie z sieci na VPS; `pnpm dlx` / `yarn dlx` nie mają trybu bez pobierania — użyj skryptu projektu |
| Przeglądarki / e2e | `playwright`, `cypress`, `maestro`, narzędzia Playwright MCP | — | przeglądarka to setki MB na instancję; e2e tylko w CI |
| Mnożenie procesów | `pytest -n` / `--numprocesses` (także `-n4`, `-nauto`, `--numprocesses=4`) | `pytest` bez xdist | xdist mnoży procesy na słabym CPU |

Obejścia też łapie: każdy segment po `&&`, `||`, `;`, `|`, `&` sprawdzany osobno
(także wnętrze `bash -c` / `bash -lc` / `sh -c`, `$( … )` i backticków), a przed
dopasowaniem zdejmowane są prefiksy `sudo` (z flagami), `env` (z flagami)
i przypisania `VAR=…`, `nice`, `ionice`, `timeout`, `nohup`, `time`, `command`,
`exec`, `xargs`, `eval` oraz ścieżka binarki (`/usr/bin/docker` → `docker`).
Sprawdzana jest też komenda za launcherem: `uv [opcje] run [flagi] X`, `npx` /
`bunx X`, `pnpm|yarn|npm dlx|exec X`, `python -m X` — `uv run --no-sync pytest -n 4`
to deny, `uv run --no-sync ruff` allow. Separatory w cudzysłowach i treść heredoca
to dane, nie komendy (`git commit -m "…; docker …"` i body PR przez heredoc
przechodzą). Backticki i `$( … )` w pojedynczych apostrofach też są danymi — bash
ich tam nie wykonuje (``--body 'Blokuje `docker compose up`'`` przechodzi); w podwójnych
cudzysłowach dalej deny. Dopasowanie po tokenach od początku segmentu (`task` nie łapie
`taskfoo`). `UV_NO_SYNC=1` w linii działa jak w env; tak samo `UV_OFFLINE=1` zdejmuje
deny `uvx`. Poza VPS guard dla narzędzi
MCP nie zwraca decyzji (zwykłe pytanie o zgodę), dla Bash jawne `allow` jak
pozostałe guardy kita.

**Wrappery wykonania: `rtk`.** Globalna wtyczka RTK przepisuje komendę, zanim
zobaczy ją plugin guarda w opencode: `bun install` jedzie jako `rtk bun install`,
a `next build` jako `rtk next` — bez słowa `build`. Guard zdejmuje więc flagi rtk
(`-v…`, `--ultra-compact`, `--skip-env`), `rtk proxy|err|test|summary X` ocenia
jak `X`, `rtk run -c "…"` jak `sh -c`, `rtk run X` jak `X`, a pozostałe
`rtk X …` jak `X …`; dodatkowo `rtk next X` to zawsze `next build X` (poza `--help`), a `rtk npm X`
to `npm X` i `npm run X`. W Claude Code hooki `PreToolUse` widzą oryginalny
`tool_input`, więc guard dostaje komendę sprzed RTK, a deny wygrywa
z `updatedInput`; normalizacja pokrywa ten sam przypadek niezależnie od
kolejności hooków.

**Rozwijanie wrapperów przy `reload`.** Guard widzi tylko tekst komendy, więc
`kit-ai reload` / bootstrap czyta `Taskfile.yml` / `.yaml` (z `includes`
krótkimi i z kluczem `taskfile:`, `cmds` jako napisy, `- cmd:`, `- task:`, block
scalar `- |`, `deps`), `scripts` z każdego `package.json` w repo (poza
`node_modules` i katalogami z kropką, np. `.ai/headless-runs`) i `turbo run <x>` (wszystkie nazwy) do skryptów `<x>` we
wszystkich pakietach workspace. Poziomy łączą się dowolnie (task → `bun run` →
`turbo run` → skrypt pakietu), rozwijanie iteruje do stabilizacji. Task / skrypt,
którego komendy (po rozwinięciu) pasują do deny kita albo `server.deny`, ląduje
jako deny (`task <nazwa>`, `bun run`, `npm run` / `run-script`, `npm test|start`,
`pnpm [run]`, `yarn [run]`, `turbo run <x>`, także z `--filter` / `--cwd`)
z łańcuchem w powodzie (`bun run build → turbo run build → next build`). Projekt nie wypisuje tasków
ręcznie. Po zmianie Taskfile albo `package.json` trzeba `kit-ai reload`; guard
bez reloadu działa na starej liście.

**Konfiguracja w Profilu** (`.ai/project.profile.yaml`, opcjonalna; brak sekcji
= `guard: auto`, sama lista kita + wrappery):

```yaml
server:
  guard: auto        # auto (domyślnie) | off
  deny:              # dodatki projektu, których automat nie wykryje
    - "bunx eas-cli"
  allow:             # wyjątki, wygrywają z deny
    - "task lints:backend:ruff:check"
```

`kit-ai reload` / bootstrap renderuje listę kita, wrappery i sekcję `server` do
`server-guard.json` obok guarda w katalogu hooków każdego klienta (guard nie
parsuje YAML-a). Nieznany klucz albo zły typ w `server` jest zgłaszany, ale nie
przerywa działania (ADR 0004). Gotowe propozycje dodatków do `server.deny`:
dev serwery i watchery, `pytest` bez ścieżki, `systemctl` / `pkill` — na serwerze
z kilkoma GB RAM nie zawieszają go same z siebie, więc nie ma ich na liście
domyślnej.

**`UV_NO_SYNC` per maszyna.** Task, który w środku woła `uv run` bez flagi,
przechodzi tylko gdy klient na serwerze ma w env `UV_NO_SYNC=1`. Dla Claude
miejscem per maszyna jest niecommitowany `.claude/settings.local.json` (`env`).
OpenCode nie ma pliku env per maszyna — guard widzi środowisko procesu, więc
zmienna musi być w powłoce serwera (np. `export UV_NO_SYNC=1` w `~/.profile`).
Bez niej task z `uv run` bez `--no-sync` w środku dostaje deny.

**Ręczne sprawdzenie guarda:**

```sh
echo '{"tool_input":{"command":"docker compose up"}}' | KIT_HOST_PROFILE=vps node .claude/hooks/server-guard.mjs
```

**Relacja z CI.** Na VPS przechodzą szybkie bramki (lint, typecheck, unit);
pełna weryfikacja (kontenery, migracje, integracje, e2e, build) należy do CI.

**Czego guard tekstowy nie złapie** (agent zapisuje własny skrypt i go odpala)
i zalecenia dla hosta: wyłącz plugin Playwright MCP na serwerze (guard blokuje
narzędzia, ale proces MCP i tak startuje), użytkownik agenta poza grupą `docker`
i bez `sudo` bez hasła, limit pamięci na sesję agenta, jeśli host na to pozwala.

**Migracja z lokalnego guarda projektu:** podbij wersję kita w projekcie,
`kit-ai reload`, usuń własny plugin guarda; listy „nie uruchamiaj" z overlayu
zastępuje guard.

Regresja: `uv run python -m unittest tests.test_guards` (tabela allow/deny każdego Guarda)
i `bash tests/test_guard_adapter.sh` (tłumaczenie kontraktu) — odpalane też przez CI
(`tests/test_shell_suites.py` wciąga suity powłoki do `unittest discover`).

## Code review (Bugbot + GitHub)

Moduł MCP: `core:code-review` (bundle `devops` lub `architecture`).

**Minimalny zestaw przed pushem** (nie odpalaj całego wachlarza):

| Zmiana | Minimum |
|--------|---------|
| Drobna | `/review-bugbot` |
| Backend / Frontend | Bugbot + `/review-backend` lub `/review-frontend` |
| API + UI | Bugbot + BE+FE **lub** para `/subagent-*` |
| Auth / płatności | `/review-security` |
| Dowód „działa” | `/review-tests` (komendy, nie styl) |

Bugbot = blocking/security. Stack `/review-*` = konwencje z MCP (`Severity | Location | Finding | Fix`).  
Przy `codegen: orval` w overlay — po zmianie API regeneruj klienta.


| Warstwa            | Plik / akcja                                                                |
| ------------------ | --------------------------------------------------------------------------- |
| Lokalnie           | `/review-bugbot`, `/review-security`, `/review-backend`…                    |
| Przed push         | `git-guard.mjs` (deny na main/master/dev) — review przypomina `/git-end`     |
| Na PR              | Bugbot (GitHub integration)                                                 |
| Reguły             | `.cursor/BUGBOT.md`                                                         |
| CI (ten kit)       | `.github/workflows/ci.yml` — unittest (w tym suity powłoki) + smoke FastMCP |
| Hook regresja      | `tests/test_gate_destructive.sh` (polityka) + `tests/test_guard_adapter.sh` |
| Suity powłoki w CI | `tests/test_shell_suites.py` — jedyny adapter `*.sh` → `unittest discover`  |



## Zależności Python (pin majora)

```toml
mcp>=1.0.0,<2      # FastMCP (1.x); mcp 2.0 usuwa mcp.server.fastmcp
pyyaml>=6.0,<7
```

`uvx` resolvuje zależności od zera (nie bierze lokalnego `uv.lock`) — upper bound chroni konsumentów przed breaking major.

## Skills / pluginy zewnętrzne (poza tym kitem)

Trzy warstwy — nie bundluj Matt/Superpowers w `guides-mcp`:


| Warstwa   | Przykłady                                                 | Gdzie                                     | Rola                         |
| --------- | --------------------------------------------------------- | ----------------------------------------- | ---------------------------- |
| Fundament | Context7, `project-guides`, `/review-*`, `/git-*`, Cursor `/compact` | MCP + agents/skills z bootstrap | stack, git, skrót czatu (Cursor) |
| Proces    | [mattpocock/skills](https://github.com/mattpocock/skills) | `npx skills@latest add mattpocock/skills` | `/grill-me`, `/tdd`          |
| Meta      | superpowers, caveman, Autopilot                                      | user / plugin Cursor                      | worktree, finishing, CI loop |


Priorytet w `AGENTS.md`: użytkownik → overlay+MCP → review kita → Matt → Superpowers.  
TDD: jeden path na feature (preferuj Matt). W repo z kitem setup Matta **nie jest potrzebny**:
`kit-ai reload` renderuje jego kontrakt (niżej); poza kitem uruchom `/setup-matt-pocock-skills`.

### Kontrakt Matta w repo z kitem (#241)

Gdy `skills-lock.json` zawiera `mattpocock/skills`, reload tworzy **brakujące** pliki,
których oczekują skille Matta. Wartości bierze z repo i z kita, a format — z ziaren
`.agents/skills/setup-matt-pocock-skills/*.md` czytanych w momencie reloadu (aktualizacja
skilli przez `skills-lock.json` zmienia render bez zmian w kicie). Istniejących plików
`docs/agents/*` nie nadpisuje — możesz je edytować. Brak ziaren albo brak skilli Matta →
krok pomijany bez błędu.

| Plik | Skąd wartości |
|------|----------------|
| `docs/agents/issue-tracker.md` | ziarno `issue-tracker-github.md` (GitHub przez `gh`; inne trackery zostają w interaktywnym `/setup-matt-pocock-skills`) |
| `docs/agents/triage-labels.md` | ziarno `triage-labels.md` + nazwy etykiet z kita (te same co `ensure_labels`) |
| `docs/agents/domain.md` | ziarno `domain.md` + układ kita: single-context (`CONTEXT.md` + `docs/adr/`), multi-context gdy w root jest `CONTEXT-MAP.md` |
| blok `## Agent skills` w `AGENTS.md` | format setupu Matta; aktualizacja w miejscu, reszta pliku bez zmian |
| `CODING_STANDARDS.md` | indeks źródeł standardów w kolejności ważności: `AGENTS.md`, `.ai/project.md`, `BUGBOT.md` (z `project:rules`), `docs/adr/`, `CONTEXT.md`, MCP `project-guides` — tylko pozycje istniejące w repo |

`CODING_STANDARDS.md` to sam indeks (bez kopii reguł), odświeżany przy każdym reloadzie.
Czytają go agenci `/review-*` kita **oraz** `/code-review` i `retro` Matta — dlatego nazwa
jest zgodna z tym, czego szukają skille Matta. Dzięki temu `/code-review` nie prosi
o `/setup-matt-pocock-skills`, a jego oś Standards widzi `BUGBOT.md`, overlay i ADR-y.
`--remove` usuwa `CODING_STANDARDS.md` i `docs/agents/*` tylko wtedy, gdy są nietkniętym
renderem kita.

Context7 (docs Django/Expo): globalnie `npx ctx7 setup --cursor`.

## Subagenty — szczegóły

Każdy plik agentów jest **cienkim wrapperem**: przy starcie woła `get_bundle` / `get_overlay` z MCP `project-guides`. Wiedza merytoryczna żyje w `modules/`.

Praca w dwóch oknach: `/subagent-backend` ↔ `/subagent-frontend` — sekcja „Raport do przekazania” na końcu odpowiedzi.

TDQS

A4.1/5.0

Scored across 12 tools

Disambiguation5/5

Each tool has a clearly distinct target: get_* returns a specific configuration piece, list_* enumerates available options, check_kit_status compares state, and bootstrap_workspace is the only write operation. Even the overlapping get_overlay and get_bundle are disambiguated by descriptions: overlay-only vs combined bundle.

Naming Consistency5/5

All tool names follow a consistent snake_case verb_noun pattern with predictable prefixes: get_, list_, check_, bootstrap_. The naming makes the tool surface easy to scan and select from.

Tool Count5/5

12 tools is well within the ideal scope for a configuration/instruction server. Every tool covers a distinct need—reading project guides, listing modules/presets/bundles/clients, checking kit status, and bootstrapping the workspace—with no obvious filler.

Completeness5/5

The tool surface covers the full lifecycle for this domain: read current project context, discover available content, inspect kit state, and perform the only intended mutation (bootstrap install with dry-run). No critical dead-end operations are missing.

Maintenance

ActivityActive
ResponsivenessResponsive