Desktop app

The desktop build is a Tauri 2 shell: a Rust process owns the window, tray and updater, starts the packaged backend as a sidecar, and renders the frontend in a WebView.

Installation

ChannelArtifactDependency
fatHetu_x.y.z_x64-setup.exe / .msiNone (bundles the .NET runtime)
slimHetu.Slim._x.y.z_x64-setup.exe / .msiRequires the .NET 10 runtime
Linux.AppImage / .debAppImage needs no installation
Version (two files) tauri.conf.json Hetu.Api.csproj PR merged main Tag scripts/tag-release.ps1 triggers Release Build CI build fat / slim × Windows / Linux signing + manifests (fails if a channel is missing) GitHub Release installers + .sig latest*.json (primary + 3 mirrors) Client update primary → three mirror fallbacks NSIS preinstall hook clears leftover backends
From tag to update: CI produces installers and manifests for both channels; the client fetches manifests in GitHub → mirror order and verifies signatures.

Auto-update

  • Endpoint order: GitHub primary, then three mirrors (ghproxy.net / gh-proxy.com / ghfast.top).
  • Each channel has its own manifest: latest.json (fat) and latest-slim.json (slim); they never overwrite each other.
  • Installers are signed; a signature mismatch aborts the install. Install mode is passive.
  • An update badge appears next to the version; opening it shows the release notes.
Installers embed a preinstall hook that terminates leftover backend processes (taskkill /F /IM Hetu.Api.exe) before overwriting files, so a locked sqlite-vec\vec0.dll can no longer break an upgrade.

Tray and process lifecycle

BehaviourDetails
Close windowMinimizes to the tray by default; the backend keeps running so background jobs continue. Disable in Settings → App
QuitTray menu “Quit Hetu” terminates the backend child process first
Hard killThe backend remembers the shell PID (HETU_PARENT_PID); if the shell disappears it exits by itself, leaving no orphan holding the port
Dev reuseIn development, if HETU_API_DEV_PORT already has a backend, the shell reuses it

Install and data directories

Path (Windows example)Content
<install>\Hetu (Slim).exeShell executable (the fat channel ships Hetu.exe)
<install>\Hetu.Api.exeBackend sidecar — the install hook makes sure it is not running
<install>\wwwroot\Frontend assets served by the backend
<install>\sqlite-vec\vec0.dllSQLite vector extension (locked by a leftover backend when installs fail)
%LOCALAPPDATA%\Hetu\hetu.dbDatabase (plus -wal / -shm)
%LOCALAPPDATA%\Hetu\logs\Logs

Install hook

src-tauri/nsis-hooks.nsh runs before files are copied (NSIS_HOOK_PREINSTALL):

!macro NSIS_HOOK_PREINSTALL
  DetailPrint "Stopping leftover Hetu backend..."
  nsExec::Exec '"$SYSDIR\taskkill.exe" /F /IM Hetu.Api.exe /T'
  Pop $0
  Sleep 500
!macroend

Worktree root and cleanup

ItemDefault / options
Root.hetu-worktrees/<repo>/<worktree> next to the repository
Custom rootSettings → Workspace: absolute path, validated to be outside every repository
Cleanup criteriaChanges merged (or remote branch deleted) + clean working tree + idle past the threshold
Interval1 / 6 / 12 / 24 hours, or automatic cleanup off
Branch deletionOff by default (directory only); can be enabled
Manual run“Clean now” in settings returns checked / removed / kept counts

Data location

The shell passes the data directory to the backend via HETU_DATA_DIR: on Windows that is %LOCALAPPDATA%\Hetu (hetu.db plus WAL, and logs/). Copy that directory to migrate machines.

Packaging it yourself

# 1) build the backend sidecar (fat or slim)
pwsh ./scripts/publish-backend.ps1 -Mode SelfContained      -Rid win-x64
pwsh ./scripts/publish-backend.ps1 -Mode FrameworkDependent -Rid win-x64

# 2) build the installer
cd shell/hetu-desktop
npm run tauri:build                                            # fat
npm run tauri:build -- --config src-tauri/tauri.slim.conf.json  # slim

Sidecar naming must follow the Tauri convention: binaries/Hetu.Api-<rust-target-triple>(.exe).

Troubleshooting

SymptomFix
Error opening file for writing during installA leftover backend holds the file: end all Hetu.Api.exe in Task Manager and retry. Newer installers handle this automatically
Could not fetch a valid release JSONThe manifest could not be fetched. Open releases/latest/download/latest.json (slim: latest-slim.json) in a browser to confirm, then upgrade to the latest build
Window is gone but the app still runsClick the tray icon to restore it; the backend intentionally keeps running