The desktop app is the same binary
Shoal is one binary. There is no separate download for the window and no packaged installer to fetch. shoal desktop is a subcommand of the same executable that runs the terminal session, and it opens the same engine behind a different surface.
Build it from the repo root with Go 1.25 or newer, then open the window:
go build -o shoal . # shoal.exe on Windows
./shoal desktop
Setup comes before anything else
A loose binary works, but shoal setup is what makes the window reachable without a terminal. It installs the running executable as a per-user program, with no elevation at any point.
./shoal setup
Setup copies the binary to the user programs directory (%LOCALAPPDATA%\Programs\Shoal on Windows, ~/.local/bin on Linux and macOS). On Windows it adds that directory to the user PATH, so a new terminal runs shoal by name, and it also registers the program with the OS: an entry in Apps and features, and two Start Menu entries. On Linux and macOS setup leaves PATH alone and tells you when ~/.local/bin is not already on it.
Running setup again from a newer binary upgrades the install in place. shoal setup --uninstall reverses all of it and leaves session data and config where they are.
A Start Menu entry opens the window directly
The two Windows shortcuts are Shoal, which starts a terminal session, and Shoal Desktop, which runs shoal desktop. The desktop shortcut starts its console minimized, so the app window is what you see and the console stays out of the way. Both shortcuts start in your home directory.
Setup also asks for a default model when none is saved yet and a terminal is attached. It lists the models already on this machine and writes your pick to the user-wide config, so every launch after that runs on it without asking. The same setting can be changed by hand at any time.
shoal config set model <name>
The window is a local web client
shoal desktop starts an HTTP listener on 127.0.0.1 on a port the OS picks, serves the shared web client from inside the binary, and opens that URL as a chromeless app-mode window. On Windows it tries Edge and then Chrome in app mode and falls back to the default browser. On macOS it uses open, and elsewhere xdg-open. The URL is printed either way, so a launch that finds no browser still tells you where the client is.
None of this is exposed to the network. The listener binds loopback only, and every route behind it checks two things before it answers: the request Host must be a loopback address or localhost, and the Origin must either match that host or be absent. Those two checks close DNS rebinding and cross-origin posts from a page in another tab.
The no-open flag serves without a window
shoal desktop --no-open
With --no-open, Shoal serves the client and prints the URL instead of opening a window. It is the flag to reach for when you want to choose the browser yourself, when the machine has no browser the launcher can find, or when you want a second window on the same session. Every window is its own subscriber and gets a replay of recent events when it connects, so two of them show one transcript.