Search your files from the command line — ranked by relevance

by Priya Sundaram · 15 July 2026
grep, but ranked. Whoosh ships a small command-line tool that indexes a folder and searches it, returning results ordered by relevance (BM25) rather than raw line-by-line matches. It's pure Python — no compiler, no server, no native dependencies — so it's one pip install whoosh3 away on any machine that has Python.

grep and ripgrep are brilliant at what they do: find every line that matches a pattern, fast. But sometimes that isn't the question you're asking. When you type a couple of words into a notes folder or a docs tree, you usually don't want every line that mentions them — you want the few files that are most about them, best first. That's a ranking problem, and it's exactly what a full-text index is for.

The whoosh CLI gives you that with three commands: whoosh index to build the index, whoosh search to query it, and whoosh stats to inspect it. Here's the whole thing, start to finish.

Install

pip install whoosh3

That's it — no build step. It installs a whoosh console script. (The distribution is named whoosh3 on PyPI; the import name and the command are both whoosh.)

Index a folder

Point it at a directory. It walks the tree, reads common text and source files, and stores a compact index in a .whoosh_index/ folder:

$ whoosh index .
Indexed /home/you/notes
  3 added  ->  3 docs total in 0.03s
  index stored at /home/you/notes/.whoosh_index

By default it picks up common text and source extensions. Narrow or widen that with --ext:

$ whoosh index docs --ext md,rst,txt

Re-run any time. Pass --update for an incremental refresh — it only re-reads files that changed and drops ones you deleted, which is much faster on a big tree:

$ whoosh index . --update

Skip generated or vendored files with --exclude (a glob, and you can repeat it), and preview exactly what would be indexed — without creating or touching an index — with --dry-run:

$ whoosh index . --exclude 'build/*' --dry-run
Would index 4 files under /home/you/proj
README.txt
docs/install.md
docs/quickstart.md
src/index.py

--dry-run is the safe way to tune your --ext and --exclude filters before committing to a build — it never writes, clears, or creates .whoosh_index/.

Search it

Now query. Results come back ranked, with the matched terms highlighted and a relevance score:

$ whoosh search "search"
3 matches for 'search':

1. README.txt  (score 1.50)
   Project SEARCH tools. Fast, pure-Python full-text SEARCH with Whoosh

2. src/index.py  (score 0.92)
   every text file under path for full-text SEARCH

3. docs/quickstart.md  (score 0.85)
   add documents to an index, then run a SEARCH query. Whoosh is pure Python, so there is no

Notice the file that's genuinely about search sorts above the ones that merely mention it in passing. That ordering is the whole point — it's what a raw substring search can't give you.

The query language

The query is more than a bag of words. You get boolean operators, quoted phrases, and field-scoped terms, straight from the shell:

# boolean
$ whoosh search "pip OR schema"

# exact phrase
$ whoosh search '"pure Python"'

# exclude a term
$ whoosh search "search NOT python"

# scope to a field inline (title = file name, body = file contents)
$ whoosh search "body:install"

You can also scope with the --field flag, which is repeatable and reads more clearly for a whole query. By default a search covers both title and body; pin it to one:

$ whoosh search "index" --field body

Order by recency, and size the snippets

Relevance is the default sort, but sometimes "what did I touch most recently?" is the real question. --sort-by mtime orders hits by file modification time, newest first — handy for notes and work logs:

$ whoosh search "search OR python" --sort-by mtime --no-highlight --snippet-chars 50
4 matches for 'search OR python':

1. README.txt  (score 3.00)
   Project search tools. Fast, pure-Python full-text...

2. src/index.py  (score 2.00)
   # Build a Whoosh index from a folder of documents....

3. docs/quickstart.md  (score 1.00)
   # Quickstart Create a schema, add documents to an...

4. docs/install.md  (score 0.00)
   # Installation Install with pip: `pip install whoo...

Here the newest file (README.txt) comes first regardless of how strongly it matches — the order is by modification time, not relevance. Two more knobs there: --snippet-chars N controls how much context each result shows (default 200), and --no-highlight prints a plain, grep-friendly leading slice of the body with no match markup — nice when you're piping into another tool.

Output for humans and for scripts

The default output is made for reading. When you're piping into something else, switch formats:

FlagWhat you get
--jsonMachine-readable results — pipe straight into jq.
--countJust the number of matching documents.
--html<mark>…</mark> highlights instead of UPPERCASE.
--no-highlightPlain leading slice of the body, no match markup — grep-friendly.
--fieldsChoose which stored fields appear in the output.
--fieldRestrict the search to a field (repeatable; default title + body).
--snippet-charsHow much context to show per result (default 200).
--sort-byscore (default) or mtime for newest-first.
--limitCap the number of results (default 10).
$ whoosh search "bm25 OR grep" --count
2

$ whoosh search "install" --json --fields path
[{"path": "docs/install.md"}]

Because --json is stable and quiet, you can build small tools on top of it — a "search my notes" alias, a pre-commit doc check, a fuzzy file opener — without ever leaving the shell.

Inspect the index with whoosh stats

Once you've built an index, whoosh stats tells you what's in it — how many documents, which fields, and how much disk it uses:

$ whoosh stats
Index: /home/you/proj/.whoosh_index
  documents:   4
  fields:      4
    - body (TEXT)
    - mtime (NUMERIC)
    - path (ID)
    - title (TEXT)
  size on disk: 17.4 KB  (3 files)
  last updated: 2026-07-18 03:04:32

Add --top-terms FIELD to see the most frequent indexed terms — a quick way to understand what a corpus is actually about (and a reminder that body is stemmed, so install and installation collapse to one term, instal):

$ whoosh stats --top-terms body --top 6
Top terms in 'body':
  4  search
  4  instal
  3  whoosh
  3  text
  3  python
  3  index

Both commands also take --json, so index health checks drop straight into a script or a CI step.

When to reach for this (and when not to)

It's the same engine as the library. The CLI is a thin wrapper over the Whoosh Python API, so anything you can do from the command line you can also do in code — and vice versa. If you outgrow the CLI, the 5-minute Python quickstart picks up exactly where this leaves off.
Whoosh is a pure-Python full-text search library — actively maintained again after two rounds of abandonment. If this saved you a dependency or a headache, a ⭐ on GitHub genuinely helps other people find a search library that's alive again.

Install from PyPI  ·  Python quickstart  ·  Try the live demo

See also: Whoosh vs SQLite FTS5 · Whoosh vs Tantivy · Whoosh vs Elasticsearch