Desktop App#

DEEIX Chat for macOS, Windows, and Linux. It runs the same web interface as a browser, and it can also start a server bundled inside the app so everything stays on your computer.

Where to find it#

Install the desktop client from the project's GitHub Releases page. It is not served by your DEEIX Chat deployment.

Use the download page to pick the right file for your platform automatically.

  1. Open https://github.com/DEEIX-AI/DEEIX-Chat/releases.
  2. Download the package for your platform.
  3. Install it and launch DEEIX Chat.
  4. On first launch, choose a server on the setup screen.
PlatformPackageRequirement
macOS.dmgmacOS 10.15 or later
Windows.exe (NSIS) or .msiWebView2 runtime
Linux.deb or .AppImageWebKitGTK

Releases built with signing secrets are signed. Unsigned installers still run, but macOS asks you to allow the app under System Settings → Privacy & Security, and Windows shows a SmartScreen prompt.

Choose a server on first launch#

On first launch the window shows a setup screen with two buttons:

ButtonWhat it does
Use on this computerStarts the server bundled with the app and signs you in locally.
Connect to a serverConnects this tab to a DEEIX Chat deployment you or your team runs.

To connect to a remote server:

  1. Click Connect to a server.
  2. Enter the full address in Server address, for example https://chat.example.com.
  3. Click Connect. The button shows Checking… while the client probes the server.
  4. The address is saved only after the server answers. The client requests /healthz first, so a typo cannot survive a restart.
  5. Click Back to return to the two choices.

If the server is already open in another tab, the client switches to that tab instead of creating a duplicate.

If the configured server cannot be started on a later launch — for example when the local sidecar fails — the tab shows Could not connect to the configured server and returns to the setup screen so you can point it somewhere else.

Use local mode#

Use on this computer runs a complete DEEIX Chat from the app itself, with no server to deploy.

  • The Go server bundled with the app starts as a sidecar process on a random 127.0.0.1 port. Nothing is exposed to your network.
  • Data lives in SQLite and local files under the app's data directory. Secrets are generated for that installation.
  • You are signed in as the only user, a passwordless owner. The shell reads a one-time grant printed once to the sidecar's standard output; the grant is single-use, expires after two minutes, and is consumed before the web page sees it.
  • The refresh token is stored in the OS keychain under refresh-token:local.
  • There is no login page, so Sign out means leaving the server: the tab drops its credential and returns to the setup screen.
  • The sidecar stops when the last local tab closes.

Local mode uses the same server code and security policy as a deployment. It is meant for personal use and evaluation. For a team or a long-running instance, connect to a PostgreSQL + Redis deployment instead.

Work with several servers in tabs#

Each tab is bound to exactly one server and runs its own copy of the web app. Sessions, caches, and streaming connections are not shared between tabs, so you can keep a local instance and one or more remote deployments open at the same time.

ActionWhat happens
New tabOpens the setup screen in a new tab.
Open a server that is already in a tabActivates the existing tab. Binding it twice shows That server is already open in another tab.
Close a tabForgets that server. Its refresh token is deleted, and the sidecar stops when the last local tab closes.
Drag a tabReorders the strip. The order is saved and restored on the next launch.
Leave a tab in the backgroundAfter 30 minutes the tab's webview is released to save memory. It reloads and signs back in from the keychain when you activate it again.
Middle-click a tabCloses it.

Bound tabs are restored on the next launch. A tab's label is This computer for local mode, the server host for a remote server, and New tab while unbound.

Interface preferences such as theme and font size are stored once and shared across tabs, because they belong to you, not to a server.

Sign in and credentials#

Remote servers accept the same sign-in methods as the browser: password, two-factor authentication, and OAuth/OIDC providers.

The desktop client keeps the long-lived refresh token in the OS keychain instead of an HttpOnly cookie. The web page never gets a way to read it back.

ItemBrowserDesktop
Access tokenPage memoryPage memory
Refresh token at restHttpOnly cookieOS keychain
Keychain entry—Service com.deeix.chat.desktop, account refresh-token:<origin>
Who sends the refresh tokenBrowser, to the cookie's originThe shell, to the bound origin only
Readable by page scriptNoNo; the shell has no read command
Server addressPage originBound per tab and persisted by the shell

The page hands the refresh token to the shell once, at sign-in. After that it can only ask the shell to refresh the session, sign in locally, or clear it. Closing a tab drops that session, and switching servers deletes the previous keychain entry.

Sign in with a third-party provider#

The webview cannot receive a provider redirect, so the desktop client uses the RFC 8252 loopback flow:

  1. The shell binds an ephemeral port on 127.0.0.1 and gives the web app http://127.0.0.1:<port>/oauth/callback as the redirect URI.
  2. The web app starts the provider bridge with the client ID com.deeix.chat.desktop.
  3. The provider's authorization page opens in your system browser, so any existing provider session is reused.
  4. The provider redirects to the server callback. The server issues a one-time DEEIX grant and redirects the browser to the loopback URI.
  5. The shell answers with a "you can close this tab" page and passes the callback to the web app, which exchanges the grant with its PKCE verifier.

The listener waits up to 10 minutes for the redirect.

The server must have PUBLIC_API_BASE_URL set and the instance callback registered with each provider. The desktop client needs no custom URL scheme and no provider allowlist entry. See Configuration for the callback format.

Tray#

The app keeps running in the system tray so notifications and the updater can reach you while the window is closed.

  • Left-click the tray icon to show and focus the window.
  • The tray menu has Show DEEIX Chat and Quit. Quit exits the app, including the local sidecar.

Updates and release channels#

The app checks for updates on launch and every four hours. Nothing is downloaded until you accept.

  1. When a newer version exists, a toast reads Version {version} is available with an Update button.
  2. Click Update. The toast changes to Downloading update….
  3. When the download finishes, the toast reads Version {version} is installed with a Relaunch button.
  4. Click Relaunch to restart into the new version.

If the download or install fails, the toast reads Update failed: {message}. Every update is verified against the public key in tauri.conf.json before it is installed.

Release tagChannelUpdate source
vX.Y.ZStablereleases/latest/download/latest.json
vX.Y.Z-beta.NBetareleases/download/desktop-beta/latest.json

A stable install never receives a prerelease. A beta install keeps receiving betas; install a stable build to move back to the stable channel. Both channels use the same signing key.

Build from source#

The desktop shell lives in apps/desktop and loads the same static build the server serves (apps/web/out), so there is no desktop-specific build of the product UI.

Prerequisites: a Rust toolchain, the Tauri 2 platform dependencies (WebKitGTK on Linux, WebView2 on Windows, Xcode command line tools on macOS), and pnpm install from the repository root.

terminal

make dev starts the API and the web app together but not the desktop shell; use make desktop for the shell. Artifacts land in apps/desktop/src-tauri/target/release/bundle/.

Building is not enough to ship. macOS packages must be notarized and Windows packages code-signed. Signing keys live only in CI secrets.

Common problems#

What you seeWhat to check
The local server could not startThe bundled server failed to launch. Quit and reopen the app, or check that the app's data directory is writable.
Enter a full address including https:// or http://The value in Server address is not an absolute http:// or https:// URL.
Could not reach the serverThe address is valid but nothing answered. Check that the server is running and reachable from this network.
The server answered with status {status}The address points at something that is not a healthy DEEIX Chat server. Check /healthz in a browser.
That server is already open in another tabThe server is already bound to a tab. Switch to that tab instead of adding it again.
A remote tab cannot connect after a working setupConfirm the address still includes https:// and that the server's /healthz responds.
The window is closed but the app still runsThat is the tray. Use Quit in the tray menu to exit fully.