JodaBot – eigene KI-Assistenten-App (Web + Android)
Find a file
2026-10-31 11:08:19 +01:00
android Registrierung & Login: /register-Seite, E-Mail optional, Passwort min. 10, Rate-Limit, run_code nur Admin/Freigabe, Android 0.4.0 2026-10-31 11:08:19 +01:00
public Landingpage unter /, App nach /chat, aktuelle Screenshots 2026-10-31 04:34:56 +01:00
screenshots Live-Screenshots der Landingpage 2026-10-31 04:39:36 +01:00
scripts Modell-Server-Auswahl in Einstellungen (Web + Android), Admin-API /settings/providers 2026-10-25 14:09:07 +01:00
src Registrierung & Login: /register-Seite, E-Mail optional, Passwort min. 10, Rate-Limit, run_code nur Admin/Freigabe, Android 0.4.0 2026-10-31 11:08:19 +01:00
tests Registrierung & Login: /register-Seite, E-Mail optional, Passwort min. 10, Rate-Limit, run_code nur Admin/Freigabe, Android 0.4.0 2026-10-31 11:08:19 +01:00
.dockerignore JodaBot Phase 1: Web-App + API (Chat, Gedächtnis, Modelle, Websuche, Sandbox, Routinen, GitHub, MCP, Multi-Bot) 2026-10-25 12:05:57 +01:00
.env.example Modell-Server-Auswahl in Einstellungen (Web + Android), Admin-API /settings/providers 2026-10-25 14:09:07 +01:00
.gitignore JodaBot Phase 1: Web-App + API (Chat, Gedächtnis, Modelle, Websuche, Sandbox, Routinen, GitHub, MCP, Multi-Bot) 2026-10-25 12:05:57 +01:00
docker-compose.coolify.yml Coolify: öffentliche URL mit https 2026-10-31 04:12:05 +01:00
docker-compose.yml JodaBot Phase 1: Web-App + API (Chat, Gedächtnis, Modelle, Websuche, Sandbox, Routinen, GitHub, MCP, Multi-Bot) 2026-10-25 12:05:57 +01:00
Dockerfile Docker: public/ ins Runtime-Image kopieren (Screenshots, sw.js) 2026-10-31 04:37:03 +01:00
next.config.mjs Browser-Werkzeuge (Playwright): öffnen, klicken, tippen, absenden, Text, Screenshot; Bestätigung für Klick/Absenden, SSRF-Schutz, ohne Chromium abgeschaltet 2026-10-25 14:51:55 +01:00
package-lock.json Push-Benachrichtigungen: Web-Push (VAPID) und FCM HTTP v1 inkl. Android-Registrierung 2026-10-25 14:33:45 +01:00
package.json Push-Benachrichtigungen: Web-Push (VAPID) und FCM HTTP v1 inkl. Android-Registrierung 2026-10-25 14:33:45 +01:00
postcss.config.js JodaBot Phase 1: Web-App + API (Chat, Gedächtnis, Modelle, Websuche, Sandbox, Routinen, GitHub, MCP, Multi-Bot) 2026-10-25 12:05:57 +01:00
README.md Landingpage unter /, App nach /chat, aktuelle Screenshots 2026-10-31 04:34:56 +01:00
tailwind.config.js JodaBot Phase 1: Web-App + API (Chat, Gedächtnis, Modelle, Websuche, Sandbox, Routinen, GitHub, MCP, Multi-Bot) 2026-10-25 12:05:57 +01:00
tsconfig.json Registrierung & Login: /register-Seite, E-Mail optional, Passwort min. 10, Rate-Limit, run_code nur Admin/Freigabe, Android 0.4.0 2026-10-31 11:08:19 +01:00
vitest.config.mts Tests: Test-DB pro Lauf zurücksetzen (globalSetup) 2026-10-25 14:42:08 +01:00

🤖 JodaBot

Dein eigener KI-Assistent: Chat mit Verlauf und Gedächtnis, umschaltbare Modelle (Cloud & lokal), Websuche, Code-Sandbox, Routinen nach Zeitplan, GitHub- und MCP-Anbindung und mehrere Bots mit eigenen Rollen. Phase 1: Web-App + Server. Die Android-App (Phase 2) nutzt dieselbe API (siehe unten).

Landingpage

Öffentliche Landingpage unter /, die App selbst unter /chat (angemeldete Nutzer werden von / direkt weitergeleitet).

Funktionen

Bereich Was geht
Bots Beliebig viele Bots mit Name, Beschreibung, System-Prompt, Modell und aktivierten Werkzeugen (Seitenleiste).
Chat Mehrere Unterhaltungen pro Bot, Verlauf in SQLite, Streaming-Antworten (SSE).
Gedächtnis Dauerhafte Fakten pro Bot & Nutzer; das Modell speichert/sucht/löscht sie per Tool, sie stehen automatisch im System-Prompt. Auch manuell pflegbar.
Modelle OpenAI, xAI (Grok), Anthropic (Claude), Ollama, beliebige OpenAI-kompatible lokale Server (llama.cpp, LM Studio, vLLM …) und ein Mock-Modell für Tests. Auswahl pro Bot. Tool-Calling bei allen.
Websuche Tavily → Brave → SearXNG (je nachdem, welcher Key/URL gesetzt ist), sonst DuckDuckGo-HTML-Fallback. Plus fetch_url (Text einer Webseite; interne Adressen gesperrt).
Code & Dateien run_code (Python/Node/Bash) in einer Docker-Sandbox pro Aufruf: kein Netzwerk, Speicher-/CPU-/PID-Limit, Zeitlimit, read-only Root-FS, nur der Bot-Workspace ist gemountet. Ohne Docker deaktiviert mit klarer Meldung. write_file/read_file/list_files im Workspace, Dateien im Chat & im Tab „Dateien“ herunterladbar.
Routinen Cron-Prompts pro Bot (Zeitzone Europe/Berlin), Ergebnis landet in der Unterhaltung „⏰ Name“. Auch manuell auslösbar.
GitHub Token-basiert: Repos, Issues, PRs lesen; Issue anlegen (mit Bestätigung).
MCP Generische Anbindung von MCP-Servern per Streamable HTTP oder stdio; deren Tools erscheinen automatisch beim Bot (standardmäßig mit Bestätigung).
Sicherheit Admin-Login (scrypt-Hash, HttpOnly-Session-Cookie bzw. Bearer-Token). API-Keys nur in .env oder AES-256-GCM-verschlüsselt in der DB; das Frontend sieht nie Werte, nur „gesetzt ja/nein“. Riskante Aktionen (Code, GitHub-Schreiben, MCP) brauchen eine Bestätigung im UI.

Architektur

Browser / Android ──REST + SSE──▶ Next.js 15 (App Router, TypeScript, Tailwind)
                                   ├─ src/app/App.tsx            UI (deutsch, mobil-tauglich)
                                   ├─ src/app/api/**             REST-API (Route Handler)
                                   └─ src/lib/
                                       ├─ agent.ts     Agenten-Schleife: Modell ⇄ Tools, Bestätigungen, SSE
                                       ├─ models.ts    Modell-Schicht (OpenAI-kompatibel, Anthropic, Mock)
                                       ├─ tools.ts     Tool-Registry (Gedächtnis, Web, Code, GitHub, MCP)
                                       ├─ sandbox.ts   Docker-Sandbox + Workspaces
                                       ├─ scheduler.ts Routinen (node-cron, startet in instrumentation.ts)
                                       ├─ mcp.ts       MCP-Client (HTTP/stdio)
                                       ├─ db.ts/schema.ts  SQLite via better-sqlite3 + Drizzle ORM
                                       └─ crypto.ts/secrets.ts/auth.ts

Warum ein einzelnes Next.js-Projekt statt Monorepo mit separatem Fastify-Server? Für Phase 1 hält das Deployment und Typen an einem Ort; die gesamte Logik liegt framework-unabhängig in src/lib, die API ist sauber unter /api versioniert dokumentiert. Wenn die Android-App oder Skalierung es erfordern, lässt sich src/lib ohne Umbau in ein eigenes packages/core + Fastify-Server auslagern. Drizzle erlaubt später den Wechsel auf Postgres.

Streaming: Server-Sent Events über POST (statt WebSocket) – funktioniert durch Proxies, einfach in OkHttp/Ktor auf Android zu lesen, und braucht keinen separaten Socket-Server.

Schnellstart (lokal)

Voraussetzung: Node.js 20+, optional Docker (für Code-Ausführung).

cp .env.example .env          # JODABOT_ADMIN_PASSWORD und JODABOT_SECRET setzen!
npm install
npm run build && npm start    # oder: npm run dev
# → http://localhost:3000, Login mit JODABOT_ADMIN_USER / JODABOT_ADMIN_PASSWORD

JODABOT_SECRET erzeugen: openssl rand -hex 32. Ohne API-Key kannst du sofort mit dem Anbieter Mock testen (probiere „merke dir: …“, „was weißt du über mich?“, „suche …“, „rechne 6*7“, „datei …“).

Start mit Docker Compose

cp .env.example .env                       # Werte setzen
docker compose up -d --build               # nur JodaBot
docker compose --profile ollama up -d --build   # inkl. lokalem Ollama
docker compose exec ollama ollama pull llama3.1 # Modell laden, dann im Bot „Ollama (lokal)“ wählen

Für die Code-Sandbox wird der Docker-Socket des Hosts gemountet (entspricht Root-Rechten auf dem Host – nur auf eigenen Servern verwenden, Zeile in docker-compose.yml sonst entfernen). Die Sandbox-Images (python:3.12-slim, node:20-slim, bash:5) werden beim ersten Lauf gezogen; vorab: docker pull python:3.12-slim.

Konfiguration

Alle Variablen stehen in .env.example.

Modell-Server (xAI, OpenAI, Anthropic, Ollama, eigener OpenAI-kompatibler Endpunkt) verwaltet der Admin unter Einstellungen → Modell-Server – in der Web-App und in der Android-App: aktivieren/deaktivieren, API-Schlüssel bzw. Server-URL eintragen, Verbindung testen (lädt die Modellliste) und Standardmodell wählen. Schlüssel werden mit AES-256-GCM (JODABOT_SECRET) verschlüsselt in der DB gespeichert und nie im Klartext ausgeliefert (nur •••• + letzte 4 Zeichen). In der UI gespeicherte Werte haben Vorrang vor der .env; OPENAI_API_KEY, XAI_API_KEY, ANTHROPIC_API_KEY, OLLAMA_BASE_URL, LOCAL_OPENAI_BASE_URL/LOCAL_OPENAI_API_KEY bleiben als Fallback. Ein nur per .env konfigurierter Anbieter gilt als aktiv, bis er in den Einstellungen deaktiviert wird. Bots können nur aktive, konfigurierte Anbieter (plus „Mock“) wählen. Weitere Schlüssel (Websuche, GitHub) unter Einstellungen → Weitere Schlüssel (dort hat .env Vorrang).

Tests

npm run typecheck
npm test            # Vitest: Verschlüsselung, Pfadschutz, DuckDuckGo-Parser, Agenten-Schleife mit Mock-Modell
npm run build && npm run smoke   # Headless-UI-Smoke-Test (Chrome/Chromium nötig, CHROME_PATH optional) → screenshots/

API-Dokumentation (für Web & Android)

Basis-URL: https://<server>/api. Alle Bodies sind JSON. Authentifizierung entweder per Cookie jodabot_session (Web) oder Header Authorization: Bearer <token> (Android). Fehler: HTTP-Status + { "error": "Text" }.

Auth

Methode Pfad Body Antwort
POST /auth/login {username, password} {token, user:{id,username}} (+ Cookie)
POST /auth/logout – {ok:true}
GET /me – {user:{id,username,isAdmin}}
GET /meta – {providers[{id,label,defaultModel,models[]}], toolGroups[], docker:boolean, dockerMessage} – providers enthält nur „mock“ + aktive, konfigurierte Anbieter

Bots

Methode Pfad Body / Antwort
GET /bots Bot[]
POST /bots {name, description?, systemPrompt?, provider?, model?, tools?} → Bot
GET/PATCH/DELETE /bots/{botId} PATCH mit beliebigen Feldern von oben

Bot = {id, name, description, systemPrompt, provider: "mock"|"openai"|"xai"|"anthropic"|"ollama"|"local-openai", model, tools: ("memory"|"web"|"code"|"github"|"mcp")[], createdAt}

Unterhaltungen & Chat

Methode Pfad Body / Antwort
GET /bots/{botId}/conversations Conversation[] (neueste zuerst)
POST /bots/{botId}/conversations {title?} → Conversation
GET /conversations/{id} {conversation, messages: Message[], pending: PendingAction[]}
PATCH /conversations/{id} {title}
DELETE /conversations/{id} –
POST /conversations/{id}/messages {content} → SSE-Stream
POST /actions/{actionId} {approve: true|false} → SSE-Stream (Fortsetzung nach Bestätigung)

Message = {id, role: "user"|"assistant"|"tool", content, toolCalls: {id,name,args}[]|null, toolCallId, toolName, createdAt}

SSE-Ereignisse (event: <type> / data: <json>):

type Daten
text {delta} – Textstück der Antwort
tool_call {call:{id,name,args}, risky}
tool_result {toolCallId, name, result, error?}
confirm {action:{id, toolName, args}} – Nutzer muss über /actions/{id} bestätigen/ablehnen
error {message}
done Stream endet

Schickt der Nutzer bei offener Bestätigung eine neue Nachricht, gilt die Aktion als abgelehnt.

Gedächtnis, Dateien, Routinen

Methode Pfad Body / Antwort
GET/POST /bots/{botId}/memories POST {content}
DELETE /memories/{id} –
GET /bots/{botId}/files {path,size}[]
GET /bots/{botId}/files/{pfad} Datei-Download
GET/POST /bots/{botId}/routines POST {name, cron, prompt, enabled?}
PATCH/DELETE /routines/{id} PATCH {name?, cron?, prompt?, enabled?}
POST /routines/{id}/run sofort ausführen

Einstellungen

Methode Pfad Body / Antwort
GET /settings/secrets {key, source: "env"|"db"|null}[] (nie Werte)
PUT /settings/secrets {TAVILY_API_KEY: "…", …} (leerer String = löschen)
GET /settings/providers Admin. ProviderSettings[] (s. u.)
GET /settings/providers/{id} Admin. ProviderSettings
PUT /settings/providers/{id} Admin. {enabled?, apiKey?, baseUrl?, defaultModel?} – fehlendes Feld = unverändert, apiKey: "" löscht den gespeicherten Schlüssel (env greift wieder), baseUrl: "" setzt die URL zurück → ProviderSettings
POST /settings/providers/{id}/test Admin. Optional {apiKey?, baseUrl?} zum Testen ungespeicherter Werte → {ok, models[], error?}; ohne Overrides wird die Modellliste gespeichert

{id} ∈ xai, openai, anthropic, ollama, local-openai. Admin = Benutzer JODABOT_ADMIN_USER; andere erhalten 403, ohne Login 401 (Cookie oder Bearer). ProviderSettings = {id, label, needsKey, needsUrl, enabled, configured, keyMasked: "••••abcd"|null, keySource: "db"|"env"|null, baseUrl, urlSource: "db"|"env"|"default", defaultModel, models[]}

POST/PATCH /bots lehnt Anbieter ab, die nicht aktiv und konfiguriert sind (400). | GET/POST | /mcp | POST {name, transport:"http"\|"stdio", url?, command?, args?, requireConfirm?} | | DELETE | /mcp/{id} | – |

Beispiel (curl):

TOKEN=$(curl -s -X POST localhost:3000/api/auth/login -H 'content-type: application/json' \
  -d '{"username":"admin","password":"…"}' | jq -r .token)
curl -N -X POST localhost:3000/api/conversations/<id>/messages -H "Authorization: Bearer $TOKEN" \
  -H 'content-type: application/json' -d '{"content":"Hallo!"}'

Screenshots

Chat Bot-Einstellungen
Modell-Server Nutzerverwaltung
Mobil: Chat Mobil: Seitenleiste

Roadmap

  • Android-App (Kotlin + Jetpack Compose, OkHttp-SSE) gegen diese API; Push für Routinen-Ergebnisse (FCM).
  • Mehrbenutzer & Rollen, Rate-Limits, Postgres-Option, Datei-Upload in den Chat, Vektor-Gedächtnis (Embeddings), GitHub-Schreibzugriffe (Kommentare, PRs), OAuth für Verbindungen.

Android-App (android/)

Native App (Kotlin, Jetpack Compose, Material 3, dunkles Theme, deutsche Oberfläche), spricht dieselbe API wie die Web-App (Bearer-Token, Chat-Streaming per SSE).

Funktionen: Login mit Server-URL + Passwort oder Token · Bot-Liste und Umschalten · Unterhaltungen · Chat mit gestreamten Antworten (Markdown) · Bestätigungskarten für Tools (Erlauben/Ablehnen) · Routinen ansehen, ein-/ausschalten, sofort ausführen · Modell-Server verwalten (nur Admin: aktivieren, Schlüssel/URL, Verbindung testen, Standardmodell) · Einstellungen/Abmelden.

Bauen (JDK 17 + Android SDK, Plattform 36/37):

cd android
echo "sdk.dir=$ANDROID_HOME" > local.properties
./gradlew assembleDebug testDebugUnitTest
# APK: android/app/build/outputs/apk/debug/app-debug.apk

Verbinden: Im Emulator ist der Rechner unter http://10.0.2.2:3000 erreichbar, auf einem Gerät im WLAN die LAN-IP des Servers. Die App prüft die URL über GET /api/health (öffentlich). Klartext-HTTP ist für lokale Tests erlaubt – im Internet nur HTTPS verwenden.

Sicherheit: Server-URL und Token liegen in EncryptedSharedPreferences (AES-256, Schlüssel im Android Keystore); das Passwort wird nicht gespeichert.

Hosting auf Render (Free-Plan)

JodaBot läuft als Docker-Web-Service auf Render (HTTPS automatisch, PORT wird vom Dockerfile übernommen). Prüfen: GET https://<dienst>.onrender.com/api/health.

Umgebungsvariablen: JODABOT_SECRET (zufällig, ≥ 16 Zeichen), JODABOT_ADMIN_USER, JODABOT_ADMIN_PASSWORD, JODABOT_DISABLE_SANDBOX=1.

Einschränkungen des Free-Plans:

  • Keine persistente Disk → die SQLite-Datenbank (Bots, Chats, Gedächtnis, gespeicherte Schlüssel) liegt im Container und geht bei jedem Neustart/Deploy verloren. Dauerhaft speichern: bezahlter Plan (z. B. Starter) + Persistent Disk unter /app/data, oder JodaBot auf eigenem Server/VPS mit Docker betreiben.
  • Der Dienst schläft nach ~15 Min. ohne Anfragen ein (erster Aufruf dauert dann ~1 Min.); Routinen laufen in dieser Zeit nicht.
  • Code-Ausführung ist abgeschaltet (kein Docker auf Render). run_code wird dem Modell nicht angeboten; die UI zeigt einen Hinweis. Abschalten auch lokal per JODABOT_DISABLE_SANDBOX=1 (auf Render automatisch über RENDER=true).

GitHub-Werkzeuge

Mit GITHUB_TOKEN (Einstellungen → Weitere Schlüssel; Fine-grained Token mit Contents, Issues, Pull requests: Read & Write) kann ein Bot mit Werkzeug „GitHub“:

Tool Bestätigung
github_list_repos, github_list_issues, github_get_issue, github_list_pulls, github_read_file nein (nur lesen)
github_write_file (Datei erstellen/ändern per Commit), github_create_branch, github_create_pull, github_comment (Issue/PR), github_create_issue ja – Karte „Erlauben/Ablehnen“ im Chat

E-Mail & Kalender

Werkzeuge „E-Mail“ und „Kalender“ (pro Bot aktivierbar):

Tool Bestätigung
mail_search, mail_read, calendar_list nein
mail_draft (Entwurf, wird nicht gesendet) nein
mail_send, calendar_create ja

Google (Gmail + Kalender, auch Drive): In der Google Cloud Console einen OAuth-Client „Webanwendung“ anlegen, Gmail-, Calendar- und Drive-API aktivieren, Weiterleitungs-URI https://<host>/api/oauth/google/callback eintragen (wird in den Einstellungen angezeigt; hinter Proxys ggf. JODABOT_PUBLIC_URL setzen). GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET unter Einstellungen → Weitere Schlüssel eintragen, dann Einstellungen → Verbindungen → Mit Google verbinden. Tokens werden pro Nutzer verschlüsselt gespeichert und automatisch erneuert. Solange die App bei Google im Testmodus ist, müssen Konten als Testnutzer eingetragen sein.

IMAP/SMTP (optional, ohne Google): IMAP_HOST, IMAP_PORT (993), IMAP_USER, IMAP_PASSWORD, SMTP_HOST, SMTP_PORT (465), SMTP_USER, SMTP_PASSWORD, MAIL_FROM. Entwürfe landen im Entwürfe-Ordner. Kalender nur über Google.

API: GET /api/connections (Status, nie Tokens), GET /api/oauth/google/start (Weiterleitung zu Google, ?json=1 liefert {url} – für die Android-App), GET /api/oauth/google/callback, DELETE /api/connections/{provider}.

Push-Benachrichtigungen

Auslöser: Routine fertig und Aktion wartet auf Bestätigung.

  • Web-Push (Browser): Einstellungen → Benachrichtigungen → „In diesem Browser aktivieren“. Die VAPID-Schlüssel erzeugt der Server beim ersten Aufruf selbst und speichert sie verschlüsselt (VAPID_PUBLIC_KEY/VAPID_PRIVATE_KEY, optional VAPID_SUBJECT). Abschalten mit JODABOT_DISABLE_WEBPUSH=1. Service Worker: public/sw.js. Funktioniert nur über HTTPS (oder localhost).
  • Android (Firebase Cloud Messaging, HTTP v1): Der alte FCM-„Legacy-Server-Key“ wurde von Google abgeschaltet; als Server-Schlüssel dient der Service-Account-JSON (Firebase-Konsole → Projekteinstellungen → Dienstkonten → „Neuen privaten Schlüssel generieren“). In den Einstellungen eintragen: FCM_SERVICE_ACCOUNT (kompletter JSON-Inhalt), FCM_PROJECT_ID, FCM_ANDROID_APP_ID (z. B. 1:123:android:abc, App mit Paketname de.crypto.jodabot in Firebase anlegen), FCM_API_KEY, FCM_SENDER_ID (alle aus der google-services.json). Die App braucht keine eigene google-services.json: Sie holt die Firebase-Optionen von GET /api/push und registriert ihr Token bei POST /api/push/register. Ohne FCM-Konfiguration bleibt Firebase komplett aus (Status in den App-Einstellungen).
  • API: GET /api/push (Konfiguration + eigene Geräte), POST|DELETE /api/push/register ({kind:"web",subscription} bzw. {kind:"fcm",token}), POST /api/push/test. Ungültige Geräte (404/410) werden automatisch entfernt.

Chat-Kanäle (Telegram, Discord), Google Drive, Notion

Eingehende Nachrichten gehen an einen Ziel-Bot (Einstellungen → Chat-Kanäle, nur Admin). Jeder Chat bekommt eine eigene Unterhaltung (sichtbar in der Web-App). Befehle: /neu (neue Unterhaltung), /ja / /nein (wartende riskante Aktion bestätigen/ablehnen). Nur freigegebene IDs dürfen schreiben; Unbekannte bekommen ihre ID genannt.

  • Telegram: Bot bei @BotFather anlegen → TELEGRAM_BOT_TOKEN; Chat-IDs in TELEGRAM_ALLOWED_CHATS (kommagetrennt, * = alle). Danach „Webhook setzen“ (POST /api/channels/telegram/setup) – benötigt eine öffentliche HTTPS-URL (z. B. Render). Der Webhook POST /api/channels/telegram prüft X-Telegram-Bot-Api-Secret-Token (aus JODABOT_SECRET abgeleitet).
  • Discord: App im Developer Portal anlegen → DISCORD_APP_ID, DISCORD_PUBLIC_KEY, DISCORD_BOT_TOKEN; „Interactions Endpoint URL“ = https://<host>/api/channels/discord (Ed25519-Signaturprüfung). „Slash-Befehle registrieren“ legt /ask, /ja, /nein, /neu an. Erlaubte Discord-User-IDs in DISCORD_ALLOWED_USERS. (Kein Gateway/Websocket nötig – passt zum schlafenden Free-Plan; die erste Antwort nach dem Aufwachen kann länger dauern.)
  • Google Drive (Werkzeug „Google Drive“, nutzt die Google-Verbindung): drive_search, drive_read (Docs/Sheets werden als Text/CSV exportiert), drive_upload (Workspace-Datei oder Text, mit Bestätigung).
  • Notion (Werkzeug „Notion“): NOTION_TOKEN = Token einer internen Integration (notion.so/my-integrations; Seiten mit der Integration teilen). notion_search, notion_read_page, notion_create_page (mit Bestätigung). Pro Nutzer kann alternativ eine Verbindung notion mit eigenem Token hinterlegt werden.

Medien: Bilder, Sprache, Bilderzeugung

  • Bild-Upload mit Vision (Web: 📎, Android: 📎 Bildauswahl, verkleinert auf 1600 px): bis zu 4 Bilder (PNG/JPEG/WebP/GIF, je ≤ 5 MB) pro Nachricht. POST /api/conversations/{id}/messages akzeptiert { content, images: ["data:image/…;base64,…"] }. Die Bilder liegen im Bot-Workspace unter uploads/ und werden bei OpenAI, xAI, Ollama und lokalen OpenAI-kompatiblen Servern als image_url, bei Anthropic als image-Block übergeben. Das Modell muss Bilder können (z. B. gpt-4o, grok-4, claude-*, llava).
  • Spracheingabe (🎙️): POST /api/media/transcribe (multipart, Feld audio) → Whisper-kompatibles /audio/transcriptions. Einstellungen: STT_PROVIDER (Standard openai, auch local-openai z. B. faster-whisper-server), STT_MODEL (Standard whisper-1).
  • Vorlesen (🔊 an jeder Antwort): POST /api/media/speak {text} → MP3 über /audio/speech. TTS_PROVIDER (Standard openai), TTS_MODEL (Standard gpt-4o-mini-tts), TTS_VOICE (Standard alloy).
  • Bilderzeugung (Werkzeug „Bilderzeugung“, image_generate; oder POST /api/media/image {prompt, botId}): IMAGE_PROVIDER xai (Standard, grok-2-image) oder openai (gpt-image-1), IMAGE_MODEL überschreibt. Bilder landen unter images/ im Workspace und werden im Chat angezeigt.
  • Schlüssel kommen aus den Modell-Server-Einstellungen des jeweiligen Anbieters. GET /api/media zeigt, was verfügbar ist (ohne Schlüssel: verständliche Fehlermeldung statt Absturz).

Mehrbenutzerbetrieb

  • Rollen: admin und user. Das Konto aus JODABOT_ADMIN_USER (Standard admin) ist immer Admin und kann weder gesperrt, herabgestuft noch gelöscht werden (Notzugang).
  • Registrierung (/login → „Registrieren“, Android: Chip „Registrieren“): Modus off (aus), invite (Standard: nur mit Einladungscode) oder open. Der Admin stellt das unter Einstellungen → Nutzerverwaltung um; JODABOT_REGISTRATION=off|invite|open in der Umgebung überschreibt die Einstellung.
  • Einladungscodes: Admin erstellt Codes mit Rolle, Anzahl Nutzungen und Ablauf (Tage) und kopiert einen Link …/login?invite=CODE. Codes lassen sich widerrufen.
  • Nutzerverwaltung (Admin): Nutzer auflisten, Rolle ändern, sperren/entsperren (beendet Sitzungen), Passwort zurücksetzen, löschen (inkl. Bots, Chats, Gedächtnis, Routinen, Verbindungen, Workspace-Dateien).
  • Daten pro Nutzer: Bots (und damit Chats, Gedächtnis, Routinen, Dateien), Konto-Verbindungen (Google, Notion) und Push-Geräte gehören dem jeweiligen Nutzer.
  • Nur Admin: Modell-Server, Schlüssel/Secrets, MCP-Server, Chat-Kanäle, Nutzerverwaltung. Werkzeuge mit server-weiten Zugangsdaten (GitHub über GITHUB_TOKEN, IMAP/SMTP, globaler NOTION_TOKEN, MCP-Server) funktionieren nur in Bots von Admins; normale Nutzer verbinden ihr eigenes Google- bzw. Notion-Konto.
  • Migration: Beim Start werden vorhandene Daten ohne gültigen Besitzer (Einzelnutzer-Installation) automatisch dem Admin zugeordnet; der bestehende Admin erhält die Rolle admin.
  • API: GET/POST /api/auth/register, GET /api/admin/users, PATCH/DELETE /api/admin/users/{id}, GET/POST /api/admin/invites, DELETE /api/admin/invites/{code}, GET/PUT /api/admin/registration.

Browser-Werkzeuge (Playwright)

Werkzeuggruppe „Browser (Playwright)“ im Bot-Editor: browser_open (URL öffnen), browser_click (Element per CSS-Selektor oder sichtbarem Text anklicken), browser_type (Text in ein Feld tippen, ohne abzusenden), browser_submit (Formular absenden), browser_text (sichtbaren Text lesen), browser_screenshot (PNG im Workspace unter screenshots/, im Chat angezeigt), browser_close.

  • Bestätigung: browser_click und browser_submit sind riskant und warten auf deine Freigabe (Web, Android, Telegram/Discord /ja). Öffnen, Tippen, Lesen und Screenshots laufen ohne Rückfrage.
  • Sicherheit: Jede Anfrage des Browsers (inkl. Weiterleitungen und Unterressourcen) wird gegen interne Adressen geprüft (localhost, 10.x, 192.168.x, 169.254.x, ::1 …). Für Tests im eigenen Netz: JODABOT_BROWSER_ALLOW_PRIVATE=1. Downloads sind aus. Pro Bot eine Seite, nach 5 Minuten Leerlauf geschlossen (BROWSER_IDLE_MS).
  • Voraussetzung: Chromium oder Chrome auf dem Server (gesucht: CHROMIUM_PATH, /usr/bin/chromium, /usr/bin/google-chrome …). Docker-Image: docker build --build-arg INSTALL_CHROMIUM=1 . (bzw. in docker-compose.yml unter build.args). Ohne Chromium oder mit JODABOT_DISABLE_BROWSER=1 werden die Werkzeuge dem Modell nicht angeboten und der Bot-Editor zeigt einen Hinweis.
  • Render (Free): Das Image wird ohne Chromium gebaut (INSTALL_CHROMIUM=0), die Browser-Werkzeuge sind dort also aus. Chromium würde die 512 MB RAM des Free-Plans sprengen; wer es trotzdem will, setzt im Render-Dashboard die Docker-Build-Variable INSTALL_CHROMIUM=1 (sinnvoll erst ab einem größeren, kostenpflichtigen Plan).