PortSlayer ⚡
Cross-platform CLI + interactive TUI to list active ports and safely kill processes by port number.
Features
- Interactive TUI dashboard — just run
pk(orportslayer): arrow keys to navigate,/to search,kto kill, live auto-refresh - Short alias — every command works as both
portslayer <cmd>and the 2-letterpk <cmd> - List all active ports — port, PID, process name, protocol, state, addresses
- Filter by port number, process name, or protocol (TCP/UDP)
- Kill processes by port or by process name — with mandatory confirmation before any destructive action
- JSON output (
--json) for scripting, plus built-in shell completion (--install-completion) - Cross-platform — Linux (via
ss/lsof), Windows (vianetstat/taskkill), macOS (vialsof) - Install however you like — pip, npx/npm, or uvx
Tech Stack
| Layer | Technology | Reason |
|---|---|---|
| TUI | Python + Textual | Full-screen keyboard-driven dashboard, no extra runtime for users |
| CLI | Python + Typer + Rich | Single language, beautiful tables, type-safe commands |
| Core | Pure Python stdlib | No external dependencies for port scanning / killing |
| Tests | pytest | Simple, fast, widely adopted |
| Packaging | pyproject.toml (setuptools) | PEP 517/518 standard, pip-installable |
Installation
Pick whichever package manager you already have — they all install the same tool.
pip install portslayer # Python / pip — requires Python >= 3.9
npx @appestox/portslayer # Node.js — try it with zero install
npm install -g @appestox/portslayer # Node.js — install permanently
uvx portslayer # zero-install, no Python setup needed
Homebrew and Scoop manifests live in packaging/ but are not
published to a public tap/bucket yet.
The npm package is a thin wrapper that installs the same portslayer PyPI
package underneath — see packaging/ for how each is built
and published.
Minimum supported versions
| Method | Requirements |
|---|---|
pip install portslayer |
Python 3.9+ |
npx @appestox/portslayer / npm install -g |
Node 14+ and Python 3.9+ (the wrapper pip-installs the PyPI package; it does not install Python for you) |
uvx portslayer |
uv — it downloads a compatible Python automatically |
If pip says No matching distribution found for portslayer, your Python is
older than 3.9 — check with python --version and upgrade.
Install from source
git clone https://github.com/AppestoX/portslayer.git
cd portslayer
pip install -e ".[dev]"
Linux — additional notes
No extra system packages required. ss is available by default on all modern
Linux distributions (iproute2). lsof is used as a fallback if ss is
not available.
To see processes owned by other users you must run with sudo:
sudo portslayer list
Windows — additional notes
Run PowerShell or Command Prompt as Administrator to see all processes.
netstat and taskkill are built into every Windows installation.
Usage
Interactive TUI (recommended)
pk
(pk is the short alias for portslayer — both commands are identical and installed together; use whichever you prefer. The rest of this doc uses portslayer for clarity, but pk works everywhere it does.)
Launches a full-screen dashboard — no flags to remember:
| Key | Action |
|---|---|
↑ / ↓ |
Navigate the port list |
/ |
Search/filter (port, process, protocol, state) |
k / Del |
Kill the selected process (asks to confirm) |
r |
Refresh now (auto-refreshes every 3s anyway) |
Esc |
Clear search |
q |
Quit |
CLI
List all active ports
portslayer list
Sample output:
╭────────────────────────────────────────────────────────────────────╮
│ Active Ports (24 entries) │
├──────┬──────────┬─────────────┬───────┬────────────┬──────────────┤
│ Port │ Protocol │ State │ PID │ Process │ Local Address│
├──────┼──────────┼─────────────┼───────┼────────────┼──────────────┤
│ 22 │ TCP │ LISTEN │ 783 │ sshd │ 0.0.0.0:22 │
│ 80 │ TCP │ LISTEN │ 1042 │ nginx │ 0.0.0.0:80 │
│ 5432 │ TCP │ LISTEN │ 2103 │ postgres │ 127.0.0.1:… │
╰──────┴──────────┴─────────────┴───────┴────────────┴──────────────╯
Filter ports
# By exact port number
portslayer list --port 443
# By partial port prefix — matches every port starting with these digits
portslayer list --port 808 # -> 8080, 8081, 8083, ...
# By process name (partial match)
portslayer list --process nginx
# By protocol
portslayer list --protocol tcp
# Only LISTENING ports
portslayer list --listening
# Combine filters
portslayer list --protocol tcp --listening
Inspect a specific port — or a partial prefix
portslayer find 8080 # exact port
portslayer find 808 # partial prefix -> matches 8080, 8081, 8083, ...
Typing fewer digits is a feature, not an error — no need to remember or type the full number if you just want to see everything in that range.
Kill the process on a port
portslayer kill 3000
kill always requires an exact port number (not a prefix) — this is a
deliberate safety choice so a mistyped digit can't broaden which processes
get terminated. Use find/list with a prefix first to see what's there,
then kill the exact port you want.
# Kill by process name instead of port (kills every port that process owns)
portslayer kill --name node
PortSlayer will:
- Show full process details
- Ask for explicit confirmation
- Kill the process only after
yis entered
# Skip confirmation (use with care)
portslayer kill 3000 --force
Scripting with JSON output
list and find both accept --json for piping into jq or other tools
instead of printing a table:
portslayer list --json | jq '.[] | select(.protocol == "TCP")'
portslayer find 808 --json
Shell completion
Typer wires this up automatically — no extra setup needed:
portslayer --install-completion # installs completion for your current shell
Version
portslayer --version
Project Structure
portslayer/
├── portslayer/
│ ├── __init__.py # Package version / metadata
│ ├── cli.py # Typer CLI (list / find / kill) — bare invocation launches the TUI
│ ├── tui.py # Textual interactive dashboard
│ ├── core/
│ │ ├── __init__.py
│ │ ├── models.py # PortInfo dataclass
│ │ ├── port_scanner.py # Platform-specific scanning + parsers
│ │ └── process_killer.py# Safe process termination
│ └── utils/
│ ├── __init__.py
│ ├── platform_utils.py# OS detection, admin check
│ └── validators.py # Port number validation
├── tests/
│ ├── test_validators.py
│ ├── test_port_scanner.py
│ └── test_process_killer.py
├── packaging/
│ ├── npm/ # npm wrapper package (`npx @appestox/portslayer`)
│ ├── homebrew/ # Homebrew tap formula
│ └── scoop/ # Scoop bucket manifest
├── pyproject.toml
├── requirements.txt
├── requirements-dev.txt
├── LICENSE
└── README.md
Running Tests
pip install -e ".[dev]"
pytest
With coverage:
pytest --cov=portslayer --cov-report=term-missing
Security
| Concern | Mitigation |
|---|---|
| Command injection | All subprocess calls use explicit argument lists — never shell=True |
| Input validation | Port numbers are validated (regex + range check) before any system call |
| Confirmation requirement | Every kill operation requires explicit user confirmation |
| Privilege transparency | Users are warned when not running as root/Administrator |
| PID validation | PID existence is verified before sending signals |
PortSlayer never executes raw shell input from the user.
Platform-Specific Commands Used
| Platform | List ports | Get process names | Kill process |
|---|---|---|---|
| Linux | ss -tulnp → lsof -i -n -P |
embedded in ss output |
os.kill(pid, SIGKILL) |
| Windows | netstat -ano |
tasklist /FO CSV /NH |
taskkill /PID <pid> /F |
| macOS | lsof -i -n -P |
embedded in lsof |
os.kill(pid, SIGKILL) |
Publishing (maintainers)
Order matters — the npm, Homebrew, and Scoop packages all install the PyPI package under the hood, so PyPI goes first.
- PyPI (source of truth):
python -m pip install build twine python -m build twine upload dist/*
- npm wrapper (
packaging/npm/) — bumpversioninpackaging/npm/package.jsonto match the PyPI release, then:cd packaging/npm && npm publish
- Homebrew tap (
packaging/homebrew/) — seepackaging/homebrew/README.mdfor generating dependency resource blocks and the sdist checksum, then push to yourhomebrew-portslayertap repo. - Scoop bucket (
packaging/scoop/) — seepackaging/scoop/README.mdfor the checksum step, then push to your bucket repo. Winget requires a compiled installer and is documented as a follow-up in the same file.
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feat/my-feature - Run tests:
pytest - Open a pull request
License
MIT — free to use, modify, and distribute.
Release files for portslayer 1.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| portslayer-1.1.2.tar.gz | 24.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| portslayer-1.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 44.6 kB
Release files / portslayer-1.1.2.tar.gz
| Download URL | portslayer-1.1.2.tar.gz |
|---|---|
| Size | 24.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2a961a3650b536b02e91e7409ea371046de3e5d0bb467ec9bcf2c0cc1fa94e28
|
|
BLAKE2b-256 checksum How to use checksums |
85aee041f25e4101e8ace556b5db3e3aa95fd6954b0fda01485c9913b2be2f49
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 14, 2026.
Transparency logRelease files / portslayer-1.1.2-py3-none-any.whl
| Download URL | portslayer-1.1.2-py3-none-any.whl |
|---|---|
| Size | 20.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
73055c6284435006863378c15a9c7eeaad81c2f95cac342520ad0955a4cfd37c
|
|
BLAKE2b-256 checksum How to use checksums |
31ba7cde951985ed867ddcd51f59401b088a1deef0493cdc5648e7dc1661ca9d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 14, 2026.
Transparency log