Dieser Leitfaden beschreibt die machine-neutrale Architektur, Einrichtung und Absicherung einer vollständigen lokalen Coding-Agent-Umgebung auf Basis von OpenCode (Coding-Harness) und OpenChamber (Web- & Mobile-UI), angebunden an den AcademicAI Proxy und remote erreichbar über ein privates Tailscale-Netzwerk.
Das Setup trennt Kernaufgaben sauber in spezialisierte Schichten:
┌─────────────────────────────────────────────────────────────┐
│ AcademicAI Backend │
└──────────────────────────────┬──────────────────────────────┘
│ HTTPS (REST / Auth Token)
▼
┌─────────────────────────────────────────────────────────────┐
│ AcademicAI-Proxy (Lokal) │
│ - Host: 127.0.0.1:11435 │
│ - OpenAI-kompatible API (/v1/chat/completions, /v1/models) │
│ - Tool-Emulation (TypeScript-Schema & JSON-Repair) │
│ - KV-Prefix-Cache-Optimierung (Azure OpenAI) │
└──────────────────────────────┬──────────────────────────────┘
│ HTTP / JSON (127.0.0.1)
▼
┌─────────────────────────────────────────────────────────────┐
│ OpenCode (Coding-Harness) │
│ - Headless Agent-Runtime & CLI │
│ - Provider: @ai-sdk/openai-compatible │
│ - Multi-Turn Tool-Execution (Bash, Edit, Read, Glob etc.) │
│ - Lauscht strikt auf Loopback (127.0.0.1) │
└──────────────────────────────┬──────────────────────────────┘
│ IPC / Headless API (127.0.0.1)
▼
┌─────────────────────────────────────────────────────────────┐
│ OpenChamber Server (Web / PWA) │
│ - Port 3333 (Port 3000 ist fuer MiroFish reserviert) │
│ - Gesteuerter OpenCode-Lifecycle │
│ - Passwortgeschuetzte Web-Oberflaeche │
│ - PWA-Support fuer Mobile Browser (iOS Safari / Android) │
└──────────────────────────────┬──────────────────────────────┘
│ Tailscale Mesh (E2E verschluesselt)
▼
┌─────────────────────────────────────────────────────────────┐
│ Remote Client (z. B. iPhone via Tailscale) │
│ - Zugriff ueber http://<tailscale-magicdns>:<port> │
│ - Keine Router-Portfreigaben, keine Cloud-Relays │
└─────────────────────────────────────────────────────────────┘
- Zero WAN Exposure: Weder der AcademicAI-Proxy noch OpenCode oder OpenChamber sind ueber oeffentliche IP-Adressen (WAN) aus dem Internet erreichbar.
- Loopback-Isolation: Proxy und OpenCode lauschen strikt auf
127.0.0.1. - Tailscale-Exklusivitaet: Eingehende Verbindungen zu OpenChamber (Port 3333) sind per Host-Firewall auf die Tailscale-Schnittstelle beschraenkt.
- Secret-Hygiene: Weder API-Schluessel noch Passwoerter stehen im Klartext in Konfigurationsdateien oder Git-Repositories; sie werden dynamisch ueber Umgebungsvariablen geladen.
- AcademicAI-Proxy: Installiert und lokal lauffähig (Standard: Port
11435). - Node.js: Version 22+ (inklusive
npmoderpnpm). - Tailscale: Installiert und im Ziel-Tailnet eingeloggt.
- Firewall: Paketfilter auf Betriebssystemebene (Windows Defender Firewall,
nftablesoderpf).
OpenCode wird über den offiziellen Node-Paketmanager installiert:
# Global via npm
npm install -g opencode-ai@latest
# Oder via pnpm
pnpm add -g opencode-ai@latestVerifikation:
opencode --versionOpenCode sucht seine globale Konfiguration machine-spezifisch unter:
- Linux/macOS:
~/.config/opencode/opencode.json - Windows:
%USERPROFILE%\.config\opencode\opencode.json
Erstelle oder ergänze die Datei mit dem Provider academicai:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"academicai": {
"npm": "@ai-sdk/openai-compatible",
"name": "AcademicAI",
"options": {
"baseURL": "http://127.0.0.1:11435/v1",
"apiKey": "{env:ACADEMICAI_PROXY_API_KEY}"
},
"models": {
"gpt-5.5": {
"name": "GPT-5.5",
"tool_call": true,
"reasoning": true,
"limit": {
"context": 128000,
"output": 128000
}
},
"gpt-5-mini": {
"name": "GPT-5 Mini",
"tool_call": true,
"reasoning": true,
"limit": {
"context": 128000,
"output": 128000
}
},
"o3": {
"name": "o3",
"tool_call": true,
"reasoning": true,
"limit": {
"context": 128000,
"output": 100000
}
},
"claude-opus-4-8": {
"name": "Claude Opus 4.8",
"tool_call": true,
"reasoning": true,
"limit": {
"context": 128000,
"output": 128000
}
},
"gemini-3.5-flash": {
"name": "Gemini 3.5 Flash",
"tool_call": true,
"reasoning": false,
"limit": {
"context": 128000,
"output": 65535
}
}
}
}
}
}Wichtig: OpenCode unterstützt native Token-Substitution via
{env:VARIABLE}. Der API-Schlüssel verbleibt in der Umgebung (ACADEMICAI_PROXY_API_KEY) und wird nicht in der JSON-Datei gespeichert.
Bei benutzerdefinierten Providern (@ai-sdk/openai-compatible) kann OpenCode die technischen Parameter und Fähigkeiten der Upstream-Modelle nicht automatisch auflösen. Es wird daher dringend empfohlen, für jedes Modell in opencode.json die spezifischen Charakteristiken explizit zu setzen:
limit.context&limit.output(Kontextfenster und Ausgabelimits):- Kontextauslastung: OpenChamber kann den Token-Verbrauch nur dann akkurat im Chat-Interface visualisieren, wenn das reale Kontextfenster hinterlegt ist.
- Pruning & Kompaktierung: Ohne explizite Limits greift OpenCode auf konservative Standardannahmen zurück (z. B. 4k oder 8k Tokens).
reasoning(true/false):- Signalisiert OpenCode, ob das Modell interne Denkprozesse (Chain-of-Thought / Thinking) besitzt. Steuert die Darstellung und Behandlung von Denkblöcken (
collapsibleThinkingBlocks) im UI.
- Signalisiert OpenCode, ob das Modell interne Denkprozesse (Chain-of-Thought / Thinking) besitzt. Steuert die Darstellung und Behandlung von Denkblöcken (
tool_call(true/false):- Bestimmt, ob OpenCode Werkzeuge (Dateizugriffe, Terminal, LSP) an das Modell weiterreicht. Reine Such- oder Chatmodelle sollten auf
falsestehen.
- Bestimmt, ob OpenCode Werkzeuge (Dateizugriffe, Terminal, LSP) an das Modell weiterreicht. Reine Such- oder Chatmodelle sollten auf
Tip
Praxis-Standard: Kontextfenster aller Modelle auf 128k begrenzen (context: 128000)
In der Praxis wird für alle Modelle in OpenCode/OpenChamber empfohlen, limit.context standardmäßig auf 128000 (128k Tokens) zu setzen:
- 100 % Tarifschutz (Basis-Preisstufe): Sowohl Google (Vertex AI / AI Studio) als auch Microsoft (Azure OpenAI / Foundry Concepts) staffeln ihre Tarife bei 128k Input-Tokens (
128.000). Ein Limit von 128k stellt sicher, dass Anfragen ausnahmslos in der günstigsten Basis-Preisstufe (Tier 1) abgerechnet werden und niemals der verdoppelte Long-Context-Zuschlag anfällt. - Ausreichend Raum: 128k Tokens entsprechen rund 400–500 Buchseiten Text – das bietet selbst für komplexe Codebases und Multi-File-Refactorings mehr als genug Kontext.
- Laufzeit-Performance & Latenz: Hält Antwort- und Streamingzeiten schnell und berechenbar.
- Frühzeitige Kompaktierung (Pruning): OpenCode fasst Chatverläufe rechtzeitig vor 128k zusammen, wodurch Sitzungen nicht unkontrolliert anschwellen.
| Modell-ID | Anzeigename | context (Praxis-Limit) |
output |
tool_call |
reasoning |
|---|---|---|---|---|---|
gpt-5.5 |
GPT-5.5 | 128000 (Backend: 1,05M) |
128000 |
true |
true |
gpt-5.2 |
GPT-5.2 | 128000 (Backend: 400k) |
128000 |
true |
true |
gpt-5 |
GPT-5 | 128000 (Backend: 400k) |
128000 |
true |
true |
gpt-5-mini |
GPT-5 Mini | 128000 (Backend: 400k) |
128000 |
true |
true |
gpt-5-nano |
GPT-5 Nano | 128000 (Backend: 400k) |
128000 |
true |
true |
gpt-4o |
GPT-4o | 128000 |
16384 |
true |
false |
o3 |
o3 | 128000 (Backend: 200k) |
100000 |
true |
true |
claude-opus-4-8 |
Claude Opus 4.8 | 128000 (Backend: 1M) |
128000 |
true |
true |
claude-opus-4-6 |
Claude Opus 4.6 | 128000 (Backend: 1M) |
128000 |
true |
true |
gemini-3.5-flash |
Gemini 3.5 Flash | 128000 (Backend: 1M) |
65535 |
true |
false |
gemini-3.1-flash-lite |
Gemini 3.1 Flash Lite | 128000 (Backend: 1M) |
65535 |
true |
false |
gemini-3.1-pro-preview |
Gemini 3.1 Pro Preview | 128000 (Backend: 1M) |
65535 |
true |
false |
gemini-2.5-pro |
Gemini 2.5 Pro | 128000 (Backend: 1M) |
65535 |
true |
false |
Mistral-Large-3 |
Mistral Large 3 | 128000 (Backend: 256k) |
4096 |
true |
false |
sonar-pro |
Sonar Pro | 128000 (Backend: 200k) |
8192 |
false |
false |
sonar-reasoning-pro |
Sonar Reasoning Pro | 128000 |
4096 |
false |
true |
Verifikation der Provider-Erkennung:
opencode models academicaiopencode kennt für Custom-Provider keine Preise; der Session-Zähler $ Spent
bliebe daher bei 0. Preishoheit und -berechnung liegen beim Proxy:
- Proxy-Endpoint (authentifiziert via
verify_key):GET /internal/opencode-modelsliefert{"currency", "models"}mit Raten pro 1.000.000 Token (inkl.context_over_200kbei gestaffelten Modellen). Der Endpoint bleibt als Preisquelle bestehen. - Config-Sync statt Plugin (opencode ≥ 2.0): opencode 2.0.22 ruft die
v1-Plugin-Hooks
config/provider.modelsnicht mehr auf. Der Proxy schreibt die statischencost-Felder daher direkt in die globale opencode-Config (provider.academicai.models.<id>.cost):- Zielpfad-Auflösung: Override
ACADEMICAI_OPENCODE_CONFIG_FILE→XDG_CONFIG_HOME/opencode/opencode.json(nicht-leer) →~/.config/opencode/opencode.json(auf dem Einsatzhost greift die XDG-Stufe: User-Config-Verzeichnis, siehe Pfad-Tabelle unten). - Der Sync läuft best-effort beim Proxy-Start (nach
write_pid_file()); opencode 2 beobachtet die Config (config.updated) und lädt sie zur Laufzeit neu. - Manueller Lauf:
python -m academicai.opencode_config_sync --config <pfad>(Exit0bei Erfolg/No-op,1bei Parse-/Schreibfehler; genau eine JSON-Zeile auf stdout). - Details und Entscheidung:
decisions/0002-opencode-v2-cost-sync.md.
- Zielpfad-Auflösung: Override
- opencode 1.18.x (Legacy): Dort übernimmt weiterhin das JS-Plugin
(Details:
../integrations/opencode/README.md).
$ Spent-Semantik (opencode 2.0.22):
- opencode rechnet
(nonCacheInput·input + cacheRead·cache_read + (output+reasoning)·output) / 1e6. context_over_200kwird alstier {type: "context", size: 200000}angewandt (hermetisch:300000/500aufgpt-5.5→3.32475=11.0/49.5).- Die Werte sind EUR, opencode rendert
$(bewusst 1:1 ohne Umrechnung). - Cache-Preise bleiben
0→$ Spentunterschätzt bei Cache-Hits. per_request_costist im opencode-Schema nicht abbildbar; die Anzeige gilt nur für neue Assistant-Messages (Alt-Sessions bleiben bei0).- Monatsstand: kein neuer Endpoint;
GET /internal/cost-statusliefert unterlocal_cost_tracking.this_montheinen Aggregations-Bucket (request_count, Tokens,costs) für den laufenden Wien-Lokalmonat, intern unter einemYYYY-MM-Monatsschlüssel abgelegt. Der Reset erfolgt implizit zum Monatswechsel um 00:00 Ortszeit (Europe/Vienna, DST-korrekt).
OpenChamber fungiert als Web- und Mobil-Arbeitsplatz für OpenCode. Es verwaltet den OpenCode-Hintergrundprozess automatisch.
npm install -g @openchamber/web@latestVerifikation:
openchamber --versionOpenChamber bietet integrierten Passwortschutz für Browser-Sessions. Das Kennwort kann über die Umgebungsvariable OPENCHAMBER_UI_PASSWORD übergeben werden.
# Server mit Authentifizierung und Bindung an alle lokalen Schnittstellen starten (Port 3333)
openchamber serve --host 0.0.0.0 --port 3333- OpenCode-Anbindung: OpenChamber erkennt das installierte
opencode-Binary automatisch und startet es als Headless-Instanz ausschließlich auf127.0.0.1. - Health-Check:
GET http://127.0.0.1:3333/healthgibt den Status von Web-UI und OpenCode-Prozess im JSON-Format aus.
Um sicherzustellen, dass Port 3333 trotz Bindung an 0.0.0.0 nicht aus dem physischen LAN/WLAN erreichbar ist, wird eine Inbound-Firewall-Regel gesetzt:
- Regel-Aktion: Eingehenden TCP-Verkehr auf Port
3333zulassen. - Schnittstellenbeschränkung: Ausschließlich das virtuelle Tailscale-Interface (z. B.
InterfaceAlias: Tailscaleoder Subnetz100.64.0.0/10) und Loopback (127.0.0.1). - Alle anderen Adapter (Ethernet, Wi-Fi, Mobilfunk) blockieren.
Sobald der Host im Tailnet aktiv ist, lauten die stabilen Adressen:
- MagicDNS (bevorzugt):
http://<hostname>.<tailnet-domain>.ts.net:3333 - Tailscale-IPv4:
http://100.x.y.z:3333
OpenChamber liefert ein vollständiges Web App Manifest (/site.webmanifest) und Touch-Icons aus.
- Sicherstellen, dass die Tailscale-App auf dem iPhone aktiv und mit demselben Tailnet verbunden ist.
- Im mobilen Safari die MagicDNS- oder Tailscale-IP-Adresse aufrufen (
http://<hostname>.<tailnet>.ts.net:3333). - Das hinterlegte UI-Passwort eingeben.
- Auf das Teilen-Symbol (Viereck mit Pfeil nach oben) tippen.
- „Zum Home-Bildschirm“ auswählen.
- OpenChamber startet nun als eigenständige Progressive Web App (PWA) im Vollbildmodus ohne Browserleisten.
Für einen unterbrechungsfreien Betrieb sollten der AcademicAI-Proxy und OpenChamber nach einem Systemneustart automatisch gestartet werden.
- Schritt 1:
AcademicAI-Proxystarten (Port11435bereitstellen). - Schritt 2:
OpenChamberstarten (mit 10–15 Sekunden Verzögerung; OpenChamber initialisiert OpenCode bei Bedarf selbst).
- Windows: Windows Aufgabenplanung (Task Scheduler) mit zwei zeitversetzten Trigger-Aktionen beim Benutzer-Login.
- Linux:
systemd --userServices mitWants=tailscaled.serviceund aktivierter Linger-Funktion (loginctl enable-linger $USER). - macOS:
launchdUser LaunchAgents unter~/Library/LaunchAgents/.
OpenCode und OpenChamber speichern umfangreiche dynamische Laufzeitdaten (SQLite-Datenbank aller Sessions, Snapshots, heruntergeladene lokale Offline-Sprachmodelle für STT/TTS von bis zu 1 GB, Chat-Exporte, Modell-Caches und Logs).
Standardmäßig liegen diese im Benutzerverzeichnis (~/.config, ~/.local/share, ~/.cache bzw. %USERPROFILE%). Um System-Partitionen (z. B. C:\) zu entlasten und alle Daten auf einer dedizierten Datenpartition (z. B. D:\) zu bündeln, werden standardisierte Umgebungsvariablen verwendet:
| Komponente | Variable | Standard | Beispiel für Datenpartition (D:\) |
|---|---|---|---|
| OpenChamber | OPENCHAMBER_DATA_DIR |
~/.config/openchamber |
D:\users\dagobert\.openchamber |
| OpenChamber | OPENCHAMBER_MANAGED_PROCESS_REGISTRY |
~/.config/openchamber/managed-opencode |
D:\users\dagobert\.openchamber\managed-opencode |
| OpenCode | XDG_CONFIG_HOME |
~/.config |
D:\users\dagobert\.opencode\config |
| OpenCode | XDG_DATA_HOME |
~/.local/share |
D:\users\dagobert\.opencode\data |
| OpenCode | XDG_CACHE_HOME |
~/.cache |
D:\users\dagobert\.opencode\cache |
OpenChamber vererbt diese Umgebungsvariablen automatisch an die verwaltete OpenCode-Kindinstanz. Dadurch werden Session-Daten (opencode.db), Logs, Snapshots und Modelle direkt auf dem Zielvolume gespeichert.