docs: bootstrap tg-bot-jetson — board, ADRs, state, session-prompts

ROADMAP mit 7 Items (F-01…F-07) und DAG. STATE aktiviert. CONVENTIONS
projektspezifisch ergänzt. ADRs 0002-0004 (Stack, Whitelist, Spike-Gate).
Kaltstartfähige Prompts für F-01 (Skeleton) und F-02 (API-Spike) erzeugt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-03 23:24:13 +02:00
parent 49cbd00677
commit b7b6766364
10 changed files with 288 additions and 13 deletions

View File

@@ -37,3 +37,15 @@ Verbindlich für **alle** Aktoren. Änderungen nur per ADR.
1. Manifest-Eintrag (`manifests/requirements.md`) mit Test + Status `done`. 1. Manifest-Eintrag (`manifests/requirements.md`) mit Test + Status `done`.
2. Tests grün. 3. Docs aktuell. 4. `STATE.md` aktualisiert. 2. Tests grün. 3. Docs aktuell. 4. `STATE.md` aktualisiert.
5. Session-Log geschrieben. 6. Quality-Gate `PASS`. 5. Session-Log geschrieben. 6. Quality-Gate `PASS`.
## Projekt: tg-bot-jetson (projektspezifisch — Änderungen per ADR)
- **Sprache / Runtime:** Python 3.11+
- **Paketmanagement:** `uv` + `pyproject.toml`; Lock-Datei `uv.lock` committen.
- **Bot-Framework:** `python-telegram-bot` v21 (asyncio) ADR-0002.
- **HTTP-Client:** `httpx` (async) für Modell-Connector.
- **Test-Befehl:** `uv run pytest tests/ -v`
- **Lint:** `uv run ruff check src/ tests/`
- **Config-Konvention:** Alle Secrets/Einstellungen via Umgebungsvariablen;
`.env.example` committen, `.env` in `.gitignore` ADR-0003.
- **Spike-Branch:** `spike/<thema>` (z. B. `spike/model-api`), wird nach GO/NO-GO verworfen.

View File

@@ -23,15 +23,38 @@ Ready-Set = { Items mit Status 🔲, deren Prereqs ALLE ✅ sind }
4. **🔌/🧱** → direkt Worker. **🔬** → erst durch das Spike-Gate (`docs/loops/spike-gate.md`). 4. **🔌/🧱** → direkt Worker. **🔬** → erst durch das Spike-Gate (`docs/loops/spike-gate.md`).
5. Nach Implement: Review-Gate (Opus) → Merge → Item hier auf ✅, Dependents werden frei. 5. Nach Implement: Review-Gate (Opus) → Merge → Item hier auf ✅, Dependents werden frei.
## Abhängigkeits-DAG (Projekt: tg-bot-jetson)
```
F-01 (Skeleton) ──┬──► F-03 (Whitelist) ──┐
├──► F-04 (Bot-Handler) ──┼──► F-06 (Integration) ──► F-07 (Deploy)
└──► F-05 (Model-Connector) ──┘
F-02 (API-Spike) ──► F-05
```
> F-02 ist 🔬: Spike-Gate muss durch, bevor F-05 dispatcht wird.
> F-05 bleibt ⏸ bis F-01 **und** F-02 ✅ sind.
> F-06 bleibt ⏸ bis F-03, F-04 **und** F-05 ✅ sind.
> F-07 bleibt ⏸ bis F-06 ✅ ist.
## Board ## Board
| ID | Item | Typ | Status | Prereqs | Rolle · Modell | Aufwand | | ID | Item | Typ | Status | Prereqs | Rolle · Modell | Aufwand |
|----|------|-----|--------|---------|----------------|---------| |----|------|-----|--------|---------|----------------|---------|
| _F-01_ | _<Feature/Paket>_ | 🔌 | 🔲 | — | Porter · Sonnet | _…_ | | F-01 | Projekt-Skeleton (pyproject.toml, Paketstruktur, CI-Stub) | 🧱 | 🔲 | — | Worker · Sonnet | ~0.5 d |
| _F-02_ | _<Feature/Paket>_ | 🔬 | | F-01 | Theorist · Opus | _…_ | | F-02 | Spike: Modell-API-Format (welches Endpoint-Schema exponiert der Jetson-Server?) | 🔬 | 🔲 | | Theorist · Opus → Spike | ~0.5 d |
| F-03 | Whitelist-Middleware (User-ID-Allowlist, Env-Var-Config) | 🧱 | ⏸ | F-01 | Worker · Sonnet | ~0.5 d |
| F-04 | Telegram-Bot-Handler (Polling-Loop, /start, /help, Nachricht-Relay) | 🔌 | ⏸ | F-01 | Porter · Sonnet | ~1 d |
| F-05 | Modell-HTTP-Connector (async httpx-Client zum lokalen Modell-Server) | 🔌 | ⏸ | F-01, F-02 | Porter · Sonnet | ~0.5 d |
| F-06 | Integration & Smoke-Test (Whitelist + Handler + Connector verdrahtet, E2E-Test) | 🧱 | ⏸ | F-03, F-04, F-05 | Worker · Sonnet | ~1 d |
| F-07 | Deployment-Config (.env.example, Docker oder systemd-Unit für Jetson) | 🧱 | ⏸ | F-06 | Worker · Haiku | ~0.5 d |
> Ein durchgespieltes, befülltes Board: `examples/walkthrough/ROADMAP.md`. > F-02 ist `🔬`: vor Produktionscode erst **Spike** (`docs/loops/spike-gate.md`) —
> Nachweis, dass wir den Modell-Server erfolgreich ansprechen können (Connectivity-GO).
> F-04 ist `🔌`: Referenz-Impl = python-telegram-bot-v21-Doku (golden oracle vorhanden).
> F-05 ist `🔌`: Referenz-Impl entsteht aus F-02-Spike-Spec.
## Done ## Done
| ID | Item | Session | Commit | | ID | Item | Session | Commit |
|----|------|---------|--------| |----|------|---------|--------|
| _…_ | _…_ | _…_ | _…_ | | — | — | — | — |

View File

@@ -2,24 +2,31 @@
> Einzige Quelle für "wo stehen wir". Jede Session aktualisiert dies am Ende. > Einzige Quelle für "wo stehen wir". Jede Session aktualisiert dies am Ende.
**Letzte Session:** _<id / datum>_ · **Aktive Rolle:** _<leader/worker/reviewer>_ **Letzte Session:** S-BOOTSTRAP / 2026-06-03 · **Aktive Rolle:** leader
## Now (in dieser Session im Fokus) ## Now (in dieser Session im Fokus)
- _…_ - Bootstrap-Planning: ROADMAP befüllt, ADRs angelegt, Session-Prompts für F-01 und F-02 erzeugt.
## In Progress (begonnen, nicht fertig) ## In Progress (begonnen, nicht fertig)
- _… (Paket, Owner, Branch)_ - _(keine — Bootstrap ist abgeschlossen, nächste Dispatch-Sessions stehen bereit)_
## Blocked ## Blocked
- _… (Grund, wartet worauf)_ - F-03 Whitelist — wartet auf F-01 (`⏸`).
- F-04 Bot-Handler — wartet auf F-01 (`⏸`).
- F-05 Model-Connector — wartet auf F-01 + F-02 (`⏸`).
- F-06 Integration — wartet auf F-03, F-04, F-05 (`⏸`).
- F-07 Deployment — wartet auf F-06 (`⏸`).
## Next (priorisiert) ## Next (priorisiert)
- _…_ 1. F-01 dispatchen (Worker · Sonnet) — `session-prompts/F-01-skeleton.md`.
2. F-02 dispatchen (Theorist · Opus → Spike-Gate) — `session-prompts/F-02-api-spike.md`.
Beide können **parallel** starten, da kein Prereq zwischen ihnen.
## Offene Audit-Findings ## Offene Audit-Findings
- _… (Verweis auf audits/<datei>, Severity)_ - _(keine — Projekt frisch gestartet)_
## Datei-Ownership (aktiv) ## Datei-Ownership (aktiv)
| Paket | Dateien/Pfade | Owner | | Paket | Dateien/Pfade | Owner |
|---|---|---| |---|---|---|
| _…_ | _…_ | _…_ | | skeleton | `pyproject.toml`, `src/`, `tests/` | worker-F01 |
| spike-api | `spike/model-api/` | theorist-F02 |

View File

@@ -0,0 +1,15 @@
# 0002 — python-telegram-bot v21 als Bot-Framework
- **Status:** accepted
- **Kontext:** Das Projekt braucht ein Python-Telegram-Bot-Framework.
Alternativen: `aiogram`, `telebot` (pyTelegramBotAPI), `ntelegram`.
- **Entscheidung:** `python-telegram-bot` v21 mit nativem `asyncio` und `httpx`
als HTTP-Client für den Modell-Connector. `uv` als Paketmanager.
- **Gründe:**
- PTB v21 hat die breiteste Doku, Beispiel-Bibliothek und Community für Telegram.
- Asyncio-first: passt zum Streaming-Potenzial künftiger Modell-Antworten.
- `httpx` ist de-facto-Standard für async HTTP in Python 3.11+.
- `uv` ist schneller und reproduzierbarer als plain pip.
- **Konsequenz:** Gesamte Codebasis ist async-first. PTB-Filter-System
(`filters.User`) eignet sich direkt für die Whitelist (F-03).
Keine Sync-Wrapper nötig.

View File

@@ -0,0 +1,16 @@
# 0003 — User-Whitelist via Umgebungsvariable
- **Status:** accepted
- **Kontext:** Nur ausgewählte Telegram-User-IDs dürfen den Bot nutzen.
Optionen: Datenbank, Config-Datei, Env-Var, hardcodiert.
- **Entscheidung:** Env-Var `ALLOWED_USER_IDS` als komma-separierte Liste
ganzer Zahlen (z. B. `ALLOWED_USER_IDS=123456,789012`).
PTB-Filter `filters.User(user_ids=...)` erzwingt die Prüfung deklarativ.
- **Gründe:**
- Kein Deployment-Artefakt für die Liste nötig — reicht für v1.
- Änderung ohne Code-Deploy: Service neu starten genügt.
- Keine persistente Zustandsverwaltung, kein Datenbankrisiko.
- Leicht in `.env`-Datei und Docker/systemd-Unit einzutragen.
- **Konsequenz:** Für v2 (dynamisches Hinzufügen per Admin-Command) muss
ein Persistenz-Layer (SQLite o. ä.) ergänzt werden — das ist ein eigenes
Board-Item und ändert diese Entscheidung.

View File

@@ -0,0 +1,15 @@
# 0004 — Modell-API-Format: erst Spike, dann Connector
- **Status:** accepted
- **Kontext:** Der Jetson Orin Nano Super hostet ein lokales Modell. Das
Endpoint-Schema ist nicht festgelegt (mögliche Backends: Ollama,
llama.cpp-HTTP-Server, vLLM, custom FastAPI). Kein golden oracle.
- **Entscheidung:** F-02 (🔬 Spike) läuft **vor** F-05 (🔌 Connector).
Der Spike bestimmt das tatsächliche API-Schema und erzeugt eine
Mini-Spec (`spike/model-api/spec.md`). F-05 portiert gegen diese Spec.
- **GO-Kriterium:** Python-Skript sendet eine Test-Nachricht und empfängt
eine nicht-leere Antwort vom lokalen Server. Latenz < 30 s akzeptabel.
- **NO-GO-Kriterium:** Kein Endpoint erreichbar oder Antwort-Format
vollständig undokumentiert Human-Entscheid, welcher Backend aufzusetzen.
- **Konsequenz:** F-05 bleibt bis Spike + GO. Wenn NO-GO: blocked-extern.
Spike-Branch `spike/model-api` wird nach GO verworfen; Spec bleibt in `docs/`.

View File

@@ -3,7 +3,16 @@
Eine Zeile je Erfolgskriterium. Der Reviewer prüft Spalte für Spalte. Eine Zeile je Erfolgskriterium. Der Reviewer prüft Spalte für Spalte.
| ID | Anforderung | Datei(en) | Test/Prüfbefehl | Status | | ID | Anforderung | Datei(en) | Test/Prüfbefehl | Status |
|----|-------------|-----------|------------------|--------| |----|-------------|-----------|-----------------|--------|
| R-0001 | _Beispiel: …_ | `path/to/file` | `pytest tests/test_x.py` | todo | | R-0001 | `uv sync` läuft ohne Fehler | `pyproject.toml`, `uv.lock` | `uv sync` | todo |
| R-0002 | Pytest-Suite grün | `tests/` | `uv run pytest tests/ -v` | todo |
| R-0003 | Ruff meldet 0 Befunde | `src/`, `tests/` | `uv run ruff check src/ tests/` | todo |
| R-0004 | Bot antwortet nur auf whitelistete User-IDs | `src/bot/whitelist.py` | `uv run pytest tests/test_whitelist.py -v` | todo |
| R-0005 | Nicht-whitelistete User erhalten keine Antwort | `src/bot/whitelist.py` | `uv run pytest tests/test_whitelist.py::test_blocked_user -v` | todo |
| R-0006 | Bot leitet Nachrichten an lokales Modell weiter | `src/bot/connector.py` | `uv run pytest tests/test_connector.py -v` | todo |
| R-0007 | Modell-Antwort wird an User zurückgesendet | `src/bot/handlers.py` | `uv run pytest tests/test_handlers.py -v` | todo |
| R-0008 | Spike-Ergebnis: Modell-API erreichbar (GO) | `spike/model-api/result.md` | manuell: `python spike/model-api/probe.py` | todo |
| R-0009 | Config lädt aus Env-Vars ohne Exception | `src/bot/config.py` | `uv run pytest tests/test_config.py -v` | todo |
| R-0010 | `.env` nicht im Git-Index | `.gitignore` | `git ls-files .env` → leer | todo |
Status: `todo` · `in_progress` · `done` · `drift` (vom Audit markiert). Status: `todo` · `in_progress` · `done` · `drift` (vom Audit markiert).

View File

@@ -0,0 +1,67 @@
# Session-Prompt F-01 — Projekt-Skeleton
```
Modell: Sonnet
Du arbeitest in /Users/tarikmoussa/Desktop/files/agent-swarm-repo auf einem neuen Branch
`feat/skeleton` (von `main`).
## Aufgabe
Lege das Python-Projekt-Skeleton für den Telegram-Bot an:
pyproject.toml, Paketstruktur unter `src/bot/`, leere Test-Dateien unter `tests/`,
.env.example und .gitignore. Kein Feature-Code — nur die Projektstruktur,
sodass `uv run pytest tests/ -v` mit 0 Tests grün durchläuft.
Scope: NUR Datei- und Konfigurationsstruktur. Kein Bot-Code, kein HTTP-Code.
## Details
Entscheidungen: `docs/adr/0002-python-telegram-bot-framework.md`
Konventionen: `CONVENTIONS.md` (Abschnitt "Projekt: tg-bot-jetson")
Gewünschte Verzeichnisstruktur:
```
src/
bot/
__init__.py
config.py # pydantic-settings: BOT_TOKEN, ALLOWED_USER_IDS, MODEL_BASE_URL
handlers.py # vorerst leer (Platzhalter)
whitelist.py # vorerst leer (Platzhalter)
connector.py # vorerst leer (Platzhalter)
main.py # Einstiegspunkt (vorerst nur "pass")
tests/
__init__.py
test_config.py # vorerst leer
pyproject.toml # [project] name="tg-bot-jetson", requires-python=">=3.11"
# deps: python-telegram-bot>=21, httpx, pydantic-settings
# [dev-deps]: pytest, ruff
.env.example # BOT_TOKEN=<dein-bot-token>, ALLOWED_USER_IDS=123456,789012
# MODEL_BASE_URL=http://192.168.x.x:11434
.gitignore # .env, __pycache__, .venv, uv.lock nicht (committen!)
uv.lock # nach `uv sync` erzeugt und committen
```
## Akzeptanzkriterien
- [ ] `uv sync` läuft ohne Fehler.
- [ ] `uv run pytest tests/ -v` läuft durch (0 Tests, kein Fehler).
- [ ] `uv run ruff check src/ tests/` → 0 Befunde.
- [ ] `src/bot/config.py` enthält eine Pydantic-Settings-Klasse mit BOT_TOKEN,
ALLOWED_USER_IDS (list[int]), MODEL_BASE_URL.
- [ ] `.env.example` vorhanden und aussagekräftig.
- [ ] `.env` ist in `.gitignore`.
## Nicht anfassen
Alles außer den oben genannten Pfaden. Kein Telegram-Handler-Code,
kein HTTP-Client-Code, keine Whitelist-Logik.
## Commit & Push
- Conventional Commit: `chore: scaffold tg-bot-jetson project skeleton`
- Trailer: `Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>`
- Push nach `origin feat/skeleton`, PR öffnen (Base: `main`).
## Abschluss
1. Manifest-Eintrag updaten: `manifests/requirements.md` → R-0001, Status `done`.
2. `STATE.md` aktualisieren: F-01 → In Progress → nach Merge: Next F-03 + F-04 frei.
3. Session-Log schreiben: `sessions/TEMPLATE.md` → `sessions/F-01-<datum>.md`.
4. Hygiene-Gate: `bash scripts/gate-session-hygiene.sh`.
5. PR-URL + Test-Zählstand reporten.
```

View File

@@ -0,0 +1,69 @@
# Session-Prompt F-02 — Spike: Modell-API-Format (Theorist + Prototyper)
```
Modell: Opus
Du arbeitest in /Users/tarikmoussa/Desktop/files/agent-swarm-repo auf einem neuen Branch
`spike/model-api` (von `main`).
WICHTIG: Dies ist ein Research-Spike. Der Branch ist Wegwerf. Kein Produktionscode.
Spike-Gate-Regeln: `docs/loops/spike-gate.md`
ADR: `docs/adr/0004-modell-api-spike-first.md`
## Aufgabe
Bestimme das API-Format des selbst gehosteten Sprachmodells auf dem Jetson Orin Nano Super
und produziere eine Mini-Spec (`spike/model-api/spec.md`), gegen die F-05 dann portiert.
Hintergrund: Das Modell läuft auf einem lokalen Server. Der wahrscheinlichste
Backend-Stack ist **Ollama** (exponiert eine OpenAI-kompatible API auf Port 11434)
oder **llama.cpp HTTP-Server** (Port 8080, eigenes Format). Wir wissen es nicht sicher.
## Phase 1 — Theorist (du selbst, Opus)
1. Liste die drei wahrscheinlichsten Backend-Optionen für Jetson Orin:
- Ollama (`/api/generate`, `/api/chat` oder OpenAI-compat `/v1/chat/completions`)
- llama.cpp HTTP (`/completion`)
- Custom FastAPI
2. Für jede Option: notiere das minimale Request-/Response-Schema (JSON).
3. Schreibe `spike/model-api/spec.md` mit den Schema-Varianten und dem
GO-Kriterium: "Antwort ist nicht-leer und unter 30 s".
## Phase 2 — Prototyper (du selbst, Opus)
Schreibe `spike/model-api/probe.py` — ein minimales, wegwerfbares Python-Skript:
- Liest MODEL_BASE_URL aus Env-Var (default: http://localhost:11434).
- Schickt eine kurze Test-Nachricht ("Hallo, antworte mit einem Wort.").
- Gibt die rohe JSON-Antwort aus.
- Kommentiert, welches Schema es probiert hat.
Das Skript ist **kein Produktionscode** — kein Error-Handling, keine Abstraktionen.
## Phase 3 — GO/NO-GO
Dokumentiere in `spike/model-api/result.md`:
- Welches Backend hast du vorgefunden (oder angenommen)?
- Funktioniert der Probe erfolgreich? (GO / NO-GO)
- Exaktes API-Schema für den Connector (Request + Response-Felder).
- Empfehlung für F-05 Porter (welche Library, welchen Endpoint).
## Akzeptanzkriterien
- [ ] `spike/model-api/spec.md` enthält ≥ 2 Schema-Varianten mit JSON-Beispielen.
- [ ] `spike/model-api/probe.py` läuft ohne Import-Fehler (`python spike/model-api/probe.py --help` o. ä.).
- [ ] `spike/model-api/result.md` enthält ein klares GO oder NO-GO mit Begründung.
- [ ] GO: Das finale API-Schema ist in `result.md` exakt spezifiziert (Felder, Typen, Endpoint-Pfad).
- [ ] NO-GO: Ursache dokumentiert + Human-Empfehlung, welches Backend aufzusetzen.
## Nicht anfassen
`src/`, `tests/`, `pyproject.toml`, `ROADMAP.md`, `STATE.md` — alles außer `spike/model-api/`.
Kein Produktionscode schreiben. Spike-Branch wird nach GO verworfen.
## Commit & Push
- Conventional Commit: `docs: spike model-api format discovery [GO/NO-GO]`
- Trailer: `Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>`
- Push nach `origin spike/model-api`.
- Kein PR — Leader entscheidet nach GO/NO-GO über nächsten Schritt.
## Abschluss
1. `STATE.md` aktualisieren: F-02 Spike-Ergebnis + GO/NO-GO eintragen.
2. Falls GO: Leader dispatcht F-05 (Porter · Sonnet) mit `result.md` als Spec.
Falls NO-GO: Leader markiert F-05 als ⛔ blocked-extern + Human-Eskalation.
3. Session-Log: `sessions/F-02-<datum>.md`.
4. Hygiene-Gate: `bash scripts/gate-session-hygiene.sh`.
```

View File

@@ -0,0 +1,42 @@
# Session S-BOOTSTRAP — 2026-06-03
- **Rolle:** leader
- **Modell:** Sonnet 4.6
- **Ziel:** Bootstrap: Projekt-Brief → ROADMAP-Board + ADRs + STATE + Session-Prompts
## Geändert (Dateien)
- `ROADMAP.md` — Board mit 7 Items (F-01…F-07), DAG, Ready-Set
- `STATE.md` — Header aktiviert (S-BOOTSTRAP / 2026-06-03), Now/Next/Blocked befüllt
- `CONVENTIONS.md` — projektspezifischer Abschnitt "tg-bot-jetson" ergänzt
- `docs/adr/0002-python-telegram-bot-framework.md` — neu
- `docs/adr/0003-whitelist-env-var.md` — neu
- `docs/adr/0004-modell-api-spike-first.md` — neu
- `session-prompts/F-01-skeleton.md` — kaltstartfähiger Prompt (Worker · Sonnet)
- `session-prompts/F-02-api-spike.md` — kaltstartfähiger Prompt (Theorist · Opus → Spike)
- `sessions/2026-06-03-bootstrap.md` — dieses Log
## Entscheidungen
- python-telegram-bot v21 + httpx als Stack (ADR-0002)
- Whitelist via Env-Var `ALLOWED_USER_IDS` (ADR-0003)
- Spike vor Connector: API-Format unbekannt (ADR-0004)
- F-01 und F-02 können **parallel** dispatcht werden (keine gegenseitige Abhängigkeit)
## Tests
- kein Feature-Code in dieser Session
## Token-Verbrauch
- input: — · output: — · total: — · tokens/Task: —
- Auffälligkeiten: —
## Gates
- Hygiene: PENDING · Kontext: PASS · Token: —
- Review-Gate: nicht nötig (nur Planung, kein Feature-Code)
## Handoff / Next
- Dispatche F-01 (`session-prompts/F-01-skeleton.md`) und F-02 (`session-prompts/F-02-api-spike.md`) **parallel**.
- Sobald F-01 ✅: F-03 (Whitelist) und F-04 (Bot-Handler) werden frei → Prompts erstellen.
- Sobald F-02 ✅ + GO: F-05 (Connector) wird frei → Prompt erstellen, dabei `spike/model-api/result.md` als Spec einbinden.
- Review-Gate nötig? Nein (Bootstrap-Session, kein Code)
## Clean-Start-Check
- [x] Orientierung allein aus AGENTS/STATE/CONVENTIONS möglich.