T-CKC1-tauri-desktop-wrapper
Status: closed/superseded · Impact: medium · Complexity: large
D-0012-monorepo-tooling names a Rust Tauri app as the validating case for the
polyglot moon workspace — a TypeScript app and a Rust app side by side, the Rust toolchain
running under moon. This task stands up a thin Tauri v2 desktop app under apps/desktop that
embeds the same static dashboard SPA bundle D-0013-dashboard-app ships, proving the
workspace is genuinely polyglot rather than JS-only.
This is the last/later item in the monorepo+dashboard arc and is a strong candidate for its own later milestone rather than part of the initial monorepo+dashboard push: it needs the Rust toolchain proven, the SPA bundle committed, and a system Rust + Tauri build environment that the earlier tasks don’t require. Treat it as the polyglot capstone — schedule it after the dashboard ships, on its own milestone if convenient.
No desktop app and no apps/ tree exist yet. The dashboard is a web SPA served by the existing
Bun/Hono server; its committed static bundle is the input Tauri would embed.
| Location | Role today |
|---|---|
apps/ | Does not exist — created (empty) by T-RVMG; no apps/desktop |
plugin/lib/services/dashboard/server.ts | Bun/Hono server: GET /, GET /api/state, POST /api/refresh; the dashboard data layer |
plugin/lib/services/dashboard/server.ts#makeApp | Hono app factory wiring the three routes above |
plugin/lib/services/dashboard/dashboard-service.ts | Lifecycle supervisor behind sdlc dashboard start/stop/list |
.moon/toolchains.yml | Declares the Bun javascript toolchain and a rust toolchain (added by T-RVMG) — no Rust project consumes it yet |
The SPA bundle Tauri embeds (apps/dashboard source, built to a static dist, committed into
the plugin as web-dist/) is produced by T-CW4K and T-JDEV — those land before this task.
Proposed
Section titled “Proposed”A thin Tauri v2 desktop app at apps/desktop that embeds the committed static dashboard SPA and is
the polyglot validating case for the moon workspace.
apps/desktop/ tauri.conf.json Tauri v2 config: frontendDist → committed SPA bundle; product name, window moon.yml moon project: declares the rust toolchain; `build` task = `tauri build` src-tauri/ Cargo.toml Rust crate: tauri v2 + tauri-build dependencies src/ main.rs Tauri entry point; spawns the dashboard server as a sidecar (v1)tauri.conf.jsonpointsfrontendDistat the committed static dashboard bundle (theweb-dist/artifact fromT-JDEV) — Tauri embeds exactly that staticdist, no rebuild of the SPA.- The Rust crate under
src-tauri/builds with moon’srusttoolchain (T-RVMG), makingapps/desktopthe second ecosystem in the workspace alongside the TypeScriptapps/dashboard. - Data layer (v1): sidecar.
main.rsspawns the existing Bun/Hono dashboard server as a Tauri sidecar and the embedded SPA talks to it over its relative/apibase — exactly as the SPA does in the browser. Zero data-layer rework. The openinvoke-vs-sidecar decision is recorded in the Approach.
Approach
Section titled “Approach”- Scaffold
apps/desktopas a Tauri v2 project. Createsrc-tauri/Cargo.toml(depends ontauriv2 +tauri-build),src-tauri/src/main.rs(Tauri app entry), andtauri.conf.json. SetfrontendDistto the committed static dashboard bundle (T-JDEV’sweb-dist/) and leavebeforeBuildCommandempty — the SPA is already built and committed, so Tauri only embeds it. - Wire the moon project. Add
apps/desktop/moon.ymldeclaring therusttoolchain and abuildtask that runstauri build. This is the load-bearing polyglot step: moon now drives a Rust project alongside the TypeScript dashboard, both under one workspace. - Choose the data transport — OPEN DECISION, recommend the sidecar. Two options:
(a) Sidecar (recommended for v1): bundle the existing Bun/Hono server as a Tauri sidecar
binary, spawn it from
main.rson startup, and let the embedded SPA hit its relative/apibase unchanged — zero data-layer rework, since the SPA already speaks HTTP to that server. (b) Tauriinvoke: reimplement theGET /api/state/POST /api/refreshdata layer as Rustinvokecommands and swap the SPA’s transport. Larger, duplicates the data layer in Rust. Recommendation: ship (a) for v1. Implement the sidecar path; capture (b) as a follow-up. - Implement
main.rsfor the sidecar path. On startup, spawn the dashboard server sidecar (bound to localhost), wait for it to be ready, then load the embedded SPA pointed at its/apibase. Tear the sidecar down on window close. - Verify the polyglot build end-to-end. Run
tauri buildto produce a desktop binary with the SPA embedded; launch it and confirm the desktop dashboard renders the same data as the web SPA; confirmmoonbuilds bothapps/dashboard(TypeScript) andapps/desktop(Rust) — the polyglot proof.
Files to touch
Section titled “Files to touch”| Location | Kind | Change |
|---|---|---|
apps/desktop/tauri.conf.json | new | Tauri v2 config; frontendDist → committed dashboard SPA bundle; product/window settings |
apps/desktop/src-tauri/Cargo.toml | new | Rust crate manifest: tauri v2 + tauri-build dependencies |
apps/desktop/src-tauri/src/main.rs | new | Tauri entry point; spawns the Bun/Hono dashboard server as a sidecar (v1) |
apps/desktop/moon.yml | new | moon project: declares the rust toolchain; build task runs tauri build |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
tauri build(driven viamoon run desktop:build) produces a runnable desktop binary with the static dashboard SPA embedded — no separate web server needed to view the UI shell. - AC-2: Launching the desktop binary shows the dashboard rendering the same data the web SPA
shows (task/milestone/lease/working state via the
/api/statesource). - AC-3:
moonbuilds bothapps/dashboard(TypeScript) andapps/desktop(Rust) from the one workspace — proving the workspace is polyglot (n ≥ 2 ecosystems under moon). - AC-4:
apps/desktop/src-tauri/Cargo.tomlandapps/desktop/moon.ymlexist and the Rust crate compiles under moon’srusttoolchain (moon run desktop:buildexits 0). - AC-5:
apps/desktop/tauri.conf.json’sfrontendDistresolves to the committed SPA bundle (T-JDEV’sweb-dist/) — the desktop app embeds the same static bundle the web server serves, with no second copy of the frontend source.
Out of scope
Section titled “Out of scope”- Scheduling — this task could be its own later milestone. It is the polyglot capstone, gated on the dashboard shipping and on a system Rust + Tauri build environment; defer it out of the initial monorepo+dashboard milestone if convenient.
- The Tauri
invokedata layer. v1 ships the sidecar; reimplementing the data layer as Rustinvokecommands is a deliberate follow-up (see Approach step 3, option b). - New dashboard features. The desktop app shows exactly what the web SPA shows — no
desktop-only views, no extra data sources beyond what
T-UUMKships for the web. - Code signing, notarization, auto-update, and multi-OS release packaging — a hardening concern for a release milestone, not this validating-case task.
- The Rust toolchain itself — declared by
T-RVMG; this task consumes it, it does not add it.
Dependencies
Section titled “Dependencies”T-JDEV(hard, independs_on:): the committed static SPA bundle (web-dist/) is what Tauri’sfrontendDistembeds — without it there is nothing to wrap.T-RVMG(prose): provides theapps/tree and the moonrusttoolchain this Rust project builds under. Not independs_on:to avoid a redundant edge —T-JDEValready transitively sequences after the workspace exists — butapps/desktopcannot build without the rust toolchain.
Depends on
Section titled “Depends on”T-JDEV