Every probe droid has one job: find what's hiding out there. pr0be sweeps your disk for code that exists nowhere else — uncommitted changes, unpushed branches, stashes, and project folders that were never put under git at all. One command, a few seconds, and you know exactly what a dead SSD would cost you.
Install · Usage · Configuration · Run it daily · Coder's Cantina
Backups cover files. They do not cover intent. The dangerous state is the one git knows about but no server does: three commits ahead on a branch you forgot, a stash from last March, a prototype folder that never got git init. Time Machine will happily restore all of it — right up until the day you're on a different machine.
pr0be answers one question, fast: which of my projects exist only here?
$ pr0be
● ~/Development/products/sabacc_ui/web
uncommitted 75 staged, 67 modified, 1 untracked
stashed 2 stash entry/entries
unpushed main is 3 commit(s) ahead
no upstream switch-2-b10cks has no upstream
● ~/Development/tools/phpantom_lsp
uncommitted 2 modified
▲ 106 of 136 projects hold code that only exists here: 13 not a repo, 57 uncommitted, 64 unpushed, 17 no remote, 22 stashed, 10 behind
(24141 directories scanned in 1047ms)cargo install --git https://github.com/coderscantina/pr0beOr from a clone:
git clone https://github.com/coderscantina/pr0be.git
cd pr0be
cargo install --path . # → ~/.cargo/bin/pr0bePre-built macOS and Linux binaries are attached to each release.
Requirements: Rust 1.74+ to build, and git on your PATH at runtime. macOS and Linux are supported; notifications use the system notifier on both.
pr0be # scan the configured roots (default ~/Development)
pr0be ~/Code ~/Sites # scan these trees instead
pr0be --all # show clean projects too
pr0be --json # machine readable, for scripts and dashboards
pr0be --fetch # fetch remotes first, so "behind" is accurate
pr0be --notify # desktop notification when something is at risk
pr0be --init > ~/.config/pr0be/config.tomlOptions: -c/--config FILE, --max-depth N, --no-color, -h/--help, -V/--version.
| finding | meaning |
|---|---|
not a repo |
project directory (package.json, Cargo.toml, …) without git |
uncommitted |
staged / modified / untracked files in the working tree |
unpushed |
branch is ahead of its upstream |
no upstream |
local branch that was never pushed |
no remote |
repository has no remote at all — nothing to push to |
upstream gone |
the upstream branch disappeared from the remote |
stashed |
stash entries — they live only in this working copy |
detached HEAD |
commits made here are easy to lose |
behind |
the remote has commits you don't (informational, not a risk) |
Everything except behind counts as at risk, and makes pr0be exit with code 1 — so it drops straight into a cron job, a git hook, or CI.
- Repositories are inspected in parallel; ~24 000 directories take about a second on an M-series Mac.
- Read-only.
pr0benever commits, pushes, cleans, or writes to your repos — the only network call it can make is the opt-in--fetch. --fetchruns with terminal prompts disabled and a per-repo timeout (default 20s), so a repository that wants credentials is skipped instead of hanging the sweep.- Directories inside a repository are never reported as
not a repo— that repo already covers them — but repositories nested inside another repository are inspected in their own right.
Config is looked up in ./pr0be.toml, ~/.config/pr0be/config.toml, then ~/.pr0be.toml; the first match wins. pr0be --init prints a starting point.
roots = ["~/Development"]
max_depth = 8
# Directory names never descended into.
ignore = ["node_modules", "vendor", "target", "dist", ".venv"]
# A directory holding one of these but no .git is reported as "not a repo".
# Plain names or a "*.suffix" pattern.
project_markers = ["package.json", "Cargo.toml", "composer.json", "go.mod", "*.xcodeproj"]
# Fetch remotes before checking (slow, needs network). Same as --fetch.
fetch = false
fetch_timeout = 20
# Native notification when problems are found. Same as --notify.
notify = falseCommand line flags always win over the config file.
A launchd agent at ~/Library/LaunchAgents/com.coderscantina.pr0be.plist — the notification only fires when something is actually at risk, so a quiet day stays quiet:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key><string>com.coderscantina.pr0be</string>
<key>ProgramArguments</key>
<array>
<string>/Users/you/.cargo/bin/pr0be</string>
<string>--notify</string>
</array>
<key>StartCalendarInterval</key>
<dict><key>Hour</key><integer>18</integer><key>Minute</key><integer>0</integer></dict>
<key>StandardOutPath</key><string>/tmp/pr0be.log</string>
<key>StandardErrorPath</key><string>/tmp/pr0be.log</string>
</dict>
</plist>launchctl load ~/Library/LaunchAgents/com.coderscantina.pr0be.plistOn Linux, the equivalent crontab line:
0 18 * * * /home/you/.cargo/bin/pr0be --notify >> /tmp/pr0be.log 2>&1--json emits the full result, including clean projects when combined with --all:
$ pr0be --json | jq '.entries[] | select(.issues[].kind == "unpushed") | .path'{
"config": "/Users/you/.config/pr0be/config.toml",
"scanned_dirs": 24141,
"projects": 136,
"at_risk": 106,
"elapsed_ms": 1047,
"entries": [
{
"path": "/Users/you/Development/tools/phpantom_lsp",
"is_repo": true,
"issues": [{ "kind": "dirty", "staged": 0, "modified": 2, "untracked": 0 }]
}
]
}Exit codes: 0 nothing at risk · 1 at least one project holds local-only code · 2 bad configuration.
Bug reports, ideas, and pull requests are welcome — see the Contributing Guide for the commit format and PR process, and the Code of Conduct for how we treat each other.
cargo test
cargo clippy --all-targets
cargo fmtPlease report vulnerabilities responsibly — see the Security Policy.
pr0be is licensed under the MIT License.
- b10cks CMS — the opinionated headless CMS (repo)
- RAVN — the email client (repo)
- gh0st — the SEO crawler
Maintained by Michael Wallner at Coder's Cantina