SPB Git forge

spb/polyllm

Public
15commits 1branches 0releases
2.2 MBsize
maindefault branch
13 days agolast push
TypeScript 97.4% SQL 1% JavaScript 0.9% CSS 0.6%

Docs for 1.0 (README, CLAUDE.md), untrack QA session file

Simon-Pierre Boucher committed 13 days ago (Sep 11, 2026) parent e850324

4 changed files +44 −35

modified .gitignore +1 −0
@@ -31,3 +31,4 @@ logs/
31 31 tmp/
32 32 .turbo/
33 33 .claude/
34 +qa/.e2e-session.json
modified CLAUDE.md +14 −0
@@ -18,6 +18,20 @@ The original product brief lives in `docs/SPEC-original.md`; the UI conventions
18 18 - **No fake integrations.** A capability is ✅ only after a real request passed (`docs/provider-test-matrix.md`).
19 19 - Secrets only in `.env` (gitignored) and the mld manifest on M1M32; `.env.example` documents the variables.
20 20
21 +## 1.0 architecture notes (2026-09-11)
22 +- Read `docs/UPGRADE-PLAN.md` (shared primitives, ownership map) and `docs/upgrade-notes/*.md` (per-area APIs, contracts) before
23 + touching chat, models, Arena, projects/library/prompts, usage/providers/endpoints, marketing or search/share.
24 +- **Mobile first.** Phones use `BottomSheet` / `ResponsiveDialog` / `ActionSheet` (`components/ui/sheet.tsx`), `useLongPress`,
25 + `.snap-row` carousels, `.tap` hit areas, `.h-app` (100dvh − keyboard) — never `window.prompt/confirm`, never `100vh`.
26 +- Schema additions go in `src/db/schema-workspace.ts` (or a new `schema-*.ts` re-exported from `src/db/index.ts`);
27 + `pnpm db:generate --name x && pnpm db:migrate` (`db:push` needs a TTY). Never edit shipped migrations.
28 +- Cross-area contracts: prompt insert event `polyllm:insert-prompt` (`components/prompts/insert.ts`), pending attachments
29 + (`components/library/use-in-chat.ts`), palette events `polyllm:open-attach` / `polyllm:switch-model`, share via
30 + `openShareSheet()`, exports via `exportConversation()`. Custom endpoints resolve in `prepareTurn` / `runArenaModel`
31 + through `resolveCustomEndpoint()` (`lib/endpoints/service.ts`); their models are keyed `custom/<endpointId>:<modelId>`.
32 +- QA: one dev server only (`.next` conflicts); `node qa/responsive-qa.mjs` + `node qa/flows.mjs` before deploying.
33 +- Brand assets are generated: edit `public/icon.svg` / `public/brand/*.svg`, then `scripts/brand-assets.sh`.
34 +
21 35 ## Commands
22 36 `pnpm dev` · `pnpm typecheck` · `pnpm lint` · `pnpm test` (vitest) · `pnpm test:e2e` (Playwright; dev server with
23 37 `EMAIL_DRY_RUN=1 EMAIL_DRY_RUN_PRINT=1`) · `pnpm db:generate` / `pnpm db:migrate` · `pnpm models:sync [provider]` ·
modified README.md +29 −10
@@ -2,10 +2,15 @@
2 2
3 3 **One interface. Every model. Bring your own keys.** — https://www.polyllm.io
4 4
5 PolyLLM is a universal control center for AI models: connect your own OpenAI, Anthropic, Google Gemini, xAI, Mistral, DeepSeek, Kimi (Moonshot), OpenRouter and Cerebras API keys,
6 discover the models your keys can reach, configure each one with only the parameters it supports, chat with real
7 token-by-token streaming, compare up to four models side by side in the Arena, and track tokens, latency and estimated
8 cost. Keys are encrypted at rest (AES-256-GCM, HKDF-derived data key, AAD-bound to the user) and only decrypted on the
5 +PolyLLM is a mobile-first, multi-model AI workspace — an "AI operating system" rather than a chat box: connect your own
6 +OpenAI, Anthropic, Google Gemini, xAI, Mistral, DeepSeek, Kimi (Moonshot), OpenRouter and Cerebras API keys (plus any
7 +OpenAI-compatible endpoint such as Ollama, LM Studio, vLLM, llama.cpp or MLX), discover the models your keys can reach,
8 +configure each one with only the parameters it supports, chat with real token-by-token streaming, let the transparent
9 +**Smart Router (AUTO)** recommend a model, compare 2–4 models inline or in the **Arena** (blind mode, votes per criterion,
10 +personal scoreboard), organise work in **Projects** with a prompt library (`{{variables}}`) and a reusable file library,
11 +search everything (`model:claude project:research after:2026-08-01`), share/export conversations, and track tokens,
12 +latency, cost, projections and savings opportunities in **Usage**. Installable as a PWA; designed first for 375–430 px
13 +phones (bottom navigation, bottom sheets, swipe gestures, keyboard-safe composer), then tablet and desktop. Keys are encrypted at rest (AES-256-GCM, HKDF-derived data key, AAD-bound to the user) and only decrypted on the
9 14 server immediately before a provider request.
10 15
11 16 ## Stack
@@ -19,12 +24,18 @@ src/app routes: (marketing) landing/legal · (auth) login/signup
19 24 src/lib/ai/core provider-neutral contract: PolyModel, UnifiedChatRequest, UnifiedStreamEvent, errors, retry, pricing, normalization
20 25 src/lib/ai/providers adapters (openai, anthropic, gemini, xai, mistral, deepseek, kimi, openrouter, cerebras) + catalogs — provider quirks live ONLY here
21 26 src/lib/ai/registry model registry: live listing → catalog merge → Postgres; scheduled + manual sync
22 src/lib/chat turn orchestration (edit/regenerate/continue/branch), built-in tools loop, SSE
27 +src/lib/chat turn orchestration (edit/regenerate/continue/branch/adopt, ephemeral temporary chats), built-in tools loop, SSE
28 +src/lib/arena sessions, streaming per model, votes/criteria, winner & scoreboard math, exports, public shares
29 +src/lib/projects|library|prompts workspaces, reusable files (token estimates), prompt templates with variables
30 +src/lib/search full-text search (Postgres FTS + filter query language) · src/lib/export conversation exports (md/txt/json/html→print)
31 +src/lib/endpoints custom OpenAI-compatible endpoints (encrypted keys/headers, discovery, SSRF guard) · src/lib/usage analytics & savings
32 +src/lib/models model intelligence: badges, lifecycle, intent search, compare slugs, parameter groups · src/lib/client router & token estimators
23 33 src/lib/providers encrypted key storage & validation
24 src/components ui kit · app shell · chat · arena · settings · marketing
25 docs/ provider-research (per provider, dated), provider-test-matrix (generated), deployment-cluster, final-audit, UI brief
26 scripts/ sync-models, provider-matrix (real-API tests)
27 e2e/, tests/ Playwright workflows, vitest unit tests
34 +src/db schema.ts (core) + schema-workspace.ts (1.0 tables) · drizzle/ migrations
35 +src/components ui kit (sheet, segmented, …) · app shell (bottom nav, drawer) · chat · models · arena · projects · library · prompts · search · share · usage · providers · settings · marketing
36 +docs/ UPGRADE-PLAN (1.0 contract) + upgrade-notes/ (per area) · provider-research · provider-test-matrix · deployment-cluster · UI brief
37 +scripts/ sync-models, provider-matrix (real-API tests), brand-assets (favicons / PWA icons / OG image)
38 +e2e/, tests/, qa/ Playwright workflows, vitest unit + integration tests, responsive QA sweeps (`qa/responsive-qa.mjs`, `qa/flows.mjs`)
28 39 ```
29 40
30 41 ## Development
@@ -38,8 +49,16 @@ pnpm providers:matrix # real-API capability matrix → docs/provider-t
38 49 EMAIL_DRY_RUN=1 EMAIL_DRY_RUN_PRINT=1 pnpm dev && pnpm test:e2e # full browser workflow (links read from the dev log)
39 50 ```
40 51
52 +## Responsive QA
53 +```bash
54 +pnpm dev # single dev server on :3000
55 +QA_EMAIL=… QA_PASSWORD=… node qa/responsive-qa.mjs # 17 screens × 375/390/393/430/tablet/desktop → qa/out/ + report.json
56 +node qa/flows.mjs --width=390 [--send] # drawer, model picker, composer, chat, Arena swipe, search, palette, sheets
57 +```
58 +
41 59 ## Deployment
42 Runs on the private MacLustr cluster behind ngrok — see `docs/deployment-cluster.md`.
60 +Runs on the private MacLustr cluster behind the MacLustr Tunnel (WireGuard + Caddy on BHS64) — see `docs/deployment-cluster.md`.
61 +Built and hosted by Simon-Pierre Boucher on [MacLustr](https://www.maclustr.io) · contact@spboucher.ai
43 62
44 63 ## Security notes
45 64 No provider key ever reaches the browser, logs or analytics (structured logger redacts key-shaped strings and sensitive
deleted qa/.e2e-session.json +0 −25
@@ -1,25 +0,0 @@
1 {
2 "cookies": [
3 {
4 "name": "polyllm.session_token",
5 "value": "ZGYXJUeEBk1wErULioJm4GRFpSQyf66t.bmCgkI83DzBd7kqQuTjPoSbkdTO9mBx0s%2B22rVYpeKo%3D",
6 "domain": "localhost",
7 "path": "/",
8 "expires": 1791705485.823704,
9 "httpOnly": true,
10 "secure": false,
11 "sameSite": "Lax"
12 },
13 {
14 "name": "polyllm.session_data",
15 "value": "eyJzZXNzaW9uIjp7InNlc3Npb24iOnsiZXhwaXJlc0F0IjoiMjAyNi0xMC0xMVQwNzo1ODowNS44MTlaIiwidG9rZW4iOiJaR1lYSlVlRUJrMXdFclVMaW9KbTRHUkZwU1F5ZjY2dCIsImNyZWF0ZWRBdCI6IjIwMjYtMDktMTFUMDc6NTg6MDUuODE5WiIsInVwZGF0ZWRBdCI6IjIwMjYtMDktMTFUMDc6NTg6MDUuODE5WiIsImlwQWRkcmVzcyI6IjAwMDA6MDAwMDowMDAwOjAwMDA6MDAwMDowMDAwOjAwMDA6MDAwMCIsInVzZXJBZ2VudCI6Ik1vemlsbGEvNS4wIChNYWNpbnRvc2g7IEludGVsIE1hYyBPUyBYIDEwXzE1XzcpIEFwcGxlV2ViS2l0LzUzNy4zNiAoS0hUTUwsIGxpa2UgR2Vja28pIEhlYWRsZXNzQ2hyb21lLzE1My4wLjgwMTAuMTIgU2FmYXJpLzUzNy4zNiIsInVzZXJJZCI6IjVzY2tTR0FlSzIwS2VSNG40NW56ZVJHaTdiQm9VcjByIiwiaWQiOiJSRXdZelN4ZzhEZVpBcDdyNXlnbkZkYnVoUlFzZTBnayJ9LCJ1c2VyIjp7Im5hbWUiOiJRQSBNb2JpbGUiLCJlbWFpbCI6InFhLm1vYmlsZUBwb2x5bGxtLnRlc3QiLCJlbWFpbFZlcmlmaWVkIjp0cnVlLCJpbWFnZSI6bnVsbCwiY3JlYXRlZEF0IjoiMjAyNi0wOS0xMVQwNzo1NToyOS4wNjZaIiwidXBkYXRlZEF0IjoiMjAyNi0wOS0xMVQwNzo1NToyOS4wNjZaIiwicm9sZSI6InVzZXIiLCJvbmJvYXJkaW5nQ29tcGxldGVkQXQiOm51bGwsImlkIjoiNXNja1NHQWVLMjBLZVI0bjQ1bnplUkdpN2JCb1VyMHIifSwidXBkYXRlZEF0IjoxNzg5MTEzNDg1ODIyLCJ2ZXJzaW9uIjoiMSJ9LCJleHBpcmVzQXQiOjE3ODkxMTM3ODU4MjIsInNpZ25hdHVyZSI6IjRWWWdDcGV3ZXpfVUhTVE1zV2M4UmRuLWczME02YU5waHZucmNHSUNhakEifQ",
16 "domain": "localhost",
17 "path": "/",
18 "expires": 1789113785.823732,
19 "httpOnly": true,
20 "secure": false,
21 "sameSite": "Lax"
22 }
23 ],
24 "origins": []
25 }
\ No newline at end of file
26