trusty-console 0.12.5

Web console that detects and surfaces running trusty services as a home page with service cards
Documentation

trusty-console

Web dashboard that detects the trusty services running on your machine and shows a home page with a card per service.

Phase 0 (P0) scope

  • Service detection: trusty-search, trusty-memory, trusty-analyze
  • Three status levels: Running (daemon up + health-checked), Available (binary on PATH, no daemon), Absent (binary not installed)
  • Embedded Svelte SPA served from the binary
  • GET /api/console/services JSON API

Usage

# Start the console (default: 127.0.0.1:7788 — localhost only)
trusty-console serve

# Custom port + open browser
trusty-console serve --http 127.0.0.1:9000 --open

# Expose on both localhost AND the machine's Tailscale IPv4 (tailnet + loopback)
trusty-console serve --tailscale

Do not bind 0.0.0.0 (ADR-0018). A wildcard listener has no tailnet address of its own, so the peer gate (below) refuses every request on it, local ones included. Use --tailscale for tailnet access.

Tailscale / tailnet exposure

--tailscale is the recommended way to make the console durable across tailnet sessions without exposing it on the public LAN.

How it works

When --tailscale is passed (or TRUSTY_CONSOLE_BIND=tailscale is set), the console:

  1. Runs tailscale ip -4 to detect the machine's Tailscale IPv4 (e.g. 100.x.y.z).
  2. Binds two TCP listeners on the configured port:
    • 127.0.0.1:<port> — loopback, for local tooling.
    • <ts-ip>:<port> — Tailscale IP, behind the tailnet peer gate.
  3. Serves the same router on both listeners.

Access model

Loopback listeners are served ungated. Every other listener — the --tailscale address, or any non-loopback --http / TRUSTY_CONSOLE_BIND address — goes through the tailnet peer gate, on every route. The gate serves a request only when the peer node belongs to this machine's own Tailscale login and is untagged, the Host header names that listener exactly, and any Origin is that same address. Anything else, including a peer whose identity tailscale whois cannot determine, gets 403.

Only the primary (loopback) address is written to the discovery file.

If tailscale ip -4 fails (Tailscale not installed / not running), a warning is logged and the server falls back to localhost-only — it does not crash.

Tailnet URL

http://100.x.y.z:7788

Replace 100.x.y.z with the machine's Tailscale IP (shown in tailscale status or tailscale ip -4).

Bind precedence (highest to lowest)

Priority Mechanism Example
1 --http <addr> (non-default value) --http 127.0.0.1:9000
2 TRUSTY_CONSOLE_BIND env var TRUSTY_CONSOLE_BIND=tailscale
3 --tailscale flag trusty-console serve --tailscale
4 Default 127.0.0.1:7788 (local only)

TRUSTY_CONSOLE_BIND accepts:

  • tailscale — dual-listener mode (loopback + Tailscale IP).
  • Any <host>:<port> string — explicit bind (same as --http); a non-loopback address is served behind the peer gate.
  • Empty / unset — no effect; falls through to next priority level.

Durable tailnet exposure via launchd (macOS)

Add TRUSTY_CONSOLE_BIND=tailscale to the launchd plist so the env var is present on every restart:

<key>EnvironmentVariables</key>
<dict>
    <key>TRUSTY_CONSOLE_BIND</key>
    <string>tailscale</string>
</dict>

Or pass the flag directly in ProgramArguments:

<key>ProgramArguments</key>
<array>
    <string>/Users/you/.cargo/bin/trusty-console</string>
    <string>serve</string>
    <string>--tailscale</string>
</array>

Either approach survives reboots without manual intervention.

CORS

The server sets CorsLayer::permissive() (wildcard * on all origins). This is intentional for a local developer dashboard and does not change with --tailscale.

Building the UI

The Svelte SPA is built automatically by build.rs when pnpm is on PATH. To skip the UI build (CI, no Node):

SKIP_UI_BUILD=1 cargo build -p trusty-console

A vanilla-JS placeholder (ui/dist/index.html) is committed to the repo so the binary always embeds a working UI even without a Node build step.