Skip to content
kithfossPublic

About

Find commands with multiple installs on PATH and flag the ones where versions disagree. The bug that makes a tool behave one way in your shell and another way under cron.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

pathdrift

Find commands with multiple installs on your PATH. Flag the ones where versions disagree.

which -a tells you how many copies of a command exist. pathdrift tells you when two copies are different versions — the bug that makes a command behave one way in your shell and another way under cron.

Python 3.8+. Standard library only. One file.

The pain

You install a CLI tool. Later you install an updated version via a different path (user-level vs system-level, snap, brew, npm‑global, nvm). Your shell finds the new one first. Cron finds the old one first. They disagree on config schema, flag syntax, output format — something — and you spend an afternoon chasing a "flaky" bug that's actually two binaries.

Real example that motivated this:

[DRIFT  ] openclaw
           /home/me/.npm-global/bin/openclaw
             version: 2026.4.15
           /usr/local/bin/openclaw
             version: 2026.3.28

Different binaries, different config validators, different error messages, same command name. which -a showed both but wouldn't tell me their versions were three weeks apart.

Install

curl -fsSL https://raw.githubusercontent.com/kithfoss/pathdrift/main/pathdrift.py -o ~/.local/bin/pathdrift
chmod +x ~/.local/bin/pathdrift

Or clone and symlink:

git clone https://github.com/kithfoss/pathdrift
ln -s "$(pwd)/pathdrift/pathdrift.py" ~/.local/bin/pathdrift

Use

# Scan everything on PATH. Print only the drift.
pathdrift

# Include commands with multiple installs at matching versions.
pathdrift --all

# Hide commands whose --version can't be probed.
pathdrift --quiet

# Check a single command.
pathdrift python3

# Simulate a different environment — e.g. cron's PATH.
pathdrift --path "/usr/bin:/bin"

Exit codes:

  • 0 — no drift detected
  • 1 — drift detected (or a named command wasn't found)
  • 2 — PATH was empty

What counts as drift

Two installs of the same command are drift when their first non-empty --version output contains different semver-ish numbers. Symlinks that resolve to the same underlying file are collapsed — those aren't drift, they're aliases.

Commands that don't answer --version (editors, pagers, random shell scripts) show as [unknown]. Hide them with --quiet.

Why not just which -a?

which -a is truthful. But two installs at version 1.2.3 are harmless. Two installs at 1.2.3 and 2.0.0-rc1 are a future incident. pathdrift is the second thing — the one that tells you to care.

How it works

  1. Walk the PATH in order, de-duplicating directory entries.
  2. Build a map of command name → list of full paths.
  3. For each command with more than one path, run <path> --version (or the right override) in a thread pool.
  4. Collapse paths that resolve to the same file via realpath.
  5. Extract a semver-shaped number from each output. If the numbers differ — drift.

Timeouts default to 3 seconds per probe. Override with --timeout.

Non-goals

  • Not a package manager. It tells you drift exists; fixing it is your call.
  • Not a replacement for update-alternatives — that's for managing, this is for noticing.
  • Not a system linter. It runs when you run it.
  • No config file. If you need more than the flags offer, fork it.

License

MIT.

About

Find commands with multiple installs on PATH and flag the ones where versions disagree. The bug that makes a tool behave one way in your shell and another way under cron.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages