Cross-platform shell autocomplete — a Rust port of Microsoft's inshellisense.
Type a partial command, see the best completion appear in grey after the
cursor, press → to accept. Same PowerShell PSReadLine feel, implemented
as a PTY wrapper around your existing shell. Linux, macOS, and Windows.
$ git ch█eckout ← grey suggestion ─ press → to accept
Close behavioral parity with upstream inshellisense, validated against the
upstream binary across the complete suggestion engine, CLI surface, and shell
init. The checked-in parity corpus passes 117/117 cases; cargo test runs 320
tests. 1470 specs are bundled (zstd-compressed), lazy-loaded on demand with
zero-copy byte slice indexing, and extracted statically; offline gaps that would
need live process state or opaque JS closures are handled with Rust-native
generators or documented as runtime boundaries. Pure Rust — no JS runtime, no
Node.js. 28 crates. Supports bash, zsh, fish, pwsh, powershell, xonsh, nushell,
and cmd.exe (Windows).
If an installed coreutils build is on PATH — Microsoft's
Coreutils for Windows, or upstream uutils/coreutils — its commands are
detected and completed too.
| Platform | Status |
|---|---|
| Linux | Fully tested |
| macOS | Compiles (POSIX-compatible), needs field testing |
| Windows 10+ | Field-tested (ConPTY, PowerShell + Git Bash in Windows Terminal). The console input layer was reworked recently and is cross-compile-checked and unit-tested, but that rework has not been run on Windows hardware. |
Measured on Linux x86-64, release build:
| Binary | 6.1 MB (3.8 MB of that is the embedded zstd spec bundle) |
| Resident memory, wrapped shell idle | ~75 MB |
| Peak memory, during cold startup | ~137 MB (down from ~216 MB via zero-copy byte slice indexing) |
is complete 'git ch' (cold, one-shot) |
~140–160 ms (down from ~220 ms) |
is init <shell> (shell init) |
3.5 ms, 2.9 MB RAM (34x faster than upstream) |
| Wrapped shell prompt | appears immediately; the spec registry loads on a background thread |
Memory is optimized via zero-copy byte slicing: the 3.8 MB zstd bundle decompresses
into a single buffer while the index maps command names directly to (offset, len)
slices, eliminating 1,470 separate heap allocations and reducing peak memory by ~80 MB.
The existing options in bash:
| Tool | Suggests new commands? | Runtime |
|---|---|---|
bash-completion |
only what you've typed before | shell |
ble.sh |
history only | shell |
fzf |
history only | native |
| Microsoft inshellisense | yes, via Fig specs | Node + V8 |
| inshellisense-rs | yes, via Fig specs | native Rust binary |
The positioning: inshellisense's feature set without the Node runtime.
cargo install --path .
is init bash --install-rc # appends the bash init snippet to ~/.bashrc--install-rc can write the snippet for bash, zsh, fish, and xonsh.
pwsh, powershell, and nu resolve their profile path at runtime, so for
those run is init <shell> and paste the printed line into your profile.
Or use the legacy bash auto-start wrapper:
cargo build --release
install -m 755 target/release/is ~/.local/bin/is
is install # appends an exec wrapper to ~/.bashrcexec is start # drop into a wrapped bash in the current terminalis start # run wrapped shell (the real thing)
is start --ui popup # popup UI instead of the default hybrid
is start --shell zsh # wrap a specific shell
is doctor # health checks + resolved configuration
is specs list # enumerate loaded commands
is complete 'git ch' # offline query → JSON (upstream's schema)
is complete 'git ch' --text # offline query → just the ghost-text tail
is init bash # print the init snippet for ~/.bashrc
is init bash --install-rc # write the bash init snippet into ~/.bashrc
is reinit # regenerate init files and re-unpack resources
is uninstall # remove cached resources (keeps user config)
is install # legacy: auto-start wrapper in ~/.bashrcis start exits with the wrapped shell's exit status, so it composes in
scripts: is start --shell bash <<< 'exit 42' exits 42.
Arguments a subcommand does not implement are rejected rather than ignored —
notably, is uninstall --dry-run fails instead of quietly uninstalling.
Ghost text (--ui ghost, and the ghost half of the default hybrid):
| Key | Action |
|---|---|
→ / End / Ctrl-E |
Accept the current ghost suggestion |
Popup (--ui popup, and the popup half of hybrid):
| Key | Action | Config key |
|---|---|---|
↓ |
Next suggestion | bindings.next_suggestion |
↑ |
Previous suggestion | bindings.previous_suggestion |
Tab |
Accept the selected suggestion | bindings.accept_suggestion |
Esc |
Dismiss until the line changes | bindings.dismiss_suggestions |
Everything else is forwarded to the shell unchanged.
~/.config/inshellisense-rs/rc.toml (%APPDATA%\inshellisense-rs\rc.toml on
Windows). Upstream's ~/.inshellisenserc and
~/.config/inshellisense/rc.toml are also read, for migration. Both camelCase
and snake_case keys are accepted; unknown keys are reported by is doctor.
# Values shown are the defaults.
ui = "hybrid" # "ghost" | "popup" | "hybrid"
max_suggestions = 5
use_nerd_font = false # Nerd Font glyphs instead of emoji in the popup
use_aliases = false # resolve shell aliases before completing
[specs]
path = ["/extra/spec/dir"]
[bindings]
next_suggestion = { key = "down", shift = false, control = false }
previous_suggestion = { key = "up", shift = false, control = false }
accept_suggestion = { key = "tab", shift = false, control = false }
dismiss_suggestions = { key = "escape", shift = false, control = false }Environment variables:
| Variable | Effect |
|---|---|
INSH_RS_SPECS_DIR |
Extra directory of JSON specs to load |
INSH_RS_NO_COREUTILS |
Skip coreutils detection |
ISTERM / INSH_RS |
Set inside a wrapped session; used as the re-entry guard |
Drop TOML files in ~/.config/inshellisense-rs/specs/ to add or override commands.
The schema mirrors the Rust model in src/spec/model.rs.
Additional JSON spec directories can be loaded with INSH_RS_SPECS_DIR or the
[specs].path array in ~/.config/inshellisense-rs/rc.toml.
# ~/.config/inshellisense-rs/specs/hello.toml
names = ["hello"]
description = "Say hello"
[[subcommands]]
names = ["world"]
description = "Say hello to the world"
[[subcommands]]
names = ["kitty"]
description = "Say hello to a cat"Microsoft's Coreutils for Windows
ships one multi-call binary with a hardlink per utility, bundling coreutils,
findutils and a GNU-compatible grep. It is a build of
uutils/coreutils, so the same detection
works for uutils on Linux and macOS.
We do not bundle these tools — we describe whichever one is installed. When a
coreutils binary is on PATH:
- A
coreutilsspec is registered whose subcommands are whatevercoreutils --listreports, socoreutils ls --<TAB>completesls's options. Microsoft's fork dropstimeout,killandchmod— they collide with Windows built-ins — and addsfind,xargsandgrep. - Utilities the bundled Fig corpus does not cover get a spec synthesized from
their
--help—b2sum,numfmt, thesha*sumfamily and the rest. On a uutils 0.9.0 install that is 50 of its 107 utilities; Microsoft's fork ships a different set, which is why the list is read from the binary rather than hardcoded. - For a utility the corpus does cover, the options the installed binary
actually accepts are merged in. Fig's
lsspec is BSD-flavored: it knows-abut not--all, sols --all<TAB>used to complete nothing on a coreutils system. Merging keeps Fig's curated descriptions and folds the missing long forms into the existing options.
The merge only happens after confirming the command on PATH really is that
binary, by comparing <util> --version against coreutils <util> --version.
Results are cached under ~/.inshellisense/coreutils/, keyed by the binary's
size and mtime, so the steady-state cost is zero subprocesses.
INSH_RS_NO_COREUTILS=1 disables detection; is doctor reports what it found.
┌─────────────────┐ bytes ┌────────────────┐
│ user's terminal │──────────▶│ platform PTY │
│ │ │ (shell wrapper)│
│ │◀──────────│ │
└────────┬────────┘ bytes └───────┬────────┘
│ │
▼ ▼
┌──────────┐ ┌───────────────┐
│ renderer │◀──────────────│ vt100 tracker │
│ (ANSI) │ suggestion │ + command mgr │
└──────────┘ ▲ └───────┬───────┘
│ │ command state
│ ▼
│ ┌────────────────┐
└────────────│ suggest engine │ ← worker thread
│ + spec walker │
└────────────────┘
The suggestion engine parses the current command-line state using a
tokenizer and resolver ported from inshellisense, walks a registry of
Fig.Spec-shaped specs, and returns a ranked Vec<Suggestion>. The
renderer picks the top suggestion and emits grey-foreground ANSI that
positions at the cursor via save/restore.
Suggestions are computed off the event loop. Spec generators shell out
(git branch, docker ps) with a 5-second default timeout, so running them
inline would freeze keystrokes for as long as the slowest one took.
inshellisense-rs aims for behavioral parity with Microsoft's inshellisense on the specs it covers. Where it differs:
| inshellisense | inshellisense-rs | |
|---|---|---|
| Runtime | Node + V8 | native Rust binary |
| Shell support | bash, zsh, fish, pwsh, nu, xonsh, cmd | bash, zsh, fish, pwsh, powershell, xonsh, nu, cmd |
| Fig spec coverage | ~715 specs via dynamic import | 1470/1470 loaded (100.0%) via the static extractor |
| JS runtime for opaque closures | always on (Node) | none — pure Rust static extraction only |
| Coreutils / uutils detection | no | yes |
| Ghost-text rendering | yes | yes |
| Right-arrow to accept | yes | yes |
Measured on Linux x86-64 (median of 20 runs, release build):
| Command / Scenario | Microsoft @microsoft/inshellisense |
inshellisense-rs |
Speedup | Memory (Ours vs Upstream) |
|---|---|---|---|---|
--version check |
103 ms | 1.5 ms | 66x faster | 2.6 MB vs 69 MB (26x less) |
--help output |
106 ms | 1.4 ms | 72x faster | 2.6 MB vs 73 MB (28x less) |
init bash (rc wrapper) |
115 ms | 3.5 ms | 33x faster | 2.9 MB vs 74 MB (25x less) |
init zsh (rc wrapper) |
120 ms | 3.7 ms | 32x faster | 2.9 MB vs 74 MB (25x less) |
complete "npm install " |
624 ms | 191 ms | 3.3x faster | 138 MB vs 75 MB |
complete "kubectl get " |
200 ms | 158 ms | 1.3x faster | 136 MB vs 75 MB |
Interactive typing (is start) |
V8 GC jitter | < 1 ms deterministic | Real-time | Zero GC pauses |
| Phase | Goal | Status |
|---|---|---|
| 1 | Schema v2 + tokenizer + resolver | ✅ done |
| 2 | Vec<Suggestion> output + concurrent multi-generator exec |
✅ done |
| 3 | Extractor tool + spec loader + 715+ spec coverage | ✅ done |
| 4 | PostProcessKind DSL + lazy LoadSpec + extractor isolation |
✅ done |
| 4.5 | Extractor identifier + property-access resolution | ✅ done |
| 4.6 | Static factory evaluator + template folding → 97.1% coverage | ✅ done |
| 5 | Initial parity corpus + GitHub Actions CI gate | ✅ done |
| 6.1 | createVersionedSpec handler → 97.6% |
✅ done |
| 6.2 | ProjectFile + FileExistsThen generators + shorthand fix → 99.86% pure / 100% loaded |
✅ done |
| 6.6 | Parity expansion to 117 cases + CI threshold tightening | ✅ done |
| 6.7 | Audit remediation for CLI/config/completion/terminal edge cases | ✅ done |
| 6.8 | Full-repo audit: 45 root causes across runtime, extractor, parity scanner, and CI | ✅ done |
| 6.9 | Coreutils / uutils detection and --help-derived specs |
✅ done |
| 7.0 | Upstream parity matching (v0.0.4) + extractor toolchain (TS 7, ts-morph 28) | ✅ done |
| — | Zero-copy byte slice indexing (cutting peak RAM by ~80 MB and eliminating 1,470 heap allocations) | ✅ done |
rquickjs JS runtime for opaque closures |
dropped — pure Rust path reached 99.86% |
inshellisense-rs stands on the shoulders of:
- inshellisense by Microsoft — the algorithmic design, the shell integration protocol, the parser/resolver reference implementation.
- @withfig/autocomplete by Hercules Labs (Fig, now AWS) — the ~715 completion specs that make this useful on real commands.
- bash-preexec by Ryan Caloras — the precmd/preexec plumbing for the shell integration.
- uutils/coreutils and Microsoft's Coreutils for Windows — the utilities detected and completed at runtime.
All are MIT licensed. See NOTICE for full attribution and LICENSES/ for upstream license texts.
inshellisense-rs is not affiliated with Microsoft, Amazon, Fig, or Hercules Labs. "IntelliSense" is a registered trademark of Microsoft Corporation.
MIT — see LICENSE.