What Changed
-
Apr 16, 2026 (v3.05.74): Web UI production hardening — persistence, multi-user auth, ops endpoints, JS module split, pytest suite
- SQLite persistence (
web/db.py,web/models.py) — SQLAlchemy-backed store with 4 tables:users,chat_sessions,messages,api_credentials. Sessions + message history now survive server restarts (previously in-memory only, lost on restart). DB file at~/.cheetahclaws/web.db(0600). Config keyCHEETAHCLAWS_WEB_DBoverrides the path. - Multi-user auth (
web/auth.py) — replaced single generated password with full accounts: bcrypt password hashing (passlib) + stateless JWT cookies (PyJWT, HS256, 7-day TTL). JWT signing secret persisted to~/.cheetahclaws/web_secret(0600) so logins survive restarts. New endpoints:POST /api/auth/register(first user becomes admin),POST /api/auth/login,POST /api/auth/logout,GET /api/auth/whoami,GET /api/auth/bootstrap(first-run routing). LegacyPOST /api/authkept for the terminal password page. - Session CRUD — new
PATCH /api/sessions/{id}to rename,DELETE /api/sessions/{id}to remove,GET /api/sessions/{id}/exportto download conversation as Markdown. Auto-titling from first user message. Cross-user isolation enforced even on in-memory cache hits (one session hit patched after smoke test revealed the leak). - Structured JSON logging (
web/logging_setup.py) —logging+ custom JSON formatter emits one record per line to stderr, e.g.{"ts":..., "level":"info", "logger":"web.server", "msg":"req", "method":"POST", "path":"/api/auth/login", "status":200, "dur_ms":259, "user_id":1}. Every HTTP response auto-logs method/path/status/dur_ms/user_id/peer. Level controlled byCHEETAHCLAWS_LOG_LEVELenv (default INFO). - Ops endpoints —
GET /healthreturns{ok, db, uptime_s}(503 if DB unreachable);GET /metricsreturns Prometheus v0.0.4 text withcheetahclaws_{uptime_seconds, requests_total, requests_4xx, requests_5xx, auth_logins_total, auth_logins_failed, auth_registrations_total, users_total, ws_connections_total}. Unauthenticated so Prometheus/k8s probes can hit them. - JS module split (
web/static/js/) — monolithic 1813-linechat.html→ 552 lines of HTML + 9 vanilla JS modules (chat.jscore class,util.js,auth.js,sidebar.js,tools.js,approval.js,settings.js,welcome.js,init.js) loaded via plain<script src>tags. Prototype-mixin pattern (Object.assign(ChatApp.prototype, {...})) keepsapp.foo()call sites unchanged. No bundler, no build step. - ETag + conditional caching — JS/CSS/HTML served with
Cache-Control: no-cache, must-revalidate+ weak ETag (mtime-size). Browser gets 304 when unchanged, fresh content after any edit. Binary assets keep 24h cache. Path traversal blocked by resolved-pathis_relative_tocheck. - pytest suite (
tests/test_web_api.py) — 21 end-to-end HTTP tests using httpx: bootstrap/register/login/whoami/logout, sessions CRUD + export + markdown, cross-user isolation, persistence after cache clear,/health,/metricscounter deltas, CORS preflight, auth gating of every endpoint. Spins the real server in a thread on a random port, DB truncated between tests. Runs in ~5s.pytest tests/test_web_api.py. - Sidebar UX — chat sessions now show title + relative time ("just now", "12m ago", "3d ago") + message count + busy dot. Search box filters by title/id on the client. Right-click (or long-press) gives a context menu: Rename / Export Markdown / Delete. Footer shows current username + Sign out link.
- Register-or-login on first visit — chat UI now calls
/api/auth/bootstrapon load; if no user exists it shows a "Create your first account" form (first registration becomes admin), otherwise the "Sign in" form. Username + password instead of a single server-generated password. - Theme: light default + system auto —
:rootnow carries the light palette;@media (prefers-color-scheme: dark)swaps in the dark palette when the user hasn't explicitly chosen a theme. Toggle button cycles system → light → dark → system, icon reflects the effective theme, title tooltip spells out the current mode. Inline pre-paint script in<head>setsdata-themebefore first paint to avoid FOUC. - Auto port selection —
cheetahclaws --web(no--port) now tries 8080 first; onEADDRINUSEit binds:0and lets the kernel pick a free port, banner reports the real URL. Explicit--port Nbinds exactly N or fails loudly (user intent preserved).--portargparse default changed from8080→Noneas a sentinel. - Favicon + MIME polish —
web/static/favicon.{png,ico}cropped fromdocs/logo-5.png(leaping cheetah, transparent background, multi-size ICO 16/32/48). Served from root as/favicon.icofor browser defaults. MIME table extended with.ico(image/vnd.microsoft.icon),.svg,.jpg,.woff,.woff2. - Welcome dashboard rebalanced — old 5-card "Bridges & Media" row (ragged in 2×2 grid) split into two 4-card sections: Bridges (Telegram · WeChat · Slack · Monitor) and Multi-Modal Media (Voice Input · Vision · Copy Output · Export).
/cwdadded to Development Tools. Tagline changed to "Personal AI Assistant · Support Any Model · Autonomous 24/7". - Bridges commands in Chat UI —
/telegram,/wechat(+/weixinalias),/slack,/voicenow registered inweb/api.py's slash registry (previously only the terminal REPL had them), so clicking the dashboard cards actually runs the command. - New extras —
pip install 'cheetahclaws[web]'installssqlalchemy>=2.0,passlib[bcrypt]>=1.7.4,PyJWT>=2.8.0. CLI-only installs remain dependency-free.[all]extra updated. Add web ui demos. - Version bumped to 3.05.74.
- SQLite persistence (
-
Apr 16, 2026 (v3.05.73): Web UI — browser-based Chat UI + structured event API
- Web Chat UI (
web/chat.html) —cheetahclaws --webnow serves a rich browser-based chat interface at/chatalongside the existing PTY terminal at/. Features: real-time streaming via Server-Sent Events (SSE), collapsible tool cards with status badges, inline permission approval buttons (Allow/Deny), activity indicator (spinner + state labels for Thinking/Running/Processing), Markdown rendering with XSS sanitization (marked.jsbundled), dark/light theme toggle withlocalStoragepersistence, mobile-responsive layout with sidebar overlay. - Structured event API (
web/api.py) — newChatSessionclass bridgesagent.run()generator to WebSocket/SSE event streams following the same pattern as the Telegram/Slack/WeChat bridges. Events:text_chunk,thinking_chunk,tool_start,tool_end,permission_request,permission_response,turn_done,command_result,interactive_menu,input_request,status,error. Event buffer with replay for late-joining subscribers. - 8 new API endpoints —
POST /api/prompt(submit prompt or slash command),WS /api/events(real-time event stream),POST /api/approve(permission response),GET /api/sessions(list sessions),GET /api/sessions/{id}(session details + message history),GET/PATCH /api/config(read/write config),GET /api/models(list all 11 providers and models),POST /api/auth(login, sets HttpOnly cookie). - Settings panel — click ⚙ to open: model selector grouped by 11 providers (Anthropic, OpenAI, Gemini, Ollama, DeepSeek, Qwen, etc.), permission mode dropdown, thinking/verbose toggles, max tokens input, per-provider API key management with status indicators, quick action buttons (Compact/Status/Cost/Context), terminal link for fallback.
- Slash command support in Chat UI — all 45+ commands work. Quick commands (
/status,/help,/model,/context) return results instantly via POST response. Long-running commands (/brainstorm,/worker,/plan,/agent) stream events in real-time via SSE (server keeps HTTP connection open)./ssjrenders a clickable 12-item interactive menu./brainstorm(no args) shows a topic input box before starting. - SSJ sub-commands —
/ssj debate,/ssj commit,/ssj readme,/ssj scan,/ssj propose,/ssj reviewnow run directly as agent queries without showing the interactive menu. The menu only appears for/ssj(no args). - Feature dashboard — welcome page shows 24 feature cards organized in 6 categories (Core, Agent Features, Session & Memory, Multi-Model, Development Tools, Bridges & Media) with 7 clickable quick-command chips.
- Security hardening —
hmac.compare_digest()for timing-safe token comparison, XSS sanitization (HTML tags escaped before Markdown rendering), CORS restricted to request Origin echo (no wildcard), HttpOnly + SameSite=Strict cookies, auth checked before WebSocket upgrade,_BufferedSocketwrapper replaces fragilesock.recvmonkey-patching. - Session management — chat sessions with idle timeout (30 min), background reaper for orphaned sessions, session list in sidebar with message count and busy indicator, click to switch, "+" to create new.
- Web bridge integration —
RuntimeContextextended withweb_input_event,web_input_value,in_web_turnfields.tools/interaction.pyroutes permission prompts to web bridge viathreading.Eventsynchronization.commands/advanced.pydetects web turns and skips interactive prompts (uses defaults like Telegram bridge). - Thread-safe stdout streaming —
_ThreadLocalStdoutinterceptsprint()only from the target command thread, broadcasts astext_chunkevents. Other threads unaffected. pyproject.tomlpackaging —webpackage added topackageslist,*.js,*.css,*.htmladded topackage-data. Static assets (xterm.min.js,marked.min.js,chat.html) correctly included inpip installdistributions.- Docs — new Web UI Guide (304 lines): quick start, full feature list, settings panel, API reference with JSON examples for all 8 endpoints and 12 event types, architecture notes, troubleshooting. README updated with Web UI section, feature table entry, CLI options, and examples.
- Version bumped to 3.05.73.
- Web Chat UI (