Omahub
← All plugins
M

Omaports

by Mich Nduka

Open dev ports on localhost in the Omarchy bar: which project holds which port, what is reachable beyond this machine, and a way to close it.

Security review

Potentially dangerous behavior detected · 1 finding

Deterministic scan — not a security guarantee

High
Risk level
High
Analyzed commit
d6c5f72
Scanned
1 month ago
  • high destructive_filesystem test/model-test.js:266

    Destructive operation on the root filesystem or a block device.

    rm -rf /"), ["kill", "-TERM", "1234"])

Automated analysis only — not a security guarantee.

AI advisory review

No obvious issues detected

Language-model assessment · ~deepseek/deepseek-v4-flash-latest — advisory only

Low
AI risk level
Low
Recommendation
install
Model
~deepseek/deepseek-v4-flash-latest
Analyzed commit
d6c5f72
Reviewed
1 month ago

The plugin is a local port/process inspector with user-initiated actions (open, copy, terminal, kill) scoped to processes owned by the current user, and it matches its documented behavior. The deterministic high finding is a false positive: the literal `rm -rf /` appears only in test data inside test/model-test.js and is never executed by the plugin.

  • The automated scan flagged `rm -rf /` in test/model-test.js, but this is a test fixture/assertion string, not runtime code.
  • The kill/force-kill actions can terminate processes owned by the user; this is intentional, requires user action, and has confirmation enabled by default.
  • No install-time scripts, obfuscation, persistence mechanisms, or credential-handling code were found.
How this check works

This review combines the deterministic scan (the rule-based results above) with an independent look at the plugin's code by a language model. The model reads a trimmed sample of the repository's files, the manifest, and the README, then gives a plain-language risk level and a recommendation: install (no notable danger), review (look closer first), or avoid (clearly dangerous).

It runs on the same analyzed commit as the deterministic scan and is strictly advisory — it is not a security guarantee and never blocks a plugin by itself. A human moderator still reviews plugins before they are listed.

AI advisory only — automated analysis, not a security guarantee.

Install
$ omarchy plugin add https://github.com/mich-nduka/omaports --enable
Developer Tools #bar #quickshell #system

Omaports

Open dev ports on localhost, in the Omarchy bar.

The widget is a count of what you are running. The panel is the list, and its whole trick is naming things properly: ss reports a port as a pid and a thread name, so a Vite server shows up as MainThread and every JavaScript project on the machine shows up as node. Omaports reads the command line, the working directory and the project root behind each pid, and reports 3000 · Vite under the heading nexahubtech instead.

From there the actions are the four things anyone actually does with a dev port: open it, copy it, open a terminal where it lives, or kill it.

The Omaports panel: dev port count, filter chips, and listening ports grouped by project, with one port flagged as reachable beyond localhost

Install

omarchy plugin add https://github.com/mich-nduka/omaports.git --enable

Everything it needs is already on an Omarchy box:

Dependency Used for Required
ss (iproute2) reading the listening sockets yes
/proc naming the process behind a port yes
xdg-open opening a port in the browser for the open action
wl-copy the copy action for the copy action
xdg-terminal-exec opening a terminal in the project for the terminal action

No sudo, no polkit, no daemon. The plugin runs as your user inside omarchy-shell and reads exactly what you could read from a shell. That is also its one limit: a port owned by another user is visible, but the process behind it is not, because only root can see whose it is. Those ports are named from a table of well-known services instead — 5432 · PostgreSQL — and never offer a kill.

Nothing here writes to your configuration, and the only thing it ever does to another process is send it the signal you asked for.

Remove

omarchy plugin remove io.github.mich-nduka.omaports

That takes the widget out of the bar and deletes the plugin directory. To keep it installed but off the bar, disable it instead:

omarchy plugin disable io.github.mich-nduka.omaports

Neither leaves anything behind. The only thing this plugin ever writes is its own entry in ~/.config/omarchy/shell.json, which remove takes with it.

Usage

Click the icon to open or close the panel. Press Escape to close it. Right-click refreshes.

The number next to the icon counts dev ports — what you are running, rather than every socket on the machine. It turns urgent when a dev port is bound beyond loopback, which is the one thing here worth interrupting you over: a server on 0.0.0.0 is reachable from every machine on the network you happen to be on, coffee shop included. Hover for the full count and the reason.

Four chips switch what the list shows.

Chip Rows
dev ports in a dev range, ports held by a dev runtime, and anything you named in settings
mine every port owned by your user, dev or not
exposed every port reachable from beyond this machine
all everything listening

Rows are grouped by project — the checkout the server was started from, found by walking up from its working directory to the nearest .git, package.json, Cargo.toml, go.mod, composer.json, pyproject.toml, Gemfile, mix.exs, pom.xml, build.gradle or deno.json. That is why a Laravel server started in public/ lands under the name of the app rather than under public. Ports with no readable owner share one system group at the bottom.

Each row reads port · what it is, then where it is reachable from, which checkout it belongs to, how long it has been up, and its pid. The dot on the left is the summary: accent for a dev port, urgent for a dev port open to the network, dim for everything else.

A dev server that binds both 127.0.0.1 and ::1 is one row, not two.

Actions

Tick rows to act on several at once. With nothing ticked, the action applies to the row under the cursor.

Action Icon Key What it does
Open 󰖟 o xdg-open http://localhost:<port>, for ports that look like they serve HTTP
Copy 󰆏 y the address, one per line for a multiple selection
Terminal 󰆍 t xdg-terminal-exec in the directory the server runs from
Kill 󰅖 x the signal set in settings, TERM by default
Force kill 󰚌 K SIGKILL

Kill asks first, unless you turn that off. Only your own processes can be killed; a row that is not yours leaves the action disabled and says so.

Keyboard

The panel takes keyboard focus when it opens.

Key Does
↑ ↓ ← → or hjkl move the cursor between chips, the filter field and the list
Return tick the row under the cursor, or take the chip under it
/ jump to the filter field
v tick or untick everything visible
1 2 3 4 dev, mine, exposed, all
r refresh
Escape close

Filtering matches the port, the project, the runtime, the process, and the command line — so 3000, vite, and the name of the checkout all find the same server.

Settings

Everything below lives in the widget's entry in ~/.config/omarchy/shell.json and can be edited there or from the bar's own settings panel.

Setting Default What it does
refreshIntervalSec 5 how often the socket table is read
barLabel Dev ports the number next to the icon: dev ports, everything, or nothing
warnExposed true turn the icon urgent when a dev port is open to the network
showSystemPorts true include ports owned by other users
includeUdp false include UDP sockets, which are mostly discovery chatter
devPorts "" extra ports to always count as yours: 7788, 9100-9110
ignorePorts "" ports to drop from every list and count
httpsPorts "" ports whose links should open as https
killSignal TERM the signal the kill action sends
confirmKill true ask before killing

A port counts as a dev port when it sits in a range dev servers take (3000-3010, 4200, 5173-5180, 8000-8010, 8080-8090, 19000-19010 and friends), when the process holding it is a recognised runtime, or when you listed it in devPorts. A well-known service port is deliberately not one: Postgres on 5432 is infrastructure, and counting it would make the number on the bar useless.

IPC

The plugin answers on its own IPC target, so a script or a keybinding can reach it:

omarchy-shell io.github.mich-nduka.omaports toggle
omarchy-shell io.github.mich-nduka.omaports refresh
omarchy-shell io.github.mich-nduka.omaports count   # 4/11 — dev ports of total
omarchy-shell io.github.mich-nduka.omaports list    # JSON, one object per port

list is the useful one for scripting:

omarchy-shell io.github.mich-nduka.omaports list \
  | jq -r '.[] | select(.dev) | "\(.port)\t\(.project)\t\(.name)"'

Development

Model.js holds every pure function — the ss parser, the /proc merge, the dev-port classifier, the grouping, and every string the panel shows. It has no Qt in it, so the whole thing runs under node:

node test/model-test.js

The fixture in that file is a real capture, threaded-runtime naming and all. Service.qml owns every process the plugin starts; Panel.qml is declarative and starts none.

License

MIT.