[HN Gopher] Show HN: Sonar - A tiny CLI to see and kill whatever...
___________________________________________________________________
Show HN: Sonar - A tiny CLI to see and kill whatever's running on
localhost
Author : raskrebs
Score : 121 points
Date : 2026-03-20 09:59 UTC (13 hours ago)
(HTM) web link (github.com)
(TXT) w3m dump (github.com)
| raskrebs wrote:
| I always have a bunch of local projects running, particularly
| during the weekend where I'm rarely working on one thing at a
| time. A big pain of mine was constantly running into port: Redis
| from one project blocking another, orphaned dev servers from old
| worktrees, Docker containers I forgot about. The usual fix is
| lsof -iTCP | grep ..., then figuring out what the PID actually
| is, then killing it. But I always forget the command, and it
| doesn't really include all the information that I like.
|
| So I built this lightweight CLI. Single binary, no dependencies.
| It shows everything listening on localhost with process names,
| Docker container info, clickable URLs etc.
|
| Sure there are workarounds, but none that satisfied my need for a
| short, easily rememberable command. Also nothing really has the
| same satisfaction as running sonar kill 3000 -- it just feels
| nice. I've already been approached by a few agent orchestration
| tools that have been struggling with the same thing. It's really
| useful when you have multiple agents running, but it's not built
| for just that use case, I have also find it handy when killing
| off all containers after a failed cleanup and so on. Also know
| that MCPs are dead and CLIs are the new thing in agentic coding,
| this might be a useful tool for Claude, particularly when a
| compose process exits before all containers are stopped.
|
| Open for contributions, ideas and feedback.
| pluc wrote:
| Have a look at Evan Hahn's murder util:
| https://codeberg.org/EvanHahn/dotfiles/src/commit/843b9ee13d...
| raskrebs wrote:
| Will check it out
| 0cf8612b2e1e wrote:
| Sold on the name alone. It also has the API I never realized
| I needed puts 'usage:' puts 'murder 123
| # kill by pid' puts 'murder ruby # kill by process
| name' puts 'murder :3000 # kill by port'
| embedding-shape wrote:
| > I've already been approached by a few agent orchestration
| tools that have been struggling with the same thing
|
| Wow, this says more about the agent orchestration tool
| ecosystem than what you might think, that they're unable to
| kill child processes they themselves spawn makes it seem like
| they have zero clue about what they're doing.
|
| Probably why my impression always end up with "Wow, what a
| vibe-coded mess" when I look through the source of all these
| harnesses, they don't seem engineered at all.
| msdz wrote:
| > that they're unable to [manage and] kill child processes
| they themselves spawn makes it seem like they have zero clue
| about what they're doing.
|
| Yeah, at the bare minimum these projects could also use
| something like portless[1] which literally maps ports to
| human- (and language model-)readable, named .localhost URLs.
| Which _should_ heavily alleviate assignment of processes to
| projects and vice versa, since at that point, hard-to-
| remember port numbers completely leave the equation. You
| could even imagine prefixing them if you've got that much
| going on for the ultimate "overview", like
| project1-db.localhost, project1-dev.localhost, etc.
|
| [1] https://port1355.dev/
| Bradd3rs wrote:
| love this, i get tired of spamming lsof -i tcp:xxxx
| raskrebs wrote:
| Glad to hear! Have quite a few ideas in mind so keep an eye out
| for some updates (one of the ideas is an easy update command).
| There's a couple of open enhancement ideas as well. Feel free
| to add any or contribute.
| Doublon wrote:
| The README made me realize I just needed a simple `alias local-
| tcp-listeners='lsof -iTCP -sTCP:LISTEN'` in my
| `~/.bash_aliases` :)
| deadbabe wrote:
| Same, not sure why a whole cli app is needed.
| paddim8 wrote:
| Because it gives more context. Quite obvious if you look at
| the readme...
| raskrebs wrote:
| Developers are nitpicky, atleast i am and i know a lot of
| others that are as well. So don't underestimate the value
| of a nice tool with good developer experience, one that's
| intuitive, clean and easy to use means a lot when juggling
| so many things during a workday. So having a clean and
| light implementation to make job even easier is in my
| opinion worth it (and thus needed) :)
| raskrebs wrote:
| True, but as i write their are workarounds, the problem is
| that they are unintuitive, difficult to remember and don't
| provide all that much usability beyond listing. So these lack
| useful features like getting process stats, killing ports
| easily without having to remember the the pid after lsof and
| so on. I often have to kill multiple process at once after a
| failed cleanup. If you are into agentic coding, then having
| your agent create a profile for all the processes it stats,
| which it can easily kill of when finished is a lot easier for
| me atleast.
|
| Some features on the way are: next available port; wait (wait
| for a host to return a successful health check before
| proceeding - good for migrations etc.). And lots more. It's
| not just about listing running ports, but a tool for managing
| them.
|
| But to each their own, that's what's lovely about the many
| options available. But if you have anything in relation to
| this you think is neat, feel free to open an issue. It may be
| able to convince you that a simple alias won't suffice.
| klaushardt wrote:
| Would be nice to have a flag to customize the URL displayed for
| Docker containers. I connect to my host via Tailscale, but I
| can't open links with localhost. It would be helpful to have a
| parameter that allows us to choose a network device or specify an
| IP address to display. 3000 wud
| (getwud/wud:latest) wud
| getwud/wud:latest 3000
| http://localhost:3000 3001 dockhand
| (fnsys/dockhand:latest) dockhand
| fnsys/dockhand:latest 3000
| http://localhost:3001
| raskrebs wrote:
| Good point. Could you add an issue, then i'll have a chance to
| look into it :)
|
| https://github.com/RasKrebs/sonar/issues
| frankdenbow wrote:
| love this, happens too often
| raskrebs wrote:
| Exactly, really hates it as well. Please post any issues you
| may have
| moezd wrote:
| Sonar as in SonarQube? That's an interesting choice for a name :)
| beart wrote:
| How about Sonar as in SOund Navigation And Ranging?
| raskrebs wrote:
| I think a cli tool that detects objects beneath the surface is
| a pretty intuitive name, but i was also reluctant in the
| beginning. But they are pretty keen on always using the qube
| part, i believe theirs is sonar-qube.
| chwzr wrote:
| i have this in my .zshrc which provides same functionality:
| lk() { if [ $# -eq 0 ]; then local
| output=$(sudo lsof -iTCP -sTCP:LISTEN -n -P) elif [ $#
| -eq 1 ]; then local output=$(sudo lsof -iTCP
| -sTCP:LISTEN -n -P | grep -i --color=always $1) else
| echo "find and kill processes listening on ports. Usage: lk
| [pattern]" return 1 fi if [ -z
| "$output" ]; then echo "No listening processes
| found." return 0 fi # Show
| header + results echo "$(sudo lsof -iTCP -sTCP:LISTEN -n
| -P | head -1)" echo "$output" echo ""
| # Extract unique PIDs (skip the header row if no grep was
| applied) local pids=($(echo "$output" | awk '{print $2}'
| | grep -E '^[0-9]+$' | sort -u)) if [ ${#pids[@]}
| -eq 0 ]; then echo "No PIDs found."
| return 0 fi echo "PIDs to kill: ${pids[*]}"
| echo -n "Kill these ${#pids[@]} process(es)? [y/N] " read
| -r confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then
| for pid in "${pids[@]}"; do echo "Killing PID
| $pid..." sudo kill -9 $pid done
| echo "Done." else echo "Aborted." fi
| }
| raskrebs wrote:
| I have added quite a lot of functionality beyond listing and
| killing ports. Please check out the readme, it may convince you
| to try it out.
| fionic wrote:
| Its funny bc the title suggests a tool for listing and
| killing
| raskrebs wrote:
| True, it was what it started as, but grew as i found my
| self missing features. Got a few users and now i don't want
| to update the name. Also easy and quick to write in the
| terminal
| bartek_gdn wrote:
| Why not grep the output to abother tool?
| tomcatfish wrote:
| HN is a place where people can be expected to go _beyond_
| the title (though I like the limited script and am glad it
| was posted). Misleading titles are not uncommonly flagged
| and changed, even.
| pdimitar wrote:
| I am absolutely installing this and starting to use it daily!
|
| For the even less patient there's also this (not mine):
| https://github.com/jkfran/killport
| raskrebs wrote:
| Glad to hear! Please join the party and post any issues you
| have.
| clutchski wrote:
| Mine is called "porthole"
|
| https://github.com/clutchski/dotfiles/blob/main/home/bin/por...
| raskrebs wrote:
| Any features you are missing or ideas for the use case?
| Brainspackle wrote:
| you picked a unique name. There is already a massively popular
| product called Sonar
| mfkrause wrote:
| I always find myself going through my zsh history for `lsof`.
| Will definitely check this out, seems interesting (even though
| I'm generally reluctant of installing third-party tools for such
| jobs).
| raskrebs wrote:
| I get that, i also often install some and forgot about them.
| But i felt that there was a big gap in managing multiple
| services running on localhost. It's pretty lightweight if that
| helps
| maciejj wrote:
| Nice! I always forget the lsof flags and end up googling them
| every time. Would be cool if it could run in the system tray and
| show what's running on your ports at a glance. Also, the name had
| me thinking SonarQube at first, might be worth considering a
| rename to avoid the confusion.
| raskrebs wrote:
| Someone else added an issue about this, and i replied
| explaining how to run the feature branch, have a look and
| please add any ideas to the issue:
|
| https://github.com/RasKrebs/sonar/issues/15
| RonanSoleste wrote:
| I just have an alias in my .bashrc :)
| raskrebs wrote:
| Try and have a look at the readme, this adds a bit more
| functionality. Maybe some if it you'll find useful :)
|
| Started with the same, but found my self wanting a bit more, so
| just built it
| RonanSoleste wrote:
| Can it do things that existing tools build into my distro
| cannot? It looks to me like a convenience tool. Which is
| fine, but i see no need for it myself
| raskrebs wrote:
| Probably not, that's what makes it so lean (it doesn't
| really pull in anything).
|
| Although i have a feature branch with a tray app (for
| macos) that let's you monitor and track any process (will
| send notifications when one goes up or down). But it's just
| gimmicks i felt i needed to make life a bit easier when
| working with compose and across worktrees
| Barbing wrote:
| That monitor sounds interesting; I manually set something
| up in Keyboard Maestro to notify me that something quit
| and potentially re-launch it.
| raskrebs wrote:
| Have a look at this issue, and the picture i posted.
| Their is an explanation on how to test it out locally if
| you wish too
|
| https://github.com/raskrebs/sonar/issues/15
| quotemstr wrote:
| Christ Almighty I hate our industry practice of binding to some
| inscrutable port number on localhost. Unix domain sockets aren't
| that hard! They're secure against all sorts of attacks and more
| convenient to boot. Instead of connecting to a number, you
| connect to a file. An ordinary file, with an ordinary name you
| can mv, chmod, and rm. Boring on a good way.
|
| So why doesn't everyone run local services over Unix sockets?
|
| The only problems: 1) web browsers don't support AF_UNIX URI
| scheme, and 2) ancient versions of Java don't have built-in APIs
| for AF_UNIX sockets.
|
| That's it. For these trivial reasons, we've beat our head against
| arbitrary opaque numbers for decades.
|
| And so, for want of a nail, the Unix was lost.
| formerly_proven wrote:
| > So why doesn't everyone run local services over Unix sockets?
|
| > The only problems:
|
| 3) 40 years of Windows not supporting UDS.
| quotemstr wrote:
| Yeah, that too. Windows supports them nowadays too, just to
| be clear. I think we're still bottlenecked, right now, on #1
| and #2 in the form of Java 8 refusing to die.
| formerly_proven wrote:
| Yeah, doing the math it's actually only 33 years of not
| supporting AF_UNIX, but that's not really right either,
| since those versions of Windows didn't support any sockets.
| I guess the technically correct answer then is that Windows
| didn't support UDS for 26 years.
|
| Which is still enough for most portable software to go "eh,
| localhost is fine*"
|
| * resolving localhost is actually a pretty bad idea (yet
| very common) and it's way more robust to listen directly on
| a numeric address.
| 0x457 wrote:
| Some random daemon binding to 3000 because it's the express
| default drives me nuts. I either do a Unix socket, a pick any
| random port if it has to bind on a port.
| jkestner wrote:
| I read the readme. :) Very nice. Thoughtful features. Get this on
| Homebrew!
| raskrebs wrote:
| I will, but the process is a bit tedious. But will look into it
| over the weekend
| 0x457 wrote:
| I recommend just doing a tap in the same repo rather than
| adding this to homebrew first.
| fcoury wrote:
| We live in crazy times. I wanted to add a PID to the list for my
| personal use and since I use Rust way more than Go, I decided to
| one-shot one app, and Codex indeed one shotted it, wow.
|
| https://github.com/fcoury/sonars
| raskrebs wrote:
| You can add PID with the c-flag, e.g.
|
| sonar list -c port,process,pid,type,url,container
|
| or just show all columns:
|
| sonar list --all-columns
|
| But yeah, it's quite cool. I believe the future lies in
| software distillation, so cool to see it happen on my own
| project :D
| fcoury wrote:
| I did this more as an experiment but man it sucks, doesn't
| it?
| raskrebs wrote:
| What sucks? Software distillation? :)
| zenoprax wrote:
| I'm tempted to one-shot this into a series of FISH
| abbreviations.
|
| And I would want someone to use that to one-shot a python
| implementation. And on and on like a game of telephone until
| the context degrades so far that it becomes an entirely
| different program.
| kohexo wrote:
| Honestly, pretty cool. I was wondering if something like this
| existed. Right now I have scripts to kill the ports I use
| consistently to avoid issues when developing. Kudos!
| raskrebs wrote:
| I looked around for a while, couldn't find anything. Someone
| posted about killport but never stumbled upon it. Has some
| features that are the same, but not all. From the reaction
| online people don't seem to know of other solutions like this,
| or have something they have made them selves in the .zshrc :)
| mustafa0x wrote:
| Nice util. It should be possible to kill inline.
|
| I like clack/prompts. See its multiselect API.
|
| https://github.com/bombshell-dev/clack/tree/main/packages/pr...
| raskrebs wrote:
| Will have a look. Mind creating an issue so i don't forget?
|
| https://github.com/raskrebs/sonar/issues
| mrbonner wrote:
| Hey, thanks for sharing this. Your app inspires me to take a look
| at Go, again! I've been searching for another primary language to
| learn. My primary used to be Java at $day$ job and now Python for
| ML/AI. I love Python but still feel insecure given the lack of
| static typing. I look at TypeScript as well, especially in the
| context of Bun runtime. I decided it may not be for me, not the
| language, but the ecosystem around it.
| raskrebs wrote:
| I quite like go for how lean it is, really nice for local
| projects with lots of constant changes. Also easy to learn. The
| biggest most annoying thing is how bad error handling is done,
| not sure why they built it like that.
|
| I primarily write typescript and python for work. But have
| dabbled in bunch of other languages at different jobs and for
| different tasks. Yet to pick up rust, but have been wanting to.
| But tend to pick what seems most right for the task, while also
| considering what i most want to be working with
| mrbonner wrote:
| I forgot that I also "try" Rust as well. But, I feel like it
| may not be suitable for my use cases and not simple enough
| for non-intelligent person like me :-). I agree error
| handling in Go could be better. But, comparing to Java I
| don't think I would feel salty.
| diablevv wrote:
| Nice -- the use case for this is immediately obvious. I've spent
| more time than I care to admit running `lsof -i :PORT` or
| `netstat -tulpn | grep PORT` trying to figure out what's
| squatting on a port before running a dev server. Having a clean
| CLI for this with kill support is the kind of small tool that
| earns a permanent spot in your toolkit. Added to my dotfiles
| setup.
| raskrebs wrote:
| Great to hear! Please add any issues or feature request if you
| find anything missing :)
| zephyreon wrote:
| Ditto. Though I always take the lazy route and just change port
| numbers until I find an open one. My Mac is probably running
| like 20 different localhost apps at any given time.
___________________________________________________________________
(page generated 2026-03-20 23:01 UTC)