Search. Pick. Fix. Fly.
A unified terminal workflow — ripgrep speed, fzf UX, thefuck smarts — in two keystrokes.
tn s auth · tn fl · tn f · tn
Thunder replaces the trio of tools you reach for dozens of times a day:
| You used to run | Now run |
|---|---|
rg foo | fzf |
tn s foo |
fd | fzf |
tn fl |
thefuck |
tn f |
fzf on history |
tn h |
| Everything at once | tn |
One binary. Two letters. Zero friction.
- Warm index daemon — sub-millisecond literal search on repeated queries via
thunderd - Streaming ripgrep search — regex queries stream into the picker as matches arrive
- Parallel index build — rayon-powered initial indexing for large repos
- Memory-mapped line corpus — line text stored on disk, mmap'd at search time
- Query router — bare
tn <query>routes to search, files, or history automatically - Git-aware palette — modified/staged files ranked higher
- Project scripts —
package.jsonand Makefile targets in the omni palette - Palette plugins — shell commands in config emit custom palette entries
- Config hot-reload — edits to
config.tomlpicked up without restart - Windows daemon — TCP transport on Windows (Unix socket on macOS/Linux)
- Fix rules crate —
thunder-fix-rulesisolates native correction rules - Daemon-backed file finder —
tn fllists files from the warm index when available - Ripgrep fallback — full regex power when the index isn't enough
- Embedded skim picker — fzf-quality TUI with a minimal monochrome theme (no clutter)
- Smart omni palette — history, recent files, and project files ranked by frecency
- 11 native fix rules — git, sudo, cd, npm, docker, python, cargo, pip, kubectl, brew, man
- Per-project daemon — each repo gets its own socket and index
- Trigram-accelerated index — fast candidate filtering on large codebases
- Fuzzy file matching — subsequence scoring for
tn fland palette - Shell integration — zsh, bash, fish with stderr capture for smart fixes
- Security hardened — preview validation, path sandboxing, dangerous command blocking
Thunder 2.0 ships with a clean monochrome TUI. Configure in ~/.config/thunder/config.toml:
[theme]
preset = "minimal" # minimal | bw | dark
minimal_chrome = true # hide match-count spinner line
[search]
streaming = true # stream ripgrep results into picker
multi_select = false # allow selecting multiple search results
[palette]
plugin_commands = [] # e.g. ["./scripts/my-palette.sh"]curl -fsSL https://raw.githubusercontent.com/desenyon/thunder/main/scripts/install.sh | bashThis will:
- Install Rust (via rustup) and ripgrep if missing
- Clone/update Thunder to
~/.local/share/thunder - Build and link
tn,thunder,thunderdto~/.local/bin - Write default config (
tn c --init) - Add PATH + shell hooks to your
~/.zshrc,~/.bashrc, or fish config
Then activate in your current shell:
export PATH="$HOME/.local/bin:$PATH"
eval "$(tn i zsh)" # or bash / fish
tn docgit clone https://github.com/desenyon/thunder.git
cd thunder
cargo build --release
export PATH="$PWD/target/release:$PATH"
tn c --init
eval "$(tn i zsh)" # add to ~/.zshrcRe-run the one-liner — it pulls latest and rebuilds:
curl -fsSL https://raw.githubusercontent.com/desenyon/thunder/main/scripts/install.sh | bash| Tool | Required | Purpose |
|---|---|---|
rg (ripgrep) |
Yes | Regex search fallback |
bat |
No | Nicer previews (auto-detected) |
thefuck |
No | Extended fix fallback |
fzf |
No | Alternative picker backend |
| Command | What it does |
|---|---|
tn |
Omni palette (files + history) |
tn QUERY |
Search + pick results |
tn s QUERY |
Search codebase |
tn fl [QUERY] |
Fuzzy-find files |
tn h [QUERY] |
Search command history |
tn f |
Suggest fix for last command |
tn f -y |
Apply fix immediately |
| Command | What it does |
|---|---|
tn s QUERY --open |
Search and open in $EDITOR |
tn s QUERY --json |
JSON output for scripting |
tn pal --execute |
Palette with immediate actions |
tn d st |
Start index daemon |
tn d ss |
Daemon status |
tn d sp |
Stop daemon |
tn d rs |
Restart daemon |
tn d ri |
Force reindex |
tn doc |
Health check / diagnostics |
tn cmp zsh |
Shell completions |
After eval "$(tn i zsh)":
ts QUERY → tn s QUERY search
tp → tn p pick
tf → tn f fix
tfl → tn fl files
th → tn h history
td → tn d daemon
tpal → tn pal palette
tdoc → tn doc doctor
fix → tn f (supports -y)
flowchart LR
Q[tn s query] --> L{literal query?}
L -->|yes| D{daemon warm?}
L -->|no regex| R[ripgrep]
D -->|yes| I[thunderd trigram index]
D -->|no| R
I --> P[skim picker]
R --> P
P --> O[--open in EDITOR]
Literal queries hit the warm per-project index first. Regex or cold starts fall back to ripgrep. Results flow into skim for interactive picking.
Config path: ~/.config/thunder/config.toml
[general]
editor = "nvim" # override $EDITOR
open_on_select = false # open files after search pick
[search]
use_daemon = true
fallback = "rg"
max_file_size_bytes = 2097152
max_results = 500
[pick]
height = "60%"
preview = "bat -n --color=always {1}" # auto-detected if omitted
use_fzf = false
reverse = true
prompt = "> "
[fix]
use_thefuck_fallback = true
enabled_rules = ["git", "sudo", "cd", "npm", "docker", "man", "python", "cargo", "pip", "kubectl", "brew"]
[daemon]
auto_start = true
max_results = 500
[history]
max_entries = 2000
palette_limit = 200- Preview commands validated against shell injection
- Index paths cannot escape project root (
..blocked) - Fix corrections blocked for dangerous patterns (
rm -rf /, etc.) - Multiline commands rejected on apply
- Daemon sockets created with
0600permissions - Explicit
-y/--applyrequired to run corrections
cargo build # debug build
cargo test # unit + integration tests
./scripts/qa.sh # full end-to-end QA
tn doc # local health checkthunder/
├── thunder-cli/ tn + thunder binaries
├── thunder-core/ config, history, security, editor
├── thunder-search/ ripgrep + daemon routing, file search
├── thunder-index/ thunderd daemon, trigram index
├── thunder-pick/ skim / fzf wrapper
└── thunder-fix/ native rules + thefuck fallback
Built on excellent open source:
See NOTICE for licenses.
MIT — see LICENSE.