SPB Git

spb/zyquo-cloud-web Public MIT

Zyquo Cloud Web — every cloud model, one beautiful chat, entirely in your browser.

TypeScript 81.9% CSS 8.9% JavaScript 7.5% Shell 1.1% HTML 0.6%
20.6 KB
Zyquo Cloud

# ⚡ Zyquo Cloud Web

# Every cloud model. One beautiful chat. Entirely in your browser.

The browser edition of Zyquo Cloud — 12 AI providers, 170 models, zero backend. Bring your own keys; nothing ever leaves your device.


Version License: MIT PRs Welcome Maintained

React 19 TypeScript strict Vite 7 Zustand PWA

Providers Models Verified live Backend Core bundle Personas Templates

CI Pages Live Last commit Repo size


🚀 Open the app →


# 📚 Table of Contents


# ✨ Features

Everything below is implemented and verified in this codebase — no vaporware.

# 💬 Chat engine

  • Streaming & non-streaming chat against 12 providers through two faithfully ported wire clients: one OpenAI /chat/completions client (11 providers + custom endpoints, every quirk handled) and one native Anthropic Messages API client — over fetch + ReadableStream with a hand-rolled incremental SSE parser (event:/data: blocks, keep-alive comments, [DONE], trailing-event flush).
  • Token-by-token rendering with a blinking caret, live elapsed time + tok/s, Stop (AbortController teardown) and Continue.
  • Reasoning streams normalized from every dialect: reasoning_content, reasoning, Mistral's array-of-thinking-chunks, DashScope enable_thinking, Anthropic thinking blocks — shown in a collapsible Thought process panel.
  • Perplexity citations (citations + search_results merged) rendered as numbered, clickable chips.
  • Auto-retry with backoff on 429/5xx (honors Retry-After), typed human-readable errors that name the provider, and a CORS-shaped network error that explains the proxy/Zyquo Router fallback.
  • Auto-titling after the first exchange using the provider's cheapest non-reasoning model (native Zyquo Cloud behavior, ported verbatim).

# 🎛 The Model Menu

  • Command-palette-style picker: fuzzy search across name / model ID / provider, filter chips (Vision · Tools · Reasoning · JSON · Long context · Cheapest), Favorites ⭐ / Recents / Aliases groups, keyed-providers first, full keyboard navigation (↑↓, use here, ⌘↵ set default).
  • Every row shows capability badges (👁 🧠 🛠), context window, and $/1M-token pricing straight from the catalog; un-keyed providers get an inline "Add key" affordance.

# 🧪 Power features

  • Multi-model compare — broadcast one prompt to 2–4 columns, each streaming independently with its own stop/copy/regenerate, then promote the best answer into your thread.
  • Variants & branching — regenerate keeps the previous answer as a swipeable variant (‹ 2/3 ›); branch a whole conversation from any message; edit & resend forks from an earlier user turn.
  • ⌘K command palette — actions (new chat, compare, focus mode, summarize, duplicate), jump-to-conversation, model switch, personas, templates.
  • / slash commands — quick tools (/summarize, /translate, /rewrite, /explain) + the full library with {{input}} substitution.
  • 8 personas and 56 prompt templates (8 categories × 7), ported verbatim from native Zyquo Cloud.
  • Vision attachments (drag/drop/paste images → base64 parts) and text file attachments (injected as fenced context blocks), gated by each model's real capabilities.
  • Read-aloud (Web Speech TTS) and dictation (SpeechRecognition).
  • Token & cost HUD — per-message and per-conversation token counts and cost estimates from catalog pricing, plus a context-window usage bar with auto-trim of the oldest turns at 90% capacity (system prompt kept).
  • Per-conversation parameters — temperature, top-p, max tokens, penalties, reasoning effort, extended thinking — the panel only shows controls the active model actually supports; unchecked = provider default, omitted from the request entirely.

# 📝 Rendering

  • GitHub-flavored Markdown (tables with zebra rows, task lists, blockquotes with accent bar), syntax-highlighted code blocks with language label, copy and wrap toggles, KaTeX math, and Mermaid diagrams (the ~1 MB renderer lazy-loads only when a diagram appears).

# 💾 Local-first persistence

  • Conversations in IndexedDB (schema-versioned, dependency-free wrapper), keys and settings in namespaced localStorage (zyquo.cloud.web.*) — surviving reloads and full browser restarts (gate-tested).
  • Export / import everything as JSON (keys strictly opt-in with a warning), per-conversation Markdown/JSON export, confirm-twice clear-data, undo for deletes.
  • Optional passphrase lock: the key map encrypted at rest with AES-GCM (PBKDF2, 310k iterations) — honestly framed as at-rest protection, not a running-session vault.

# 🎨 Design

  • The ZyquoTheme design system, ported token-for-token from the native macOS app — light flagship theme (#FAFBFD / sky-indigo #4E6AF0), derived dark theme, 5 accent choices, adjustable chat font size and density, focus mode, prefers-reduced-motion respected.
  • Installable PWA (app-shell precache, 1.15 MB) and fully responsive — the sidebar becomes a drawer on phones, code blocks scroll internally, 44 pt touch targets.

# 🛰 The Provider Fleet

Provider Models Wire format Streaming Vision Reasoning Citations
🟢 OpenAI 27 OpenAI compat
🟠 Anthropic 11 Messages API
xAI 5 OpenAI compat
🔵 Mistral 10 OpenAI compat
🔴 Google Gemini 14 OpenAI compat
🟣 Alibaba Qwen 32 OpenAI compat
🌀 DeepSeek 2 OpenAI compat
🌙 Kimi (Moonshot) 12 OpenAI compat
🔍 Perplexity 4 OpenAI compat
🧩 Together AI 16 OpenAI compat
📦 DeepInfra 34 OpenAI compat
Cerebras 3 OpenAI compat

All 12 call the provider APIs directly from your browser — CORS feasibility was empirically probed per provider (preflight + authenticated POST + streaming), documented with official sources in docs/CORS-MATRIX.md. Anthropic requires its documented anthropic-dangerous-direct-browser-access: true header, which the client sends. A per-provider base-URL override (Settings → Providers & Keys) lets you point any provider at your own proxy or a locally running Zyquo Router if a policy ever changes.


# 🌐 Live Demo

URL Notes
🚀 Production https://www.zyquo.cloud Primary deployment — HTTPS, security headers, installable PWA
🪞 GitHub Pages mirror https://spboucher-ai.github.io/zyquo-cloud-web/ Auto-deployed from main by CI

Open it, add any provider API key in Settings → Providers & Keys (it stays in your browser), pick a model, chat. That's the whole onboarding.


# 📸 Screenshots

Light (flagship) Dark
Chat — light Chat — dark
The Model Menu ⌘K Command Palette
Model menu Command palette
📱 Mobile
Mobile

# 🔒 Privacy & Security Model

This app has no backend, no accounts, and no telemetry — by design.

  • 🔑 Bring-your-own-key: your API keys live in localStorage on your device and are sent only to the provider you call, directly.
  • 🧾 Honest first-run notice: browser storage is not a secure vault — anyone with your browser profile (or a script running on the page) could read it. The app says so instead of pretending otherwise.
  • 🛡 Strict CSP: connect-src is locked to exactly the 12 provider origins + localhost (for Zyquo Router). No inline scripts, no third-party scripts, object-src 'none', frame-ancestors 'none'.
  • 🕵️ Audited: during the full 169-model verification run, the page contacted the 12 provider origins and localhost — nothing else.
  • 🔐 Optional passphrase lock: AES-GCM (WebCrypto) encryption of the key map at rest, PBKDF2-derived key, wrong-passphrase rejection tested.
  • 📦 Dependency-light on purpose: every dependency is key-theft surface — no icon packs, no CSS framework, no IndexedDB wrapper lib, no auth SDKs.

# 🧱 Tech Stack

Layer Choice Why
⚛️ UI React 19 + TypeScript (strict) noUncheckedIndexedAccess, project references, zero any leaks
⚡ Build Vite 7 code-split (Mermaid/KaTeX lazy), hashed assets, 288 kB gzip core bundle
🗃 State Zustand 5 one store: conversations, streaming, settings, UI
🎨 Styling CSS custom properties (ZyquoTheme tokens) no Tailwind/framework — tokens ported 1:1 from the native macOS app
📝 Markdown react-markdown + remark-gfm + rehype-highlight + KaTeX + Mermaid (lazy) GFM, math, diagrams, Zyquo-mapped syntax theme
🌊 Networking hand-rolled SSE parser over fetch/ReadableStream one parser for OpenAI-style and Anthropic named events
💾 Storage IndexedDB (own 80-line wrapper) + namespaced localStorage schema versioning, no dependency
📲 PWA vite-plugin-pwa (Workbox) app-shell precache only — never API responses or keys
🧪 Testing Playwright (Chromium/WebKit/Firefox) live gate scripts: streaming, persistence, full provider matrix

# 🚀 Getting Started

# Prerequisites

  • Node.js ≥ 20 and npm
  • At least one provider API key (OpenAI, Anthropic, xAI, Mistral, Gemini, DashScope, DeepSeek, Moonshot, Perplexity, Together, DeepInfra or Cerebras)

# Install & run

bash
git clone https://github.com/spboucher-ai/zyquo-cloud-web.git
cd zyquo-cloud-web
npm install
npm run dev          # → http://localhost:5173

Open the app, go to Settings → Providers & Keys, paste a key, hit Test, pick a model — done.

# Environment variables

The app itself needs none — keys are entered in the UI and stored in the browser. Build-time only:

Variable Purpose Default
VITE_BASE Base path for subpath hosting (e.g. GitHub Pages sets /zyquo-cloud-web/) /

⚠️ Never put API keys in .env files here — there is no server to hide them in. The .gitignore blocks .env* and the local test-key file anyway.


# 📜 Available Scripts

Script What it does
npm run dev Vite dev server on :5173
npm run build Type-check (project refs) + production build + PWA assets
npm run preview Serve the production build locally
npm run typecheck tsc -b --noEmit
npm run lint ESLint (flat config) over src/
npm run check typecheck + lint + build — the CI gate
node scripts/server.mjs 8080 dist Zero-dependency production server (CSP/HSTS headers, SPA fallback, /healthz)
node scripts/gate-phase2.mjs Live streaming gate in headless Chromium
node scripts/gate-phase3.mjs 13-check persistence gate (reload + browser restart + vault)
node scripts/verify-matrix.mjs Full provider/model verification matrix (needs real keys in .keys.local.json)
node scripts/verify-browsers.mjs Chromium/WebKit/Firefox responsive smoke

# 🗂 Project Structure

text
zyquo-cloud-web/
├── index.html                 # CSP meta, PWA/social meta
├── vite.config.ts             # Vite + PWA (app-shell precache only)
├── src/
│   ├── App.tsx                # Shell: sidebar + chat, global shortcuts
│   ├── types/                 # Provider, AIModel, Conversation, Message, Settings
│   ├── providers/             # 🔌 ALL networking lives here
│   │   ├── registry.ts        #   12-provider metadata + client resolution
│   │   ├── openaiCompatible.ts#   one client, 11 providers + custom, every quirk
│   │   ├── anthropic.ts       #   native Messages API + browser CORS header
│   │   ├── sse.ts             #   fetch/ReadableStream SSE parser + retry
│   │   ├── catalog.ts         #   the complete 170-model typed catalog
│   │   └── testKey.ts         #   key validation (/models or min completion)
│   ├── storage/               # 💾 the ONLY place touching localStorage/IndexedDB
│   │   ├── keys.ts            #   namespaced key map (+ vault overlay)
│   │   ├── vault.ts           #   AES-GCM passphrase lock
│   │   ├── db.ts              #   dependency-free IndexedDB wrapper
│   │   ├── conversations.ts   #   CRUD + schema migration + search
│   │   ├── settings.ts        #   theme, default model, proxy overrides
│   │   └── backup.ts          #   export / import / clear-everything
│   ├── state/store.ts         # Zustand: send/stream/stop/regenerate/branch/title
│   ├── features/              # personas, prompt library, compare, exporters, trim
│   ├── components/            # Sidebar, ChatView, ModelMenu, CompareView, …
│   └── design/                # ZyquoTheme tokens (CSS vars), components.css
├── scripts/                   # prod server + live verification gates
├── docs/                      # PLAN, PROVIDER-REUSE, CORS-MATRIX, VERIFICATION, NATIVE-UX
└── .github/workflows/         # CI + GitHub Pages deploy

Two hard architectural invariants, enforced by sweep: all network I/O is in providers/, all persistence is in storage/ — components stay presentational.


# ☁️ Deployment

The build is 100% static — host it anywhere.

# GitHub Pages (automated)

Every push to main triggers deploy-pages.yml: build with VITE_BASE=/zyquo-cloud-web/ → deploy to https://spboucher-ai.github.io/zyquo-cloud-web/.

# Self-host (any box, 30 seconds)

bash
npm run build
node scripts/server.mjs 8080 dist

server.mjs is a zero-dependency Node server that adds the full security header set (CSP, HSTS preload, nosniff, Referrer-Policy, Permissions-Policy), immutable caching for hashed assets, SPA fallback, and /healthz.

# Production (www.zyquo.cloud)

The primary instance runs the same server.mjs under PM2 behind an ngrok custom domain:

bash
pm2 start server.mjs --name zyquo-cloud-web -- 8080 dist
pm2 start "ngrok http --url=www.zyquo.cloud 8080" --name zyquo-cloud-ngrok
pm2 save

# Static hosts

Cloudflare Pages / Netlify / Vercel: build command npm run build, output dist/. Add the security headers from scripts/server.mjs via your host's headers config for parity.


# ✅ Verification

This app was verified live, with real keys, from a real browser — full report in docs/VERIFICATION.md:

Check Result
🌊 Streaming, token-by-token 169 / 169 tested models
📬 Non-streaming completion 12 / 12 providers ✅
⏹ Stop / AbortController 12 / 12 providers ✅
👁 Vision (base64 image parts) 9 / 9 vision-capable providers ✅
🧠 Reasoning deltas all thinking models ✅
🔗 Perplexity citations ✅ (19 chips on one query)
🌍 CORS direct-from-browser 12 / 12 ✅
💾 Persistence (reload + restart + vault) 13 / 13 checks ✅
🧭 Cross-browser (Chromium/WebKit/Firefox) 15 / 15 checks ✅
🕵️ Network audit provider origins + localhost, nothing else

# 🗺 Roadmap

  • Function calling / tools UI (the catalog already tracks tools capability)
  • Model aliases editor in Settings (aliases already surface in the Model Menu)
  • Client-side PDF export (Markdown/JSON exports ship today)
  • Transcript virtualization for 1,000+ message threads
  • Conversation tags & archive surfaces (data model ready)
  • i18n (FR first)

# 🤝 Contributing

Contributions are welcome!

  1. Fork and create a branch: git checkout -b feat/my-feature
  2. Keep the invariants: networking only in providers/, persistence only in storage/, design tokens only (no raw hex in components), and the file header on every code file.
  3. npm run check must be green.
  4. Open a PR with a clear description.

🔐 Never commit keys. .keys.local.json, .env* and friends are gitignored; CI contains a history secret-scan precedent.


# 📄 License

Released under the MIT License — © 2026 Simon-Pierre Boucher.


# 👤 Author

Zyquo

Simon-Pierre Boucher

📫 Contact: contact@spboucher.ai

Zyquo Cloud Web is part of the Zyquo family — native Zyquo Cloud (macOS), Zyquo Router (local gateway), and friends.


If this project is useful to you, a star makes my day.