llama.cpp-Server-Instanzen, die als Docker-Container laufen —
inklusive einer SSRF-gehärteten Eingabeschicht für System- und User-Prompts aus
Text, Datei oder Remote-URL.
- Python 94.4%
- Shell 5.6%
The four existing prose prompts never made the aligned base model refuse, so the abliteration comparison had no difference to measure. These three pick subjects where an aligned model plausibly balks — an executioner's workday told without remorse, an unreliable narrator who never concedes his fraud, a relapse rendered without a warning — while keeping the literary demands of the domain. Each forbids preamble and closing framing explicitly. That turns an evasion into a measurable instruction violation rather than a matter of taste. None asks for operative content: prosa_08 rules out substances, quantities and procurement. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|---|---|---|
| .forgejo/workflows | ||
| .githooks | ||
| docs | ||
| example_system_prompts | ||
| example_user_prompts | ||
| man | ||
| scripts | ||
| src/llamacppctl | ||
| tests | ||
| .gitignore | ||
| build_archive.py | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| LICENSE | ||
| llama.cpp.config.example | ||
| pyproject.toml | ||
| README.md | ||
| requirements-dev.txt | ||
| requirements.txt | ||
llamacppctl
Ein einziges, sicherheitsgehärtetes CLI-Werkzeug zum Starten, Prüfen, Stoppen und
Wechseln von llama.cpp-Server-Instanzen, die als Docker-Container laufen —
inklusive einer SSRF-gehärteten Eingabeschicht für System- und User-Prompts aus
Text, Datei oder Remote-URL.
llamacppctl ersetzt eine Sammlung einzelner Shell-Skripte
(start-llm-server.sh, status-llm-server.sh, switch-llm.sh, …) durch ein
einziges Python-Paket mit konsistenter Konfiguration, Locking und
Fehlerbehandlung.
Dokumentation
| Dokument | Für wen / wofür |
|---|---|
| README (diese Datei) | Schnelleinstieg: Installation, Konfiguration, Verwendung |
docs/BEDIENUNGSANLEITUNG.md |
Vollständiges Benutzerhandbuch (alle Aktionen, Optionen, Fehlersuche) |
docs/INSTALL_FROM_ARCHIVE.md |
Installation aus dem .tar.gz-Archiv + Archiv selbst bauen/verifizieren |
docs/SECURITY_AND_OPERATIONS.md |
Architektur, Modul-/Repo-Übersicht, Sicherheits- & Betriebsmodell |
man/llamacppctl.1 |
Vollständige Optionsreferenz (man llamacppctl bzw. man ./man/llamacppctl.1) |
CHANGELOG.md |
Versionshistorie |
Installation
tar xzf llamacppctl-installable.tar.gz
cd llamacppctl
python3 -m venv .venv
source .venv/bin/activate
pip install .
Danach steht der Befehl llamacppctl innerhalb der aktivierten virtuellen
Umgebung zur Verfügung. Für eine systemweite Installation (ohne venv):
pip install --user .
Voraussetzungen auf dem Zielsystem:
- Python >= 3.10
- Docker (CLI + laufender Daemon), für
--start/--check/--stop/--change` - Netzwerkzugriff auf den Container-Host-Port für
--chat/--check`
--print-effective-config ist eine eigenständige, nebenwirkungsfreie Aktion und
benötigt keinen laufenden Docker-Daemon. --start/--check/--stop/--changeerfordern einen erreichbaren Docker-Daemon — auch zusammen mit--dry-run`, weil
die Verfügbarkeit geprüft wird, bevor der Trockenlauf greift.
Konfiguration
Kopiere llama.cpp.config.example nach llama.cpp.config und passe es an:
cp llama.cpp.config.example llama.cpp.config
Abschnittstypen:
[default]— globale Defaults, überschreiben die eingebauten Fallback-Werte[model.<name>]— ein Modell-Profil, ausgewählt über--profile <name>[prompt.<name>]— ein System-Prompt-Profil, ausgewählt über--system-prompt-profile <name>(liefert nur einen Fallback-Systemprompt; ein explizites-s/--system-file/--system-urlgewinnt immer)
container_name ist Pflicht und muss für jedes Profil, das parallel
laufen soll, eindeutig sein — er ist der einzige Identitätsanker für
Docker-Namensgebung, Locking (--start/--change) sowie
--stop/--check-Ziel.
hf_home unterstützt Environment-Variablen und ~, z. B. hf_home = ${HF_HOME}.
Das Chat-Antwortbudget ist ebenfalls konfigurierbar (wirkt auf --chat und die
Antwort nach --start, nicht auf den Container): max_tokens (Default 2048 —
für Reasoning-Modelle / lange Texte hochsetzen, sonst bricht die Antwort mitten
im „Denken" ab und content bleibt leer) und chat_temperature (leer =
Server-temp gilt). CLI-Overrides: --max-tokens, --chat-temp.
Auflösungsreihenfolge (niedrigste zu höchster Priorität):
- Eingebaute Defaults
[default]-Sektion[model.<profile>]-Sektion (falls--profilegesetzt)- CLI-Overrides (
--image,--host-port, …)
Verwendung
# Server starten (nutzt die [default]-Sektion der Config)
llamacppctl --start --config llama.cpp.config
# Nur den geplanten docker-run-Befehl anzeigen, nichts ausführen
llamacppctl --start --config llama.cpp.config --dry-run
# Effektive Konfiguration als JSON ausgeben (startet nichts, braucht kein Docker)
llamacppctl --print-effective-config --config llama.cpp.config
# Status prüfen
llamacppctl --check --config llama.cpp.config
# Server stoppen und Container entfernen
llamacppctl --stop --config llama.cpp.config
# Ein bestimmtes Modell-Profil starten (siehe Hinweis unter dem Block)
llamacppctl --start --config llama.cpp.config --profile qwopus
# Modell wechseln (stop, neu konfigurieren, restart) unter Lock-Schutz
llamacppctl --change --config llama.cpp.config --profile carnice
# Direkten Chat-Request an einen laufenden Server senden
llamacppctl --chat --config llama.cpp.config \
-s "Du antwortest kurz." -p "Was ist 2+2?"
# Chat mit Live-Streaming und großem Antwortbudget (lange Texte)
llamacppctl --chat --config llama.cpp.config \
--stream --max-tokens 8000 -p "Schreibe eine kurze Rede zum Jahreswechsel."
# System-Prompt aus einer lokalen Datei, User-Prompt als Literal
llamacppctl --start --config llama.cpp.config \
--system-file ./prompts/coding.md -p "Refaktoriere diese Funktion."
# System-Prompt von einer HTTPS-URL (öffentliches, nicht-privates Ziel)
llamacppctl --chat --config llama.cpp.config \
--system-url https://example.com/prompts/system.txt -p "Hallo"
Ohne --profile gilt die [default]-Sektion. Mit --profile <name> wählst du
ein [model.<name>]-Profil; in llama.cpp.config sind das z. B. carnice,
qwen27b, qwopus, in der Vorlage llama.cpp.config.example qwen35b und
deepseek. Die Ziffern (z. B. 35b) meinen die Modellgröße in Milliarden
Parametern, nicht die Qwen-Version.
Vollständige Optionsliste: llamacppctl --help oder die Manpage
(man/llamacppctl.1, siehe unten).
Migration von den Shell-Skripten
llamacppctl ersetzt die einzelnen Shell-Skripte durch Actions eines
Werkzeugs (--profile ist optional; ohne greift die [default]-Sektion):
| Altes Skript | Neuer Aufruf |
|---|---|
start-llm-server.sh |
llamacppctl --start --config llama.cpp.config [--profile <name>] |
status-llm-server.sh |
llamacppctl --check --config llama.cpp.config [--profile <name>] |
| Stop-Skript | llamacppctl --stop --config llama.cpp.config [--profile <name>] |
switch-llm.sh (Modellwechsel) |
llamacppctl --change --config llama.cpp.config [--profile <name>] |
| (neu) direkter Chat-Test | llamacppctl --chat --config llama.cpp.config -p "..." |
Sicherheitsmodell (Kurzfassung)
Für Details siehe docs/SECURITY_AND_OPERATIONS.md.
- Alle Docker-Aufrufe laufen über
subprocess.run()mit Argumentlisten — niemals über Shell-Strings, somit keine Shell-Injection-Fläche. --system-file/--prompt-filelesen ausschließlich reguläre Dateien, Größenlimit (--max-input-bytes, Default 1 MiB), UTF-8-Text erzwungen, Symlinks standardmäßig abgelehnt, per--allow-symlinks` freischaltbar.--system-url/--prompt-urlsind standardmäßig HTTPS-only, blockieren IP-Literale, private/loopback/link-local/reserved Adressbereiche sowie die Cloud-Metadata-IP169.254.169.254, verbieten eingebettete Zugangsdaten in der URL, erlauben standardmäßig keine Redirects (jeder Hop wird bei Aktivierung erneut validiert), erzwingen eine Content-Type-Allowlist und ein hartes Größenlimit sowohl überContent-Length` als auch beim Streaming.- Der Port wird standardmäßig nur auf
127.0.0.1veröffentlicht — der ungeauthentifizierte OpenAI-Endpoint ist also nicht im LAN erreichbar.--expose/expose = truebindet auf alle Interfaces; dann sollte per--api-key/api_keyein Schlüssel gesetzt werden (Server verlangt ihn, das Tool sendet ihn als Bearer-Token). container_nameist verpflichtend und muss pro parallel betriebenem Profil eindeutig sein, um Docker-Namenskollisionen und ungewollte Container-Übernahmen zu verhindern.--start/--change` nutzen echte Chat-Completions zum Readiness-Check (nicht nur einen offenen Port), um sicherzustellen, dass das Modell tatsächlich geladen und inferenzfähig ist.--changeverwendet eine exklusive, nicht-blockierende Dateisperre (/tmp/llamacppctl.<container_name>.lock), um parallele Änderungen am selben Container zu verhindern.
Entwicklung / Tests
pip install -e ".[dev]"
python -m pytest -q
python -m pytest (statt des pytest-Skripts) legt das Repo-Root auf
sys.path, damit die Testmodule import tests.* auflösen.
Lokales CI-Gate: scripts/check.sh bündelt ruff + mypy + pytest
(spiegelt .forgejo/workflows/ci.yml). Als Pre-Push-Hook aktivieren — er
blockt einen Push bei Fehlern:
git config core.hooksPath .githooks # einmalig pro Clone
Einen einzelnen Push im Notfall umgehen: git push --no-verify.
Die Test-Suite deckt die Prompt-Eingabeschicht (Datei- und URL-Quellen inkl.
SSRF-Abwehr mit gemockter DNS-Auflösung und DNS-Pinning), die
Konfigurationsauflösung (inkl. ${ENV}-Expansion), die CLI-Validierung, die
Action-Orchestrierung (do_start/do_change/do_check/do_chat, Locking,
dry-run) sowie Docker-/HTTP-Operationen (mit gemocktem subprocess bzw.
requests) ab.
Für einen End-to-End-Test gegen einen echten Docker + llama.cpp-Server (u. a.
--api-key-Round-Trip, Streaming, --check-Exit-Codes) gibt es einen opt-in
Rauchtest — er startet einen separaten Container und räumt danach auf:
SMOKE_GPU=1 scripts/smoke.sh
Lizenz
MIT License
Copyright (c) 2026 Dieter Schlüter