{"id":31576023,"url":"https://github.com/alexykn/whi","last_synced_at":"2026-01-20T17:55:16.024Z","repository":{"id":317290458,"uuid":"1066780170","full_name":"alexykn/whi","owner":"alexykn","description":"stupid simple path management","archived":false,"fork":false,"pushed_at":"2025-09-30T11:21:22.000Z","size":31,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-30T11:33:28.716Z","etag":null,"topics":["cli","path","path-management","path-manipulation","rust","shell","unix","which"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alexykn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-30T00:33:00.000Z","updated_at":"2025-09-30T11:21:25.000Z","dependencies_parsed_at":"2025-09-30T11:33:34.678Z","dependency_job_id":null,"html_url":"https://github.com/alexykn/whi","commit_stats":null,"previous_names":["alexykn/whicha","alexykn/whi"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/alexykn/whi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexykn%2Fwhi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexykn%2Fwhi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexykn%2Fwhi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexykn%2Fwhi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alexykn","download_url":"https://codeload.github.com/alexykn/whi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alexykn%2Fwhi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278486308,"owners_count":25994945,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","path","path-management","path-manipulation","rust","shell","unix","which"],"created_at":"2025-10-05T17:16:14.082Z","updated_at":"2026-01-20T17:55:15.991Z","avatar_url":"https://github.com/alexykn.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# whi\n\n`whi` is a smarter `which` that also lets you rearrange your current shell's `PATH` safely. Install the shell integration once, run the high level commands (`prefer`, `add`, `move`, `switch`, `clean`, `delete`, `undo`, `redo`, `reset`, `diff`, `apply`, `save`, `load`, `list`, `rmp`, `file`, `source`, `exit`, `var`, `shorthands`), and grab the helper shortcuts if you like terse aliases.\n\n\u003e **Heads up**: mutation commands only run after the integration exports `WHI_SHELL_INITIALIZED=1`. If you see the integration warning, run the snippet for your shell and add it to your config for persistence.\n\n## Install \u0026 Integrate\n\n```bash\ncargo install whi\n```\n\nPick the snippet for your shell and paste it into a terminal. **Add the same line to the END of your shell config** so it runs on startup after all PATH modifications.\n\n```bash\n# Bash\neval \"$(whi init bash)\"      # add to the END of ~/.bashrc (or the file you source)\n\n# Zsh\neval \"$(whi init zsh)\"       # add to the END of ~/.zshrc\n\n# Fish\nwhi init fish | source        # add to the END of ~/.config/fish/config.fish\n```\n\n**Important:** The integration must be at the END of your config so `whi` captures your final PATH after all modifications (homebrew, cargo, etc.).\n\nThe snippet:\n- Loads any previously saved PATH (from `~/.whi/saved_path_*`)\n- Defines helper functions (`whip`, `whiad`, `whia`, `whim`, `whis`, `whiu`, `whir`, `whil`, `whiv`, `whish`, etc.)\n- Exports `WHI_SHELL_INITIALIZED=1` so `whi` knows it's safe to mutate PATH\n- Captures the final PATH as your session baseline for undo/diff tracking\n\n## Core Commands\n\nAll of these operate on the current shell session. Each command prints the updated `PATH`; the integration captures the string and updates `PATH` for you.\n\n### Querying executables\n\n```bash\nwhi cargo                    # show the first match (with PATH index)\nwhi -n cargo                 # no index, same output which gives\nwhi -a cargo                 # show all matches\n# Shorthand: whia\nwhi -an cargo                # all matches, no index\n\n# Fuzzy search fallback (if exact match fails)\nwhi carg                     # finds \"cargo\" via fuzzy matching\n\n# Show full path (line separated)\nwhi -f                       # list all PATH entries\nwhi -fn                      # list all PATH entries, no index\n\n# This is cool ... list all matches, newline, list full path\n# with all path entries containing the binary highlighted\nwhi --full cargo\n```\n\nUseful flags:\n- `-a/--all`\n- `-f/--full`\n- `-l/--follow-symlinks`\n- `-s/--stat`\n- `-0/--print0`\n- `-q/--quiet`\n- `--silent`\n- `--color \u003cauto|never|always\u003e`\n- `--path \u003cPATH\u003e`\n\n### PATH manipulation\n\n```bash\n# Add paths to PATH (prepends by default)\nwhi add ~/.local/bin                 # add single path\nwhi add ~/bin ~/.cargo/bin           # add multiple paths\n# Shorthand: whiad\n\n# Prefer: make an executable win (or add a path)\n# The Swiss Army knife - works with index, path, or fuzzy pattern\n# Makes minimal changes to achieve the goal\n\nwhi prefer cargo 5                   # prefer by index\nwhi prefer cargo ~/.cargo/bin        # prefer by exact path (moves if present)\nwhi prefer cargo ~/new/rust/bin      # adds path if not in PATH (validates cargo exists!)\nwhi prefer cargo toolchain stable    # prefer by fuzzy pattern\nwhi prefer bat github release        # another fuzzy example\nwhi prefer ~/.local/bin              # no executable -\u003e add path (like fish_add_path)\n\n# Move and swap entries by index (1-based)\nwhi move 12 1\nwhi switch 4 9\n\n# Clean duplicates\nwhi clean\n\n# Delete entries\nwhi delete 3 9               # specific indices\nwhi delete ~/.local/bin      # exact path\nwhi delete build temp        # fuzzy - all paths matching pattern\n```\n\n### History \u0026 state management\n\n```bash\n# Undo/redo/reset PATH changes\nwhi undo                     # undo last operation\nwhi undo 3                   # undo last 3 operations\nwhi redo                     # redo next operation\nwhi redo 2                   # redo next 2 operations\nwhi reset                    # reset to initial session state\n\n# Inspect PATH changes\nwhi diff                     # show changes since session start\nwhi diff full                # show all entries (including unchanged)\n```\n\n### Persistence \u0026 profiles\n\n```bash\n# Persist PATH to shell config files\nwhi apply                    # save to current shell's config\nwhi apply fish               # save to specific shell\nwhi apply all                # save to all shells (bash/zsh/fish)\nwhi apply --force [--no-protect]   # required when running inside an active whi venv\n\n# Profile management\nwhi save work                # save current PATH as profile \"work\"\nwhi load work                # load profile \"work\"\nwhi list                     # list all saved profiles\nwhi rmp work                 # remove profile \"work\"\n```\n\n### Environment variables\n\n```bash\n# Query environment variables\nwhi var PATH                 # show PATH variable (exact match, case-insensitive)\nwhi var cargo                # fuzzy search for variables matching 'cargo'\nwhi var -f                   # list all environment variables (sorted)\n# Shorthand: whiv\n\n# Show all available shortcuts\nwhi shorthands               # display table of all whi* shorthands\n# Shorthand: whish\n```\n\n### Virtual environments (venv)\n\n`whi` can create project-specific PATH environments similar to Python virtualenvs or direnv, but for PATH management. This is perfect for projects that need specific tool versions or custom PATH configurations.\n\n```bash\n# Create whifile from current PATH (like requirements.txt for PATH)\nwhi file                     # create whifile in current directory\nwhi file -f                  # force overwrite existing whifile\n\n# Activate venv (read whifile and switch PATH)\nwhi source                   # activate venv from ./whifile\n# Shell shows: [dirname] user@host:~/project $\n\n# Exit venv (restore previous PATH)\nwhi exit                     # deactivate and restore PATH\n```\n\n**How it works:**\n- `whi file` snapshots your current PATH into a `whifile` in the current directory\n- `whi source` reads `whifile` and replaces your PATH (saves old PATH for restore)\n- `whi exit` restores your previous PATH\n- Your shell prompt shows `[venv-name]` when active (like Python venvs)\n- All PATH operations (`prefer`, `move`, `delete`, etc.) work normally inside venvs\n- Venv state is session-specific (different terminals = different venv states)\n\n**Use cases:**\n- Lock tool versions per project (e.g., specific Node, Python, Ruby versions)\n- Isolate project-specific binaries from global PATH\n- Test PATH configurations before applying globally\n- Share reproducible development environments via version control\n\n**Auto-activation:**\nYou can enable auto-activation in `~/.whi/config.toml`:\n```toml\n[venv]\nauto_activate_file = true   # automatically source whifile when entering directories\nauto_deactivate_file = true # automatically run whi exit (and extra exit hooks) when leaving\n```\n\nWhen enabled, the shell integration will automatically activate venvs when you `cd` into directories containing `whifile` and automatically run `whi exit` (including `$source … \u003cexit_command\u003e` hooks and `$pyenv` deactivation) when you leave.\n\n\u003e **Known Issue:** Auto-activation currently does not work in Zsh. Bash and Fish work correctly. For Zsh users, please manually run `whi source` when entering directories with a `whifile`. This will be fixed in a future release.\n\n**whifile format (v2 / 0.6.0+):**\nThe file uses a directive-based format with multiple PATH and ENV strategies:\n```\n# Replace session PATH entirely\n!path.replace\n/usr/local/bin\n/usr/bin\n/bin\n~/custom/bin\n/Users/$USER/.local/bin\n\n# Or prepend to session PATH\n# !path.prepend\n# ~/my-tools/bin\n\n# Or append to session PATH\n# !path.append\n# ~/extra/bin\n\n# Set environment variables\n!env.set\n# Comments are supported\nRUST_LOG debug\nPROJECT_ROOT $(pwd)\nCONFIG_DIR $HOME/.config/myapp\nMY_VAR hello world\n\n# Or replace all env vars (whitelist mode)\n# !env.replace\n# KEEP_THIS value\n# AND_THIS value\n\n# Or unset specific vars\n# !env.unset\n# REMOVE_THIS\n# AND_THIS\n```\n\n**PATH directives (mutually exclusive):**\n- `!path.replace` - Replace session PATH entirely with listed paths\n- `!path.prepend` - Prepend paths to session PATH\n- `!path.append` - Append paths to session PATH\n- Each path is on its own line\n- Supports shell variable expansion: `$VAR`, `${VAR}`, `~`, `$(command)`\n- Variables are expanded when sourcing the venv\n\n**ENV directives:**\n- `!env.set` - Set specific environment variables (default)\n- `!env.replace` - Replace all env vars (whitelist mode, auto-unsets others)\n- `!env.unset` - Unset specific variables\n- Fish-style syntax: `KEY value` (space-separated, no `=` or quotes needed)\n- Supports shell variable expansion: `$VAR`, `${VAR}`, `~`, `$(command)`, `` `command` ``\n- Values can contain spaces, special characters (`:`, `=`, `/`, etc.)\n- Comments start with `#`\n- Variables are set when entering venv, unset when exiting\n\n**Extra directives (optional):**\n- `!whi.extra` - Source scripts or activate Python virtual environments\n- Executed AFTER `!path` and `!env` sections to prevent interference\n- Two directive types:\n  - `$source /path/to/script` – Source any shell script (user's responsibility for shell compatibility). Append an optional exit command to run during `whi exit`: `$source /path/to/script cleanup_command --flag`. The exit command runs before Whi unsets venv variables so you can undo whatever the script configured.\n  - `$pyenv /path/to/venv` – Activate Python venv (auto-detects shell and sources activate/activate.fish). Whi keeps a guard around the virtualenv so calling `deactivate` directly prints `environment managed by whi...`; use `whi exit` (or auto-deactivate) so Whi can restore history and PATH correctly. Regular `$source` directives do **not** install this guard.\n- Supports shell variable expansion: `$VAR`, `${VAR}`, `~`, `$(command)`\n- Python venv example: `$pyenv $(pwd)/.venv` or `$pyenv .venv` (both work)\n- On `whi exit`, runs `deactivate` for Python venvs automatically and executes any `$source … \u003cexit_command\u003e` hooks you defined\n- With `[venv] auto_activate_file`/`auto_deactivate_file` enabled in `config.toml`, the shell integration automatically applies `$pyenv`/`$source` directives (and their exit commands) when you `cd` into or out of a whifile directory.\n\nExample:\n```\n!whi.extra\n$pyenv $(pwd)/.venv\n$source ~/.config/project-setup.sh\n```\n\n**Legacy format support:**\nFiles with `PATH!` and `ENV!` sections (pre-0.6.0) are automatically converted to `!path.replace` and `!env.set` for backward compatibility.\n\n### Shell prompt behaviour\n\nWhi uses virtualenv's standard environment variables (`VIRTUAL_ENV` and `VIRTUAL_ENV_PROMPT`) for venv indication. Modern prompt frameworks (Starship, oh-my-posh, Tide, powerlevel10k, etc.) automatically detect these variables and display the venv indicator in their own style - no manual configuration needed!\n\n`whi --help` shows the verbs (`prefer`, `add`, `move`, `switch`, `clean`, `delete`, `undo`, `redo`, `reset`, `diff`, `apply`, `save`, `load`, `list`, `rmp`, `file`, `source`, `exit`, `var`, `shorthands`). The integration intercepts those public names and rewrites them to the hidden `__…` subcommands that actually mutate the environment.\n\n## Helper Shortcuts\n\nThese are defined by the integration and map directly to the core commands:\n\n```bash\n# whip: Swiss Army knife for PATH management\nwhip cargo 5                 # prefer by index\nwhip cargo ~/.cargo/bin      # prefer by path (adds if needed!)\nwhip cargo toolchain stable  # prefer by fuzzy pattern\nwhip ~/.local/bin            # add path to PATH\n\n# Other shortcuts\nwhia cargo                   # -\u003e whi --all cargo\nwhiad ~/.local/bin ~/bin     # -\u003e whi add ...\nwhim 12 1                    # -\u003e whi move ...\nwhis 4 9                     # -\u003e whi switch ...\nwhic                         # -\u003e whi clean\nwhid 3 9                     # -\u003e whi delete ...\nwhiu                         # -\u003e whi undo\nwhiu 3                       # -\u003e whi undo 3\nwhir                         # -\u003e whi redo\nwhir 2                       # -\u003e whi redo 2\nwhil work                    # -\u003e whi load work\nwhiv PATH                    # -\u003e whi var PATH\nwhiv -f                      # -\u003e whi var -f (list all env vars)\nwhish                        # -\u003e whi shorthands (show all shortcuts)\n```\n\nUse whichever spelling you prefer—both routes converge in Rust.\n\n## Persistence \u0026 State\n\n- **Saved PATH files** live in `~/.whi/` (`saved_path_bash`, `saved_path_zsh`, `saved_path_fish`). `whi apply all` writes to all three. Each save creates a `*.bak` backup before overwriting. Files use a human-friendly directive format with `!path.replace` and `!env.set` sections (v0.6.0+). Legacy `PATH!`/`ENV!` format (pre-0.6.0) and colon-separated files (pre-0.6.0) are automatically detected and supported for backward compatibility.\n\n- **Profile storage** lives in `~/.whi/profiles/`. Each profile is a file in the same human-friendly format as saved PATH files. Use `whi save \u003cname\u003e` to save current PATH as a profile, `whi load \u003cname\u003e` to restore it, and `whi list` to see all profiles. You can manually edit these files - use `!path.replace`/`!path.prepend`/`!path.append` for PATH directives and `!env.set`/`!env.replace`/`!env.unset` for environment variables (all support shell variable expansion).\n\n- **Configuration** lives in `~/.whi/config.toml`. Auto-created on first run with defaults. Controls venv auto-activation and protected paths (preserved during `whi apply` to prevent breaking your shell).\n\n- **Session snapshots** live in `${XDG_RUNTIME_DIR:-/tmp}/whi-\u003cuid\u003e/session_\u003cppid\u003e.log` (or `session_\u003cppid\u003e/\u003cvenv-dir-hash\u003e.log` when in a venv). Each PATH modification writes a snapshot (timestamp + full PATH string). The undo/redo system navigates through these snapshots with a cursor. Sessions keep up to 500 snapshots (initial + last 499) and auto-cleanup old sessions after 24 hours.\n\n- **Undo cursor** lives in `${XDG_RUNTIME_DIR:-/tmp}/whi-\u003cuid\u003e/session_\u003cppid\u003e.cursor` (or `session_\u003cppid\u003e/\u003cvenv-dir-hash\u003e.cursor` when in a venv). Tracks your position in the snapshot history. No cursor file means you're at the latest state.\n\n- **Venv state** (when active) is stored in `${XDG_RUNTIME_DIR:-/tmp}/whi-\u003cuid\u003e/session_\u003cppid\u003e/venv_restore` (PATH to restore on exit), `venv_dir` (venv directory path), and `venv_exit_commands` (any `$source … \u003cexit_command\u003e` hooks). This is session-specific - each terminal has independent venv state.\n\n## How undo/redo works\n\nEvery PATH mutation writes a snapshot. The undo system navigates backwards through snapshots, and redo moves forward. If you undo then make a new change, the \"future\" timeline is discarded (standard undo/redo behavior).\n\n```bash\n# Example session:\n$ whi move 5 1              # snapshot 1 (initial is snapshot 0)\n$ whi delete 3              # snapshot 2\n$ whi undo                  # cursor moves to snapshot 1\n$ whi undo                  # cursor moves to snapshot 0 (initial)\n$ whi redo                  # cursor moves to snapshot 1\n$ whi prefer cargo 2        # snapshot 3 (snapshot 2 discarded, new timeline)\n$ whi reset                 # back to snapshot 0, cursor cleared\n```\n\n`whi diff` compares your current PATH to the initial session snapshot, so it shows **all** changes including manual `export PATH=...` modifications (not just whi operations).\n\n## Notes\n\n- Mutating commands exit with an instructional message if the integration is missing. Copy the snippet shown, run it, and add it to your shell config for future sessions.\n\n- The shell integration uses absolute paths to `whi`, so it continues to work even if PATH is modified or replaced during initialization.\n\n- If you want to script against `whi` directly, capture stdout and export the string yourself. The integration just automates that for interactive use.\n\n## License\n\nMIT License. See [LICENSE](LICENSE) for details.\n\n## Acknowledgments\n\n- Prompt integration approach inspired by [virtualenv](https://github.com/pypa/virtualenv). Thanks to the virtualenv team for their battle-tested solution using `VIRTUAL_ENV` and `VIRTUAL_ENV_PROMPT` environment variables that works seamlessly with modern prompt frameworks (Starship, oh-my-posh, Tide, etc.).\n- The \"whifile\" name was inspired by [just](https://github.com/casey/just)'s \"justfile\" naming convention.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexykn%2Fwhi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexykn%2Fwhi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexykn%2Fwhi/lists"}