Run your long-running coding sessions on a server. Watch them through your browser.
This project started because I was scratching my itch: I wanted a simple remote terminal that survives any interruption, preferably runs through browser, and has a few must-haves: file tree, file upload, diff window, editor and preview.
I managed to get by with mosh/tmux/md-tui, but that setup just did not understand projects and worktrees.
So I created a lightweight Rust tool that gives any coding project its own browser tab and all needed info in one place. Backed by dtach shells that survive tab close, laptop sleep, network down and even restart of roost itself.
Why
Because you want a simpler way to have remote access to your server box. Roost is a 4MB Rust binary that gives every one of your projects or worktrees a tab in a browser.
| roost | ttyd / Wetty | code-server | tmux + ssh | |
|---|---|---|---|---|
| Terminals survive restart | ✅ | ❌ | n/a | ✅ |
| Editor + diffs + tree | ✅ | ❌ | ✅ | ❌ |
| Mirrors across browsers | ✅ | ❌ | ❌ | ✅ |
| Claude Code IDE protocol | ✅ | ❌ | ❌ | ❌ |
| Paste a screenshot to the agent | ✅ | ❌ | ❌ | ❌ |
| Single binary, no Node | ✅ | ✅ | ❌ | ✅ |
| Auto-reconnects after the laptop sleeps | ✅ | ❌ | ✅ | ❌ |
| Needed on the laptop | browser | browser | browser | ssh client + terminal |
| Drag-and-drop files to upload | ✅ | ❌ | ✅ | ❌ |
| Multiple git worktrees, switchable | ✅ | ❌ | ❌ | ❌ |
| Server binary | 4 MB | 0.7 MB | 235 MB download | 1.3 MB |
| Server memory | 16 MB (7 shells) | 9 MB (1 shell) | 770 MB (1 workspace) | 3 MB (1 shell) |
Install
Install roost on the box your code lives on — the remote dev machine, not your laptop. Your laptop only ever needs a browser.
# Homebrew — installs dtach for you brew install peterknego/tap/roost # or Linux packages — these install dtach for you and ship a systemd user unit. # Grab the .deb or .rpm for your architecture from the releases page first: sudo apt install ./roost_*.deb # Debian, Ubuntu sudo dnf install ./roost-*.rpm # Fedora, RHEL systemctl --user enable --now roost # packages only; starts roost # or with cargo — dtach and git must already be on PATH apt install dtach # or: brew install dtach cargo install roost # or, to build unreleased work off `develop` rather than a release — the # channels above install a tagged version, this one does not: cargo install --git https://github.com/PeterKnego/roost ROOST_ROOTS="$HOME/Projects" roost 8444 # or just: roost 8444 — then add your projects directory on the front page # open http://127.0.0.1:8444/
Prebuilt binaries for Linux (x86_64 and aarch64, statically linked — no glibc
version to match) and macOS (Intel and Apple Silicon) are on the
releases page, with checksums and
build attestations. cargo binstall roost fetches them directly.
macOS is used daily; Windows is untested.
On macOS, a tarball downloaded in a browser hangs rather than failing. Safari and Chrome set
com.apple.quarantineon the download,tarcopies it onto the extracted binary, and Gatekeeper then waits on a GUI prompt nobody sees over ssh: no output, no error, no exit status, indistinguishable from a server that started. Strip it before the first run — doing it afterwards does not clear a prompt already pending:tar xf roost-aarch64-apple-darwin.tar.xz xattr -d com.apple.quarantine roost-aarch64-apple-darwin/roost ./roost-aarch64-apple-darwin/roost --version # roost 0.5.2
brew installandcurlare both unaffected — Homebrew strips the attribute andcurlnever sets it, and the binary is byte-identical in all three cases. Measured on macOS 26.6.2 (Apple Silicon) on 2026-09-12: the release binaries are ad-hoc/linker-signed and not notarized, sospctlreportsrejectedeven for the Homebrew copy that runs — the quarantine attribute is the gate, not the signature.
roost has no authentication of its own. It only binds to
127.0.0.1. Put an auth layer in front of it —tailscale serveis what I use. Read Security model before exposing it.
Features
A tab per project/worktree
Every tab represents a project or worktree, and has panes in familiar IDE-like arrangement: file-tree, file-diffs, file preview/editor, terminal.
Terminals that survive reload/re-attach/restart
Each terminal is a PTY owned by roost and wrapped in dtach, so sessions survive a tab reload, network disconnect, laptop sleep, and even a roost restart.
All state lives on the server and mirrors live
Open a file in one browser and it opens in every connected browser. Layout and unsaved buffers persist across restarts, stored outside the repo — so pane drags never show up in git status.
Drag-n-drop files/images or paste images
Drag-n-drop files into the file tree for instant upload to remote filesystem.
As for images, you can drag them or paste them into claude terminal and they will be uploaded and pasted directly into claude as image - this is a must-have feature when you just want to quickly paste a screenshot into claude for analysis.
Claude Code integrates with the project
A claude running in a terminal pane connects back to roost via the IDE protocol, the same as VS Code or JetBrains IDEs. This gives it unique integration abilities: paste image, links to @file, "live" links in the terminal that open when you click them and claude initiated file diff viewer (if in manual permission mode).
Desktop notifications
Roost supports sending desktop notifications from any terminal. Clicking a notification will take you directly to that terminal.
Also, Roost can install hooks into claude to enable a notification every time claude needs attention. See docs/notifications.md.
Security model
roost only binds to 127.0.0.1 and is meant to be fronted by an auth layer,
such as tailscale. More about it in SECURITY.md
Contributing
See CONTRIBUTING.md for the branch flow and how to run the test suite, and CODE_OF_CONDUCT.md for the project's conduct expectations.
License
Dual-licensed under either of
- MIT (LICENSE-MIT)
- Apache License 2.0 (LICENSE-APACHE)
at your option — the Rust ecosystem's usual MIT OR Apache-2.0, and what
Cargo.toml declares. Note that GitHub's sidebar reports "Apache License 2.0"
alone: its detector picks a single LICENSE-* file and drops the other. serde,
regex, clap and cargo itself all read the same way. Cargo.toml and this
section are authoritative; the sidebar is not.

