Luna's native face on the Linux desktop β a thin client of the Hermes agent that lives in luna-os.
She already runs as an always-on agent inside luna-os. This repo is how you
reach her without a browser tab: the luna binary, which is both
- a CLI β
luna ask/chat/repl/status/sessions, and - a GUI β
luna gui: a Slint frosted-glass chat window + a StatusNotifierItem tray + freedesktop notifications.
Design rule: the brain owns the API; this repo owns the clients. Every surface talks to Hermes over its local API (see
docs/hermes-gateway-api.md). That keeps Hermes (the upstream-tracked Python agent) clean and these clients decoupled.
The GUI is deliberately not a per-desktop widget. The desktops NixOS supports
share no panel-applet API, so rather than maintain a dozen bespoke applets in a
half-dozen toolchains, luna gui is one Rust app that rides the two freedesktop
standards every desktop implements:
- StatusNotifierItem β the crescent-moon tray icon (KDE, LXQt, Cinnamon, Budgie, Pantheon, XFCE, MATE show it natively; GNOME via the AppIndicator extension luna-os enables; Enlightenment falls back to the menu launcher).
- org.freedesktop.Notifications β a "Luna replied" notification when her answer lands while you're looking elsewhere. Works everywhere.
Built with Slint (pure Rust, no webview) on its software renderer, so it
survives headless / flaky-GPU VMs. Each tab is a Hermes session with its own
transcript, persisted under ~/.local/state/luna/ so conversations survive
logout/reboot. Replies stream, there's a stop button, text is
selectable/copyable, and it's single-instance (a second luna gui just raises
the running one β which is how the menu entry and the autostart tray coexist).
cd cli
cargo build --release # β target/release/luna
luna ask "what's on my plate today?" # one-shot via `hermes -z` (no server)
luna chat "hi" # streamed + threaded (needs the dashboard)
luna repl # interactive terminal chat
luna gui # the graphical chat + tray
luna gui --hidden # start in the tray only (used by autostart)
luna status / luna sessions # dashboard APIConnection defaults to http://127.0.0.1:9119; override with --url or
$LUNA_GATEWAY_URL. The session token comes from $HERMES_DASHBOARD_SESSION_TOKEN
or luna-os's /var/lib/hermes/dashboard.env (see src/config.rs).
The GUI links fontconfig and Slint's winit backend dlopens the windowing libraries, so a non-Nix build needs those present, e.g.:
nix-shell -p pkg-config fontconfig libxkbcommon wayland libGL \
xorg.libX11 xorg.libXcursor xorg.libXi xorg.libXrandr \
--run "cargo build"luna-os's modules/luna-desktop.nix
packages it reproducibly and wraps the binary's LD_LIBRARY_PATH, so on luna-os
none of this is your problem.
luna-desktop/
βββ cli/ # the `luna` binary β CLI + Slint GUI + tray
β βββ src/ # main Β· client (API) Β· config Β· gui Β· tray Β· state
β βββ ui/luna.slint # the frosted-glass chat UI
β βββ build.rs # compiles the .slint
βββ docs/ # the gateway API contract + notes