Every tool I reached for during an incident described the system without explaining it. ps and top tell you what is running, lsof tells you what holds a file, systemctl tells you a unit is active. But the question I actually had was always "why is this here, and what is keeping it alive?" Answering it meant chaining four tools by hand and holding the result in my head: find the PID, walk the parents with ps, check whether systemd owns it, then docker inspect when it turned out to be a container. Doing that at 2am on a machine you didn't set up, you lose the thread halfway through. The moment it became a project: a port was bound, the owning process had been reparented, and nothing I ran could tell me which unit was actually responsible. All of it was sitting in /proc and the cgroup already. Nothing was going to assemble it for me.
Demo
Terminal previewOverview
Trace any process, port, container, or file back to what started it
From the maintainer
The "port is already in use" moment, because everyone has had it. witr --port 8080 Instead of just a PID you get the chain that explains it: the process, who owns it, when it started, the systemd unit or container actually responsible, and warnings worth knowing (bound to 0.0.0.0, running as root, binary deleted since it started). Then run it bare: witr That opens the TUI. Start on the Ports tab, find the port, hit enter, and the ancestry panel shows the same chain interactively. From there the Containers and Locks tabs answer the neighbouring questions - which container that actually is, and what is holding the file you can't replace. There's a browser playground with a guided tutorial for anyone who wants to try the whole thing before installing.
Two, and both come from the same idea: you almost never start from a PID. The TUI is organised around what you actually have in hand rather than around the process table. The tabs are Processes, Ports, Containers and Locks, because real questions arrive as "port 8080 is taken", "what is this container", or "what is holding this file". Every tab resolves into the same ancestry panel, so whichever door you come in through you land on the same answer: the causal chain. The second is that destructive actions are guarded by identity, not by PID. Linux recycles PIDs quickly, so before the TUI sends a signal or a renice it re-reads the process and compares its start time against what was on screen. If the PID has been recycled, the action doesn't land. A process manager that kills the wrong thing once is worse than no process manager.
Hardening how witr represents certainty, so machine-readable output is as rigorous as what a human sees. In flight: - Explicit signalling for undetermined ancestry, with its own exit code, so scripts can branch on determined vs undetermined as cleanly as a person reading the report. - Start-time validation while walking the parent chain, keeping ancestry correct on busy systems where the kernel recycles PIDs fast. - A stable machine-readable uncertainty field in --json, so callers key on a structured value instead of parsing prose. Beyond that: more source detectors for deeper supervisor stacks, and continued parity across Linux, macOS, Windows and FreeBSD.
Latest Release
What's Changed
- Fix/darwin lsof fd parse by @mleonidas in https://github.com/pranshuparmar/witr/pull/202
- feat(linux): detect incus/LXC containers via cgroup lxc.payload pattern by @lets-build-an-ocean in https://github.com/pranshuparmar/witr/pull/203
- fix(output): use bright ANSI colors for dark-theme contrast by @lets-build-an-ocean in https://github.com/pranshuparmar/witr/pull/206
- feat: v0.3.3 Main PR by @pranshuparmar in https://github.com/pranshuparmar/witr/pull/209
New Contributors
- @mleonidas made their first contribution in https://github.com/pranshuparmar/witr/pull/202
- @lets-build-an-ocean made their first contribution in https://github.com/pranshuparmar/witr/pull/203
Full Changelog: https://github.com/pranshuparmar/witr/compare/v0.3.2...v0.3.3
Discussions