grepnotes
by LuthfiMirza
README.md
# grepnotes
**Search your notes from Claude Code, Cursor, or any MCP client.
Zero dependencies, runs fully offline.**
[](https://github.com/LuthfiMirza/grepnotes/actions/workflows/ci.yml)
[](https://www.python.org/downloads/)
[](LICENSE)
[](pyproject.toml)
Point `grepnotes` at a folder of notes, docs or runbooks. It becomes an MCP server
that any coding agent — Claude Code, Cursor, Cline, Zed — can search instead of
reading whole files into context.
```console
$ grepnotes search "why are jobs piling up while CPU is idle"
deployment.md:9 [11.6999] Scaling the worker pool
Workers autoscale on queue depth, not CPU. If jobs are piling up while CPU
looks idle, the bottleneck is almost always the database connection pool.
postgres.md:3 [0.7389] Connection pooling
Every service goes through pgbouncer in transaction mode. Prepared statements
are disabled because transaction mode does not keep them across checkouts.
deployment.md:3 [0.5434] Rolling back a release
If the error rate crosses two percent, roll back before investigating.
Run `deployctl rollback --to previous` and confirm the health check turns green.
Never roll back the database migration in the same step; migrations are
forward-only by design.
```
## Why
Agents are good at reasoning and bad at knowing where things are written down.
The usual fix is to paste whole documents into the prompt, which is slow,
expensive, and pushes out the context the agent actually needed.
`grepnotes` gives the agent a search tool instead. It returns the three or four
passages that matter, with file path and line number, so the agent can pull the
full document only when it decides it needs to.
Every other tool in this space wants an embedding API, a vector database, or a
Docker Compose file. `grepnotes` is BM25 ranking over a JSON index, written against
the Python standard library. No install step beyond the package itself, nothing
leaves your machine, and no third-party code in your supply chain.
## Try it in 30 seconds
Nothing to install — there are no dependencies to resolve.
```bash
git clone https://github.com/LuthfiMirza/grepnotes && cd grepnotes
python -m grepnotes search "rollback policy" --path examples/notes
```
## Install
```bash
pip install grepnotes
```
Or install the clone so the `grepnotes` command is available everywhere. The `-e`
flag keeps it editable, so your changes take effect without reinstalling:
```bash
pip install -e .
grepnotes --version
```
If your shell reports `grepnotes: command not found`, Python's script directory is
not on your `PATH`. Either add it, or use `python -m grepnotes` in place of
`grepnotes` in every command below.
## Use it as an MCP server
**Claude Code**
```bash
claude mcp add grepnotes -- grepnotes serve --path ~/notes
```
**Cursor, Cline, Zed and anything else that reads `mcpServers`**
```json
{
"mcpServers": {
"grepnotes": {
"command": "grepnotes",
"args": ["serve", "--path", "/absolute/path/to/your/notes"]
}
}
}
```
If `grepnotes` is not on your `PATH`, use `"command": "python"` with
`"args": ["-m", "grepnotes", "serve", "--path", "..."]` instead.
Restart the client and confirm the server is connected — in Claude Code, run
`/mcp` and look for `grepnotes` in the list. The agent now has three tools:
| Tool | What it does |
| --- | --- |
| `search_notes` | Ranked passages for a query, with path, heading and line number |
| `read_note` | Full text of one document, once the agent decides it needs it |
| `list_notes` | Every indexed document and its headings, for orientation |
The index refreshes itself on each call, so edits to your notes show up without
restarting the server.
## CLI
```bash
grepnotes index [path] # build or refresh the index
grepnotes search "query" # search from the terminal
grepnotes serve --path ~/notes # run as an MCP server over stdio
grepnotes stats # what is currently indexed
```
Useful flags: `--force` re-reads every file, `-n` sets the result count,
`--full` prints whole passages, `--ext` picks which file types to index
(`.md`, `.markdown`, `.mdx`, `.txt`, `.rst`, `.org` by default).
## How it works
1. **Chunk.** Documents are split on markdown headings, then on paragraph
boundaries if a section runs past 1200 characters. Headings inside code
fences are ignored. Each chunk keeps its heading and starting line.
2. **Index.** Tokens are lowercased and stripped of accents, so Indonesian,
English and most Latin-script text work without a language-specific
tokenizer. Term frequencies land in `.grepnotes/index.json`.
3. **Rank.** Standard BM25 (`k1=1.5`, `b=0.75`) over the chunks.
4. **Refresh.** Files are stamped with mtime and size, so a rebuild only
re-reads what actually changed.
Indexing is roughly linear in corpus size, and a few thousand notes index in
under a second. The index is a plain JSON file you can inspect or delete.
## Limits, stated honestly
- **Keyword ranking, not semantic.** BM25 matches words. If your query and your
notes use entirely different vocabulary, it will miss. This is the deliberate
trade for having no model and no dependencies. Semantic reranking as an
optional extra is the obvious next step — see the issues.
- **Latin-script tokenizer.** Chinese, Japanese, Korean and Thai need word
segmentation that the current tokenizer does not do.
- **Whole index in memory.** Fine up to tens of thousands of chunks. Past that
it wants a real inverted index on disk.
- **No stemming.** "running" and "run" are separate terms today.
## Contributing
Tests are plain `unittest`, no runner to install:
```bash
python -m unittest discover -s tests -v
```
Pull requests are welcome. The one hard rule is that the runtime stays at zero
dependencies — CI enforces it. Optional features belong behind an extra.
## License
MIT
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues