ADR 0002 — UI stack: Wails v3, Svelte 5 and their components
- Status: accepted — prototype verified on macOS by the project owner on 2026-10-29
- Date: 2026-10-29
- Issue: #3 — Spike : choisir la stack Wails et frontend
Context
The draft imposes Go and Wails. Wails leaves the frontend open, and Sidekicks needs four non-trivial UI parts: a Zed-like layout of resizable panels, a Markdown conversation that streams, a code editor (Settings, workspace files) and a terminal. The target machine is a MacBook Air; the users are not developers.
A prototype (spikes/wails-ui) assembles the candidates below in one window.

Decisions
1. Wails v3.0.0
| Wails v2.17 | Wails v3.0.0 | |
|---|---|---|
| Status | stable, maintenance | stable since 2026-10-26 (after a long alpha/beta, beta.34) |
| Backend model | one bound struct, context-based runtime | services with startup/shutdown hooks; managers for windows, events, dialogs |
| Events | untyped | typed events registered in Go (application.RegisterEvent[T]), generated TypeScript constants |
| Bindings | generated | generated by static analysis, Go doc comments carried to TypeScript |
| Windows | one | several (useful later: detach a channel, a terminal) |
| Streaming to the UI | events | events, plus streams and raw messages |
| macOS packaging | app bundle | app bundle, DMG, signing, notarisation, in-app updater |
| Build | opaque wails build |
a readable Taskfile |
| Go | ≥ 1.22 | ≥ 1.26 (we use 1.27.3) |
v3 maps directly onto Sidekicks: agents and the terminal are services, ACP updates are typed events, and #36 (packaging) is largely covered. The risk — a .0 release three days old — is limited by the length of its beta and by our timeline (v0.1 in February 2027). If a blocking v3 bug appears, the fix is to pin a later v3.0.x, not to go back to v2.
2. Svelte 5 + TypeScript, with Vite
Svelte 5 is the lightest of the official Wails templates (no virtual DOM, fine-grained reactivity through runes), which suits a UI updated many times per second by streaming. React 19 or Vue 3 would work too, but nothing in our needs requires their ecosystems, and the components below are framework-agnostic.
3. Components
| Need | Choice | Licence | Why, and rejected alternatives |
|---|---|---|---|
| Panels | paneforge 1.0 | MIT | Svelte 5 native, nested groups, collapsible panes, autoSaveId persists the layout (issue #12). A home-made splitter would re-implement keyboard and persistence handling. |
| Markdown | markdown-it 15, html: false |
MIT | Mature, CommonMark, renders an unclosed code fence as a block — streaming-friendly. marked is close; markdown-it's plugin model is richer. |
| Code colouring | Shiki 4, JavaScript regex engine, bundled languages only | MIT | VS Code-quality colouring, dual light/dark themes through CSS variables. The JS engine avoids shipping the Oniguruma WebAssembly. highlight.js is lighter but visibly poorer. |
| Sanitising | DOMPurify 3 | MPL-2.0 / Apache-2.0 | Model output is untrusted: even with html: false, the rendered HTML goes through DOMPurify. |
| Editor | CodeMirror 6 + @codemirror/lang-yaml |
MIT | Modular and light, YAML mode, lint API for live schema validation (issue #18). Monaco is the VS Code editor but heavy (several MB, web workers) for a YAML file. |
| Terminal | xterm.js 6 + addon-fit, Go side creack/pty |
MIT | The de-facto web terminal; with a real PTY htop/vim and resizing work. |
4. Rendering rules that came out of the prototype
- Streamed chunks are appended to a string, and the Markdown is rendered at most once per animation frame, not once per chunk. Measured in the sandbox (software rendering): 219 chunks at 50/s in 4.6 s (4.4 s of sleep), and at 500/s in 0.6 s — the UI keeps up.
- Shiki loads asynchronously; the message is rendered again when it is ready.
- Theme: design tokens as CSS variables, dark and light following the system (
prefers-color-scheme).
Measured cost
| Size | |
|---|---|
frontend/dist (all assets) |
1.9 MB |
| Main JS chunk (CodeMirror, xterm, markdown-it, Shiki core) | 1.16 MB, 368 kB gzipped |
| Shiki grammars and themes (lazy chunks) | ≈ 420 kB |
| Linux arm64 binary with assets embedded | 17.9 MB |
Assets are embedded in the binary and never downloaded, so the size matters little for a desktop app.
Verification
npm run buildandsvelte-check(0 errors, 0 warnings),go vet.- Built and run on Linux arm64 (GTK4 + WebKitGTK 6.0, under Xvfb): layout, resizing, streaming, colouring, sanitising and a real shell in the terminal, driven with
xdotool. - Run on macOS by the project owner (
wails3 dev,wails3 package), following the macOS test guide: everything as expected; the traffic lights covered the left dock heading, fixed with a--titlebar-insetpadding (38 px on macOS, equal toInvisibleTitleBarHeight).
Consequences
- Issue #8 starts from
wails3 init -t svelte(v3.0.0) and keeps the Taskfile that Wails generates; the projectMakefilestays the single entry point and delegates to it. - Third-party licences (Apache-2.0, MIT, MPL-2.0) are listed in a
THIRD_PARTY_NOTICESfile shipped with the binary (issue #36). - Building on Linux needs
pkg-config,libgtk-4-devandlibwebkitgtk-6.0-dev; on macOS, the Xcode command line tools.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
|