Add: Cline integration

This commit is contained in:
2026-06-16 14:12:56 +02:00
parent 415c265db7
commit 599822036f
21 changed files with 409 additions and 28 deletions
+16
View File
@@ -0,0 +1,16 @@
# Cline's Memory Bank
Du bist Cline, ein erfahrener Softwareentwickler. Du hast eine Besonderheit: Dein Gedächtnis wird periodisch komplett zurückgesetzt. Das ist kein Bug, sondern sorgt dafür, dass du eine perfekte Dokumentation führst. Nach jedem Reset verlässt du dich VOLLSTÄNDIG auf deine "Memory Bank", um das Projekt zu verstehen und die Arbeit fortzusetzen.
## Struktur der Memory Bank
Die Memory Bank besteht aus Markdown-Dateien im Ordner `docs/clinememory/` im Projekt-Root:
- `projectbrief.md`: Das übergeordnete Ziel des Projekts (Was ist das, für wen ist es?).
- `productContext.md`: Warum existiert dieses Projekt, welche Probleme löst es, wie soll es sich verhalten?
- `systemPatterns.md`: Systemarchitektur, technische Muster, wichtige Design-Entscheidungen.
- `techContext.md`: Verwendete Technologien, Laufzeiten, Tools, Build-Befehle, Abhängigkeiten.
- `activeContext.md`: Woran wird *aktuell* gearbeitet, was sind die nächsten Schritte?
- `progress.md`: Was wurde bereits erreicht, was fehlt noch (Roadmap)?
## Deine Pflichten
1. **Prüfung beim Start:** Lies bei JEDER neuen Aufgabe als Erstes die Dateien in `docs/clinememory/`, um den Kontext zu laden. Sollte der Ordner oder die Dateien fehlen, lege sie sofort selbstständig an, indem du das Projekt analysierst!
2. **Aktualisierung:** Wenn du Änderungen am Projekt vornimmst oder wichtige Erkenntnisse gewinnst, aktualisiere die entsprechenden Dateien in der Memory Bank (besonders `activeContext.md` und `progress.md`), bevor du die Aufgabe als beendet erklärst.
+4 -1
View File
@@ -3,7 +3,7 @@
# ==========================================
# --- LLM ENGINE & MODEL SELECTION ---
MODEL_LIST=gemma4:e4b,qwen3.6:35b-a3b-q4_K_M
MODEL_LIST=qwen2.5-coder:14b,qwen3:14b,deepseek-coder-v2:16b
OLLAMA_KEEP_ALIVE=-1
# KV cache quantization for large contexts (recommended on desktop GPUs): q8_0 or q4_0
# OLLAMA_KV_CACHE_TYPE=q8_0
@@ -41,6 +41,9 @@ CONTAINER_ENGINE=podman
# HOST_OPENCLAW_CONFIG_MOUNT_OPTS=:ro,Z
# Optional explicit host workspace path seen by sandbox runtime
# OPENCLAW_SANDBOX_HOST_WORKSPACE=/absolute/path/to/storage/workspace
# Optional localhost publish settings for the MCP router (used by host clients like Cline)
# TOOL_ROUTER_BIND=127.0.0.1
# TOOL_ROUTER_HOST_PORT=3000
# Sandbox base image is auto-built by ghostnet.sh as
# localhost/ghostnet-openclaw_sandbox:latest to include rootless apt defaults.
+61
View File
@@ -27,6 +27,67 @@ Use the integrated management script, which automatically selects the correct ve
### 3. Open the Interactive Chat
`podman exec -it openclaw-agent openclaw chat`
## Using the Stack with Cline in VS Code
You do not need a second local model runtime for Cline. The existing Ollama container is already published on the host at `http://127.0.0.1:11434`.
### 1. Configure Cline to use Ollama
In Cline, select the Ollama provider and use:
```text
Base URL: http://127.0.0.1:11434
Model: qwen3-coding
```
Use `ollama list` inside the container or on the host to see the exact model names currently available.
Recommended custom profiles for this stack:
```text
qwen3-coding -> Qwen3 14B, balanced default for agentic coding
qwen25-coding -> Qwen2.5-Coder 14B, code-first edit and repair profile
deepseek-coding -> DeepSeek-Coder-V2 16B, long-context repo analysis profile
```
### 2. Reuse the existing MCP router for tools
The GhostNet router exposes an MCP SSE endpoint at `http://127.0.0.1:3000/sse`. Add it to your Cline MCP configuration:
```json
{
"mcpServers": {
"ghostnet-router": {
"transport": "sse",
"url": "http://127.0.0.1:3000/sse"
}
}
}
```
This lets Cline reuse the same routed tool surface that OpenClaw uses internally.
### 3. What Cline does not need
Cline does not need to connect to the OpenClaw gateway on port 8080 for normal local usage. The direct path is:
* Cline -> Ollama for model inference
* Cline -> GhostNet router for MCP tools
If you change the host binding, use `TOOL_ROUTER_BIND` and `TOOL_ROUTER_HOST_PORT` in `.env`.
## Benchmarking Custom Models
The repository includes a reproducible benchmark script for comparing local models through the OpenClaw agent path.
```bash
./scripts/benchmark-stack.sh --model ollama/qwen3-coding:latest --lines 140 --timeout-sec 300 --no-start
./scripts/benchmark-stack.sh --model ollama/qwen25-coding:latest --lines 140 --timeout-sec 300 --no-start
./scripts/benchmark-stack.sh --model ollama/deepseek-coding:latest --lines 140 --timeout-sec 300 --no-start
```
This benchmark is useful for latency, stability, and tool-path comparison under identical conditions.
## Technical Architecture & Key Highlights
This setup relies on unique architectural design patterns engineered to overcome container engines boundaries and system strictness:
+2
View File
@@ -109,6 +109,8 @@ services:
environment:
- PORT=3000
- LOG_LEVEL=debug
ports:
- "${TOOL_ROUTER_BIND:-127.0.0.1}:${TOOL_ROUTER_HOST_PORT:-3000}:3000"
expose:
- "3000"
dns:
+28
View File
@@ -0,0 +1,28 @@
# Active Context
## Aktuelles Epic: Tool-Router online bringen
**Status**: Code-Basis repariert, bereit für Build
**Datum**: 15.06.2026
### Ziel
Den Tool-Router Container erfolgreich starten und mit OpenClaw verbinden, sodass MCP-basierte Skill-Orchestrierung funktioniert.
### Erledigt
- Containerfile korrigiert (Python 3.11, Poetry, Healthcheck)
- main.py Import-Pfade repariert (app.* prefixed)
- MCP-Client-Integration vollständig validiert
- Memory Bank vollständig erstellt
### Nächste Schritte
1. Container-Image bauen (`podman build -t ghostnet-router .`)
2. In compose.amd.yaml integrieren
3. Gateway-Konfiguration validieren
4. Health-Endpunkt testen (`/health` auf Port 8090)
5. MCP-Verbindung zu OpenClaw testen
### Wichtige Erkenntnisse
- Tool-Router läuft auf Port 8090
- Nutzt FastAPI mit SSE-Support für MCP
- Skill-Registry in `app/registry/skill_registry.py`
- Gateway-Konfiguration in `config/gateway.json`
- Import-Pfade müssen mit `app.` Prefix geschrieben werden (da Python von innerhalb des `app/` Verzeichens startet)
+16
View File
@@ -0,0 +1,16 @@
# Product Context
**Warum existiert dieses Projekt?**
Um ein vollständig lokales, souveränes KI-Agenten-System zu betreiben, das ohne externe Cloud-APIs auskommt. Der Nutzer soll komplexe Aufgaben automatisieren können (Forschung, Code-Generierung, Datenverarbeitung) durch Kombination von LLM-Fähigkeiten mit konkreten Tools.
**Welche Probleme löst es?**
- Cloud-Abhängigkeit bei LLM-APIs (Kosten, Datenschutz, Verfügbarkeit)
- Manuelle Tool-Orchestrierung zwischen verschiedenen Diensten
- Fehlende zentrale Koordination für MCP-basierte Skills
**Wie soll es sich verhalten?**
- Der Tool-Router dient als zentrales Gateway, das Skill-Anfragen empfängt, validiert und an die richtigen MCP-Tools weiterleitet
- Skills sind modular erweiterbar (z.B. Searchfetch für Web-Suche)
- Der Openclaw-Agent kommuniziert mit dem Router über MCP-Protokoll
- Alle Komponenten laufen isoliert in Podman-Containern
- Konfiguration über JSON-Dateien, Logging über structured logging
+18
View File
@@ -0,0 +1,18 @@
# Progress
## Abgeschlossene Meilensteine
- [x] Projektstruktur analysiert
- [x] Memory Bank angelegt
- [x] Systemarchitektur dokumentiert
- [x] Technology-Stack katalogisiert
## Roadmap: Tool-Router Epic
- [ ] Container-Image bauen
- [ ] Compose-Integration prüfen
- [ ] Konfiguration validieren
- [ ] Health-Check testen
- [ ] MCP-Verbindung etablieren
- [ ] End-zu-End-Test
## Blocker
- Keine bekannt
+16
View File
@@ -0,0 +1,16 @@
# Projekt-Brief: Ghostnet-Openclaw
**Was ist das?**
Ein Container-basiertes LLM-Agent-System, das Openclaw (Agent-Framework) mit Ollama (lokaler LLM-Server) und einem MCP-Tool-Router verbindet.
**Für wen?**
Für den Betreiber selbst – ein lokal laufendes, souveränes KI-Agenten-System ohne Cloud-Abhängigkeiten.
**Kernkomponenten:**
- **Ollama**: Lokaler LLM-Server (Qwen-Modelle) mit SSE-Proxy (Squid)
- **Openclaw**: Haupt-Agent mit Sandbox-Container
- **Tool-Router**: MCP-Gateway zur Orchestrierung externer Skills (z.B. Searchfetch)
- **Searchfetch**: SearXNG-basierter Suchdienst als MCP-Skill
**Laufzeit-Umgebung:**
Podman-Container-Stack auf Linux mit AMD/Intel/NVIDIA Hardware-Support.
+31
View File
@@ -0,0 +1,31 @@
# System Patterns
## Architektur
```
┌─────────────────────────────────────────────────────────┐
│ Host (Podman) │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ Ollama │ │ OpenClaw │ │ Tool Router│ │
│ │ (LLM Backend)│◄──►│ (Agent) │◄──►│ (FastAPI) │ │
│ │ Port 11434 │ │ Port 18789 │ │ Port 8090 │ │
│ └──────────────┘ └──────────────┘ └────────────┘ │
│ │
│ ┌──────────────┐ │
│ │ SearchFetch │ (SearXNG Search Tool) │
│ │ (SearXNG) │ Port 8888 │
│ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
```
## Design-Entscheidungen
1. **Podman statt Docker**: Rootless Container, keine Daemon-Abhängigkeit
2. **GPU-Unterstützung**: 3 compose-Dateien (AMD/Nvidia/Intel) für verschiedene Hardware
3. **MCP-Protokoll**: Tool-Router nutzt Model Context Protocol für Skill-Orchestrierung
4. **Sandbox**: OpenClaw hat separaten Sandbox-Container für sichere Code-Ausführung
5. **Gateway-Proxy**: Squid-Proxy vor Ollama für Request-Logging und Caching
## Kommunikationsmuster
- Ollama ↔ OpenClaw: HTTP REST (Port 11434)
- OpenClaw ↔ Tool-Router: MCP over HTTP/SSE (Port 8090)
- Tool-Router ↔ externe APIs: HTTP (httpx Client)
+35
View File
@@ -0,0 +1,35 @@
# Tech Context
## Technologien
- **Container Runtime**: Podman (rootless)
- **Orchestrierung**: Podman Compose
- **LLM Backend**: Ollama (Qwen2.5-Coder:7b, bge-large:1.5)
- **Agent**: OpenClaw (Python/FastAPI)
- **Tool-Router**: Python 3.11 + FastAPI + httpx + pydantic
- **Search**: SearXNG
- **Proxy**: Squid
## Build-Befehle
```bash
# Stack starten (AMD-GPU)
podman compose -f compose.amd.yaml up -d
# Images bauen
./ghostnet.sh build
# Tool-Router separat bauen
podman build -t tool-router tools/router/
# Logs
podman compose -f compose.amd.yaml logs -f tool-router
```
## Ports
- Ollama: 11434
- OpenClaw: 18789
- Tool-Router: 8090
- SearXNG: 8888
## Abhängigkeiten
- Python: fastapi, uvicorn, httpx, pydantic, mcp, pydantic-settings
- Host: podman, podman-compose
@@ -0,0 +1,22 @@
# Basis-Modell aus der Registry laden
FROM deepseek-coder-v2:16b
# Long-context-faehiges Profil fuer Repo-Analysen und groessere Patches
PARAMETER num_ctx 12288
PARAMETER num_predict 4096
PARAMETER temperature 0.15
# Dem Modell seine primaere Identitaet verpassen
SYSTEM """
Du bist ein hochentwickelter, autonomer KI-Coding-Agent innerhalb des OpenClaw-Frameworks.
Deine Aufgaben:
- Schreibe sauberen, performanten und fehlerfreien Python- und C#-Code.
- Analysiere Code-Strukturen tiefgehend und halte dich strikt an Best Practices.
- Gib praezise Antworten und vermeide unnoetiges Blabla.
Arbeitsregeln:
- Simuliere keine Terminal-Ausgaben, keine "Let me check..."-Monologe und keine erfundenen Befehlslogs.
- Nutze verfuegbare Tools/Befehle tatsaechlich und berichte nur echte Ergebnisse.
- Wenn etwas nicht fertig ist, nenne den konkreten naechsten Schritt statt langer Zwischenkommentare.
- Antworte standardmaessig auf Deutsch, ausser der Nutzer fordert explizit etwas anderes.
"""
@@ -1,22 +1,22 @@
# Basis-Modell aus der Registry laden
FROM qwen3.6:27b
FROM qwen2.5-coder:14b
# Long-Context-Profil fuer umfangreiche Edits
PARAMETER num_ctx 16384
# Code-spezifisches Profil fuer stabile Edits und Repairs
PARAMETER num_ctx 12288
PARAMETER num_predict 4096
PARAMETER temperature 0.2
PARAMETER temperature 0.15
# Dem Modell seine primäre Identität verpassen
# Dem Modell seine primaere Identitaet verpassen
SYSTEM """
Du bist ein hochentwickelter, autonomer KI-Coding-Agent innerhalb des OpenClaw-Frameworks.
Deine Aufgaben:
- Schreibe sauberen, performanten und fehlerfreien Python- und C#-Code.
- Analysiere Code-Strukturen tiefgehend und halte dich strikt an Best Practices.
- Gib präzise Antworten und vermeide unnoetiges Blabla.
- Gib praezise Antworten und vermeide unnoetiges Blabla.
Arbeitsregeln:
- Simuliere keine Terminal-Ausgaben, keine "Let me check..."-Monologe und keine erfundenen Befehlslogs.
- Nutze verfügbare Tools/Befehle tatsächlich und berichte nur echte Ergebnisse.
- Wenn etwas nicht fertig ist, nenne den konkreten nächsten Schritt statt langer Zwischenkommentare.
- Antworte standardmäßig auf Deutsch, außer der Nutzer fordert explizit etwas anderes.
"""
- Nutze verfuegbare Tools/Befehle tatsaechlich und berichte nur echte Ergebnisse.
- Wenn etwas nicht fertig ist, nenne den konkreten naechsten Schritt statt langer Zwischenkommentare.
- Antworte standardmaessig auf Deutsch, ausser der Nutzer fordert explizit etwas anderes.
"""
@@ -1,12 +1,12 @@
# Basis-Modell aus der Registry laden
FROM qwen3.6:27b
FROM qwen3:14b
# VRAM- und Kontext-Parameter direkt einbacken
PARAMETER num_ctx 8192
# Ausgewogenes Profil fuer reaktives Agentic Coding auf 24-GB-GPUs
PARAMETER num_ctx 12288
PARAMETER num_predict 4096
PARAMETER temperature 0.2
# Dem Modell seine primäre Identität verpassen
# Dem Modell seine primaere Identitaet verpassen
SYSTEM """
Du bist ein hochentwickelter, autonomer KI-Coding-Agent innerhalb des OpenClaw-Frameworks.
Deine Aufgaben:
+1 -1
View File
@@ -9,7 +9,7 @@
},
"agents": {
"defaults": {
"model": "ollama/qwen-coding",
"model": "ollama/qwen3-coding",
"workspace": "/home/node/.openclaw/workspace",
"sandbox": {
"mode": "all",
+132
View File
@@ -0,0 +1,132 @@
#!/usr/bin/env bash
set -euo pipefail
PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$PROJECT_DIR"
usage() {
cat <<'EOF'
Usage: ./scripts/benchmark-model-suite.sh [options]
Fuehrt den bestehenden Stack-Benchmark fuer die drei lokalen Coding-Profile aus
und schreibt Artefakte plus eine Vergleichszusammenfassung.
Optionen:
--lines <n> Erwartete Zeilenanzahl LINE_1..LINE_n (default: 140)
--timeout-sec <n> Timeout je Lauf in Sekunden (default: 300)
--artifact-root <p> Zielordner fuer alle Benchmark-Artefakte (default: auto)
--session-prefix <s> Prefix fuer Session-Keys (default: suite:<timestamp>)
-h, --help Hilfe anzeigen
EOF
}
slugify_model() {
local model="$1"
local slug="${model#ollama/}"
slug="${slug//:/-}"
slug="${slug//./-}"
printf '%s' "$slug"
}
extract_value() {
local label="$1"
local file="$2"
local value
value="$(sed -n "s/^${label}: //p" "$file" | head -n 1)"
printf '%s' "${value:-n/a}"
}
extract_metric() {
local label="$1"
local file="$2"
local value
value="$(sed -n "s/^- ${label}: //p" "$file" | head -n 1)"
printf '%s' "${value:-n/a}"
}
EXPECTED_LINES=140
TIMEOUT_SEC=300
ARTIFACT_ROOT=""
SESSION_PREFIX="suite:$(date +%Y%m%d-%H%M%S)"
while [ "$#" -gt 0 ]; do
case "$1" in
--lines)
EXPECTED_LINES="$2"
shift 2
;;
--timeout-sec)
TIMEOUT_SEC="$2"
shift 2
;;
--artifact-root)
ARTIFACT_ROOT="$2"
shift 2
;;
--session-prefix)
SESSION_PREFIX="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unbekannte Option: $1" >&2
usage >&2
exit 1
;;
esac
done
if [ -z "$ARTIFACT_ROOT" ]; then
ARTIFACT_ROOT="$PROJECT_DIR/storage/workspace/benchmarks/model-suite-$(date +%Y%m%d-%H%M%S)"
fi
mkdir -p "$ARTIFACT_ROOT"
MODELS=(
"ollama/qwen3-coding:latest"
"ollama/qwen25-coding:latest"
"ollama/deepseek-coding:latest"
)
SUMMARY_TABLE="$ARTIFACT_ROOT/summary.tsv"
printf 'model\tbenchmark_rc\tvalidation\trequest_exit\twall_ms\tprovider_tps\tend_to_end_tps\tload_sec\tkv_tokens\n' > "$SUMMARY_TABLE"
for model in "${MODELS[@]}"; do
slug="$(slugify_model "$model")"
run_dir="$ARTIFACT_ROOT/$slug"
session_key="$SESSION_PREFIX:$slug"
echo "=== Benchmark fuer $model ==="
benchmark_rc=0
if ! ./scripts/benchmark-stack.sh \
--model "$model" \
--lines "$EXPECTED_LINES" \
--timeout-sec "$TIMEOUT_SEC" \
--session-key "$session_key" \
--artifact-dir "$run_dir" \
--no-start; then
benchmark_rc=$?
fi
summary_file="$run_dir/summary.txt"
validation="$(extract_value 'Validation' "$summary_file")"
request_exit="$(extract_value 'Request exit code' "$summary_file")"
wall_ms="$(extract_metric 'end_to_end_wall_ms' "$summary_file")"
provider_tps="$(extract_metric 'output_tokens_per_sec_provider' "$summary_file")"
end_to_end_tps="$(extract_metric 'output_tokens_per_sec_end_to_end' "$summary_file")"
load_sec="$(extract_metric 'model_load_time_sec' "$summary_file")"
kv_tokens="$(extract_metric 'kv_size_tokens' "$summary_file")"
printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
"$model" "$benchmark_rc" "$validation" "$request_exit" "$wall_ms" "$provider_tps" "$end_to_end_tps" "$load_sec" "$kv_tokens" \
>> "$SUMMARY_TABLE"
done
echo
echo "Vergleich gespeichert unter: $ARTIFACT_ROOT"
column -ts $'\t' "$SUMMARY_TABLE"
+3 -3
View File
@@ -35,7 +35,7 @@ Startet den Stack (optional), fuehrt eine reproduzierbare OpenClaw-Anfrage aus,
validiert den Output und zeigt Metriken (Laufzeit, Token, KV-/VRAM-Metriken).
Optionen:
--model <name> OpenClaw-Modell (default: ollama/qwen-coding-long:latest)
--model <name> OpenClaw-Modell (default: ollama/qwen3-coding:latest)
--lines <n> Erwartete Zeilenanzahl LINE_1..LINE_n (default: 120)
--timeout-sec <n> Timeout fuer den Agent-Call in Sekunden (default: 480)
--session-key <key> Session-Key fuer den Lauf (default: auto)
@@ -45,7 +45,7 @@ Optionen:
-h, --help Hilfe anzeigen
Beispiel:
./scripts/benchmark-stack.sh --model ollama/qwen-coding-long:latest --lines 140
./scripts/benchmark-stack.sh --model ollama/qwen3-coding:latest --lines 140
EOF
}
@@ -132,7 +132,7 @@ extract_unquoted_metric() {
fi
}
MODEL="ollama/qwen-coding-long:latest"
MODEL="ollama/qwen3-coding:latest"
EXPECTED_LINES=120
TIMEOUT_SEC=480
SESSION_KEY=""
+8 -7
View File
@@ -4,14 +4,15 @@ FROM docker.io/library/python:3.12-slim
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
# Application dependencies
WORKDIR /app
COPY app/requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
WORKDIR /opt/router
COPY app/requirements.txt /tmp/requirements.txt
RUN pip install --no-cache-dir -r /tmp/requirements.txt
COPY app/ .
COPY config/ /app/config/
# Copy application maintaining package structure
COPY app/ /opt/router/app/
COPY config/ /opt/router/config/
# Default environment variables
ENV CONFIG_PATH=/app/config/gateway.json
ENV CONFIG_PATH=/opt/router/config/gateway.json
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "3000", "--log-level", "info", "--timeout-keep-alive", "120", "--limit-concurrency", "10"]
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "3000", "--log-level", "info", "--timeout-keep-alive", "120", "--limit-concurrency", "10"]
+2 -2
View File
@@ -12,8 +12,8 @@ from app.registry.skill_registry import SkillRegistry
from app.services.skill_manager import SkillManager
from app.mcp.server import master_server
from app.mcp.handlers import register_handlers
from app.mcp_client.mcp_server import master_server
from app.mcp_client.handlers import register_handlers
from app.api.routes import register_routes