docs: README with architecture, setup and quickstart; R8 rule for Tink annotations
This commit is contained in:
parent
1c5f7f582f
commit
bf00f56117
2 changed files with 125 additions and 0 deletions
123
README.md
Normal file
123
README.md
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
# OpenClaw
|
||||
|
||||
Schlanker, selbst gehosteter KI-Assistent: **Go-Backend** (ein statisches Binary, kein CGO) + **nativer Android-Client** (Kotlin, Jetpack Compose).
|
||||
|
||||
## Architektur
|
||||
|
||||
```
|
||||
Android-App (Compose) Go-Backend (cmd/openclaw)
|
||||
├─ Einstellungen (EncryptedSharedPrefs) ├─ internal/server HTTP-API + WebSocket, Bearer-Token, Origin-Check
|
||||
├─ Chat ──── WebSocket /api/ws ───────▶ ├─ internal/agent Agent-Loop mit Tool-Calling, Lock pro Session
|
||||
└─ Sessions ─ REST /api/sessions ──────▶ ├─ internal/llm Provider-Interface + OpenAI-kompatibler Streaming-Provider
|
||||
├─ internal/tools time_now, web_fetch, file_read/_write/_list
|
||||
├─ internal/store SQLite (modernc.org/sqlite, pure Go)
|
||||
└─ internal/config YAML/JSON + Umgebungsvariablen
|
||||
```
|
||||
|
||||
Ablauf einer Nachricht: Client → `/api/ws` → Agent speichert User-Nachricht → LLM (Streaming) → bei Tool-Calls werden Tools ausgeführt, Ergebnisse gespeichert und das LLM erneut gefragt (max. `agent.max_iterations`) → Tokens werden live als `delta`-Events gestreamt, am Ende `done`.
|
||||
|
||||
Abhängigkeiten des Backends: `gopkg.in/yaml.v3`, `modernc.org/sqlite`, `github.com/coder/websocket`.
|
||||
|
||||
## Sichere Defaults
|
||||
|
||||
- Start verweigert ohne `auth_token` (mind. 16 Zeichen); Vergleich in konstanter Zeit.
|
||||
- Lauscht standardmäßig nur auf `127.0.0.1:8787`.
|
||||
- Browser-Origins: nur gleicher Host oder explizit in `allowed_origins`; `*` muss bewusst gesetzt werden. Native Clients (ohne `Origin`-Header) brauchen trotzdem das Token.
|
||||
- TLS-Zertifikatsprüfung ist überall an (LLM-Provider, `web_fetch`); es gibt keinen Schalter zum Abschalten.
|
||||
- `web_fetch`: nur http(s), Timeout, Größenlimit, max. 5 Redirects, blockiert Loopback/Private/Link-Local/CGNAT-Adressen beim Verbindungsaufbau (schützt auch gegen DNS-Rebinding und Redirect-Tricks). Abschaltbar per `allow_private`.
|
||||
- Datei-Tools sind per `os.Root` auf den Workspace beschränkt (kein `..`, keine absoluten Pfade, keine Symlink-Ausbrüche) und größenbegrenzt.
|
||||
- Kein Shell-Tool.
|
||||
- Docker: distroless, User `65532` (nonroot), Go-Version fixiert.
|
||||
- Android: Release-Builds erlauben nur HTTPS/WSS; Klartext (http/ws) nur im Debug-Build für lokale Entwicklung. Token/URL verschlüsselt per Android Keystore.
|
||||
|
||||
## Quickstart Backend
|
||||
|
||||
```bash
|
||||
cp config.example.yaml config.yaml
|
||||
export OPENCLAW_AUTH_TOKEN=$(openssl rand -hex 32)
|
||||
export OPENCLAW_LLM_API_KEY=sk-... # OpenAI / OpenRouter; für Ollama leer lassen
|
||||
make run # = go build + ./bin/openclaw -config config.yaml
|
||||
```
|
||||
|
||||
Provider-Beispiele (`llm.base_url` / `llm.model`):
|
||||
|
||||
| Provider | base_url | model (Beispiel) |
|
||||
|------------|---------------------------------|-------------------------|
|
||||
| OpenAI | https://api.openai.com/v1 | gpt-4o-mini |
|
||||
| OpenRouter | https://openrouter.ai/api/v1 | openai/gpt-4o-mini |
|
||||
| Ollama | http://localhost:11434/v1 | llama3.1 (Tool-fähig) |
|
||||
|
||||
Test:
|
||||
|
||||
```bash
|
||||
curl localhost:8787/healthz
|
||||
curl -H "Authorization: Bearer $OPENCLAW_AUTH_TOKEN" -d '{"text":"Wie spät ist es in Berlin?"}' localhost:8787/api/chat
|
||||
```
|
||||
|
||||
### API
|
||||
|
||||
| Methode | Pfad | Zweck |
|
||||
|---------|------------------------------------|------------------------------------------|
|
||||
| GET | /healthz | Health (ohne Auth) |
|
||||
| GET | /api/sessions | Sessions (neueste zuerst) |
|
||||
| POST | /api/sessions | Session anlegen `{"title":""}` |
|
||||
| GET/PATCH/DELETE | /api/sessions/{id} | Lesen / umbenennen / löschen |
|
||||
| GET | /api/sessions/{id}/messages | Verlauf |
|
||||
| POST | /api/chat | Nicht-streamend `{"session_id"?, "text"}`|
|
||||
| GET | /api/ws | WebSocket-Streaming |
|
||||
|
||||
Alle `/api/*` brauchen `Authorization: Bearer <token>`.
|
||||
WebSocket: Client sendet `{"type":"message","session_id":"<optional>","text":"..."}`; Server sendet Events
|
||||
`session`, `delta`, `tool_call`, `tool_result`, `done` oder `error` (`{"type","text","tool","args","call_id","session_id"}`). `{"type":"ping"}` → `pong`.
|
||||
|
||||
### Build, Tests, Cross-Builds
|
||||
|
||||
```bash
|
||||
make # vet + test + build
|
||||
make race # Tests mit Race-Detector (benötigt CGO)
|
||||
make cross # dist/: linux-amd64, linux-arm64, linux-armv7, termux-arm64, termux-armv7
|
||||
make docker
|
||||
```
|
||||
|
||||
Termux: `openclaw-termux-arm64` ist ein `GOOS=android`-Build; für armv7 wird ein statisches `linux/arm`-Binary gebaut, da `android/arm` ohne NDK/CGO nicht linkbar ist. In Termux z. B. nach `$PREFIX/bin` kopieren, `chmod +x` und starten.
|
||||
|
||||
### Docker
|
||||
|
||||
```bash
|
||||
docker build -t openclaw .
|
||||
docker run -d -p 127.0.0.1:8787:8787 -v openclaw-data:/data \
|
||||
-e OPENCLAW_AUTH_TOKEN=... -e OPENCLAW_LLM_API_KEY=... openclaw
|
||||
```
|
||||
|
||||
Im Container lauscht der Server auf `0.0.0.0:8787`; nach außen nur hinter einem TLS-Reverse-Proxy (Caddy, Traefik) oder in einem VPN (z. B. Tailscale) freigeben.
|
||||
|
||||
## Android-Client
|
||||
|
||||
```
|
||||
android/
|
||||
├─ app/src/main/java/dev/openclaw/client/
|
||||
│ ├─ MainActivity.kt Navigation (Chat, Sessions, Einstellungen)
|
||||
│ ├─ data/OpenClawApi.kt OkHttp REST + WebSocket-Flow
|
||||
│ ├─ data/SettingsStore.kt EncryptedSharedPreferences
|
||||
│ ├─ data/Models.kt kotlinx.serialization
|
||||
│ └─ ui/ ChatViewModel, Compose-Screens
|
||||
└─ gradle/libs.versions.toml Versionskatalog (AGP 8.7.3, Kotlin 2.0.21, compileSdk 35, minSdk 26)
|
||||
```
|
||||
|
||||
Build (JDK 17 + Android SDK, `ANDROID_HOME` oder `local.properties` mit `sdk.dir`):
|
||||
|
||||
```bash
|
||||
cd android
|
||||
./gradlew assembleDebug # app/build/outputs/apk/debug/app-debug.apk
|
||||
./gradlew testDebugUnitTest
|
||||
./gradlew assembleRelease # unsigniert; Signing-Config fehlt noch
|
||||
```
|
||||
|
||||
In der App unter Einstellungen Server-URL (`https://…`; im Debug-Build auch `http://10.0.2.2:8787` für den Emulator) und Token eintragen, „Verbindung testen", speichern.
|
||||
|
||||
## Nächste Schritte
|
||||
|
||||
- Release-Signing, App-Icon, CI (GitHub Actions) für Go + Android
|
||||
- Session-Kontext zusammenfassen statt nur Fenster der letzten N Nachrichten
|
||||
- Weitere Provider (Anthropic nativ), Abbrechen laufender Antworten über WebSocket
|
||||
- Optional: Einrichtung per QR-Code (URL + Token)
|
||||
Loading…
Add table
Add a link
Reference in a new issue