Zurück zu den Updates
New releaseSep 4, 2026

sonar v0.4.1

CLI-Tool zum Inspizieren und Verwalten von Diensten, die auf Localhost-Ports lauschen.

Teilen
██████    ███    ██████    ██    ██████
██           ██      ██  ██  ██      ██
██      ██   ██  ██  ██  ██  ██      ██
  ██  ██   ██  ██  ██  ██  ██  ████
    ██  ██       ██  ██  ██  ██  ██  ██
██████    ███    ██  ██  ██  ██  ██  ██

Erfahre, was auf deiner Maschine läuft.

Sonar zeigt alles an, was auf localhost lauscht, und bringt es in Ordnung: Jeder Port gehört zu einer Gruppe – normalerweise das Repository, aus dem er gestartet wurde – und innerhalb dieser Gruppe zu einem benannten Dienst. Starte deine Dev-Server mit sonar start, und das gesamte Projekt wird zu einer einzigen Sache, die du als Baum auflisten, auf die du warten, die du verfolgen und mit einem einzigen Befehl stoppen kannst. Docker-Container, Compose- Projekte und Prozesse, die du von Hand gestartet hast, werden ebenfalls erfasst, ohne jegliche Konfiguration.

$ sonar list --tree
my-app  (3 ports, running)                        ~/code/my-app
├─ 5432  db          postgres:17                  http://localhost:5432
├─ 5173  frontend    vite (v5.4)                  http://localhost:5173
└─ 8000  api         uvicorn app:app              http://localhost:8000
ungrouped (1 port)
└─ 3000  next-server (v16.1.6)                    http://localhost:3000

Installation

Homebrew (macOS / Linux)

brew install raskrebs/sonar/sonar

Homebrew 6 verweigert Formeln aus Drittanbieter-Taps, bis du den Tap einmal vertraust (Error: Refusing to load formula raskrebs/sonar/sonar from untrusted tap):

brew trust raskrebs/sonar

Installationsskript

curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | bash

Lädt die neueste Binärdatei nach ~/.local/bin herunter und fügt sie bei Bedarf zu deinem PATH hinzu. Starte dein Terminal neu oder führe source ~/.zshrc aus.

Unter Windows (PowerShell):

irm https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.ps1 | iex

Benutzerdefinierter Installationspfad:

curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | SONAR_INSTALL_DIR=/usr/local/bin bash

Installiere eine bestimmte Version:

curl -sfL https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.sh | SONAR_VERSION=vX.Y.Z bash
$env:SONAR_VERSION="vX.Y.Z"; irm https://raw.githubusercontent.com/raskrebs/sonar/main/scripts/install.ps1 | iex

Verwendung von Go

go install github.com/raskrebs/sonar@latest

Shell-Vervollständigungen (Tab-Vervollständigung für Portnummern):

sonar completion zsh > "${fpath[1]}/_sonar"   # zsh
sonar completion bash > /etc/bash_completion.d/sonar  # bash
sonar completion fish | source                 # fish

Sechzig Sekunden

Beschreibe, wie dein Projekt läuft, in einer sonar.yaml im Repository-Stammverzeichnis, anstelle einer dev.sh:

name: my-app
services:
  - name: db
    cmd: docker compose up db
    port: 5432
  - name: api
    cmd: uv run uvicorn app:app --port ${port}
    port: auto
    depends_on: [db]
  - name: frontend
    cmd: npm run dev -- --port ${port} --strictPort
    port: auto
    depends_on: [api]
    env:
      VITE_API_URL: ${api.url}

Dann starte es:

sonar start
  ✓ db        http://localhost:5432   pid 41022  ~/.config/sonar/logs/my-app/db.log
  ✓ api       http://localhost:21408  pid 41040  ~/.config/sonar/logs/my-app/api.log
  ✓ frontend  http://localhost:21409  pid 41077  ~/.config/sonar/logs/my-app/frontend.log

3 started
following the logs; Ctrl+C stops the 3 services started here
api      | INFO:     Uvicorn running on http://127.0.0.1:21408
frontend | VITE v5.4  ready in 312 ms

Sonar wählt einen freien Port für jeden port: auto-Dienst und teilt jedem Dienst mit, wo sich die anderen befinden, sodass ein zweiter Worktree neben dem ersten läuft, ohne dass ein einziger Port kollidiert. sonar start -d macht dasselbe im Hintergrund, und sonar down stoppt ihn und gibt die Ports zurück. In einem anderen Terminal:

sonar list --tree
my-app  (3 ports, running)                        ~/code/my-app
├─ 5432   db          postgres:17                 http://localhost:5432
├─ 21408  api         uvicorn app:app             http://localhost:21408
└─ 21409  frontend    vite (v5.4)                 http://localhost:21409

Keine sonar.yaml? sonar start -- npm run dev führt einen Befehl als benannten Dienst aus, und sonar list und sonar kill funktionieren mit allem, was lauscht.

Die unten mit # check markierten Beispiele werden bei jedem CI-Lauf gegen einen frischen Build durch scripts/readme-check.sh ausgeführt.

Befehle

sonar list

sonar list
sonar list --tree
sonar list --group my-app
sonar list --json
# check
sonar list --stats             # CPU, memory, threads, uptime, state
sonar list --health            # HTTP health checks
sonar list --filter docker     # only Docker ports
sonar list --sort name         # port | pid | name | type
sonar list -a                  # include desktop apps
sonar list -c port,process,group,cpu,mem
sonar list --host user@server  # scan a remote machine over SSH

Standardspalten sind port, process, group, container, image, containerport, url, wobei process den Namen anzeigt, den du dem Port gegeben hast (sonar rename), dann den Dienstnamen, dann das, was erkannt wurde.

Verfügbare Spalten: port, process, pid, type, url, group, cpu, mem, threads, uptime, state, connections, health, latency, container, image, containerport, compose, project, user, bind, ip.

Desktop-Apps und Systemdienste, die zufällig lauschen — Figma, Discord, Spotify, ControlCenter, macOS .app-Bundles, /System/Library/-Daemons — werden ausgeblendet, es sei denn, du übergibst -a.

sonar start

Starte ein Projekt aus seiner sonar.yaml:

sonar start                    # every service in the nearest sonar.yaml
sonar start api frontend       # only these (they still wait for their dependencies)
sonar start ../other-project   # the sonar.yaml in or above another directory
sonar start -d                 # in the background, like `sonar up`

Im Vordergrund startet sonar die Dienste über den Daemon, verfolgt deren Logs mit dem Dienstnamen vor jeder Zeile und stoppt bei Drücken von Ctrl+C die Dienste, die es gestartet hat. Ein Dienst, der bereits lief, wird in Ruhe gelassen, und sonar kehrt von selbst zurück, sobald jeder von ihm gestartete Dienst beendet wurde.

Argumente vor -- benennen ein Verzeichnis oder Dienste; alles nach -- ist ein Befehl. Oder führe einen Befehl als benannten Dienst in einer Gruppe aus:

sonar start -- npm run dev
sonar start --group my-app --name frontend -- npm run dev
sonar start --port 5173 -- npm run dev        # expected port, before it binds
sonar start --detach --name api -- uv run uvicorn app:app
sonar start --list

Nichts muss übergeben werden:

  • Group — --group, sonst der name in der nächstgelegenen sonar.yaml, sonst der Verzeichnisname des Git-Roots (ein Worktree wird zu repo@worktree), sonst der Name des aktuellen Verzeichnisses.
  • Name — --name, sonst der sonar.yaml-Service, dessen cmd übereinstimmt, sonst abgeleitet aus dem Befehl (npm run dev → dev, uv run api → api, python -m uvicorn → uvicorn, ./dev.sh → dev.sh).
  • Port — --port ist ein Hinweis, keine Bindung: Der Lauf wird als starting angezeigt, bis der Port tatsächlich lauscht, und der Daemon verwendet ihn, um den Prozess dem Port zuzuordnen.

Das Kind erbt stdin, stdout, stderr, cwd und die Umgebung sowie SONAR_GROUP, SONAR_NAME und SONAR_RUN_ID. Es erhält eine eigene Prozessgruppe, sodass sonar kill den gesamten Baum beendet — einen Dev-Server mit seinen Watchern und Workern. Ctrl+C wird weitergeleitet, und sonar beendet sich mit dem Exit-Code des Kindes.

Kategorien