A watercolour flock of sheep grazing among rocks under a dark teal sky

Herdr keeps the herd.
gothalo keeps watch.

gothalo is a self-hosted phone remote for Herdr. See which agents are working, blocked, or done. Get pushed when one needs you. Approve or reply from your phone. Drop into a real terminal. All over your own Tailscale network.

curl -fsSL https://raw.githubusercontent.com/dipeshdulal/gothalo/main/install.sh | sh

macOS or Linux host · Android and PWA · MIT · the script verifies the release against checksums.txt

acme-app needs you

Delete the stale release branch? feat/cleanup

The gothalo home screen: one agent flagged as needing you, the rest grouped by state

You are not at the terminal.

You run five agents in Herdr. Four are grazing: heads down, working. One is stood at the fence, bleating. It needs a yes. You are at lunch, or on the bus, or in the other room.

A गोठालो [gothalo, herder] does not stare at every animal all day. The herd grazes. The herder listens for the one that calls, and walks down only when it matters.

Herdr already tells the herd apart. Every agent, whichever vendor, is idle, working, blocked, or done. gothalo puts that on your phone and makes the blocked one ring.

Hear the one that bleats.

The dog on the ridge

A small Go binary on your Herdr host waits on Herdr's agent.wait for every agent in every session. When one turns blocked or done, it barks: one outbound push through your own Firebase project. Nothing comes in.

The bell reaches you

The notification opens on that agent. Read what it is asking. Approve, or type a reply, from wherever you are sitting. A stale tap does nothing, because the approval is keyed to the state it was shown for.

Walk down if you must

For anything a shout will not fix, attach gives you the real terminal on the phone. xterm.dart, not a web view. Esc, sticky Ctrl, Tab, arrows.

Interactive traffic runs over your tailnet with a per-device token, so one lost phone can be turned away without moving the fence.

An agent's chat on the phone, asking a question with approve and reply below it

The bell, answered. One tap from the phone, and the agent is back to work.

What it does.

The gothalo home screen, a blocked agent at the top under "needs you"

Home

What needs you, first.

An agent's conversation on the phone, with an approve button and a reply field

Chat

Approve, or type a reply.

A full terminal on the phone with a key bar for Esc, Ctrl, Tab and arrows

Terminal

The real pane. xterm.dart.

Plus a day-grouped timeline, git diffs, worktree launch, branch-delete safety, pull requests through the agent, a dev-server relay and a PWA from the bridge. All of it over your own tailnet.

No store. Just a URL.

The same app, built for the web and published here. Open it in a browser, point it at the bridge on your own machine, and you get the same board, the same chat, the same terminal. Add it to the home screen and it runs as a PWA — offline shell, push and all.

What it needs

A bridge on your machine with an https URL — tailscale serve in front of it, not a bare http://100.x.x.x:8787, because a page served over https is not allowed to call a plain-http address. The page itself is static; every request it makes goes to your bridge.

Pairing

Add a server, give it the bridge URL and a bearer token — the same pairing the Android build does, and the token stays in that browser. A browser is just another device: gothalo devices list shows it and gothalo devices revoke turns it away.

Push, without a project of its own

This build has no Firebase project baked in. It asks the bridge it pairs with for one (GET /firebase-config) and registers against that, so one public build works for every install and no one's project values are published here. The push guide has the setup.

Open the web app

Nothing to install on the phone. Set up the bridge first.

Install.

Herdr agent integration

Run this on the Herdr host for every agent you use, or the transcript view shows one agent's conversation under another.

herdr integration install claude
herdr integration install codex
herdr integration install gemini
herdr integration install hermes
herdr integration install opencode

One line per agent kind. Agent integration lists where each one keeps its transcript.

The bridge

macOS or Linux, from the latest release:

curl -fsSL https://raw.githubusercontent.com/dipeshdulal/gothalo/main/install.sh | sh

The script detects your OS and architecture, downloads the matching release archive, and verifies its SHA-256 against the release's checksums.txt before installing. That check is best effort: it needs shasum or sha256sum on the host and a checksums.txt on the release. From source instead:

go install github.com/dipeshdulal/gothalo/cmd/gothalo@latest

Run it and pair a phone

gothalo serve            # writes config.json and an admin token
gothalo-service install  # supervise via launchd or systemd
gothalo pair             # a one-time QR, about a 5 minute TTL

It defaults to 127.0.0.1:8787. Point it at the tailnet so the phone can reach it:

GOTHALO_ADDR=$(tailscale ip -4):8787 \
GOTHALO_PUBLIC_URL=https://<host>.<tailnet>.ts.net:8787 \
gothalo serve

The app

Android, no packaged APK yet. Point it at your own Firebase project first, then build it:

./scripts/setup-firebase.sh --project <firebase-project-id>
cd app && flutter pub get && flutter build apk --release

Or skip the build entirely and open the web app — the same client, hosted, pairing with your bridge (how that works). A bridge built with ./scripts/build.sh also bakes the app in and serves it as a PWA from its own URL, the same address the app pairs to. The install.sh binary does not include the web UI yet.

Push, when you want it

Without credentials the bridge logs instead of notifying. Two steps turn it on, credentials for the bridge and a Firebase project for the app:

gothalo push login --project <firebase-project-id>
./scripts/setup-firebase.sh --project <firebase-project-id>

The full walkthrough, including why every fork needs its own project, is in the push guide.

The complete walkthrough, with config, env overrides and revoking a device, is at Install.

गोठालो

go-THAA-lo. Nepali, noun: the herder.

The kid on the hillside with a flute and a dog, who takes the animals up to the high pasture in the morning and brings them back to the pen at dusk. The herd mostly looks after itself. The herder's whole job is to notice the one that is stuck and call it in. That is what this is: a small bridge and a phone app that watch every Herdr session and let you answer the one that bleats, without leaving your own valley.

गोठ goth
the pen. Where the herd comes back to at dusk, and where the bridge lives.
खर्क kharka
the high pasture. Herdr, where the agents graze.
भोटे कुकुर bhote kukur
the dog that guards and warns. It does not herd. The watcher.
घण्टी ghanti
the bell. A push notification.

Herding was never a one-person job.

The hill kids went up together. Issues, pull requests and rough edges are welcome. The event stream the app codes against is written down, so a second client is a weekend, not a reverse-engineering project.