SPB Git

spb/polyllm

Public

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

Simon-Pierre Boucher committed (Sep 11, 2026) parent e850324 Browse files

4 changed files +44 −35

modified .gitignore +1 −0
@@ -31,3 +31,4 @@ logs/
31 tmp/ 31 tmp/
32 .turbo/ 32 .turbo/
33 .claude/ 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 - **No fake integrations.** A capability is ✅ only after a real request passed (`docs/provider-test-matrix.md`). 18 - **No fake integrations.** A capability is ✅ only after a real request passed (`docs/provider-test-matrix.md`).
19 - Secrets only in `.env` (gitignored) and the mld manifest on M1M32; `.env.example` documents the variables. 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 ## Commands 35 ## Commands
22 `pnpm dev` · `pnpm typecheck` · `pnpm lint` · `pnpm test` (vitest) · `pnpm test:e2e` (Playwright; dev server with 36 `pnpm dev` · `pnpm typecheck` · `pnpm lint` · `pnpm test` (vitest) · `pnpm test:e2e` (Playwright; dev server with
23 `EMAIL_DRY_RUN=1 EMAIL_DRY_RUN_PRINT=1`) · `pnpm db:generate` / `pnpm db:migrate` · `pnpm models:sync [provider]` · 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 **One interface. Every model. Bring your own keys.** — https://www.polyllm.io 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, 5+PolyLLM is a mobile-first, multi-model AI workspace — an "AI operating system" rather than a chat box: connect your own
6−discover the models your keys can reach, configure each one with only the parameters it supports, chat with real 6+OpenAI, Anthropic, Google Gemini, xAI, Mistral, DeepSeek, Kimi (Moonshot), OpenRouter and Cerebras API keys (plus any
7−token-by-token streaming, compare up to four models side by side in the Arena, and track tokens, latency and estimated 7+OpenAI-compatible endpoint such as Ollama, LM Studio, vLLM, llama.cpp or MLX), discover the models your keys can reach,
8−cost. Keys are encrypted at rest (AES-256-GCM, HKDF-derived data key, AAD-bound to the user) and only decrypted on the 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 server immediately before a provider request. 14 server immediately before a provider request.
10 15
11 ## Stack 16 ## Stack
@@ -19,12 +24,18 @@ src/app routes: (marketing) landing/legal · (auth) login/signup
19 src/lib/ai/core provider-neutral contract: PolyModel, UnifiedChatRequest, UnifiedStreamEvent, errors, retry, pricing, normalization 24 src/lib/ai/core provider-neutral contract: PolyModel, UnifiedChatRequest, UnifiedStreamEvent, errors, retry, pricing, normalization
20 src/lib/ai/providers adapters (openai, anthropic, gemini, xai, mistral, deepseek, kimi, openrouter, cerebras) + catalogs — provider quirks live ONLY here 25 src/lib/ai/providers adapters (openai, anthropic, gemini, xai, mistral, deepseek, kimi, openrouter, cerebras) + catalogs — provider quirks live ONLY here
21 src/lib/ai/registry model registry: live listing → catalog merge → Postgres; scheduled + manual sync 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 src/lib/providers encrypted key storage & validation 33 src/lib/providers encrypted key storage & validation
24−src/components ui kit · app shell · chat · arena · settings · marketing 34+src/db schema.ts (core) + schema-workspace.ts (1.0 tables) · drizzle/ migrations
25−docs/ provider-research (per provider, dated), provider-test-matrix (generated), deployment-cluster, final-audit, UI brief 35+src/components ui kit (sheet, segmented, …) · app shell (bottom nav, drawer) · chat · models · arena · projects · library · prompts · search · share · usage · providers · settings · marketing
26−scripts/ sync-models, provider-matrix (real-API tests) 36+docs/ UPGRADE-PLAN (1.0 contract) + upgrade-notes/ (per area) · provider-research · provider-test-matrix · deployment-cluster · UI brief
27−e2e/, tests/ Playwright workflows, vitest unit tests 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 ## Development 41 ## Development
@@ -38,8 +49,16 @@ pnpm providers:matrix # real-API capability matrix → docs/provider-t
38 EMAIL_DRY_RUN=1 EMAIL_DRY_RUN_PRINT=1 pnpm dev && pnpm test:e2e # full browser workflow (links read from the dev log) 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 ## Deployment 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 ## Security notes 63 ## Security notes
45 No provider key ever reaches the browser, logs or analytics (structured logger redacts key-shaped strings and sensitive 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
Menu

Theme