A fuzzy, recursive cd replacement.
Type a few letters, land several directories deep — not just the immediate
children cd's own tab-completion gives you.
curl -fsSL https://raw.githubusercontent.com/iwandejong/i/main/install.sh | shi # cd $HOME, same as plain `cd`
i test # cd to the best fuzzy match for "test" under $PWD
i ../project # scoped one level up first, then fuzzy-searching "project"
i te<TAB> # cyclable menu of the top matches, non-contiguous chars highlighted
i -2 # cd up 2 directories (../..)- Scoped to
$PWD, not your whole home directory — and matches at any depth, not just immediate children. - Live navigation while typing:
../rescopes to the parent (repeat for further up),~/jumps home,/jumps to filesystem root. Whatever follows the last/is the fuzzy query. - Ranked sensibly: an exact path match always wins outright; otherwise name matches beat full-path matches, and shallower results beat deeply-buried ones (cache dumps, app-support ephemera) when scores are close.
- No daemon, no whole-disk cache — each root is walked live, per query.
There's no full-screen picker UI: the i binary just prints its best
match(es) and exits, and the shell wrapper cds to whatever came back
(or hands zsh a real completion menu for <TAB>). A fully-typed,
unambiguous path resolves and cds there directly, no fuzzy noise mixed in.
One-liner (no Rust required, macOS/Linux) — downloads the right prebuilt
binary (macOS x86_64/arm64, Linux x86_64), installs it to ~/.local/bin,
and wires up zsh or bash integration:
curl -fsSL https://raw.githubusercontent.com/iwandejong/i/main/install.sh | shRestart your shell (or source ~/.zshrc/~/.bashrc) and you're done.
One-liner (Windows, PowerShell) — same idea, installs to
~\.local\bin and wires up your $PROFILE:
irm https://raw.githubusercontent.com/iwandejong/i/main/install.ps1 | iexRestart PowerShell (or . $PROFILE) and you're done.
Manual install, or building from source
Prebuilt binary — grab the tarball for your platform from the
latest release. Each one
bundles the i binary plus i.zsh/i.bash/i.ps1 (the shell wrappers):
tar xzf i-<target>.tar.gz
cp i-<target>/i ~/.local/bin/i # i-<target>/i.zsh is what you'll `source` belowOn Windows, install.ps1 (above) does this for you; by hand, put i.exe
somewhere on your PATH and dot-source i.ps1 from your $PROFILE (see
Shell integration below).
From source — requires Rust (stable, 1.75+):
git clone https://github.com/iwandejong/i.git && cd i
cargo build --release
cp target/release/i ~/.local/bin/iThe i binary only prints matching paths — it can't change your shell's
directory itself. install.sh wires this up automatically on macOS/Linux;
by hand:
# ~/.zshrc
source /path/to/i/shell/i.zsh
# ~/.bashrc
source /path/to/i/shell/i.bash# $PROFILE
. /path/to/i/shell/i.ps1Rename the i function in any wrapper to whatever you'd rather type — the
binary can stay named i either way, since the wrappers call it
explicitly (command i, or i.exe in PowerShell, where a same-named
function would otherwise call itself). zsh, bash, and PowerShell all ship;
bash and PowerShell get plain-list <TAB> completion (no menu-select or
fuzzy-char highlighting — neither completion system supports that). fish
isn't supported, but a port would be straightforward:
function i; set d (command i $argv); and cd $d; end, minus completion.
Config
Optional JSON config, all fields optional (a partial file only overrides
what it sets, the rest falls back to defaults). A lean starter file with
just the scalar knobs (include_hidden, max_depth, max_entries) is
created automatically on first run — excludes is deliberately left out of
it so a future default change to that list still applies; add it yourself
if you want to override it. Location follows the platform config dir +
i/config.json, that's ~/Library/Application Support/i/config.json on
macOS, ~/.config/i/config.json on Linux, %APPDATA%\i\config.json on
Windows. Run i --config to print the
full effective config (defaults merged with your overrides) and where the
file lives. Shown below with defaults:
{
"excludes": [".git", ".hg", ".svn", "node_modules", ".venv", "venv",
"__pycache__", "target", ".cache", ".npm", ".cargo",
".rustup", ".Trash", "dist", "build", "proc", "sys", "dev",
"Library"],
"include_hidden": false,
"max_depth": 5,
"max_entries": 50000
}excludes— directory names pruned entirely (never listed, never descended into), applied everywhere a walk can reach as you go../.include_hidden— settrueto also walk into dot-directories.max_depth/max_entries— safety caps so~/or/on a huge tree doesn't hang; you still get whatever it collected before hitting the cap.
How path navigation is parsed
See src/pathnav.rs (has unit tests) — each /-terminated segment is
checked in order: .. pops the root up one level, ~ (only as the very
first character) jumps to $HOME, a leading / jumps to filesystem root,
and any other segment is consumed only if it's an exact, existing child
directory — otherwise parsing stops and everything from there on is the
fuzzy query. That's what lets ../test mean "go up one, then fuzzy-search
test" without a query that merely contains a slash getting misparsed as
navigation.
Project layout
src/
main.rs — CLI entry (clap), wires config + walker + search together
config.rs — loads i/config.json from the platform config dir, defaults
pathnav.rs — parses typed text into (resolved root, fuzzy query)
walker.rs — recursive directory walk with prune-list + safety caps
search.rs — fuzzy scoring, sorting, exact-match and depth preference
tests/
walker_smoke.rs — confirms excludes prune subtrees, deep dirs still surface
shell/
i.zsh — the `i` wrapper function that actually cd's, plus completion
i.bash — bash equivalent (plain-list completion, no menu-select)
i.ps1 — PowerShell equivalent (plain-list completion, no menu-select)
install.sh — one-command installer for macOS/Linux (binary + shell integration)
install.ps1 — one-command installer for Windows (binary + PowerShell integration)
Known limitations
- No frecency ranking (most-recently/often visited dirs) — pure fuzzy score today.
- No
.gitignoreawareness — exclusion is the flatexcludeslist only. - Symlinked directories are skipped outright (avoids cycles).
- No prebuilt Linux or Windows arm64 binary yet — build from source there.
- zsh, bash, and PowerShell ship; fish ports are welcome contributions.
See CONTRIBUTING.md.