Decision record distilled from the 2026-09-04 Svelte AI chat research corpus β traps, the verified stack, the security floor, voice licensing, and what the executable proof did and did not show.
Everything here was re-derived from upstream registries, OSV, licences and a built proof on 2026-09-04; version numbers are dated observations, not live facts. The deployed app uses a deliberately small subset of this stack; see Wired versus evaluated.
Fork huggingface/chat-ui (Apache-2.0) or build your own
npm i vite@7
ERESOLVE: the Svelte plugin needs vite ^8
Pin vite@^8
sveltekit from @sveltejs/vite-plugin-svelte
Export removed
Import from @sveltejs/kit/vite
import DOMPurify from 'dompurify'
SSR 500
isomorphic-dompurify
{@html marked(msg)} per token
Quadratic; kills selection, scroll and code state
Block-split with stable keys
DOMPurify stops data leaks
 leaks on image load
CSP img-src 'self' data: blob:
Piper is MIT
Archived 2025-08-26; piper-tts is GPL-3.0-or-later
Kokoro (Apache-2.0 code and weights)
Verified stack (2026-09-04)
Layer
Pick
Version
Licence
Framework
svelte
5.57.0
MIT
Meta
@sveltejs/kit
2.70.3
MIT
Build
vite + @sveltejs/vite-plugin-svelte
8.x / 7.3.0
MIT
Markdown
marked
18.0.11
MIT
Sanitise
isomorphic-dompurify
3.19.0
MPL / Apache
AI logic
@tanstack/ai-svelte or @ai-sdk/svelte
0.21.0 / 5.0.92
MIT / Apache-2.0
Virtual list
virtua
0.51.0
MIT
Highlight
highlight.js / shiki
11.12.0 / 4.4.3
BSD-3 / MIT
Math
katex
0.18.5
MIT
TTS in browser
kokoro-js
1.2.1
Apache-2.0
STT server
speaches
pushed 2026-09-04
MIT
VAD
@ricky0123/vad-web
0.0.30
ISC
Only the first five layers are in the deployed app.
Security floor
Component
Minimum
Reason
svelte
β₯ 5.55.7
2026 SSR-XSS set
@sveltejs/kit
β₯ 2.70.2
Accept ReDoS; 2.70.0 fixed CSRF off outside production
mermaid
β₯ 11.16.1
five advisories 2026-08-06
dompurify
β₯ 3.4.13
avoid IN_PLACE and setConfig() entirely
pdfjs-dist
β₯ 6.2.108
arbitrary JS from a malicious PDF
ollama
never internet-exposed
critical missing-auth advisory with no listed fix
Voice licensing: code is not weights
Engine
Code
Weights
Verdict
Kokoro-82M
Apache-2.0
Apache-2.0
default
Whisper / Moonshine
MIT
MIT
fine
Chatterbox
MIT
MIT
fine
Piper (piper1-gpl)
GPL-3.0+
per voice
separate service only
F5-TTS
MIT
CC-BY-NC-4.0
non-commercial
Coqui / XTTS-v2
MPL-2.0
CPML
dead and non-commercial
What the proof showed
The stack installs and builds together; a real browser turn produced three closed blocks, rendered bold and code, and zero console errors.
Character-by-character replay of seven document shapes (tilde fences, nested longer fences, unterminated fences, trailing newlines) produced zero closed-block identity churn.
590-character, 12-section document: 59 keyed block renders versus 7,350 naive renders (124.6Γ). The ratio is length-dependent (88Γ at 410 characters) and counts renders, not milliseconds.
What the proof did not show
No LLM integration and no SSE endpoint: its /api/chat was a local timed emitter. The deployed app replaces it with real rooms and an optional upstream; see Backend boundary.
No timings, no framework benchmark, no runtime test of @lostgradient/chat components.
The proofβs send path lacked HTTP checks, cancellation and cleanup; these were proof limitations, not patterns to copy.
Pick-one decision
You want
Choose
Ship a product today
Open WebUI, accepting the branding lock under 50 users
Clean fork, best code
huggingface/chat-ui
Fastest own-UI result
@lostgradient/chat (pre-1.0)
Max control
@tanstack/ai-svelte plus own components
Max stability
@ai-sdk/svelte plus own components
Svelte Chat took the last shape in spirit: own components, the proofβs render path, and no SDK at all until an upstream exists. Build steps are in Setup.