nub/README.md
Tom a97013d876 initial commit
- v 0.1.0 siehe CHANGELOG.md
2026-07-25 11:08:01 +02:00

338 lines
11 KiB
Markdown

# nub
Schlanker, terminal-nativer Coding-Agent als einzelnes Go-Binary. Keine
Laufzeit-Abhängigkeiten, interaktive TUI, skriptbarer Print-Modus.
- Features: [docs/FEATURES.md](docs/FEATURES.md)
- Architektur/Design: [docs/KONZEPT.md](docs/KONZEPT.md)
- Entwicklung/Tests: [docs/TESTING.md](docs/TESTING.md)
## Voraussetzungen
- Go 1.24+
- OpenAI-kompatibler Endpoint (OpenAI-API-Key oder lokaler Server: Ollama,
LM Studio, vLLM, …)
- Linux/macOS (Windows nur über WSL)
## Installation
```bash
git clone <repo-url> nub && cd nub
go build -o nub ./cmd/nub
mv nub /usr/local/bin/ # optional
```
## Schnellstart
```bash
export OPENAI_API_KEY=sk-...
cd /pfad/zu/deinem/projekt
nub
```
Startet eine interaktive Session im aktuellen Verzeichnis — das wird zur
Wurzel für alle Datei-Tools und `bash`-Aufrufe. Ohne Config-Datei laufen
sinnvolle Defaults (Modell `gpt-4o` gegen die echte OpenAI-API).
## Konfiguration
Geschichtet, spätere Schicht gewinnt: `Defaults``~/.config/nub/config.toml`
(global) → `<projekt>/.nub/config.toml` (projektlokal) → `NUB_*`-Env-Vars.
### Nur Umgebungsvariablen
| Variable | Pflicht | Default | Bedeutung |
|---|---|---|---|
| `NUB_API_KEY` | nein* | — | API-Key, Vorrang vor `OPENAI_API_KEY` |
| `OPENAI_API_KEY` | nein* | — | Fallback |
| `NUB_BASE_URL` | nein | `https://api.openai.com/v1` | Endpoint-URL |
| `NUB_MODEL` | nein | `gpt-4o` | Modellname |
\* Pflicht, außer der Endpoint beginnt mit `http://` (lokal, kein Key nötig).
```bash
export OPENAI_API_KEY=sk-...
export NUB_MODEL=gpt-4o-mini
```
```bash
export NUB_BASE_URL=http://localhost:11434/v1
export NUB_MODEL=qwen2.5-coder:7b
```
### Mit Config-Datei
`nub init` (oder `/init` in der TUI) legt `.nub/config.toml` (kommentierte
Beispiel-Config inkl. Permissions) und ein minimales `AGENTS.md` an — nur
falls noch nicht vorhanden.
Von Hand, `.nub/config.toml` (`version = 1` ist Pflicht):
```toml
version = 1
[model]
default = "gpt-4o-mini"
endpoint = "openai"
[[endpoint]]
name = "openai"
base_url = "https://api.openai.com/v1"
api_key = "env:OPENAI_API_KEY" # oder direkt der Key, oder "none" für lokal
[context]
files = ["AGENTS.md", "REPOMAP.md"]
walk_up = true
max_tokens = 20000
```
- Mehrere `[[endpoint]]`-Blöcke möglich; `model.endpoint` wählt aus.
- `[endpoint.caps]` überschreibt einzelne Fähigkeiten (z.B.
`parallel_tool_calls = false` für Server, die das nicht unterstützen).
- Fehlt bei einem Nicht-lokalen Endpoint der Key, bricht `nub` sofort ab.
## Bedienung
TUI standardmäßig im Terminal (stdin+stdout), sonst Print-Modus. `-p`
erzwingt Print-Modus.
### TUI
| Taste/Kommando | Wirkung |
|---|---|
| `Enter` | Nachricht senden (läuft ein Turn: als Steering zwischen zwei Tool-Aufrufen eingeschleust) |
| `Alt+Enter` | als Follow-up queuen (erst nach Ende des laufenden Turns) |
| `↑`/`↓` | Eingabe-Historie (bei leerer Eingabezeile) |
| `PgUp`/`PgDn`, `Ctrl+U`/`Ctrl+D`, Mausrad | Nachrichtenliste scrollen |
| `Ctrl+C`, `/exit`, `/quit` | beenden |
Diffs (`write`/`edit`) farbig im Transkript, fertige Antworten als Markdown.
Farben passen sich automatisch an helles/dunkles Terminal-Theme an.
**Slash-Kommandos:**
| Kommando | Wirkung |
|---|---|
| `/model [name]` | Modell anzeigen oder für den Rest der Session wechseln |
| `/tree`, `/branch` | Session-Baum anzeigen, Rewind mit ↑/↓ + Enter |
| `/sessions` | Sessions auflisten, wechseln (Enter), löschen (Entf, Rückfrage) |
| `/compact` | Session sofort zusammenfassen |
| `/context` | geladenen Kontext mit Herkunft/Tokenkosten anzeigen |
| `/mcp` | verbundene MCP-Server und ihre Tools |
| `/skills` | gefundene Skills |
| `/export [pfad]` | Transkript als Markdown exportieren |
| `/init` | `.nub/config.toml` + `AGENTS.md` anlegen, falls nicht vorhanden |
| `/clear` | Anzeige leeren (Session bleibt erhalten) |
| `/exit`, `/quit` | beenden |
| `/help` | Kommando-Übersicht |
Jeder gefundene Skill ist zusätzlich direkt als `/<name> [Zusatzinfo]`
aufrufbar (siehe [Skills](#skills)).
### Print-Modus (`-p`)
Zeilenweise stdin = eine Nachricht. Antworten auf stdout, Tool-Aktivität
(`→ tool_name {...}`, `← tool_name [ok|error]`, `bash`-Output) auf stderr.
`Ctrl+D` (EOF) beendet sauber nach dem aktuellen Turn.
```bash
./nub -p
Lies die Datei go.mod und fasse in einem Satz zusammen, was das Modul ist.
```
Beim Start gibt `nub` (beide Modi) auf stderr die Session-ID aus
(`session: 01J...`).
## Sessions
Jeder Lauf ohne Subcommand startet eine neue Session, persistiert unter
`.nub/sessions/<id>.jsonl` (automatisch von Git ausgeschlossen via
`.git/info/exclude`).
```bash
nub sessions # Sessions im aktuellen Verzeichnis auflisten
nub resume <session-id> # Session fortsetzen
```
In der TUI: `/sessions` (Liste, wechseln, löschen).
**Rewind/Branch:** in der TUI über `/tree`/`/branch`. Über CLI/Print-Modus
per Node-ID:
```bash
cat .nub/sessions/<session-id>.jsonl | jq -r 'select(.node) | .node.id + " " + (.node.message.content[0].text // "" | .[0:60])'
nub resume <session-id> --branch <node-id>
```
Setzt den Head auf den gewählten Knoten zurück; eine neue Nachricht bildet
dort einen zweiten Ast. Der ursprüngliche Ast bleibt erhalten.
## Kontext (AGENTS.md, REPOMAP.md, nub map)
System-Prompt = Basis-Prompt (überschreibbar durch `SYSTEM.md` im
Projekt-Root) + statische Umgebungsinfo (OS/Shell/Repo-Root/Branch) + Dateien
aus `context.files` (Default: `AGENTS.md`, `REPOMAP.md`). Mit
`walk_up = true` (Default) werden Treffer zwischen aktuellem Verzeichnis und
Projekt-Root eingesammelt.
```bash
nub context # geladene Kontext-Dateien mit Herkunft und Tokenkosten
nub map # REPOMAP.md generieren/aktualisieren
```
`context.max_tokens` (Default 20000) begrenzt Kontext-Dateien, kürzt sichtbar
statt still. `nub map` erzeugt Verzeichnisbaum + exportierte Symbole
(`.go` über `go/ast`, sonst erste Zeile als Fallback); warnt, wenn die
Repomap vom Git-Stand abweicht.
## Compaction & todo-Tool
Vor jedem Turn geschätzte Tokenkosten; über Schwelle (Default 75 % des
Modell-Fensters) wird automatisch komprimiert: ältere Hälfte der Session
wird per separatem Prompt zusammengefasst, letzte Turns bleiben im Original.
Original-Nodes bleiben erhalten — Rewind vor die Compaction funktioniert
weiterhin.
```bash
nub compact <session-id> # Compaction sofort erzwingen
```
`todo`-Tool: In-Memory-Todo-Liste für lange Aufgaben (nicht persistiert),
das Modell entscheidet selbst über die Nutzung.
## Skills
`.nub/skills/<name>/SKILL.md` (projektlokal) oder
`~/.nub/skills/<name>/SKILL.md` (global, konfigurierbar über
`[skills] paths = [...]`). Projektlokal überschreibt global.
```markdown
---
name: refactoring
description: Vorgehen für größere Refactorings in diesem Repo.
---
# Refactoring
...Body...
```
Beim Start landet nur `name`+`description` im System-Prompt (~30 Token pro
Skill); den Body lädt das Modell selbst nach (`read_skill`), weitere
Dateien im Skill-Verzeichnis über `read`/`glob`.
```bash
nub skills # Index-Vorschau
```
**Als Slash-Command:** `/<name> [Zusatzinfo]`, z.B. `/refactoring fokus auf
error handling` — schickt eine kurze Direktive statt Rohdaten, Progressive
Disclosure bleibt erhalten. Eingebaute Kommandos haben bei Namenskollision
Vorrang.
## MCP
```toml
[[mcp]]
name = "github"
command = "gh-mcp-server"
args = []
tools = ["create_issue", "get_pull_request"] # Allowlist; leer = alle
[[mcp]]
name = "linear"
url = "https://mcp.linear.app/mcp"
```
Alle Server parallel verbunden (Timeout 5s/Server), Tools mit
`<server>__`-Präfix (z.B. `github__create_issue`). Nicht erreichbare Server
verhindern den Start nicht (Warnung, `nub` läuft weiter).
```bash
nub mcp # verbindet und listet Tools
```
**Profile** grenzen ein, welche Server pro Aufruf verbunden werden:
```toml
[profiles]
review = ["github"]
default = []
```
```bash
nub --profile review
nub resume <session-id> --profile review
```
Ohne `[profiles]`-Sektion: immer alle konfigurierten Server.
## Permissions
```toml
[permissions]
read = "auto"
glob = "auto"
grep = "auto"
write = "ask"
edit = "ask"
bash = "ask"
deny_paths = [".git/**", "**/.env", "**/id_rsa*"]
deny_bash = ["rm -rf /", "git push --force*"]
```
| Modus | Verhalten |
|---|---|
| `auto` (Default) | läuft ohne Rückfrage |
| `ask` | TUI: Rückfrage-Block im Transkript, `y`/`Y` erlaubt, jede andere Taste lehnt ab. Print-Modus: harter Fehler |
| `deny` | läuft nie |
- `deny_paths`/`deny_bash` überstimmen `auto`/`ask` immer. `deny_paths` gilt
für `read`/`write`/`edit`/`grep` (`path`-Feld), `deny_bash` matcht den
Befehlstext (Glob/Teilstring).
- Tools ohne eigenes Config-Feld (MCP, `todo`, `read_skill`) laufen immer
`auto`.
- Mehrere gleichzeitige Tool-Aufrufe: Rückfragen laufen nacheinander vor dem
parallelen Start der erlaubten Calls — nie zwei Dialoge gleichzeitig.
### `question`-Tool
Gleiche Rückfrage-Mechanik als eigenständiges Tool: Modell oder
Skill-Anweisung stellt eine freie Frage (optional mit Vorschlägen), Antwort
kommt als Tool-Ergebnis zurück. TUI: Block im Transkript, nächste Eingabe
zählt als Antwort statt neuer Nachricht/Kommando. Print-Modus: sofortiger
Fehler (kein Blockieren, Print läuft headless).
## Alle CLI-Kommandos
```
nub init .nub/config.toml + AGENTS.md anlegen, falls nicht vorhanden
nub neue Session starten (TUI im Terminal)
nub -p Print-Modus erzwingen
nub resume <session-id> Session fortsetzen
nub resume <session-id> --branch <node-id>
von einem früheren Knoten fortsetzen (Rewind)
nub sessions Sessions auflisten
nub map REPOMAP.md erzeugen/aktualisieren
nub context geladenen Kontext anzeigen
nub compact <session-id> Compaction erzwingen
nub skills gefundene Skills auflisten
nub mcp MCP-Server verbinden, Tools auflisten
nub [resume ...] --profile <p> nur MCP-Server aus profiles.<p> verbinden
```
## Bekannte Grenzen
- Bilder werden nicht verarbeitet, auch wenn der Endpoint sie unterstützt.
- Permissions/`deny_paths` gelten nur für die sechs eingebauten Datei-/
Bash-Tools — MCP-Tools laufen immer `auto`.
- Compaction nutzt immer dasselbe Modell wie die Session.
- MCP-Server reconnecten nicht zur Laufzeit (Neustart nötig); nur Tools
angebunden, keine Prompts/Resources.
- Skills müssen von Hand angelegt werden.
Ausführlichere Liste: [docs/TESTING.md](docs/TESTING.md).
## Mitentwickeln
Build, Tests, manuelle Testrezepte: [docs/TESTING.md](docs/TESTING.md).
Architektur/Design-Entscheidungen: [docs/KONZEPT.md](docs/KONZEPT.md).