Linking the Swarm: Hub, Herdr, and an Ornith That Routes (Not Works)

Tailscale wasn't enough — I wired a private control plane, CLI dispatch, dual-GPU Ollama, and an orchestrator that picks the right worker.

  • tailscale
  • hermes
  • herdr
  • ollama
  • homelab
  • agents

Tailscale connects boxes — not workflows

I run agents across a MacBook, a Ryzen desktop (gnomadgaming), an MSI laptop, a home server (gnomad-server), and a Hostinger VPS. Tailscale made SSH work. Hermes on Telegram made ops alerts work. What I still lacked was a map, persistent agent sessions, and IDE paths that didn’t require remembering five hostnames and three CLIs.

Today’s push was to fix that without spinning up another $40/month GCP dashboard.

Three layers (not one mega-bot)

LayerWhatTools
ConnectivityReach every machineTailscale, SSH mesh, swarm-dispatch.sh
ExecutionRun work headlesslyagy on MSI, Cursor CLI on Ryzen, local-offload lanes
Control planeSee what’s upSwarm Hub on gnomad-server (Tailscale-only)

Hermes stays ops — email, site health, trading on the VPS. It is not my IDE and not my coding chat.

Herdr is not a chatbot either. It’s a terminal multiplexer for agent sessions — tmux with a sidebar that shows idle, working, or blocked. I start a long agy job on MSI, close the Mac, and reattach later with ssh msi herdr attach.

Swarm Hub — zero-cost control plane

I shut down the old GCP fleet-monitor stack (always-on Cloud Run was the cost leak). The replacement is a static hub on gnomad-server:

https://gnomad-server.tail9fac0c.ts.net:8080

Panels: fleet health, SSH targets, Hermes fleet map, Ollama endpoint, Jellyfin/Kun links. Status JSON aggregates from each node every few minutes.

Gotcha: MagicDNS must be on (tailscale set --accept-dns=true) or the hostname won’t resolve in the browser. I hit that twice today — Linux and Mac.

Mac SSH: one line was breaking everything

My Mac ~/.ssh/config had ProxyCommand tailscale nc for gnomadgaming. Non-interactive SSH couldn’t find tailscale in PATH — connections failed with opaque errors. Removing that line and using Tailscale IPs directly fixed Remote SSH to the Ryzen.

Ornith as orchestrator (not worker)

I wanted Ornith — DeepReinforce’s agentic coding model — but not as the thing that writes all my code. I want it as a router:

Your task → Ornith (or qwen 7b + router prompt) → JSON route → worker runs
Workers: fast | copy | code | reason | image | msi | cloud | status

GPU split on the Ryzen (24/7 now):

GPUPortRole
RTX 4060Ollama :11434Router + qwen 7b (warm)
RTX 5060 TiOllama :11435deepseek-r1, 14b, coder
5060 Tiimage-gen.pySDXL
4060image-gen.pyFLUX (unload small Ollama first)

CLI:

python3 scripts/context-stack/ornith-route.py run "generate hero image for tulsa.cloud"

Honest snag: Ornith-9B weights pulled fine, but my Ollama build doesn’t support the qwen35 architecture yet. Until I upgrade Ollama, routing uses qwen 7b with the Ornith router prompt on the 4060. Weights sit ready as ornith-9b for the day the runtime catches up.

Small homelab hygiene

The MSI was flashing a PowerShell window every minute — a Swarm status task I’d set to run too often with a visible window. Fixed: hidden task, every 5 minutes. The hub doesn’t need second-by-second telemetry.

What I’d do differently

  • Stand up the hub before debugging SSH from three machines — one URL beats ten terminal tabs.
  • Don’t route IDE work through Telegram. Ever.
  • Treat Ornith as air traffic control, not the plane.

Next step

Wire a chat panel on the Swarm Hub that calls ornith-route.py — same routing contract, browser UI on the tailnet. Until then: swarm-dispatch from the Mac and Hermes for ops alerts on the phone.

AI-assisted architecture and implementation; human-verified on the live mesh.