Setup & running
How to get horrible-dashboard running from a fresh clone — the browser layout and the desktop (Tauri) layout share one frontend, so most of the setup is common.
package.jsonThe Scripts reference below mirrors the scripts block in the
repo-root package.json. If you add, rename, or change a pnpm script, update this
page in the same change (a Stop hook flags a package.json change that doesn't touch
docs/). See the sync policy.
Prerequisites
| Tool | Version | Notes |
|---|---|---|
| Node.js | LTS (≥ 20) | Runtime for pnpm and Vite. |
| pnpm | 10.28.2 | Pinned via packageManager. Easiest: corepack enable (uses the pinned version automatically). |
| Python | ≥ 3.12 | The backend (requires-python = ">=3.12"). |
| uv | latest | Python package/venv manager — install guide. The backend is managed with uv, never pip. |
| Rust + Tauri prereqs | stable toolchain | Desktop layout only. rustup plus the Tauri v2 system dependencies (WebView2 — preinstalled on Windows 11; webkit2gtk on Linux; Xcode Command Line Tools on macOS). The Tauri CLI itself comes from pnpm install. |
Install
corepack enable # make the pinned pnpm available (first time only)
pnpm install # JS deps for every workspace (apps/*, packages/*)
uv sync # backend Python deps + a local .venv
Optional: uv sync --extra webrtc adds the WebRTC data-channel transport for the peer
fabric (heavy native deps, so it's opt-in).
Run the browser layout
pnpm dev # backend + Vite UI together
Open http://localhost:5173. pnpm dev (via scripts/dev.mjs) starts the FastAPI
backend on :8000 and the Vite UI on :5173, which proxies /api and /ws to
the backend — so API panels work out of the box. Backend health check:
GET http://localhost:8000/api/health.
pnpm dev:web— UI only, when a backend is already running.pnpm dev:lan— bind both servers to0.0.0.0so other machines can reach this node (needed for the peer fabric / collaboration).
Run the desktop layout (Tauri)
pnpm dev:desktop # runs `tauri dev`
The Tauri shell supervises the backend itself (apps/desktop/src-tauri/src/backend.rs):
it spawns uvicorn, or reuses one already running on :8000 — no separate backend start
needed. The first run compiles Rust and takes several minutes; that's expected.
Production builds
pnpm build # static web bundle (apps/web/dist)
pnpm build:desktop # native desktop installers (Tauri)
Backend on its own
pnpm dev already runs the backend; start it standalone only when iterating on Python:
uv run uvicorn backend.app:app --reload --reload-dir backend --reload-exclude "logs/*" --port 8000 # dev server
uv run pytest # backend tests
uv run ruff format . && uv run ruff check --fix . # format + lint Python
--reload-dir backend scopes the watcher to Python source only; --reload-exclude
additionally excludes logs/ (where backend.log lives) so writing a log line never
triggers a reload loop.
Checks
pnpm typecheck # all TS workspaces
pnpm lint # ESLint
pnpm format # Prettier (writes)
uv run pytest # backend tests
Scripts reference
Every script in the repo-root package.json:
| Script | Underlying command | Purpose |
|---|---|---|
pnpm dev | node scripts/dev.mjs | Full browser stack: FastAPI backend and Vite UI together (localhost:5173). |
pnpm dev:web | pnpm --filter @horrible/web dev | Frontend only (assumes a backend is already up). |
pnpm dev:lan | node scripts/dev.mjs --host 0.0.0.0 | Same as dev but bound to 0.0.0.0 for LAN / peer-fabric access. |
pnpm dev:desktop | pnpm --filter @horrible/desktop dev | Desktop layout (tauri dev); the shell supervises the backend. |
pnpm build | pnpm --filter @horrible/web build | Production web bundle. |
pnpm build:desktop | pnpm --filter @horrible/desktop build | Native desktop build (tauri build). |
pnpm build:icons | node scripts/build_icons.mjs | Regenerate app icons from source art. |
pnpm typecheck | pnpm -r typecheck | Typecheck every workspace package. |
pnpm lint | eslint . | Lint the whole repo. |
pnpm format | prettier --write . | Format the whole repo. |
Troubleshooting
- Vite proxy
ECONNRESET/ECONNREFUSED, or the backend aborts withOPENSSL_Uplink ... no OPENSSL_Applink(Windows). A MinGWlibcryptoonPATH(e.g.C:\msys64\mingw64\bin) can get loaded for TLS and crash the worker.backend/__init__.pystrips MinGW dirs from the processPATHat import, so the standard commands above work regardless of your shellPATH. - Port :8000 stays bound after Ctrl-C (Windows).
pnpm devtree-kills the backend on exit, but a manually starteduv run uvicorn --reloadcan orphan a worker — kill the whole process tree if a stale one holds the port. - Backend stuck in a restart loop. Almost always the reload watcher seeing its own
log writes. Use the standard commands above (
--reload-dir backend --reload-exclude "logs/*", already set inscripts/dev.mjs/dev-backend.ps1) rather than a bareuvicorn --reloadwith no scoping — that watches the whole repo root, includinglogs/backend.log. - Desktop first build seems stuck. It's compiling Rust; give it a few minutes.
For how to verify a change in the running app, see the running-the-app workflow.