Rysh Desktop — the Electron app for Rysh,
and the web renderer the CLI serves from rysh web start.
One codebase, two targets:
| Target | Built with | Where it runs |
|---|---|---|
| desktop | electron-vite |
a native window on macOS, Windows, Linux, with the rysh binary bundled as a sidecar |
| web | vite.web.config.ts |
embedded into the CLI at internal/web/static, served by rysh web start |
The desktop app ships the CLI inside it, so a user installs one thing and gets both. The web target is the same renderer with no Electron around it, which is what you reach from a browser or a phone.
- Node.js 22.12 or newer, and npm. Electron 41 requires it — on an older
Node,
npm installfails in Electron's postinstall withERR_REQUIRE_ESM. - Go 1.25.3 or newer — only to build the sidecar binary
- A checkout of
rysh-cli-codeas a sibling directory, for the same reason
Cloning rysh-cli-parent with
--recursive gives you that layout:
rysh-cli-parent/
├── rysh-cli-code/ the CLI — also the sidecar binary
├── rysh-cli-shared/
└── rysh-cli-app-code/ you are here
npm install
make dev # builds the sidecar for your platform, then opens the appOnly after the web renderer, not the desktop app? That part needs no Electron
binary, so npm ci --ignore-scripts is enough and any Node 18+ will do.
make dev runs electron-vite dev: hot reload on the renderer, and the app
talks to a real rysh daemon it spawned itself. To run it detached from your
terminal instead, make start puts it in the background and make logs tails
it. make stop and make status do what they say — they match on this
directory's absolute path, so they never touch a rysh session you started
yourself.
make build # renderer + electron main -> dist/
make build-app # sidecar + build, the full desktop bundle
make typecheck # tsc over both tsconfigs, no emitPackaging an installer, per platform:
make package-mac # .dmg and .zip, arm64 + x64
make package-win # NSIS installer
make package-linuxelectron-builder.yml holds the packaging config — app id com.rysh.desktop,
code-signing entitlements, target matrix. Output lands in release/.
npx vite build --config vite.web.config.tsThis writes straight into ../rysh-cli-code/internal/web/static, which the CLI
picks up through //go:embed. Rebuild the Go binary afterwards or the old
assets stay baked in. From the CLI side, make build-frontend does the same
thing.
| Path | What |
|---|---|
src/ |
the React renderer — panes, input handling, file browser, email client |
electron/ |
main process: window and menu management, IPC, shell completion |
scripts/build-sidecar.sh |
cross-compiles the rysh binary into sidecar/ |
electron.vite.config.ts |
desktop build |
vite.web.config.ts |
web build, output redirected into the CLI |
resources/ |
icons and macOS entitlements |
The renderer detects which UI to show — desktop, or the phone-sized drill-down — from the URL and the pointer type, so the same bundle serves a laptop browser and a phone without a separate build.
This repository is a one-way export of a tree developed elsewhere, so a commit pushed straight here is overwritten by the next export rather than kept — CONTRIBUTING.md explains where a patch actually lands.
Found a vulnerability? Do not open a public issue, PR or discussion — SECURITY.md has the private channels.