Desktop app
Install Trestl on macOS, Windows, or Linux and keep your work locally.
Trestl Desktop runs the existing workspace in a native Tauri v2 window on macOS, Windows, and Linux. The application includes its runtime, frontend, and PGlite embedded PostgreSQL database. End users do not need Node.js, Docker, PostgreSQL, or a web server. Core project, task, roadmap, and canvas features work offline; remote repository and documentation integrations still need a connection.
Install and get started
The desktop app and bundled server use v0.6.0, matching the web app and CLI. Signed installers for this release are pending signing configuration and are not included in its web/CLI downloads. The Desktop installers workflow provides test artifacts from successful pull-request or branch workflow runs. These are not signed release installers and do not provide a published updater feed.
Once signing is configured, the workflow attaches installers and
desktop-SHA256SUMS to the same GitHub Release
as the CLI:
| Platform | Architecture | Installer |
|---|---|---|
| macOS 12+ | Apple Silicon and Intel, separate builds | .dmg containing Trestl.app |
| Windows 10/11 | x64 | NSIS .exe or .msi |
| Linux | x64 | .AppImage, .deb, .rpm |
Windows installers include an offline WebView2 installer. Linux packages use the
system WebKitGTK 4.1 runtime. AppImages may need FUSE or the distribution's
AppImage extraction option. The app checks for updates in the background. You can also choose Trestl →
Check for Updates…. Download an update, then choose Install and Restart
when you are ready. Linux .deb and .rpm users update through their package
manager or download the newer package; AppImage installations update in the app.
Open the application and create your local administrator account. Choose an empty workspace or the example projects. This account belongs to this desktop installation. It does not require a Trestl cloud account. Desktop installations use local accounts; organization OIDC/Google/proxy sign-in belongs to the hosted web version.
Use the native Trestl → Open Data Folder menu to find your data. Standard editing shortcuts, an integrated macOS title bar with real traffic lights, window size/position restoration, external links in your browser, and native download dialogs are supported. Closing the application also stops the local database process. Launching a second copy focuses the existing window.
Updates
To see the installed version, choose Trestl → About Trestl. The footer of
Trestl → Check for Updates… also shows the current version, even when the
release feed is unavailable. Development builds can share a version number:
replacing a local 0.6.0 build with a newer 0.6.0 build requires a manual
installation because the updater only offers higher versions.
Trestl checks once after startup and every six hours while open. Checks that find no update or cannot reach GitHub stay quiet. A newly available version opens a small update window without taking keyboard focus. The menu's Check for Updates… action always lets you check manually.
The update window shows the new version, release notes, download progress, and Install and Restart. Downloads are verified against the public key shipped with the app. Downloading does not interrupt your work. Before installation, save and close open forms or editors; the app flushes canvas autosaves, waits for pending API writes, and requires the database process to exit successfully. A save failure or shutdown timeout stops installation. Local data and the persistent encryption key remain in the app-data folder, outside the replaced application.
Updates work for macOS, Windows NSIS/MSI (preserving the installed package type),
and Linux AppImage. Linux .deb/.rpm installations show a link to downloads
instead of replacing files managed by the package manager. Updater downloads use
public GitHub Releases; a private repository's downloads will not work without
GitHub authentication, and no GitHub credential is bundled into the app.
Before publishing, rehearse an update with two separately versioned test builds
using the same dedicated test bundle identifier and signing key. Use a separate
app-data folder and a test feed configured only in a disposable source copy;
keep the production GitHub endpoint and download restrictions unchanged.
Create a task in the older build, check for updates, download, install, and
verify the automatic restart reports the newer version with the task and
app-secret preserved. Also verify a modified download is rejected and an
unsaved draft prevents installation. Repeat the check after upgrading to ensure
the same version is not offered again. Local feed testing does not replace
testing signed/notarized installers and public GitHub downloads on each platform.
Local data and backups
| System | Data folder |
|---|---|
| macOS | ~/Library/Application Support/app.trestl.desktop/ |
| Windows | %APPDATA%\app.trestl.desktop\ |
| Linux | ${XDG_DATA_HOME:-~/.local/share}/app.trestl.desktop/ |
The folder contains database/, app-secret, port, and desktop.log.
desktop.lock exists while the database is running. The persistent app-secret
encrypts integration credentials: back it up together with the database. The
webview also retains account cookies and appearance preferences in its own
operating-system storage. The desktop database is separate from development
.data/ and all hosted installations.
For a full backup, quit Trestl, wait for it to stop, and copy the entire data folder to a safe location. To restore, quit Trestl and replace the data folder with that backup. Preserve the original before replacing anything. Do not copy a live database or run an older version against data migrated by a newer one. Uninstalling the application is not a request to erase your workspace.
For selective transfer between desktop and web installations, use project export/import. The administration JSON export is an inspection/export format, not a full database restore.
Build from source
Install Node.js 22.23.2+, pnpm 10.7.1, stable Rust, and the Tauri platform prerequisites. macOS requires Xcode command-line tools, Windows requires MSVC C++ build tools, and Linux requires WebKitGTK 4.1 and GTK development libraries (see the workflow).
pnpm install --frozen-lockfile
pnpm desktop:devdesktop:dev builds the desktop frontend and starts the native shell. Rust changes
reload through Tauri; restart the command after frontend/server changes to rebuild
the packaged resources. Use pnpm dev for the regular web hot-reload workflow.
pnpm typecheck
pnpm test:desktop
pnpm desktop:prepare
pnpm test:desktop-package
pnpm desktop:buildBuild on each target OS and architecture; the preparation script deliberately
rejects a mismatched runtime target. It downloads official Node.js 22.23.2,
checks its SHA-256 against Node's published checksum manifest, and caches it in
node_modules/.cache/trestl-desktop/. A first build needs network access;
installed applications do not. Generated runtime/resources live in ignored
src-tauri/binaries/ and src-tauri/resources/. Tauri emits installers under
src-tauri/target/release/bundle/ (or the target triple's release directory).
Release v0.6.0
Merge the tested release into main before tagging. The app, CLI, and desktop
share one version and release tag, which must point to a commit already in
main's history. Desktop publication can follow the web/CLI release after the
required signing configuration is available.
Before tagging, run pnpm desktop:version. The root package, CLI package,
Tauri config, Cargo manifest, and Cargo lockfile must all say 0.6.0. The workflow
also checks the tag equals v0.6.0. Desktop installer releases currently use
stable major.minor.patch versions; use manual workflow artifacts for candidates.
Pushing the v0.6.0 tag starts the image, CLI, and desktop workflows. Desktop
publication waits for the reusable application/container/Raycast CI and all four
native build jobs (Apple Silicon, Intel Mac, Windows x64, Linux x64). Each native
runner tests the bundled service, including first setup, writing a project and
task, restart persistence, origin isolation, and parent-process shutdown. macOS
also tests the runtime inside the finished .app; Windows extracts the MSI and
tests its shipped runtime and resources. Release builds verify the signatures of
that extracted application and runtime.
The seven installers are named
trestl-desktop-0.6.0-<target-triple>.<extension>. The publishing job validates the
complete set, verifies updater signatures with the same Minisign verifier used
by Tauri, calculates SHA-256 checksums, and attaches the files to the shared
GitHub Release. It uploads latest.json last, after every referenced artifact.
The feed includes separate Windows MSI and NSIS entries and both Mac architectures. desktop-SHA256SUMS is separate from the CLI's SHA256SUMS.
The CLI and desktop jobs can finish in either order without racing release
creation. Installers are never silently overwritten. For a partial upload, inspect
existing assets before retrying; do not move published tags or replace downloads
with a different build under the same version.
After downloading the installers and checksum file, verify with
shasum -a 256 -c desktop-SHA256SUMS on macOS or
sha256sum -c desktop-SHA256SUMS on Linux (download all listed files for a full
manifest check). On Windows, compare
Get-FileHash .\trestl-desktop-0.6.0-x86_64-pc-windows-msvc.exe -Algorithm SHA256
with the matching line in the checksum file.
Signing setup
PR and branch workflow builds need no signing credentials. Tagged releases never publish unsigned desktop installers. If required signing settings are missing, the workflow reports desktop publication as pending and skips native release builds and uploads. Invalid configured credentials still fail the build. Configure these repository secrets before publishing desktop installers:
| Secret | Purpose |
|---|---|
APPLE_CERTIFICATE |
Base64-encoded Developer ID Application .p12 |
APPLE_CERTIFICATE_PASSWORD |
Password for the exported certificate |
APPLE_SIGNING_IDENTITY |
Full Developer ID Application: … identity |
APPLE_ID |
Apple account email for notarization |
APPLE_PASSWORD |
Apple app-specific password, not the account password |
APPLE_TEAM_ID |
Apple Developer team ID |
AZURE_CLIENT_ID |
Windows signing service principal client ID |
AZURE_CLIENT_SECRET |
Service principal credential |
AZURE_TENANT_ID |
Azure directory ID |
For Windows, configure an Azure Artifact Signing account and certificate profile,
grant the service principal signing access, and set these repository variables:
AZURE_SIGNING_ENDPOINT (for example https://wus2.codesigning.azure.net),
AZURE_SIGNING_ACCOUNT, and AZURE_SIGNING_PROFILE. The workflow installs a
pinned artifact-signing-cli and uses Tauri's custom signing hook to sign the
application and both installers. It verifies Authenticode before uploading.
See Tauri's Windows signing guide.
A valid signature does not guarantee immediate SmartScreen reputation.
Tauri imports the Apple certificate, signs the application and Node sidecar with the included hardened-runtime/JIT entitlements, notarizes, and staples the app. The workflow independently verifies code signatures, the notarization ticket, and Gatekeeper assessment. See Tauri's macOS signing guide. Credentials are never committed to the repository and signing runs only on trusted version tags, not pull requests.
After configuring the signing settings and the existing updater private key,
rerun Desktop installers for the immutable v0.6.0 tag. Do not move the tag,
replace existing release assets, or generate a new updater key. Verify all
installers, checksums, and latest.json before marking desktop downloads available.
Updater signing key
Updater signatures are separate from Apple/Windows code signing. The public key
is committed in src-tauri/updater.pub and tauri.conf.json; the native updater
and bundler must use the same key. The release workflow needs the private half in
the repository secret TAURI_SIGNING_PRIVATE_KEY, and
TAURI_SIGNING_PRIVATE_KEY_PASSWORD if the key is password-protected. PR/manual
builds do not need private keys and do not produce publishable update feeds.
Keep a secure backup of the private key. Do not generate a replacement key for each release. Installed apps trust the public key they shipped with. Losing or replacing its private key breaks the update path for those users unless a key migration is shipped first. Never commit the private key or place it in an app bundle, log, release asset, or public environment variable.
For a local signed updater build, point TAURI_SIGNING_PRIVATE_KEY to the private
key file, set TAURI_SIGNING_PRIVATE_KEY_PASSWORD (an empty string for an
unprotected key to prevent an interactive prompt), run
node scripts/desktop-release.mjs configure-updater, then build
with --config src-tauri/updater.release.json. The generated override enables
createUpdaterArtifacts; ordinary local builds leave it disabled. Release CI
collects .app.tar.gz archives for macOS and signatures for those archives, both
Windows installers, and the Linux AppImage. It verifies all five signatures
before publishing any update manifest.
Platform acceptance checks
Before publishing each platform's installers, validate installation, first-run setup, restart persistence, import/export (including cancellation of the save dialog), canvas editing/export, external links, second-launch focus, offline operation, quit, and upgrade with a copied database. CI tests the packaged service but does not replace native webview/installer QA on all platforms.
Architecture and troubleshooting
Rust owns the native window and bundled Node process. Node starts the same
Fastify application and PGlite database used by the web version, listens only on
127.0.0.1, and announces readiness over a private pipe. A random one-use launch
credential establishes an HttpOnly session cookie before assets or API endpoints
are accessible. Requests validate Host and Origin. On macOS, only the exact local
origin receives permission to drag or zoom its own window; the webview receives
no native filesystem or shell IPC capabilities. Its only additional update
permission is to acknowledge save readiness. Update installation commands are
restricted to the separate bundled update window, whose navigation is locked to
local app content. Arbitrary web pages cannot use the local
API. The regular CLI/Raycast clients cannot connect to this private desktop
service; use a hosted installation for those clients.
The service reuses its last local port to preserve webview preferences, or chooses a free one if it is occupied. A changed port can reset appearance/view preferences but does not affect database contents. The shell passes only OS runtime variables, and the service ignores inherited database and authentication configuration.
Quit requests a database flush and waits up to 15 seconds before forcing an
unresponsive process to exit. The stdin pipe closing also triggers a graceful
shutdown if the native shell crashes. A per-database lock prevents concurrent
writers; stale locks are recovered only when their process no longer exists.
If startup fails, read desktop.log in the data folder. Do not delete a lock
while a Trestl/trestl-node process is still running. Retain backups before trying
to repair a damaged database or secret file.