# witr traces what started a process, and its Unix install script does what its Windows one skips

> witr is a Go CLI and terminal UI that answers why something is running by walking the supervisor, service, container, or shell chain behind it. We read its manifest, Makefile, and install paths to show what it resolves, what it cannot resolve, and which channel decides your version.

**pranshuparmar/witr** — Why is this running? Trace any process, port, container, or file back to what started it - CLI + TUI. 

- Repository: https://github.com/pranshuparmar/witr
- Website: https://pranshuparmar.github.io/witr/
- Stars: 22,573 · Forks: 789
- Language: Go
- License: Apache-2.0
- Published: 2026-08-17 · Updated: 2026-08-18 · Language: en
- Canonical page: https://hysenlabs.com/projects/pranshuparmar-witr

## The systemd and D-Bus dependencies are Linux only, while one binary ships to four systems

witr is built around a single question, why is this running, and its design is a complaint about correlation work. The README names the tools it stands in place of: ps, top, lsof, ss, systemctl, and docker ps. Those expose state and metadata, so they answer what is running and leave you to infer the cause by manually correlating outputs across several of them. witr reports the cause instead, covering a process, a service, anything bound to a port, a container, or a file, and it states where the thing came from, how it was started, and which chain of systems is responsible for it existing right now. The direct dependencies explain the shape of that chain. go.mod pins coreos/go-systemd/v22 at v22.7.0 and godbus/dbus/v5 at v5.1.0, so systemd units and D-Bus activation are first class inputs rather than afterthoughts. Both are Linux interfaces, and that is the constraint to plan around. The same static binary is also distributed for macOS, FreeBSD, and Windows, where there is no systemd unit and no D-Bus activation to resolve, so the deepest inputs in the premise have nothing to read. The README does not enumerate which backends are compiled in per platform, so you would be guessing at coverage unless you read the generated man page.

## The Unix script installs to /usr/local/bin with no checksum step, unlike the PowerShell one

Distribution is a single static binary for Linux, macOS, FreeBSD, and Windows, reached through two first party scripts that behave differently. On Unix:

```bash
curl -fsSL https://raw.githubusercontent.com/pranshuparmar/witr/main/install.sh | bash
```

The script details enumerate the whole job: detect the operating system as linux, darwin, or freebsd, detect the CPU architecture as amd64 or arm64, download the latest released binary and man page, install it to /usr/local/bin/witr, install the man page to /usr/local/share/man/man1/witr.1, and accept INSTALL_PREFIX to override the default install path. On Windows the entry point is a PowerShell one-liner:

```powershell
irm https://raw.githubusercontent.com/pranshuparmar/witr/main/install.ps1 | iex
```

Two differences matter in practice. The PowerShell script downloads a zip and verifies a checksum, a step the Unix detail list never mentions, so integrity checking on the Unix path is undocumented rather than promised. And instead of a shared prefix it extracts witr.exe into %LocalAppData%\witr\bin and adds that directory to your User PATH. INSTALL_PREFIX is therefore the only documented escape from writing into /usr/local/bin, which on a locked down host means you have to know the variable before you run the script.

## Nine channels ship witr, and the one you pick decides which version you run

Packaging is the widest part of the project, and the README attaches the same caveat to all of it: community packages may lag GitHub releases because of independent review and validation, with Repology named as the place to read current status. The apt entry carries the most specific constraint, requiring Ubuntu 26.04+ and Debian sid and later plus derivatives including Kali Linux, Devuan, and Raspbian, and it repeats the lag caveat on its own. The rest are brew install witr for macOS and Linux, sudo port install witr through MacPorts, conda install -c conda-forge witr with mamba and pixi as alternatives, yay -S witr-bin or paru -S witr-bin from the AUR, winget install -e --id PranshuParmar.witr, npm install -g @pranshuparmar/witr, pkg install witr or pkg install sysutils/witr on FreeBSD, and choco install witr. FreeBSD users can also build from ports with cd /usr/ports/sysutils/witr/ followed by make install clean. The README then advises against the script for regular use, pointing to package managers such as Homebrew, Conda, or Winget for easier updates. The consequence for a reader is that the version on your PATH is a property of the channel you chose, and a lag notice is the ordinary condition of a community package rather than a sign that something broke.

## The browser sandbox teaches the model on a simulated box, not on your machine

Two entry points let you see the tool without touching a production host, and neither substitutes for running it there. The first is the browser build hosted at pranshuparmar.github.io/witr, presented as a simulated Linux box with a guided tutorial and a free-play sandbox and no install required. A simulated box is exactly what it says: it teaches the model of supervisors, containers, services, and shells on a machine the project owns, with processes and files that are not yours. It cannot read your host, so the one thing witr exists to do, point at the real reason something is running on your system, is the one thing the sandbox cannot do. Treat it as training, not as evidence. The second entry point is the npm channel, which installs the same artifact rather than exposing a library API: npm install -g @pranshuparmar/witr writes a global binary, so it is a deployment route that happens to be cross platform, not something you add as a project dependency and call from JavaScript. Two routes remain for real answers, the static binary you install yourself, or a package from one of the nine channels, and the README treats the package manager as the better of those for keeping up with updates.

## The Makefile generates the flag reference into docs/cli instead of maintaining it by hand

Build and documentation are wired together, and the tooling reveals where the authoritative flag list lives. The relevant targets are short:

```
build:
	CGO_ENABLED=0 go build -o $(BINARY) $(CMD)

test:
	go test ./...

man:
	go run ./internal/tools/docgen -format man -out docs/cli

markdown:
	go run ./internal/tools/docgen -format markdown -out docs/cli
```

BINARY is set to witr and CMD to ./cmd/witr, and the build exports CGO_ENABLED=0, which is what allows one artifact to ship as a static binary across four operating systems. The two docs targets run a generator that lives inside the repository at ./internal/tools/docgen and write both a man page and a markdown reference into docs/cli, with a docs target that depends on both. The practical consequence is that flags are derived from the command tree rather than transcribed into prose. The README's table of contents links a flags and options section, but the flag names themselves do not appear in the surrounding text, and nothing in the repository tells a reader to treat the README as the current list. If you are scripting against a switch, read the man page the install script already placed at /usr/local/share/man/man1/witr.1, or regenerate the reference yourself.

## Go 1.25 with a pinned toolchain and a committed vendor directory shape local builds

The module definition is strict about versions and the repository carries its dependencies in tree. go.mod declares module github.com/pranshuparmar/witr with go 1.25 and an explicit toolchain line of go1.25.10, so building from source wants a recent Go rather than an older one, and the toolchain directive makes that floor concrete. The direct dependency list stays short and reveals the architecture: cobra v1.10.2 for the command line, bubbletea v1.3.10 with bubbles v1.0.0 and lipgloss v1.1.0 for the interactive TUI, go-isatty v0.0.20 and muesli/reflow for terminal handling, plus the two Linux system interfaces named earlier. Everything else in the file is marked indirect. A vendor/ directory sits at the top level, so the build and the test run without fetching anything, at the cost of the pinned indirect versions in your checkout being exactly what you compile against, from golang.org/x/sys v0.38.0 down to terminal libraries such as termenv and xo/terminfo. The lint target matches that layout, checking gofmt over Go files while excluding vendor/ and then running go vet ./..., so a change that reformats nothing but trips vet will fail on its own.

## Tags move every two months on a 0.x line, with no stability policy stated

The release record is the last thing to check before depending on the output, because the version numbers carry no compatibility promise. Tags run v0.3.1 on 2026-03-18, v0.3.2 on 2026-05-16, and v0.3.3 on 2026-06-24, and the default branch received its last push on 2026-08-15. The project is not marked as archived, so work is continuing, but the 0.x prefix means a minor bump can still carry breaking changes and the repository states no stability policy or upgrade guarantee. Its own table of contents names the sections that decide what you can rely on: an interactive mode TUI, flags and options, a core concept, example outputs, output behavior, platform support, and success criteria. The tagline advertises three ways in, one command, machine-readable JSON, or an interactive TUI dashboard, which means there are two output shapes to verify rather than one, and the section on output behavior is where their differences would be settled. If you plan to parse the JSON, pin a version and read its output behavior and man page before wiring it into automation, since an unannounced 0.x change would reach your parser without warning.

## Conclusion

Use witr when you have a live Linux host and need the causal chain behind a process, port, container, or file, and install through a package manager rather than the script so upgrades stay simple. Do not treat the browser sandbox as a probe of your own machine, and verify three things first: which channel supplied your version, what the JSON output shape looks like at that tag, and how much of the systemd and D-Bus chain your platform can resolve.

## FAQ

### How do I install witr on Linux or macOS?

The Unix install script detects linux, darwin, or freebsd plus amd64 or arm64, downloads the latest binary and man page, and installs them to /usr/local/bin/witr and /usr/local/share/man/man1/witr.1, with INSTALL_PREFIX available to override the location. Package managers are also supported through brew install witr, sudo apt install witr on Ubuntu 26.04+ and Debian sid and later, conda install -c conda-forge witr, and others.

### What does witr tell me that ps and systemctl do not?

ps, top, lsof, ss, systemctl, and docker ps expose state and metadata, so they show what is running and leave you to correlate outputs to find the cause. witr reports where a process, service, port, container, or file came from, how it was started, and which chain of supervisors, containers, services, or shells is responsible.

### Can I try witr without installing it?

There is a browser build at pranshuparmar.github.io/witr that runs against a simulated Linux box, offering a guided tutorial and a free play sandbox with no install required. Because the machine is simulated, it cannot inspect processes, ports, or files on your own host.

## Sources

- [Official documentation](https://pranshuparmar.github.io/witr/)
- [Official README](https://github.com/pranshuparmar/witr#readme)
- [Project repository](https://github.com/pranshuparmar/witr)
- [Release notes](https://github.com/pranshuparmar/witr/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pranshuparmar-witr
