Every dev server, one keystroke from the tray.

Tray Stack auto-detects every local server running on your machine — knows the project, branch, port, and uptime — and lets you open, copy, or kill any of them without breaking focus.

nodeViteNext.jsNUXTBUNDenowebpackesbuildTurbopythonDjangoFLASKuvicorncargoTrunkGoHugoRailsPHOENIXrubyCaddyJekylldotnetJavanodeViteNext.jsNUXTBUNDenowebpackesbuildTurbopythonDjangoFLASKuvicorncargoTrunkGoHugoRailsPHOENIXrubyCaddyJekylldotnetJava

Three-signal detection

Every 5 seconds, scans listening TCP ports and matches them by three signals: ~60 known dev runtimes (node, Vite, Cargo, Python, Hugo…), a process whose cwd lives inside a Git repo, or any of ~25 conventional dev ports.

Project-aware

Reads .git/HEAD directly — no libgit2, no shelling out — so the menu shows your repo name and current branch (or short commit when detached). Worktrees and submodules just work.

Filters the noise

Skips privileged ports (<1024) and a curated list of OS/service processes — svchost, lsass, dwm, RuntimeBroker, SearchIndexer — so only your dev work shows up. IPv4 + IPv6 dupes are collapsed.

Anatomy of a row

Every server, in a single line.

One row tells you everything you need to know about a running server — what it is, where it is, how it's doing — without leaving the tray.

traystack-webNext.js:3000master220m
CPU
0%
MEM
2.9GB
traystack-web:49316Extra port
  • 01

    Status dot

    Green while the process is alive and listening.

  • 02

    Project

    Repo name from .git/HEAD, or the working-dir name as fallback.

  • 03

    Runtime

    The dev tool the scanner matched — Vite, Next.js, Cargo, Django, and friends.

  • 04

    Port + branch

    Localhost port and current Git branch (or short commit when detached).

  • 05

    Quick-jump

    Press the number to open the row. Sequence resets on each scan.

  • 06

    CPU + MEM

    Per-row sparkline and gauge — sampled while the popover is hidden, too.

More than just ports

Your dev machine, on tap.

The same tray icon opens onto Network, Storage, and your Dev Environment. Tab through with [ and ] — same shortcuts, same chrome, all your dev metrics in one card.

Tray Stack popover — the Ports tab, showing four running dev servers
PortsLive dev server detection

Every server running on your machine — project, branch, port, uptime — with live CPU and MEM sparklines. Open, copy, or kill straight from the row.

Tray Stack popover — the Network tab, showing live ping, jitter, latency, and download/upload speeds
NetworkRealtime connectivity

Ping, jitter, packet loss, latency, down/up throughput — all live, all in one card. Trigger a Cloudflare bufferbloat speed test without leaving the tray.

Tray Stack popover — the Storage tab, showing drive usage and reclaimable disk space ready to clean
StorageDisk usage & cleanup

See every drive at a glance, then reclaim gigabytes from temp files, pnpm/npm/cargo stores, and browser caches — categorised, opt-in, one big button.

Tray Stack popover — the Dev Environment tab, showing installed toolchains and PATH analysis
Dev EnvironmentToolchain & PATH

Versions for Node, Bun, Python, Git, Rust, .NET — at a glance, with PATH duplicates and missing entries flagged before they bite.

Git, all the way down

Knows your repo without asking.

No daemons, no indexes, no git on your PATH. Tray Stack reads .git/HEAD directly — so the menu names projects the way you do, in every corner case Git can throw at you.

  • .git/HEAD, read directly

    No libgit2, no shelling out to git. A handful of syscalls reads the branch ref — or the short commit hash when you're on a detached HEAD.

  • Worktrees + submodules

    Resolves .git-file gitdir: pointers, so a server running inside a worktree, submodule, or sparse checkout still shows the right repo name and branch.

  • Walks the tree

    Crawls up from each process's working directory until it hits the repo root. Falls back gracefully to the working-dir name (or the process image) when there's no repo.

  • Detached HEAD

    Bisecting, on a tag, or mid-rebase? The menu shows a short commit hash instead of an empty branch — so you always know exactly what's running.

Two flavors, one detection core

Pick the one that fits your taste.

Both binaries share the same scanner — they only differ in how they paint the menu. Use the small one if you live in your OS's native UI; use the popover if you like sparklines and keyboard shortcuts.

Native menu

port-menu·~550 KB

An idiomatic OS tray menu — header with a live server count, one item per service, with Open / Copy URL / Kill nested in a submenu. Per-port Open/Copy for each extra port. Looks and feels like every other menu-bar app on your machine.

  • Native widgets
  • Live header count
  • Smallest footprint

Glassy popover

port-menu-ui·~3.3 MB

A frameless, always-on-top card that floats next to the tray. Live CPU & MEM sparklines per server, a separate usage-history page, dark/light themes, toast confirmations, full keyboard navigation.

  • CPU + MEM sparklines
  • Usage history page
  • Keyboard-first
Live metrics

Watch your servers breathe.

The popover samples per-process CPU and memory in the background, even while hidden, so the moment you open it you see what each server has been up to.

Stacked memory chart

Aggregate view at the top of the popover — total memory in use plus per-port history, so you can see at a glance which port is hogging RAM.

Per-row sparklines

Each server row carries its own CPU sparkline and a MEM gauge. The popover keeps a rolling ~48 samples per process — accruing even while it's hidden.

Usage history page

Press H for a dedicated page with larger CPU and MEM charts per service, plus current and peak readouts at a glance.

Sampled every ~1.5 s

Background sampler runs continuously so history accrues even when the popover isn't open. Multi-port services collapse into one row, kill once stops them all.

Keyboard-first

Hands stay on the home row.

Click the tray, hit a key, get back to your editor. The popover navigates with arrows or vim keys, opens with Enter, and dismisses on focus loss.

All of these are global to the popover.
  • Move selection (or J / K)
  • Open in browser (or O)
  • Copy localhost URLC
  • Kill the process
  • Quick-open by index19
  • Toggle history pageH
  • Toggle themeT
  • Back / dismissEsc
  • Quit Tray StackQ
Headless mode

Drop the GUI when you don't need it.

Every binary doubles as a CLI. Pass --scan (or -l) to print every detected server — including nested extra ports — and exit. Perfect for pre-commit hooks, status-bar integrations, or one-off sanity checks.

Release builds run windowless — no console flash.
$ port-menu --scan

3 dev servers running:

  :3000  acme-storefront      main             up 1h 12m  http://localhost:3000
         vite (pid 4821)
  :8000  ml-dashboard         main             up 4m      http://localhost:8000
         python (pid 2207)
  :5173  api-gateway          feat/webhooks    up 22m     http://localhost:5173
         node (pid 9134)
         ↳ :49316  http://localhost:49316
Built native

Quietly, ridiculously small.

No Electron, no webview, no background JS runtime. Just a single Rust binary that draws into the OS tray, depends only on standard system libraries, and can be set up to run at login with a Startup-folder shortcut. Release profile is size-optimized, LTO'd, and stripped.

Tray menu binary

~550 KB

no webview

Popover binary

~3.3 MB

egui + glow

Written in

Rust

single native exe

Runs on

Win · macOS · Linux

tao + tray-icon

One install, every project you start.

A one-time $29 purchase — no subscription, free updates.