Skip to content
zlxlabsPublic

About

Monitor and drive your coding agents from your phone.Voice Input, Paste Image, webhook notification, multi devices server support..

Topics

Resources

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Latest commit

 

History

1,362 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

herdweb logo

herdweb

Web UI for herdr — drive Herdr servers from your phone.

c9dfaa317676eae66a65f6b079013daa

One herdweb process attaches to Herdr servers: the default server on this machine, other named servers on the same machine, and servers on other machines via herdr --remote. The phone path is built for weak networks, one-handed controls, voice, and attention that reaches you even when the page is backgrounded.

It is a self-hosted fork of connorads/remobi — independent since 2026-08-20. See the fork decision.

How it fits together

Herdweb uses Herdr's words, then adds one of its own:

Word Meaning
Server Herdr background process that owns panes. A named session is a separate server namespace on the same machine.
Device A machine running Herdr — this laptop, a workbox, anything herdr --remote can reach.
Target One herdweb spawn command that attaches to one server: herdr --session … or herdr --remote ….
herdweb One process that can hold several targets. The browser attaches to one target at a time.
flowchart LR
    Phone[Phone or desktop]
    HW[herdweb]
    A["herdr --session default"]
    B["herdr --session work"]
    C["herdr --remote workbox"]

    Phone --> HW
    HW --> A
    HW --> B
    HW --> C
Loading

The picker is a flat list of targets. Two servers on one device are two rows, not a device → server submenu. Runtime details live in How herdweb works.

Three shapes

Shape Herdr fact What you run
Single device, one server One machine, default session herdweb serve — no picker
Single device, several servers Named sessions on this machine targets with herdr --session …
Several devices Herdr servers on other machines Add herdr --remote <host> rows

Opening the same herdweb URL on a phone and a laptop shares the live target. That is a client of herdweb, not a Herdr device.

Why herdweb

These are the optimizations the product is built around — not extras on a generic terminal.

  • Weak networks — a drop marks the screen stale and blocks replay until a fresh snapshot lands. Composer drafts stay on the phone; heartbeat + backoff reconnect; returning to the tab always resyncs instead of trusting an old OPEN socket. See Networking.
  • Phone control — the soft keyboard stays down unless you tap ⌨. The toolbar lifts above the IME (--kb-inset). 44px taps, haptics, floating d-pad, swipe between herdr tabs, pinch to zoom. Soft keyboard is an escape hatch, not the default input path.
  • Voice input — toolbar opens a second-layer composer; Mic is tap-to-toggle. Edit the transcript before send. Draft and pending send survive disconnect. Needs HTTPS on a phone and a private .local key. See Configuration — Voice.
  • Many Herdr servers — one page switches local named sessions and herdr --remote machines from a flat badge. One WebSocket, one committed attachment. See Three shapes.
  • PWA notifications — add to the Home Screen, subscribe from ☰ → 🔔. Web Push fires on silence, process exit / restart, and tests. A tap focuses the open page and selects that target (iOS only works as a standalone PWA). See Configuration — Push.
  • Webhook notifications — notify.channels posts the same events in parallel to message-pusher, WeCom, or a raw webhook. Use this when the phone cannot reach FCM; a failed channel does not block Web Push or the others.

Also: defaults match herdr keybindings, and the process stays on localhost until you publish it through a layer you trust.

Requirements

Quick start

This is single device, one server: default Herdr session on this machine.

git clone <your-fork-url> herdweb && cd herdweb
pnpm install
git config core.hooksPath .hk-hooks   # enable commit hooks (conventional commits, biome)

# Start (attaches to herdr --session default, serves on 127.0.0.1:7681)
pnpm exec tsx cli.ts serve

Or build first, then run from dist/:

pnpm run build:dist
node dist/cli.mjs serve

Open http://localhost:7681 on the same machine to verify. For phone access, deploy behind a trusted proxy or tunnel — see Deploying herdweb.

herdr captures mouse input by default, so touch scroll and tap-to-focus work with no extra multiplexer configuration.

Install as a herdr plugin

If you already run herdr, you can install herdweb as a plugin instead of cloning by hand:

herdr plugin install zlxlabs/herdweb
herdr plugin action invoke zlxlabs.herdweb.start

install clones this repository, runs a preflight check, builds, and registers the plugin. start launches herdweb in a herdr tab; the server's lifetime is that pane's.

The git clone path in Quick start still works. Both paths are valid.

Platform notes

Node.js ≥ 22 is required on every platform — see Requirements.

macOS. The node-pty npm package ships darwin prebuilds, so install usually does not need a local compile.

Linux. That package ships no linux prebuilds. Install therefore compiles node-pty on the machine, which needs Python 3, make, and a C++ compiler:

Distro Command
Debian/Ubuntu sudo apt install python3 make g++
Fedora sudo dnf install python3 make gcc-c++
Arch sudo pacman -S python make gcc
Alpine sudo apk add python3 make g++

The plugin checks for these before it builds and names anything missing, so you are not left guessing from a long npm log.

At runtime (both platforms) the plugin needs either perl or python3 to take the flock that keeps a single herdweb serving at a time. macOS and every distro above ship at least one of them, so this normally needs no action — but it is a runtime dependency, separate from the build toolchain above, and doctor reports the two separately.

Optional keybinding

The plugin manifest does not declare keybindings. To add a shortcut, paste this into your own herdr config.toml — it is optional:

[[keys.command]]
key = "prefix+u"          # example; prefix+w is already herdr's workspace_picker — do not use it
type = "plugin_action"
command = "zlxlabs.herdweb.show"
description = "show herdweb URL"

Without a shortcut, this still works:

herdr plugin action invoke zlxlabs.herdweb.show

Pick your setup

Single device, several servers — each named session is its own Herdr server:

export default {
  defaultTargetId: 'local',
  targets: [
    { id: 'local', name: 'Local', command: ['herdr', '--session', 'default'], imageDrop: 'local-path' },
    { id: 'dev', name: 'Local · Dev', command: ['herdr', '--session', 'herdweb-dev'], imageDrop: 'local-path' },
  ],
}

Several devices — add a remote Herdr server as another flat row:

export default {
  defaultTargetId: 'local',
  targets: [
    { id: 'local', name: 'Local', command: ['herdr', '--session', 'default'], imageDrop: 'local-path' },
    { id: 'workbox', name: 'Workbox', command: ['herdr', '--remote', 'workbox'], imageDrop: 'disabled' },
  ],
}

A picker appears only when there is more than one target. Explicit configs must set defaultTargetId and must not pass a trailing command after --. Full rules: Configuration — Targets and Deploying herdweb.

herdr --remote is a local thin client over SSH. herdweb can tell that this local process started or exited; it cannot tell whether a remote pane is healthy.

Set up with AI

The herdweb-setup skill checks your environment, interviews you about your workflow, generates a validated herdweb.config.ts, and walks through deployment — one conversation.

Tell your coding agent:

Read .agents/skills/herdweb-setup/SKILL.md in this repo and follow it to onboard me.

Security model

herdweb is a remote-control surface for your terminal. Anyone who can reach it can drive the attached Herdr server with your user privileges.

  • herdweb serve binds to 127.0.0.1 by default.
  • Plugin-installed herdweb also binds 127.0.0.1 by default. The plugin does not provide any one-click way to expose it on the network; phone access still goes through a trusted tunnel or VPN.
  • The inner PTY-backed session stays local to the herdweb process.
  • There is no built-in login, password, or ACL in herdweb itself.
  • Safe default: keep it on localhost and publish it through a trusted layer like Tailscale Serve.
  • If you use herdweb serve --host 0.0.0.0, you are exposing terminal control to your LAN / whatever can route to that port. Do that only if you intentionally want direct network exposure and have separate network controls in place.

To report a vulnerability, see SECURITY.md.

Configure

Buttons, gestures, voice, image drop, and push notifications live in Configuration. Config search order, .local secrets, and the remobi-migration trap are there too.

Voice capture needs a secure context (HTTPS on a phone; localhost is fine). A plain HTTP LAN address is not — herdweb hides the control rather than showing a dead mic.

Drawer: Ctrl+] (question card)

The default bottom toolbar carries only general terminal keys. The agent-only Ctrl+] button lives in the drawer's Agent section, right below Reply. One tap writes a single 0x1d byte (Ctrl+]) to the agent's PTY; a second tap writes it again.

Agents that bind Ctrl+] — Pi's ask_user_question plugin, for one — use that byte to collapse the question card so you can read and scroll the context underneath it. The answers you already picked are kept: tapping Ctrl+] again brings the same card back with your selections intact.

It is not a hide switch, and it is not stateful: herdweb cannot see whether a question is open, so it only ever sends the byte and lets the agent decide. Cancelling a question is a different key — Ctrl+[ or Esc — and neither is what this button sends. With no question on screen, the byte reaches the agent like any other keystroke.

CLI reference

herdweb serve [--config <path>] [--port <n>] [--host <addr>] [--base-path <path>] [-- <command...>]
  Start herdweb with its built-in web terminal and PWA support.
  Default host: 127.0.0.1. Default port: 7681. Single default command: herdr --session default
  Example: herdweb serve --host 0.0.0.0 --port 8080
  Example: herdweb serve --base-path /random-token
  Example: herdweb serve --port 8080 -- herdr --session dev

herdweb build [--config <path>] [--output <path>] [--dry-run]
  Deprecated. herdweb no longer patches ttyd HTML.

herdweb inject [--config <path>] [--dry-run]
  Deprecated. herdweb no longer patches ttyd HTML.

herdweb init
  Scaffold a herdweb.config.ts with commented defaults.

herdweb --version
herdweb --help

Short flags: -c (--config), -p (--port). Legacy deprecated flags: -o (--output), -n (--dry-run).

The -- escape hatch after serve overrides the command only in single mode, for example herdweb serve -- bash --norc. Explicit targets configs must not use a trailing command after --.

Docs

Kind Where
Start This README
How-to Deploy · Configuration · Tailscale Serve · Mobile panes · Keep awake
Explain How herdweb works · Networking · Herdr concepts

Development

git clone <your-fork-url> herdweb && cd herdweb
pnpm install
git config core.hooksPath .hk-hooks

From source (bundles the browser client on the fly via esbuild — no build step):

pnpm exec tsx cli.ts serve              # localhost:7681, default herdr session

Checks

pnpm test            # vitest (unit + integration)
pnpm run test:pw     # playwright e2e (needs: pnpm exec playwright install chromium webkit --with-deps)
pnpm run check       # biome lint + format

Release channels

  • main publishes stable GitHub Releases
  • dev publishes prereleases
  • merge dev into main to promote an experimental line to stable

This fork does not publish to npm. Versioning and changelog are driven by semantic-release on push to main and dev.

FAQ

What is a target? One spawn command that attaches to one Herdr server. Local named sessions and herdr --remote hosts are all targets. See Three shapes.

Does herdr --remote mean the remote pane is healthy? No. It only proves the local thin-client process. See How to work with Herdr.

Can a phone and a laptop share the same server? Yes. Open the same herdweb URL. They share that target's live session. Switching targets in one browser does not switch the other.

Is this secure? herdweb doesn't handle auth — it's a UI overlay. Use a tunnel or VPN you trust. See Deploying herdweb and Tailscale Serve. Security is your responsibility.

Why not Termux / Termius / SSH apps? They work, but you're managing SSH keys and fighting a UI that wasn't built for touch. herdweb keeps your herdr workflow and adds touch controls on top.

Why not chat-based mobile apps? Those tools change your workflow. herdweb gives you the raw terminal — full power, self-hosted, works with every agent herdr can host.

Is this production-ready? It's early. The author uses it daily. Feedback welcome.

Android shows no install prompt when herdweb is behind Cloudflare Access? Chromium's PWA installability check fetches manifest.json separately, and the <link rel="manifest"> fetch sends no cookies by default. Behind Cloudflare Access (or any authenticating proxy) that fetch gets redirected to the login page, the check fails, and no install UI appears. Since v1.6.1 the manifest link carries crossorigin="use-credentials" so the fetch includes cookies — but only if the proxy lets credentialed requests through. The reliable fix is to bypass auth for these five paths at the proxy (Cloudflare Access: create a self-hosted application matching the paths with a Bypass + Everyone policy; Access matches the most specific path first, so the rest of the site still requires login): /manifest.json, /sw.js, /icon-192.png, /icon-512.png, /apple-touch-icon.png. These paths only expose the app name and icons. If you serve with --base-path, prefix the paths accordingly. iOS "Add to Home Screen" never validates the manifest or service worker, which is why only Android is affected.

Licence

MIT

About

Monitor and drive your coding agents from your phone.Voice Input, Paste Image, webhook notification, multi devices server support..

Topics

Resources

Security policy

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages