Installation¶
Shipping builds¶
Most people want a released build, not a source checkout.
Linux (Ubuntu Noble / Pop!_OS 24.04+) — add the apt.stridelabs.ai
apt repo once, then:
For a one-off install without adding the repo, grab the .deb from
the latest GitHub release
and install it with apt, substituting the version and architecture you
downloaded — e.g. sudo apt install ./roost_0.0.18_amd64.deb.
macOS — download Roost-<version>.dmg from the
latest GitHub release,
open it, and drag Roost.app into /Applications. Release DMGs
are Developer-ID signed and notarized by Apple, so
Roost opens with a normal double-click — no Gatekeeper detour.
If you drive Roost from an agent — the Claude skill,
roostctl open/wait/events, or tab prompt — install
Roost-Iced.app below instead of Roost.app. Roost.app is the
classic Swift + AppKit build, and it does not serve the agent-facing
surface: it has no project.ensure, so open and project ensure
refuse with unsupported, and it serves no event stream, so events
and tab prompt fail and wait falls back to polling. tab send-file
and the host verbs are iced-only too. Roost-Iced serves all of it.
See the direction note below.
Roost-Iced.app (experimental)¶
The same release also publishes Roost-Iced-<version>.dmg. That is the
iced UI — the Rust codebase Linux ships — built for macOS, packaged as
Roost-Iced.app. It's still experimental as a general daily driver —
Roost.app (Swift + AppKit) remains the more polished, accessible Mac
build — but for the agent-facing surface above, Roost-Iced is already
the more complete of the two, which is why agent-driving users are
pointed at it above.
Direction note. After this release, Roost will either sunset the
Swift app and make Roost-Iced the Mac default, or rebuild the Swift UI
as a thin layer over the same Rust core Roost-Iced already uses. Either
way, the agent-control surface lives in the Rust core going forward.
Nothing is decided yet — this is recorded as a pending entry in
development/vision.md's decision log, not
a commitment.
It is deliberately built to sit beside the Swift app rather than replace it:
- Its own bundle id (
ai.stridelabs.Roost.iced) and its own app name, so Dock, Cmd-Tab and Finder treat it as a separate app. - Its own state: the
Icedbundle profile (~/Library/Application Support/Roost-iced/,~/Library/Caches/Roost-iced/roost.sock,~/Library/Logs/Roost-iced/) — see Paths & Environment. Your Swift-app projects and tabs are untouched, and both can run at once. - Its own Sparkle feed (
appcast-iced.xml), so updating one never offers the other.
Install it the same way: open the DMG, drag Roost-Iced.app to
/Applications. It is signed and notarized on the same terms as
Roost.app. Beyond the agent-facing surface above, try it if you want
the newer renderer (iced + wgpu) or want to report parity gaps against
the Swift app.
Note that roostctl auto-detects a single running UI, but with both apps
running it will ask you to choose — pass --target mac or --target iced
(see CLI reference → Where roostctl lives).
Updating¶
- macOS. Both apps check for updates through
Sparkle, and checks are user-invoked:
choose Check for Updates… from the app menu. Neither app polls in the
background (
SUEnableAutomaticChecksisfalsein both bundles), so you will never get an unprompted update panel. The feeds are served from this documentation site —appcast.xmlforRoost.app,appcast-iced.xmlforRoost-Iced.app— and each app only ever sees its own. - Linux. Updates come from apt:
sudo apt update && sudo apt upgrade(or justsudo apt install --only-upgrade roost). The package upgrades in place — same socket,state.json, and log paths as the version it replaces.
The rest of this page covers building from source.
Building from source¶
Roost ships a native UI on each platform. Each UI embeds the
workspace + PTY supervisor in-process and serves a JSON IPC
socket for external tooling (roostctl, Claude Code hooks):
| Platform | UI | How it builds |
|---|---|---|
| macOS | Swift + AppKit (Roost.app) |
SwiftPM via mac/scripts/bundle.sh |
| macOS (experimental) | Rust + iced (Roost-Iced.app) |
mac/scripts/bundle-iced.sh |
| Linux | Rust + iced (roost) |
cargo build -p roost-iced -p roost-cli; the .deb adds --features roost-iced/linux-package |
The roost-iced UI, the roostctl CLI, the JSON IPC crate, and the
libghostty-vt FFI all live in one Cargo workspace under crates/. The
Swift UI is its own SwiftPM package under mac/ and links the same
vendored libghostty-vt static archive.
The Linux .deb ships the iced UI as /usr/bin/roost. The
linux-package Cargo feature is the only difference between a dev build
and the packaged one: it flips the compiled-in bundle profile to Linux,
so the installed binary resolves the production socket / state.json /
log paths every previous Linux release used. See
Paths & Environment.
mac/scripts/bundle.sh embeds target/<config>/roostctl under
Roost.app/Contents/Resources/bin/roostctl so a packaged .app is
self-contained: that is the binary each tab's $ROOST_AGENT_HOOK points
at, and the one the shell integration and agent hooks run.
Prerequisites¶
| Tool | Purpose | Pinned version |
|---|---|---|
| Rust | CLI + the iced UI | 1.97.1 (via mise) |
| Zig | Builds libghostty-vt from the vendored Ghostty source |
0.16.x (via mise) |
| Xcode Command Line Tools | Builds the Mac UI | macOS only |
libclang-dev + pkg-config |
Build-time deps of the Rust UI's FFI bindings | Linux only |
mise |
Manages the pinned Rust + Zig versions | any |
macOS¶
Install system packages:
Recommended: JetBrains Mono. Roost defaults to the system monospace; this
is the family the docs' examples set via font-family (see
Fonts).
Clone the repo and provision the toolchain:
Build libghostty-vt once (idempotent on cache hit):
Build the roostctl CLI:
Bundle the Mac .app (this builds and embeds roostctl for you):
Optionally, bundle the experimental iced app the same way. It resolves the
isolated Iced bundle profile, so it will not touch Roost.app's state.
A locally bundled Roost-Iced.app deliberately carries no Sparkle
feed URL — only the release pipeline stamps one in — so Check for
Updates… does nothing in a local build:
macOS 26 (Tahoe) libghostty-vt shim¶
third_party/ghostty/build.sh ships an arm64-macos SDK shim. When it detects macOS 26+ on Apple Silicon with an arm64e-only system SDK, it redirects Zig's SDK lookup to a sibling MacOSX1[45].sdk for the duration of the zig build call. Xcode Command Line Tools usually keeps one prior major SDK installed; reinstall (xcode-select --install) if you hit the no sibling MacOSX1[45].sdk error.
Linux (Ubuntu / Debian)¶
This section builds the iced UI from source. If you just want to use
Roost, install the .deb — see Shipping builds above.
System packages:
That is the whole build-time set. At run time the UI needs winit's
keyboard/window client libraries and a wgpu backend; on a normal desktop
they are already installed, and the .deb declares them explicitly
(libxkbcommon0, libxkbcommon-x11-0, libwayland-client0, libx11-6,
libx11-xcb1, libxcb1, libxcursor1, libxi6, plus libegl1 +
libwayland-egl1 for the GLES fallback). Vulkan is recommended, not
required — with no usable Vulkan ICD, wgpu falls back to its compiled-in
software renderer and the app still opens a window. Both Wayland and X11
sessions are supported.
Recommended font:
mise install (one-time, see the official instructions):
Clone and provision:
Build libghostty-vt:
Build the Linux UI and CLI:
Run it:
A build without --features roost-iced/linux-package resolves the
isolated Iced bundle profile, so it runs beside an installed roost
without touching its state — see
Paths & Environment.
Building the .deb package¶
The packaged .deb is the same binary built with
--features roost-iced/linux-package, installed as /usr/bin/roost,
plus roostctl. With mise install and ./third_party/ghostty/build.sh
already done (above) and nfpm on PATH:
See linux/README.md and
packaging/nfpm.yaml for what the
package contains.
CLI on PATH¶
Install roostctl so it's reachable from any shell (Claude Code hooks call it without a full path):
Verifying the install¶
With the UI running:
Prints key=value lines with the running UI's socket path, PID, and active project / tab IDs. If you see a connection error, the UI isn't running or the socket path is wrong — see Paths & Environment.
Updating¶
When the pinned Ghostty SHA changes, re-build libghostty-vt:
--force discards the cached Ghostty source tree and re-clones at the new SHA. After it finishes, the Mac UI's next bundle.sh run picks up the new archive automatically.