IndexSearch is a high-performance search tool tailored for large source trees, designed to accelerate repeated searches by utilizing a persistent project index and a per-project daemon. This approach eliminates the need to scan directories each time, significantly speeding up operations.
Key Features:
Persistent Indexing: Maintains an index across sessions to enable faster subsequent searches.
Daemon-Based Search: Utilizes a per-project daemon to keep indexes up-to-date and serve future queries efficiently.
Multiple Interfaces: Supports 'is' for rg-like usage and 'isgrep' for grep-compatible operations, offering flexibility in command-line interactions.
Winget Installation: Can be installed via winget, ensuring ease of setup for users on compatible systems.
Configuration Options:
Project Rules: Allows customization through .indexsearch/is-project-config.txt to ignore specific paths or file types.
Shell Completions: Provides support for various shells, enhancing user experience with auto-completion features.
Audience & Benefit:
Ideal for developers and teams managing extensive codebases, IndexSearch enhances productivity by reducing search times. It is particularly beneficial for projects with high file activity, offering efficient resource management and quick access to information.
This tool stands out for its efficiency and flexibility, catering to the needs of modern development environments without unnecessary complexity.
README
IndexSearch
IndexSearch is a fast indexed search tool for very large source trees. It is
designed to feel close to rg, but repeated searches use a persistent project
index and a per-project daemon instead of walking the filesystem every time.
Use the short command:
is -n "SomeSymbol" .
is -i -w -g "*.cpp" "render pass" .
is --files .
isgrep -n "A\\|B" file.txt
Install
macOS / Linux:
curl -fsSL https://raw.githubusercontent.com/Abyss116/IndexSearch/main/install.sh | sh
brew tap Abyss116/indexsearch
brew trust Abyss116/indexsearch
brew install indexsearch
brew trust is a one-time local trust grant for the third-party tap. Homebrew
may require it before future brew update / brew upgrade runs can update the
formula.
WinGet, after package-manager moderation has accepted the manifest:
cd /path/to/large/repo
istool index .
is -n "SomeSymbol" .
The first is PATTERN inside a project automatically starts a per-project
daemon. That daemon keeps the index mmaped, watches filesystem changes, serves
future searches, and can compact deltas while idle.
If no IndexSearch project exists above the current directory, interactive is
asks whether to create one in the current directory. Choosing n runs the
current search through the external compatible searcher instead. istool index .
always rebuilds the base index explicitly.
When is or isgrep is used non-interactively by coding agents outside an
IndexSearch project, it does not create project config. The one-off search is
routed internally through rg or grep so the command still returns results
without leaving .indexsearch/ behind.
IndexSearch.paths.live is for high-churn or generated text directories that
should not be persisted into the project index. Explicit searches inside those
paths are routed internally through rg, for example is Error Saved/Logs,
while ordinary project searches stay fast and stable. The bundled Unreal Engine
template uses this for logs and shader debug output, while excluding Saved/
from persistent indexing.
Use **/Name/ for a directory name that should match at any depth, such as
**/DerivedDataCache/. Directory patterns with a trailing slash also cover the
directory's full subtree.
When a command names multiple explicit paths, IndexSearch splits the work: paths
covered by IndexSearch.paths.ignore, IndexSearch.paths.live, or file
include/exclude rules are routed internally through the external stream searcher,
while indexed paths continue through the daemon. is uses rg; isgrep
translates compatible grep syntax to rg as well, and invokes system grep
internally for grep-only features that cannot be translated safely.
For Unreal Engine source trees, copy the bundled template into the project
root's .indexsearch/ directory:
mkdir -p /path/to/UnrealEngine/.indexsearch
cp templates/unreal-engine/is-project-config.txt /path/to/UnrealEngine/.indexsearch/is-project-config.txt
cd /path/to/UnrealEngine
istool index .
When creating a project, IndexSearch writes .indexsearch/.gitignore with *
so local index files stay out of Git status even in repositories that use
allow-list style root .gitignore rules.
If the first interactive search discovers an Unreal Engine root or a .uproject
root, the generated config uses the UE template automatically.
update refreshes an existing index. If the daemon is running, it first flushes
pending filesystem events, so normal edit-and-search workflows stay current
without a full tree scan.
By default, update reconciles against the filesystem for correctness across
Git and non-Git trees. update --git remains an explicit fast path after
git pull, checkout, or rebase. compact folds delta indexes back into the
base index.
rg-Like Usage
Common flags:
is -F "literal" .
is -i "case insensitive" .
is -w Actor .
is -g "*.cpp" Nanite .
is -n -C 3 "SomeSymbol" .
is --json "SomeSymbol" .
is -v -F "exclude this line" .
is --files-without-match "TODO" .
is --count-matches -F "Tick" .
is -x -F "exact whole line" .
When stdout is a terminal, output is grouped by file like rg --heading. When
stdout is captured or piped, output uses flat path:line:match rows. Use
--heading, --no-heading, -n, and -N to override.
For a pattern that starts with punctuation or looks like an option, use --:
is -- "--help" .
Unsupported rg flags are logged in the project log and ignored when that is
safe, so agent and editor integrations can keep running. Use rg for PCRE-only
patterns, multiline matching, preprocessors, archive search, or other behavior
that must exactly match ripgrep.
grep-Compatible Usage
Use isgrep when replacing an existing grep command or when you want grep
option spellings:
isgrep defaults to grep Basic Regex syntax, so A\|B is translated to the
Rust regex alternation used by IndexSearch. For rg-style, RTK grep-style, or
extended-regex patterns with bare A|B alternation, keep or add -E; plain
isgrep "A|B" follows grep BRE semantics and searches for a literal |.
It also maps grep-specific flags whose meanings conflict with is, such as
grep -h and grep -L. For grep semantics that the indexed backend cannot
provide, such as PCRE mode, backreferences, or null-data mode, isgrep falls
back to the system grep when available.
For pipeline input, the persistent project index is not used. is forwards
rg-style stdin searches to rg; isgrep translates compatible grep-style
stdin searches to rg too, and uses system grep only for grep-only semantics:
Claude Code installs get an additional guardrail: istool install-skills --target claude copies a PreToolUse hook that blocks bare Bash rg/ripgrep
and grep/egrep/fgrep commands. Retry ordinary local source searches with
is or isgrep; they route stdin, live/generated paths, ignored explicit
paths, and compatible translated grep syntax through the necessary external
search internally. Exit code 1 with no output means no matches, not a reason to
rerun the same local search with bare rg or grep.
Profiling
istool index --profile .
istool update --profile .
is --profile -n -g "*.cpp" Nanite .
profile: lines are printed to stderr and are intended for sharing performance
reports from large repositories.
Performance Snapshot
Local Unreal Engine benchmark on macOS, hot filesystem cache. The is column
uses median is --stats search time with stdout discarded, matching the timing
shown by the CLI. qgrep, rg, and grep columns are median process wall times.
The grep column uses macOS /usr/bin/grep over the same pre-enumerated
benchmark file set because BSD grep does not provide recursive include/exclude
glob options.
Workload
is
qgrep
rg
grep
vs qgrep
vs rg
vs grep
Fresh index / qgrep update
10.56s
18.28s
n/a
n/a
1.7x
n/a
n/a
Nanite
3.71ms
23.47ms
2784.08ms
32528.27ms
6.3x
751x
8772x
SkeletalMeshComponent
3.33ms
18.04ms
2769.81ms
33534.75ms
5.4x
832x
10067x
missing literal
0.08ms
14.86ms
2767.36ms
33634.95ms
186x
34592x
420437x
qualified-call regex
77.61ms
358.93ms
3030.85ms
85606.64ms
4.6x
39x
1103x
Nanite in *.cpp
1.96ms
24.03ms
967.51ms
5492.97ms
12.2x
493x
2797x
The unrestricted rows use each tool's closest CLI-equivalent filtering rules,
so matched-line counts can differ slightly. The *.cpp row is a stricter
same-file-set comparison and matched 10,136 lines for all four tools.
cargo build --release
cargo test --locked
./tests/smoke.sh
./target/release/istool --version
Local builds append build metadata to the displayed version, for example
0.4.8+build.1770000000.g8d2644d.dirty. The package/release version remains
plain SemVer for package managers.
Tagged pushes create GitHub Releases with Linux, macOS, and Windows archives.
Agent Skills
Bundled instructions for Codex, Claude Code, OpenCode, and Cursor can be
installed with:
Claude Code is the strictest target because it supports a PreToolUse hook for
Bash commands. Codex and OpenCode receive skill/AGENTS.md instructions, and
Cursor receives an always-on rule file; those surfaces guide the agent but do
not provide the same hard interception as Claude's hook.
License
IndexSearch is distributed under the terms of both the MIT license and the
Apache License 2.0. You may choose either license; see LICENSE-MIT and
LICENSE-APACHE.
The references to ripgrep and qgrep are compatibility and benchmark references
only; their source code is not vendored into IndexSearch.