docs: define host workspace and MCP access
This commit is contained in:
@@ -23,6 +23,23 @@ Neovim, Termdebug, nvim-dap oraz MCP tmuxa i Neovima. Kod karty, wyniki i
|
||||
artefakty są bind-mountem na hoście. Kontenery nie dostają kluczy SSH, tokenów,
|
||||
socketu Podmana/Dockera ani całego `/dev`.
|
||||
|
||||
## Pierwsza instalacja
|
||||
|
||||
Pierwszy klon launchera również należy do workspace. Nie uruchamiamy
|
||||
`stemctl` z przypadkowego katalogu domowego ani z kontenera:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/dev/workspace/stem/tools
|
||||
git clone http://77.90.8.171:3001/edu-tools/stem-launcher.git \
|
||||
~/dev/workspace/stem/tools/stem-launcher
|
||||
cd ~/dev/workspace/stem/tools/stem-launcher
|
||||
./stemctl workspace sync
|
||||
```
|
||||
|
||||
Od tego momentu wszystkie komendy `stemctl`, karty i repozytoria odpowiedzi
|
||||
pozostają pod `~/dev/workspace/stem`. Kontener dostaje wybraną kartę jako
|
||||
`/workspace`, ale nie jest miejscem przechowywania źródeł.
|
||||
|
||||
## Szybki start
|
||||
|
||||
```bash
|
||||
@@ -69,6 +86,10 @@ Domyślny układ:
|
||||
└── tokens/tokens.json
|
||||
```
|
||||
|
||||
Pierwszym repozytorium w `tools/` jest `stem-launcher`; to ono pobiera
|
||||
workspace-info, źródła kart oraz repo środowiska. Pozostałe repozytoria są
|
||||
zarządzane przez `stemctl`, a nie klonowane wewnątrz kontenera.
|
||||
|
||||
Jeżeli istnieje tylko starszy `~/dev/workspace/rv`, launcher wykrywa go bez
|
||||
niszczenia danych. Jawna migracja:
|
||||
|
||||
@@ -102,6 +123,30 @@ się w wybranym kontenerze:
|
||||
Oddzielne wpisy klienta MCP mogą wskazywać inne nazwy instancji, więc jeden
|
||||
Codex obsługuje kilka kontenerów bez globalnego „ostatniego socketu”.
|
||||
|
||||
Klient MCP działający stale na hoście może także przełączać oba narzędzia
|
||||
atomowo przez wspólny wskaźnik `current`:
|
||||
|
||||
```bash
|
||||
./stemctl mcp list
|
||||
./stemctl mcp select rp2350-pointers-final
|
||||
./stemctl mcp status
|
||||
./stemctl mcp select 3aca2c1c4c7a
|
||||
```
|
||||
|
||||
Selektor przyjmuje nazwę instancji, nazwę kontenera albo co najmniej 12 znaków
|
||||
ID. Weryfikuje ID i label przez `podman inspect`, a także aktywnie sprawdza oba
|
||||
serwery. Dopiero wtedy atomowo przełącza:
|
||||
|
||||
```text
|
||||
$XDG_RUNTIME_DIR/stem/mcp-selected/current/n.sock
|
||||
$XDG_RUNTIME_DIR/stem/mcp-selected/current/t.sock
|
||||
```
|
||||
|
||||
Wskaźniki prowadzą do katalogu zawierającego aktualny `container12`, więc
|
||||
odtworzony kontener nie może przejąć socketów poprzednika. Neovim i tmux
|
||||
otwierają nowe połączenie przy każdym wywołaniu narzędzia MCP, dlatego zmiana
|
||||
działa bez restartowania klienta.
|
||||
|
||||
## Komputer zdalny
|
||||
|
||||
Na komputer ucznia wchodzimy wyłącznie SSH z parą kluczy. Launcher, Git,
|
||||
@@ -134,6 +179,7 @@ Nowe materiały powinny używać nazw kanonicznych.
|
||||
|
||||
- [plan architektury](doc/architecture-plan.md)
|
||||
- [kontenery i interfejs](doc/containers.md)
|
||||
- [wytyczne dokumentowania debugowania](doc/debug-documentation-guidelines.md)
|
||||
- [migracja nazw i workspace](doc/migration-stem-launcher.md)
|
||||
- [serie i karty](doc/series.md)
|
||||
- [tokeny Gitea](doc/tokens.md)
|
||||
|
||||
@@ -17,6 +17,10 @@ mieć wgląd w tę samą sesję, w której pracuje uczeń:
|
||||
|
||||
Dzięki temu agent widzi środowisko debugowania, a nie tylko statyczne pliki.
|
||||
|
||||
Punkt wejścia `stemctl` jest także projektem hostowym: pierwszy klon znajduje
|
||||
się w `~/dev/workspace/stem/tools/stem-launcher`. Agent ani użytkownik nie
|
||||
klonują launchera, kart lub repozytoriów odpowiedzi do kontenera.
|
||||
|
||||
## Aktualny fundament
|
||||
|
||||
`rv32i-hazard3-student-env` dostarcza źródła wspólnego modelu:
|
||||
@@ -108,6 +112,91 @@ Aktualny ID uniemożliwia użycie socketu pozostałego po odtworzeniu kontenera.
|
||||
`stemctl` traktuje te pliki jako szczegóły implementacyjne. Użytkownik i agent
|
||||
dostają komendy wyższego poziomu.
|
||||
|
||||
### Kto tworzy sockety
|
||||
|
||||
Hostowy launcher `stem` najpierw tworzy katalog runtime i przekazuje go
|
||||
Podmanowi jako bind-mount pod **tą samą bezwzględną ścieżką**. Po uruchomieniu
|
||||
interfejsu debuggera procesy wewnątrz kontenera tworzą sockety:
|
||||
|
||||
- `tmux` tworzy `t.sock`,
|
||||
- `nvim` tworzy `n.sock`.
|
||||
|
||||
Nie są one kopiowane ani przekazywane przez sieć: host i kontener widzą ten sam
|
||||
plik Unix socket w zamontowanym katalogu. ID kontenera jest częścią ścieżki,
|
||||
więc nowy kontener po `rm/start` dostaje nowy katalog i nie może przypadkiem
|
||||
obsłużyć socketu poprzednika.
|
||||
|
||||
### Dynamiczny wybór kontenera
|
||||
|
||||
Stały provider MCP na hoście używa dwóch krótkich ścieżek:
|
||||
|
||||
```text
|
||||
$XDG_RUNTIME_DIR/stem/mcp-selected/current/n.sock
|
||||
$XDG_RUNTIME_DIR/stem/mcp-selected/current/t.sock
|
||||
```
|
||||
|
||||
Polecenie `stemctl mcp select INSTANCE_OR_CONTAINER_ID` weryfikuje registry,
|
||||
pełny ID i label kontenera oraz oba żywe serwery. Następnie atomowo przełącza
|
||||
symlink `current` dla obu socketów. Dzięki temu kolejna operacja MCP trafia do
|
||||
wybranej sesji tmuxa i Neovima bez restartowania Codexa. `stemctl mcp list`
|
||||
pokazuje tylko rekordy registry, a `stemctl mcp status` potwierdza bieżący
|
||||
wybór.
|
||||
|
||||
Wybór pozostaje jawny: samo stworzenie kontenera tworzy jego katalog socketów,
|
||||
ale nie przejmuje automatycznie aktywnego MCP innej sesji.
|
||||
|
||||
### Wiele kont użytkowników i pomoc nauczyciela
|
||||
|
||||
Sockety muszą pozostać prywatne dla unixowego konta, które uruchamia
|
||||
kontener, np.:
|
||||
|
||||
```text
|
||||
/run/user/<uid-ucznia>/stem/<thread>/<instance>/<container-id>/
|
||||
```
|
||||
|
||||
Nie montujemy ich do wspólnego `/tmp`, nie zmieniamy grup socketów tmuxa i nie
|
||||
udostępniamy ich przez port sieciowy. Codex nauczyciela łączy się przez SSH na
|
||||
konkretne konto ucznia; po drugiej stronie ograniczony wrapper MCP łączy się
|
||||
lokalnie z jego `n.sock` i `t.sock`. Stdio SSH jest transportem MCP — socket
|
||||
Unix nie opuszcza komputera ucznia.
|
||||
|
||||
Każdy uczeń ma własny tmux i Neovim. Można uruchomić wiele serwerów MCP dla
|
||||
tej samej sesji (np. ucznia i nauczyciela), ale oba mogą równocześnie edytować
|
||||
bufor lub wysyłać klawisze, więc nie ma gwarancji arbitrażu zmian.
|
||||
|
||||
Dostęp nauczyciela rozdzielamy na dwa klucze SSH:
|
||||
|
||||
- zwykły klucz nauczycielski z pełną powłoką, używany wyłącznie do świadomej,
|
||||
ręcznej interwencji na koncie ucznia;
|
||||
- osobny klucz automatyzacji Codexa z forced command, bez TTY, forwardingu i
|
||||
powłoki, ograniczony do `nvim`, `tmux`, `status` i dozwolonych kontenerów.
|
||||
|
||||
Pełny klucz nauczyciela nie trafia do kontenera ani do konfiguracji MCP.
|
||||
|
||||
### Poziomy uprawnień MCP
|
||||
|
||||
Każdy wpis MCP otrzymuje jawny poziom dostępu. Poziom jest własnością klucza
|
||||
SSH i wrappera po stronie konta ucznia, a nie ustawieniem przekazywanym przez
|
||||
model lub klienta MCP:
|
||||
|
||||
| Poziom | Przeznaczenie | Dozwolone działania |
|
||||
| --- | --- | --- |
|
||||
| `observe` | podgląd postępów | stan nvim, lista i capture pane’ów tmuxa, logi i metadane; bez edycji i wysyłania klawiszy |
|
||||
| `assist` | wspólne rozwiązywanie problemu | działania debuggera i jawnie dozwolona edycja/panele; bez ogólnego terminala oraz bez poleceń powłoki |
|
||||
| `full` | interwencja nauczyciela | pełne sterowanie nvimem i tmuxem, w tym terminalem w wybranym kontenerze, jako konto ucznia |
|
||||
|
||||
`full` jest równoważny interaktywnej pracy na koncie ucznia w granicach
|
||||
wybranego kontenera. W szczególności arbitralne `nvim-remote-expr`, `nvim-ex`
|
||||
lub wysyłanie poleceń do pane’a tmuxa mogą uruchomić kod. Taki wpis tworzymy
|
||||
wyłącznie dla nauczyciela i zapisujemy w audycie konto, instancję, container ID,
|
||||
czas oraz użyty poziom.
|
||||
|
||||
Nie wystarczy przekazać `MCP_ACCESS_LEVEL=observe` do tego samego pełnego
|
||||
serwera: niższe poziomy wymagają osobnych providerów z allowlistą narzędzi.
|
||||
W przeciwnym razie użytkownik nadal mógłby użyć ogólnego Ex/Vimscriptu albo
|
||||
terminala do obejścia ograniczenia. Klucz `full` może korzystać z obecnego
|
||||
providera STEM, ponieważ jego możliwości są celowo pełne.
|
||||
|
||||
## Role profili
|
||||
|
||||
Profil `hazard3-sim`:
|
||||
|
||||
@@ -195,6 +195,29 @@ re-enumeracji. Nie przekazuje całego `/dev`. Build i test offline nie wymagają
|
||||
artefaktu. Bez niego odmawia wykonania, chyba że użytkownik jawnie zaakceptuje
|
||||
istniejący firmware. Zapobiega to testowaniu starego programu.
|
||||
|
||||
## Źródła projektu
|
||||
|
||||
Źródła kart i projektów pobiera wyłącznie `stemctl` na hoście, zawsze pod
|
||||
`~/dev/workspace` danego konta Unix. Kanoniczny workspace STEM ma postać
|
||||
`~/dev/workspace/stem`; nie używamy do pracy katalogów kontenera ani
|
||||
przypadkowych klonów poza `~/dev/workspace`. Pierwszy klon launchera trafia do
|
||||
`~/dev/workspace/stem/tools/stem-launcher` i od niego zaczyna się cały
|
||||
bootstrap workspace. Typowy przepływ to:
|
||||
|
||||
```bash
|
||||
stemctl workspace sync
|
||||
stemctl series cards fetch inf pointers
|
||||
stemctl debug rp2350 inf pointers 4
|
||||
```
|
||||
|
||||
Katalog karty pozostaje na hoście, na przykład
|
||||
`~/dev/workspace/stem/series/inf/pointers/`, i jest przekazywany kontenerowi
|
||||
jako bind-mount `/workspace`. Nie klonujemy repozytoriów źródłowych wewnątrz
|
||||
kontenera: kontenery są odtwarzalne i mogą zostać usunięte, natomiast host
|
||||
zachowuje Git, zmiany ucznia, odpowiedzi i historię pracy. W obrazie lub
|
||||
osobnym cache volume mogą znajdować się wyłącznie narzędzia, zależności i
|
||||
odtwarzalne cache budowania.
|
||||
|
||||
## Instancje i sockety MCP
|
||||
|
||||
Stabilna nazwa logiczna:
|
||||
@@ -227,6 +250,33 @@ Publiczne wejścia launchera to `stemctl mcp tmux INSTANCE` oraz
|
||||
zweryfikowanego kontenera. Neovim MCP publikuje również stan i komendy
|
||||
Termdebug/nvim-dap.
|
||||
|
||||
Dla jednego stale działającego klienta hostowego dostępny jest również jawny,
|
||||
atomowy przełącznik obu socketów:
|
||||
|
||||
```bash
|
||||
stemctl mcp list
|
||||
stemctl mcp select INSTANCE_OR_CONTAINER_ID
|
||||
stemctl mcp status
|
||||
```
|
||||
|
||||
`mcp select` sprawdza registry, pełny ID i label kontenera, aktywnie testuje
|
||||
serwery Neovima i tmuxa, a następnie jednym `rename(2)` przełącza symlink
|
||||
`$XDG_RUNTIME_DIR/stem/mcp-selected/current`. Jeśli choć jeden serwer nie
|
||||
odpowiada, poprzedni wybór pozostaje bez zmian.
|
||||
|
||||
Katalog socketów jest tworzony przez launcher na hoście i bind-mountowany do
|
||||
kontenera pod identyczną ścieżką. Dopiero `nvim` i `tmux` działające w
|
||||
kontenerze tworzą odpowiednio `n.sock` i `t.sock`; hostowy Codex łączy się z
|
||||
tym samym plikiem przez widok hosta. Sockety nie są przekazywane przez sieć ani
|
||||
nie dają kontenerowi dostępu do socketu Podmana.
|
||||
|
||||
Połączenia MCP mają profil `observe`, `assist` albo `full`. `full` jest
|
||||
przeznaczony dla nauczyciela: może wykonywać dowolne działania dostępne w
|
||||
Neovimie, tmuxie i terminalu wybranego kontenera jako konto ucznia. Profile
|
||||
`observe` i `assist` muszą używać oddzielnych, ograniczonych providerów;
|
||||
nie wolno udawać ograniczenia przez samą zmienną środowiskową przy providerze
|
||||
udostępniającym ogólny Vimscript lub polecenia pane’a.
|
||||
|
||||
MCP nie jest czwartym kontenerem. Bridge jest częścią `dev-ui-base`, a hostowy
|
||||
resolver jest częścią `stem-launcher`.
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Wytyczne dokumentowania debugowania
|
||||
|
||||
## Cel
|
||||
|
||||
Zrzut debuggera jest dowodem pomiaru, nie dekoracją. Ma pozwolić uczniowi
|
||||
połączyć jedną operację w C z instrukcjami RISC-V, rejestrami, ramką stosu i
|
||||
konkretnymi bajtami w RAM.
|
||||
|
||||
## Kadr dowodowy
|
||||
|
||||
- Używaj rzeczywistej sesji `stemctl debug` z karty, symulatora albo płytki.
|
||||
- Zatrzymaj program w jednym nazwanym punkcie: breakpoint, checkpoint albo
|
||||
instrukcja bezpośrednio przed obserwowaną operacją.
|
||||
- Zachowaj wspólny układ: dashboard Termdebug/GDB po lewej, źródło C po
|
||||
prawej, listing `.lst` pod źródłem. Listing musi być zsynchronizowany z PC.
|
||||
- Pokaż tylko dane potrzebne do tezy: wywołanie w C, odpowiadającą instrukcję,
|
||||
argument w rejestrze, fragment stosu albo pamięć w RAM.
|
||||
- Dołącz podpis z platformą, taskiem i stanem pomiaru, na przykład „przed
|
||||
pierwszym przydziałem pamięci”.
|
||||
|
||||
## Oznaczenia
|
||||
|
||||
- Stosuj najwyżej cztery krótkie oznaczenia numeryczne na jednym kadrze.
|
||||
- Każdy numer ma odpowiadać jednemu zdaniu w podpisie lub legendzie.
|
||||
- Bieżący kolor oznaczeń to czerwony: oznacza „zatrzymaj się i sprawdź”.
|
||||
Paleta może później ulec zmianie, ale numeracja i podpis muszą pozostać
|
||||
zrozumiałe bez koloru.
|
||||
- Nie zasłaniaj kodu ani nie zmieniaj jego treści. Zachowaj surowy zrzut jako
|
||||
źródło, a adnotowany obraz zapisz jako osobny plik.
|
||||
|
||||
## Wstawienie do karty
|
||||
|
||||
- Zasoby zapisuj w `doc/assets/`, np.
|
||||
`task04-first-allocation-annotated.png`.
|
||||
- W `doc/main.tex` umieść obraz blisko instrukcji, której dotyczy, oraz dodaj
|
||||
zwięzły podpis wyjaśniający numery.
|
||||
- Po zmianie zbuduj PDF skryptem `scripts/render_pdf.sh` i sprawdź stronę
|
||||
wynikową w rozmiarze A4.
|
||||
- W materiałach dla ucznia używaj słowa **RAM**, nie skrótu „SRAM”.
|
||||
|
||||
## Przykład referencyjny
|
||||
|
||||
Karta `inf/pointers`, Task04: `alloc_local(5)` przed pierwszym przydziałem.
|
||||
Kadr pokazuje wywołanie C, `li a0,5` i `jal alloc_local`, wartość `a0=5` oraz
|
||||
pusty `allocbuf`. Taki obraz dokumentuje związek źródła, ABI i pamięci bez
|
||||
zastępowania go opisem narracyjnym.
|
||||
Reference in New Issue
Block a user