onpath
Get your tools on the PATH — cross-shell, cross-platform, zero fuss.
Built for CLI tool installers that need to persistently add a directory to the user's PATH. Detects installed shells, writes the right config for each, and removes everything cleanly on uninstall. Linux, macOS, Windows.
Quick start
// Add ~/.myapp/bin to PATH for all detected shells
let report = add?;
println!;
// [sh] wrote env script: /home/user/.myapp/env
// [sh] added source line to /home/user/.profile
// [Bash] wrote env script: /home/user/.myapp/env
// [Bash] added source line to /home/user/.bashrc
// [Zsh] wrote env script: /home/user/.myapp/env
// [Zsh] added source line to /home/user/.zshenv
To undo everything during uninstall:
let report = remove?;
Env scripts land in the parent of the directory you pass in (~/.myapp/ for ~/.myapp/bin). Override with .env_dir() on the builder.
Shells: Bash, Zsh, Fish, Nushell, PowerShell, Tcsh, Xonsh, POSIX sh.
Windows: Modifies HKCU\Environment\PATH in the registry directly.
How it works
On Unix, onpath uses the same two-layer approach as rustup:
1. Writes a self-guarding env script that only adds the directory if it's not already in PATH:
#!/bin/sh
# Generated by onpath. Do not edit.
Fish, Nushell, PowerShell, Tcsh, and Xonsh each get a script in their native syntax (.fish, .nu, .ps1, etc.). Fish scripts go directly into ~/.config/fish/conf.d/ (auto-loaded, no source line needed).
2. Adds a source line to the shell's RC file, wrapped in markers for clean removal:
# >>> onpath:myapp >>>
# <<< onpath:myapp <<<
Multiple tools can coexist — each gets its own marker block. Adding the same directory twice is a no-op.
On Windows, onpath reads the raw PATH from HKCU\Environment, prepends or appends the directory, writes it back, and broadcasts WM_SETTINGCHANGE so running programs pick up the change. It preserves unexpanded %VARIABLES% like %USERPROFILE% and the original registry value type (REG_SZ vs REG_EXPAND_SZ).
Builder API
For more control, use PathManager:
use ;
let report = new
.env_dir // where to write env scripts (default: dir.parent())
.position // default is Prepend
.backup // back up RC files before modifying (default)
.dry_run // preview without writing anything
.allow_relative // reject relative paths (default)
.add?;
for action in &report.actions
Inspecting results
The returned Report contains a list of Action values describing what happened. Use report.has() to check for specific outcomes:
use ActionKind;
if report.has
Input validation
onpath validates all inputs before writing anything:
- Tool names must match
[a-zA-Z0-9_.-]+(non-empty). - Paths must be absolute (unless
.allow_relative(true)is set), valid UTF-8, and must not contain shell-dangerous characters (",`,$,\) on Unix.
Invalid inputs return descriptive errors rather than producing broken shell scripts.
Concurrency safety
RC file modifications are serialized with advisory file locking (flock(2) on Unix, a named mutex on Windows) to prevent corruption when multiple installers run concurrently.
Shell detection
Shells are auto-detected by checking for existing RC files and the $SHELL environment variable. POSIX sh (.profile) is always included on Unix. No configuration needed.
Features
| Feature | Description |
|---|---|
tracing |
Enables structured logging via the tracing crate. Disabled by default. |
= { = "0.1", = ["tracing"] }
Install
[]
= "0.2"
MSRV: 1.71 (edition 2021)
License
MIT OR Apache-2.0