harbor is a small native macOS app for the thing you do before you write any code: starting npm run dev in one folder, php artisan serve and a queue worker in another — and then remembering which of them is still running.
┌──────────────┬─────────────────────────────────────────────────┐ ┌───────────────┐ │ ● nott 2 │ nott start all ✦ magic + │ │ ─── │ │ ● ustad │ ~/Documents/GitHub/nott │ │ ● nott 2 │ │ ● medvise │ │ │ ■ backend │ │ ● harbor │ ■ backend › │ │ ● :4000 │ │ │ ● running · :4000 │ │ ▶ horizon │ │ + add │ │ │ ○ stopped │ │ │ ■ client › │ │ ● ustad │ │ │ ● running · :3000 │ │ ■ serve │ │ │ │ │ ● starting│ │ │ ▶ horizon › │ └───────────────┘ │ │ ○ stopped │ ↑ the edge strip, │ │ │ over every app │ ‹ collapse │ ▶ admin › │ │ │ ✕ exited (1) · :3000 held by node (4821) │ └──────────────┴─────────────────────────────────────────────────┘
The window is where you set things up. The strip on the right edge of the screen is where the rest of the day happens — it is there while you are in the editor, and pressing play never takes your focus.
Named from a stable hash of the project path, so the same folder maps to the same session on every launch. That is how harbor finds services it did not start in this run instead of starting a second copy of your dev server.
Every two seconds: one list-panes for liveness and exit codes, one ps for the process tree, one lsof for the ports. No per-service polling, and nothing is drawn again unless the value actually moved.
Give a service a health path and the dot turns green only when the URL responds — not when the port opens. While a framework is still booting, yellow is the truth.
# a service, really tmux -S /tmp/harbor-501.sock new-session -d -s hb-3b92hjqj-5de35ab8 \ 'cd backend && npm run dev' # what the dot means ● running pane alive, health answering, :4000 ● starting pane alive, nothing listening yet ✕ exited kept on screen with its exit code ○ stopped not running
Builds a release bundle, installs it into /Applications and launches it. Installs tmux with Homebrew if you do not have it. The app is ad-hoc signed, so the first launch may need right-click → Open.