A minimal web GUI client for Herdr. It talks to a running Herdr server through its local socket API and gives you a browser dashboard: workspace/tab/pane tree, a spatial layout view, agent status, and basic pane control (send text, read output, split/close/zoom).
中文使用说明见 USAGE.md。长期运行可直接使用
herdr-gui service 安装 systemd/launchd 用户服务。
Workspace terminal with live agent and session inspection.
| File explorer | Diff viewer | Command palette |
|---|---|---|
![]() |
![]() |
![]() |
| Workspaces and agents | Full terminal control | File explorer |
|---|---|---|
![]() |
![]() |
![]() |
Click any screenshot to open the full-resolution image.
Herdr must be installed and running before starting herdr-gui. The installer
supports Linux and macOS on x86-64 and arm64, verifies the release checksum,
and installs the standalone binary to ~/.local/bin/herdr-gui:
curl -fsSL \
https://github.com/powerfooI/herdr-gui/releases/latest/download/install-herdr-gui.sh \
| shMake sure ~/.local/bin is in PATH, then start the application:
herdr-gui --version
herdr-guiOpen the URL printed by the process. To update, run the installer again. For a long-running installation managed by systemd or launchd, run:
herdr-gui service installSee USAGE.md for fixed-version installation, authentication, remote Herdr connections, and service configuration.
For day-to-day use, we recommend installing herdr-gui as a standalone web app instead of keeping it in a normal browser tab. This gives it a dedicated app window and icon while removing browser chrome from the terminal UI.
First start herdr-gui and authenticate with the URL printed by the process, then install it from your browser:
- iPhone or iPad (Safari): tap Share → Add to Home Screen, keep Open as Web App enabled, then tap Add.
- macOS (Safari 17+): choose File → Add to Dock.
- Chrome or Edge: choose Install app from the browser menu. If only Create shortcut is available, enable Open as window.
Launch herdr-gui afterward from the Home Screen, Dock, or Applications folder. The installed app still requires the herdr-gui server to be running and reachable; PWA mode does not provide offline access.
Browsers can't open Unix domain sockets, so a tiny local bridge sits between the browser and Herdr:
Browser (React + Vite)
│ WebSocket (JSON: RPC + pushed events)
▼
Bridge (Bun + TypeScript) ── node:net NDJSON ──▶ ~/.config/herdr/herdr.sock
The bridge mirrors Herdr's socket methods over a WebSocket: the frontend sends
{ id, method, params }, the bridge forwards to Herdr, and returns
{ id, result } / { id, error }. Herdr events (from events.subscribe) are
broadcast to every connected browser as { event: ... }.
- Herdr running locally (
herdrserver up, socket at~/.config/herdr/herdr.sock) - Bun >= 1.3 for source builds
# 1) start the bridge (talks to herdr.sock, serves ws://localhost:8787/ws)
bun run dev:server
# 2) in another shell, start the web app (http://localhost:5173)
bun run dev:webThen open http://localhost:5173.
Flags override env vars, which override defaults. Run herdr-gui --help for the
full list.
| Flag | Env var | Default |
|---|---|---|
--host <addr> |
HOST |
127.0.0.1 |
--port <n> |
PORT |
8787 |
--password <pw> |
HERDR_GUI_PASSWORD |
(generated token for non-localhost) |
--socket-path <path> |
HERDR_SOCKET_PATH |
~/.config/herdr/herdr.sock |
--client-socket-path <p> |
HERDR_CLIENT_SOCKET_PATH |
~/.config/herdr/herdr-client.sock |
--ssh-host <user@host> |
HERDR_SSH_HOST |
(auto tunnel remote Herdr sockets) |
--session <name> |
HERDR_SESSION |
(named herdr session) |
--public-dir <path> |
PUBLIC_DIR |
(embedded assets) |
--open |
OPEN_BROWSER=1 |
(disabled) |
Additional runtime settings:
| Environment variable | Purpose |
|---|---|
HERDR_GUI_UPDATE_BASE_URL |
Override the latest release asset directory (HTTPS; loopback HTTP allowed) |
HERDR_GUI_DISABLE_UPDATE_CHECK=1 |
Disable update checks |
HERDR_GUI_RESTART_SUPERVISOR=0|1 |
Declare or override external supervisor detection |
A custom update mirror uses the same flat asset layout as GitHub Releases. It
must provide each platform archive, its .sha256 file, and the corresponding
herdr-gui-<platform>.update.json metadata file. Update base URLs containing
credentials, query strings, or fragments are rejected so secrets cannot leak
through update status responses or process arguments. HTTPS is required except
for mirrors bound to the local loopback interface.
# local use (no auth)
./herdr-gui
# listen on all interfaces with a generated token
./herdr-gui --host 0.0.0.0 --port 8787
# prints URLs such as http://192.0.2.23:8787/?token=<token>
# optionally use a fixed password and the login page instead
./herdr-gui --host 0.0.0.0 --port 8787 --password 's3cr3t'The standalone binary can install and manage the platform-native user service:
herdr-gui service install
herdr-gui service status
herdr-gui service restart
herdr-gui service reload
herdr-gui service uninstall| Command | Behavior |
|---|---|
service install |
Create or update the user-service definition and start it |
service install --force |
Replace an existing definition not generated by herdr-gui |
service status |
Show the native service-manager status |
service restart |
Restart the process after changing herdr-gui.env |
service reload |
Reload the systemd/launchd definition, then restart |
service uninstall |
Stop the service and remove its definition; preserve config and token files |
Verify the running service with:
curl -fsS http://127.0.0.1:8787/healthzLinux uses a systemd user service with Restart=always; macOS uses a launchd
LaunchAgent with KeepAlive. A new service listens on 0.0.0.0:8787, creates
the persistent login token, and prints tokenized localhost and LAN URLs during
installation. The command creates
~/.config/herdr-gui/herdr-gui.env with mode 0600 when missing and preserves
it on reinstall or uninstall. Edit that file for HOST, PORT, an optional
fixed password, and Herdr connection settings, then run
herdr-gui service restart. Use
herdr-gui service uninstall to remove the service definition.
Use herdr-gui service reload after editing the systemd unit or launchd plist;
it reloads the platform definition and restarts the process.
The random token is stored in ~/.config/herdr-gui/auth-token with mode 0600.
A successful visit to a printed ?token=... URL sets the normal HttpOnly
session cookie and immediately removes the token from the address bar. Delete
the token file while the service is stopped, then run service restart, to
rotate the token.
The templates under deploy/ remain available for manual installation and
customization. On Linux, enable linger with
sudo loginctl enable-linger "$USER" when the user service must survive logout.
When a deployment requires a custom process wrapper, replace ExecStart with
its absolute executable path and keep systemd as the restart owner:
[Service]
ExecStart=
ExecStart=/absolute/path/service-wrapper -- %h/.local/bin/herdr-gui --host 0.0.0.0The updater saves the replaced executable as herdr-gui.previous, atomically
installs the verified binary, and exits; it never starts a replacement process.
See the detailed user-service guide for
generated file locations, installation, verification, logging, and update
behavior. Subsequent herdr-gui service install runs preserve a custom
ExecStart from a managed unit when it still invokes the same herdr-gui binary.
The project builds into one self-contained executable (Bun runtime + the embedded frontend). No need for the target machine to have Bun installed.
bun run build # builds the web app, embeds it, compiles the binary
# → server/herdr-guiCross-compile for other platforms (Bun downloads the target runtime automatically):
bun run build:linux-x64 # → server/herdr-gui-linux-x64 (x86-64 Linux, glibc)
bun run build:linux-arm64 # → server/herdr-gui-linux-arm64 (arm64 Linux, glibc)
bun run build:darwin-x64 # → server/herdr-gui-darwin-x64 (Intel macOS)
bun run build:darwin-arm64 # → server/herdr-gui-darwin-arm64 (Apple Silicon)
bun run build:allLinux x86-64 note: use the glibc build (
herdr-gui-linux-x64) for Ubuntu / Debian / Fedora / CentOS. The musl build currently fails to start on glibc hosts because Bun's musl binary still dynamically linkslibstdc++/libgcc_s.
Run it:
./server/herdr-gui # opens http://localhost:8787 by defaultThe executable serves the embedded frontend, the /ws bridge, and the /api
endpoints, and connects to your local Herdr sockets. Distribute the single
herdr-gui file; users run it and open the printed URL.
herdr-gui can be published as an npm package, but there are two distinct
distribution models:
- Node-native package:
npx herdr-guiruns with the user's Node runtime and does not bundle Bun. This requires porting the bridge away from Bun APIs (Bun.serve,Bun.spawn,Bun.file,Bun.write) to Node HTTP/WebSocket/fs APIs. - Binary-wrapper package:
npx herdr-guiselects and runs a precompiled platform binary. Users do not need Bun installed, but the package still ships binaries that embed the Bun runtime.
The current implementation is Bun-based, so the single-file executable path is
the supported distribution path today. A true Node-only npx package is
possible, but it is a separate server-runtime port rather than a packaging-only
change.
For remote Herdr sessions, pass --ssh-host; herdr-gui will create SSH
Unix-socket forwards for both the control and terminal-render sockets:
./herdr-gui --ssh-host user@host--ssh-host also makes pasted images and worktree-hook config writes happen on
the remote host. If you need custom local socket paths, pass
--socket-path <path> and --client-socket-path <path> explicitly; those flags
override the automatic tunnel paths.
- Bridge: Bun,
node:net. Speaks both Herdr protocols — the NDJSON control API (herdr.sock) and the bincode thin-client render protocol (herdr-client.sock) — and bridges them to a WebSocket. - Web: Vite + React + TypeScript,
xterm.jsfor the terminal view (renders the server-rendered ANSI stream at the exact client cols×rows).
herdr-gui can control terminal sessions and modify workspace files. Keep the default loopback binding unless you understand the trust boundary. See SECURITY.md before exposing the service to another device.
See CONTRIBUTING.md for development and validation instructions. The project code is available under the MIT License. Bundled fonts and brand assets retain their original terms; see THIRD_PARTY_NOTICES.md.






