Skip to content

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

semanticfs

Search your notes by meaning, not keywords. Runs 100% offline.

You write a query like "what was the rollback strategy for the production migration?" — even if you can't remember which file it was in or what exact words you used — and semanticfs finds the right chunk, semantically.

Local-first. No cloud, no API keys, no telemetry after first setup. All embeddings and search happen on your machine.

Project status

SemanticFS is a working local-first CLI prototype for semantic file search.
It supports Markdown, text files, and text-based PDFs, with incremental indexing, local embeddings, ChromaDB vector search, and SQLite metadata storage.

What it does

  • Indexes local .md, .txt, and text-based .pdf files
  • Splits documents into searchable chunks
  • Generates embeddings locally using sentence-transformers
  • Stores metadata in SQLite and vectors in ChromaDB
  • Searches by semantic meaning instead of exact keywords
  • Works offline after the first model download

Preview

semanticfs terminal search preview


Why

Keyword search breaks the moment you forget the exact phrasing. You know you wrote something about the database migration incident — but the file says "schema change" and "reversal procedure", the filename is 2023-11-03.md, and grep finds nothing.

Semantic search encodes meaning into vectors. At query time, your question lands near the right content in that space regardless of word overlap. "rollback strategy" matches "reversal procedure". "agent observability" matches "trace collection and span analysis". The model understands intent, not literals.

Why local-first? Most semantic search tools send your documents to a cloud, require an API key, and charge per query. semanticfs runs the embedding model on your own CPU, stores everything under ~/.semanticfs/, and never makes a network request after the one-time model download. Your notes stay on your machine.


How it works

Your notes (~/notes, Obsidian vault, project docs, runbooks)
        │
        ▼
semanticfs index ~/notes
        │
        ├── Scanner   — recursive file discovery, SHA-256 hash
        ├── Parser    — .md / .txt / text-based .pdf text extraction
        ├── Chunker   — fixed-size + overlap, word-boundary snap
        └── Embedder  — sentence-transformers (all-MiniLM-L6-v2, local)
        │
        ├── SQLite    ← folder / file / chunk metadata (~/.semanticfs/semanticfs.db)
        └── ChromaDB  ← vector embeddings (~/.semanticfs/chroma/)
        │
        ▼
semanticfs search "database rollback strategy"
        │
        ├── Embed query (local)
        ├── Cosine similarity over ChromaDB
        └── Rank + format results

Privacy: document text never leaves your machine. The only network request is the one-time model download (~90 MB).


Example

$ semanticfs search "database rollback strategy"

Results for "database rollback strategy" (2 hit(s))

╭─ #1 ~/notes/runbooks/postgres_migration.md (chunk 1) — score 0.87 ───────╮
│ Before applying schema changes in production, document a rollback         │
│ strategy that includes backup verification and replay steps.              │
│                                                                           │
│ Why matched: High semantic similarity (87%); Overlapping terms: strategy  │
╰───────────────────────────────────────────────────────────────────────────╯

╭─ #2 ~/notes/incident_notes.md (chunk 0) — score 0.71 ────────────────────╮
│ Recovery procedure: restore from snapshot, validate FK constraints,       │
│ replay audit log. Verified on staging before production apply.            │
│                                                                           │
│ Why matched: Moderate semantic similarity (71%)                           │
╰───────────────────────────────────────────────────────────────────────────╯

Install

Requires Python 3.10+.

python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate

pip install -e ".[dev]"

First run

semanticfs config show          # create ~/.semanticfs/ and display settings
semanticfs index ~/notes        # scan, chunk, embed, store (downloads model on first run)
semanticfs search "<query>"     # semantic search over indexed chunks
semanticfs list                 # indexed folders, file/chunk counts, last index time
semanticfs remove <folder> --yes  # drop folder from index (SQLite + Chroma)
semanticfs status               # runtime paths, model cache status

Try it immediately with the bundled benchmark corpus:

semanticfs index benchmarks/corpus
semanticfs search "postgres migration"
semanticfs search "veritabanı migration geri alma"   # Turkish query
semanticfs index benchmarks/corpus                   # second run: unchanged files are skipped

Search options

semanticfs search "your query" --limit 5          # cap result count
semanticfs search "your query" --min-score 0.5    # filter low-confidence hits

--min-score filters out results below the given similarity threshold (0.0–1.0). The default (0.0) returns all ranked results; 0.4–0.5 is a reasonable baseline for high-precision mode.


Runtime layout

Data lives under ~/.semanticfs/ (override with SEMANTICFS_HOME env var):

Path Purpose
config.json embedding model, chunk size/overlap, result limits
semanticfs.db SQLite metadata (folders, files, chunks, index runs)
chroma/ ChromaDB vector store
logs/ Exported reports (chunk quality, benchmark)
semanticfs config show      # all settings + paths
semanticfs config path      # path to config.json

Offline use

  1. Run semanticfs index <folder> once while online — downloads all-MiniLM-L6-v2 (~90 MB) into the HuggingFace cache.
  2. After that, both index and search work without network access.
  3. semanticfs status shows model cached: yes when the model is ready.

To force offline mode explicitly:

# Windows (PowerShell)
$env:HF_HUB_OFFLINE = "1"
$env:TRANSFORMERS_OFFLINE = "1"

# macOS / Linux
export HF_HUB_OFFLINE=1
export TRANSFORMERS_OFFLINE=1

See docs/offline-validation.md for the full checklist.


Benchmark and chunk quality

semanticfs benchmark run --export          # chunk gold regression
semanticfs benchmark run --verbose         # show all rule results
semanticfs inspect-chunks <folder>         # heuristic chunk quality report
semanticfs inspect-chunks <folder> --export

See docs/benchmark.md.


Limitations

Item Status
.md and .txt indexing ✅ Full support
Text-based .pdf indexing ✅ Supported (PyMuPDF)
Scanned / image PDF ❌ Not supported — ParserError is raised, file is skipped
Code files (.py, .js, .ts) ❌ Not indexed
Realtime file watcher ❌ Run index again to pick up changes
Multi-user / cloud sync ❌ Single-user, local only
LLM-generated explanations ❌ Rule-based why matched only

Re-indexing is incremental: files with unchanged content (SHA-256 hash match) are skipped automatically.


Troubleshooting

"No indexed chunks" error on search: Run semanticfs index <folder> first. The vector store must be populated before searching.

PDF files show as Failed in index summary: Check semanticfs status — if it's a scanned PDF, text extraction is not possible. Text-based PDFs (where you can copy-paste text in a viewer) work correctly.

Results seem off or missing: Try a more descriptive query — the model works best with full phrases rather than single keywords. Use --min-score 0.0 to see all ranked results without filtering.

Model download is slow: The first semanticfs index downloads ~90 MB. After that, all runs are fully offline.


Architecture

See docs/architecture.md.


Development

From the repo root, install the package in your active environment (once):

pip install -e ".[dev]"

Default pytest excludes @pytest.mark.integration tests (no embedding model required). Prefer python -m pytest so it uses the same interpreter as pip install:

python -m pytest tests/ -v

Integration tests need a cached model (semanticfs index benchmarks/corpus once online):

# bash / macOS / Linux
SEMANTICFS_OFFLINE_TEST=1 pytest -o addopts= -m integration tests/test_offline.py -v
SEMANTICFS_SEARCH_GOLD_TEST=1 pytest -o addopts= -m integration tests/test_search_gold.py -v
# Windows PowerShell
$env:SEMANTICFS_OFFLINE_TEST = "1"
python -m pytest -o addopts= -m integration tests/test_offline.py -v

$env:SEMANTICFS_SEARCH_GOLD_TEST = "1"
python -m pytest -o addopts= -m integration tests/test_search_gold.py -v

Search-only (PowerShell): set $env:SEMANTICFS_SEARCH_GOLD_TEST = "1" then pytest -o addopts= -m search_gold tests/test_search_gold.py -v

See docs/offline-validation.md for manual offline checks.

About

Local-first semantic search CLI for indexing and searching notes by meaning, fully offline after setup.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages