triaged 0.1.4

Long-running daemon that owns Triage terminal session state and serves a built-in web client and WebSocket API for PIN-paired remote attach.
docs.rs failed to build triaged-0.1.4
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.

triaged

Persistent daemon process that manages terminal session state, PTY multiplexing, and canonical VT performance structures for Triage, the attention-routing terminal supervisor.

The daemon runs persistently in the background, keeping terminal scrollbacks, layout grids, and active PTY handles alive even when no clients are attached.

Installation

cargo install triaged

Running the Daemon

Start the persistent supervisor process:

triaged

Web Server & Connecting

triaged embeds an HTTP/WebSocket server that, by default, listens on 127.0.0.1:7777 (loopback only). A single TCP port serves three things:

  • Web client — a built-in browser UI is served at /. Open http://127.0.0.1:7777 to attach to your sessions from a browser, no separate install required.
  • WebSocket API — clients (the web UI, the native desktop/mobile clients, or your own integration) attach over ws://127.0.0.1:7777/ws.
  • Pairing approval page — served at /pair (see Pairing below).

Connecting from another device

The default bind is loopback, so the daemon is only reachable from the same machine. To attach from another device on your network, set a routable bind address in ~/.config/triage/config.toml:

[remote]
bind = "0.0.0.0:7777"
require_pairing = true

Then point a client at http://<daemon-host>:7777 (web UI) or ws://<daemon-host>:7777/ws (API). The daemon serves plain HTTP and WebSocket only — it does not terminate TLS, so front it with a reverse proxy (e.g. Caddy or nginx) if you need https/wss. Because the daemon owns live PTYs and scrollback, you can detach and re-attach from any client without disturbing the running shells.

Pairing still happens on the host. Even with a routable bind, the /pair approval page is only served to loopback / same-host connections (see Pairing), so approving a remote client requires access to the daemon machine itself.

Prebuilt desktop clients

Besides the browser UI, native desktop clients are published as artifacts on each GitHub release. Publishing a new triaged version automatically creates the v<version> tag, compiles the Flutter client on each platform, and attaches the builds to the Releases page:

Platform Asset Contains
macOS Triage-macos-v<version>.zip Triage.app
Windows Triage-windows-v<version>.zip triage_client.exe + DLLs + data/
Linux Triage-linux-v<version>.tar.gz triage_client + lib/ + data/

Download the one for your OS, unpack it, and point it at your daemon's address.

The release binaries are unsigned. They are ad-hoc signed (macOS) or fully unsigned (Windows/Linux) — no notarization and no code-signing certificate — so each OS will warn before running them. This is expected for these builds; follow the per-platform steps below, or build from source if you'd rather not bypass those protections.

macOS — unzip, then clear the download quarantine so Gatekeeper allows the app:

unzip Triage-macos-v<version>.zip
# Remove the "downloaded from the internet" flag so macOS will run the unsigned app:
xattr -dr com.apple.quarantine Triage.app
open Triage.app

Without the terminal you can instead right-click Triage.appOpenOpen in the dialog (only needed once); if it's still blocked, allow it under System Settings → Privacy & Security → Open Anyway.

Windows — unzip and run triage_client.exe. SmartScreen may show "Windows protected your PC" → choose More info → Run anyway.

Linux — extract and run the binary. A Secret Service provider (e.g. gnome-keyring) must be available for the pairing token to persist:

tar -xzf Triage-linux-v<version>.tar.gz
chmod +x triage_client
./triage_client

Pairing

When require_pairing is enabled (the default), every client must complete a one-time PIN exchange before it can attach. This is a device-authorization-style flow, and crucially the approval step is restricted to the daemon host itself, so a remote client can never authorize its own access.

  1. Challenge. A new client connects to /ws and sends a hello with its client_id (and a stored token, if it has one). With no valid token the daemon treats it as unauthenticated, and the client requests a pairing challenge. The daemon returns a short-lived device_code.
  2. Approve (on the daemon host). The client surfaces the device code. Open the approval URL on the machine running the daemonhttp://127.0.0.1:7777/pair?device_code=<device_code>. The /pair page is only served to loopback / same-host connections (is_local_pairing_peer), so it cannot be opened from the remote client's own browser (that request 404s); approving a remote device means having local or SSH access to the daemon host. The page validates the device code and displays a one-time, device-bound PIN with an expiry.
  3. Enter the PIN. That PIN is typed back into the waiting client. The client exchanges it (pair(pin, client_id)) and the daemon — after verifying the PIN is bound to that exact client/device — issues a bearer token.
  4. Attach. The client stores the token and reconnects with hello { client_id, token }; the daemon authenticates it and the session attaches. The token is reused on subsequent launches, so pairing is a one-time step per client.

Pairing can be disabled for trusted, isolated setups by setting require_pairing = false under [remote], in which case clients attach without the PIN exchange.


Zero-Downtime Upgrades (Process Handover)

On Unix-like operating systems (including Linux, WSL, and macOS), triaged supports zero-downtime updates. This allows you to upgrade the daemon binary or restart the service without dropping active terminal sessions or interrupting running foreground shells.

How it Works

The upgrade is performed using a robust, low-level Three-Phase Sync Protocol:

  1. Transfer Phase: The new daemon process is launched and connects to the running old daemon over a Unix Domain Socket, initiating a file descriptor transfer using SCM_RIGHTS (sendmsg/recvmsg). The old daemon passes all active master PTY file descriptors and the bound TCP listening socket directly to the new process.
  2. Adoption & Sync Phase: The new daemon adopts the active descriptors, reconstructs the in-memory virtual terminal grids and scrollback history by replaying the session log files, and starts network supervision.
  3. Teardown Phase: Once adopted, the new daemon writes a synchronization byte back to the old daemon. The old daemon gracefully drops its session references (without closing the underlying shells), closes its Unix socket, and exits, completing a zero-downtime handover.

Initiating a Handover

To upgrade or restart the daemon with zero downtime, run the new binary with the --handover (or -U) flag:

triaged --handover

Windows Graceful Fallback

Because low-level file descriptor passing and raw Unix domain sockets are native to POSIX platforms, native Windows installations will fall back gracefully to Triage's robust Session Restore flow, which saves session metadata and restores shell/workspace layout structures on restart.