grepdown
Knowledge base management for Markdown — search, link, and lint.
grepdown turns a folder of Markdown files into a queryable knowledge base. It indexes your .md files and lets you search, traverse link graphs, and detect stale references. Ships as a CLI and as an MCP server for AI agent integration — zero config, fast incremental indexing, and out-of-the-box Open Knowledge Format (OKF) support.
Features
- CLI + MCP. Use from the terminal or via an MCP server for AI agent integration
- Full-text search. SQLite FTS5 with BM25 ranking and phrase/prefix/NEAR queries
- Incremental indexing. Only re-processes changed files (mtime + blake3 content hashing)
- Parallel processing. Reads and parses files concurrently
- Tag search. Extracts YAML frontmatter tags and searches them alongside body text
- Link graph. Forward links, backlinks, citations, and BFS reachability traversal
- Linting. Detects stale references, orphaned documents, and broken links
- JSON output. Machine-readable output for scripting and programmatic use
- Highlighted snippets. ANSI-colored context snippets with match highlighting
- Zero config. Just run it in any directory of Markdown files
Installation
# From source (requires Rust toolchain)
&&
# Install both binaries
# or manually:
No system SQLite required — it's already bundled.
Quick Start
# Initialize the project (creates the index)
# Search
# Search with a result limit
# Skip re-indexing before search (faster if index is fresh)
# Literal search (no FTS5 operators)
Commands
| Command | Description |
|---|---|
init |
Initialize and index all .md files in the current directory |
index |
Re-index (refresh) the database |
search <query> |
Search indexed files (auto-refreshes by default) |
lint |
Run lints on the knowledge base (exit 0 = clean, 1 = issues found) |
approve-edits |
Approve stale references by updating pinned versions |
reach <doc> |
Show documents reachable from a given document via the link graph |
read <path> |
Read a document's content from the knowledge base |
Search Options
| Flag | Default | Description |
|---|---|---|
-l, --limit <N> |
20 |
Maximum number of results |
--no-refresh |
false |
Skip index refresh before searching |
--literal |
false |
Treat the query as a literal string (no FTS5 operators) |
--json |
false |
Output results as compact JSON |
--path <SUBPATH> |
— | Filter results to files under this subfolder |
--snippet-length <N> |
32 |
Number of tokens in search snippets |
Lint Options
| Flag | Description |
|---|---|
--json |
Output lint results as compact JSON |
Approve Edits
Requires --all or explicit paths:
| Flag | Description |
|---|---|
--all |
Approve all stale references |
<paths...> |
Approve stale references only in the specified files/folders |
Global Flags
| Flag | Description |
|---|---|
-v / -vv / -vvv |
Verbosity: Warn → Info → Debug → Trace |
Search Syntax
grepdown uses the SQLite FTS5 query syntax:
deployment guide # all words must match
deploy OR guide # either word
"exact phrase" # phrase search
config* # prefix match
NEAR(server client, 5) # words within 5 tokens
Use --literal to search for a plain string without FTS5 operators.
How It Works
- Walk — recursively finds all
.mdfiles - Diff — compares mtimes and content hashes to skip unchanged files
- Parse — extracts body text, YAML frontmatter tags, and internal/external links
- Index — bulk-inserts into SQLite FTS5 in a single transaction
- Search — queries both body and tag indexes, returns BM25-ranked results with snippets
The database lives at md.db in your project root (gitignored by convention).
Linting
grepdown runs three types of lints:
- Stale references — when a linked document changes, the link is flagged until you approve it
- Orphaned documents — documents with no incoming links from other documents
- Broken links — links that point to non-existent documents
Example workflow
# Initialize
# Check for lint issues
# Output: No lint issues found.
# Edit a document that other documents link to
# Re-index to detect changes
# Check for stale references
# Output:
# WARNING: pinned version 1 is behind current version 2 (/path/to/doc-a.md → /path/to/doc-b.md)
#
# 1 issue(s) found.
# Review the changes, then approve all stale references
# Output: Approved 1 link(s).
# Verify no more issues
# Output: No lint issues found.
Each document has a version counter that increments when its content changes. Links capture the target's version at link time; a link is stale when pinned_version < current_version.
MCP Server
grepdown ships an MCP (Model Context Protocol) server (grepdown-mcp) that exposes the knowledge base to AI agents over stdio.
Tools
| Tool | Description |
|---|---|
search |
Full-text search with optional path filter and snippet length |
refresh |
Re-index the project |
lint |
Run all lints and return diagnostics |
approve_edits |
Approve stale references (optionally scoped to specific paths) |
get_links |
Get outgoing links and backlinks for a document |
get_citations |
Get external URLs referenced in a document |
get_reachable |
BFS traversal of the link graph from a starting document |
get_document |
Read the full content and frontmatter of a document |
Usage
# Start the MCP server in a grepdown project directory
Configure your MCP client to use grepdown-mcp as a stdio transport:
License
See LICENSE for details.