Local searchable index of all your git repos. Combines FTS5 keyword search with semantic vector search (via Ollama) so you can find repos by name, tag, or plain English description like "something that monitors kubernetes pods".
- Prerequisites
- Installation and Usage
- CLI
- Configuration
- Files
- Search
- Tag Generation
- Duplicate Detection
- Interactive Duplicate Cleanup
- Deduplication
- Python 3.10+ (stdlib only — no pip installs required)
- Ollama with
nomic-embed-text— installed automatically on first run if missing
| Platform | Status |
|---|---|
| Linux | ✅ Fully supported |
| macOS | ✅ Fully supported (Homebrew used for Ollama install) |
| Windows (native) |
On Windows, install WSL and run repo-browser inside it as you would on Linux.
Download the latest release tarball from the Releases page and extract it:
cd ~/bin
tar xzf RepoBrowser-1.0.1.tgz
ln -sfn RepoBrowser-1.0.1 RepoBrowser
ln -sf ~/bin/RepoBrowser/repo-browser.py ~/bin/repo-browser.pyThe RepoBrowser symlink makes future upgrades a one-liner — just extract the new tarball and update the symlink.
Set up a stable data directory so your database survives upgrades:
mkdir -p ~/.local/share/repo-browserCreate /etc/rb.config:
sudo cp ~/bin/RepoBrowser/rb.config.example /etc/rb.config
sudo vi /etc/rb.configSet these two values:
gitParent=/path/to/your/git/repos
workDir=/home/youruser/.local/share/repo-browser
Start the server and scan:
repo-browser.py start
repo-browser.py rescanOpen http://localhost:8642 — your repos are now searchable.
Upgrading: extract the new tarball, update the
RepoBrowsersymlink, and runrepo-browser.py rescan. Your database and config are untouched.
repo-browser.py start # start server on :8642
repo-browser.py stop # stop server
repo-browser.py restart # stop + start
repo-browser.py status # PID, config source, repo/tag/embed counts
repo-browser.py rescan # re-scan git dir + re-embed (server stays up)
repo-browser.py duplist # report duplicate clones to ~/Clone-Duplist.txt
repo-browser.py dupclean # interactive TUI to delete duplicate clonesThe config file is read from /etc/rb.config. If not found, the script falls back to rb.config in its own directory. If neither exists, the server starts with defaults and serves the settings UI so you can create one.
# /etc/rb.config
gitParent=/home/user/git
workDir=/home/user/bin/repo-browser
rb.config.example is the template included in the repo. Your local rb.config is gitignored.
| File | Purpose |
|---|---|
repo-browser.py |
Cross-platform launcher — start/stop/restart/status/rescan/duplist/dupclean |
scan_repos.py |
Walks gitParent, extracts metadata, auto-generates tags, deduplicates by remote URL, populates SQLite |
embed_repos.py |
Generates semantic embeddings via Ollama nomic-embed-text |
repo_search.py |
HTTP server on port 8642 — search API + settings API + serves UI |
index.html |
Single-page frontend with search, tag cloud, settings modal |
find-dupe.py |
Reports duplicate repo clones across category folders |
dupe_clean.py |
Curses TUI — interactively select which duplicate clone to delete per repo |
rb_config.py |
Shared config loader used by all scripts |
rb.config.example |
Template config (copy to /etc/rb.config) |
repos.db |
SQLite database (gitignored, regenerated by scan) |
Three modes (toggle in the UI header):
- keyword — FTS5 full-text search across repo name, description, README, and tags
- semantic — cosine similarity on
nomic-embed-textvectors via Ollama. Finds conceptually related repos even without keyword overlap - both (default) — weighted blend: 20% keyword + 30% semantic + 20% name match + 30% tag match
Scoring signals:
- Exact name match gets highest priority
- Substring name match (e.g. "MonVisor" finds "MonVisor-Corpus")
- Tag match (searching "rust" prioritises repos tagged
rust) - Semantic-only results are filtered below a 0.65 cosine threshold to reduce noise
Tags are auto-generated on scan from multiple sources:
- File extensions —
.py→python,.go→golang,.rs→rust,.tf→terraform, etc. - README keywords — matches against ~80 known infra/tool terms (kubernetes, docker, prometheus, ansible, etc.)
- Directory category — parent folder name becomes a tag (e.g.
security-automation/) - Special files — Dockerfile→docker, Jenkinsfile→jenkins, ansible.cfg→ansible
Tags sourced as auto are regenerated on every scan. Manual tags (source manual) are preserved across rescans.
If you organise repos into category folders, the same repo may end up cloned in multiple places. The duplist command finds these and writes a report to ~/Clone-Duplist.txt:
repo-browser.py duplistOutput example:
App Name Loc1 Loc2 Loc3
---------------------------------------------------------------------
bash-textgen bash learning machine-learning
kubernetes-chatgpt-bot kubernetes robusta
WSL-Hello-sudo WSL security-automation
Locations are directory names under gitParent. Duplicates are detected by normalised remote URL, with a fallback to name matching for repos without a remote.
Note: the scanner's rescan command also deduplicates automatically — it keeps one copy (the deepest/most specific path) and removes the others from the search index. The duplist report shows you what's on disk. Use dupclean to interactively remove the extras.
dupclean opens a curses TUI that walks you through each duplicated repo one at a time:
repo-browser.py dupcleanFor each repo with duplicates you see all clone paths and pick which one to keep. Keys:
| Key | Action |
|---|---|
| ↑ / ↓ or k / j | Move cursor |
| Space | Mark path to keep |
| Enter / → / n | Confirm selection and proceed to deletion |
| S | Skip this repo (leave all copies, move on) |
| Q / Ctrl-C | Quit cleanly |
After confirming, you are prompted to confirm each individual deletion before anything is removed. Run repo-browser.py rescan afterwards to update the search index.
Many repos exist in multiple category folders. The scanner deduplicates by:
- Normalising remote URLs (
git@↔https://, trailing.git) - Grouping repos with the same URL
- Keeping the deepest path (most specific category folder)
- For repos without a remote, deduplicating by name
Stale entries (removed or deduped repos) are cleaned from all tables including FTS5 on every scan.

