Archivist is a local-first personal web archive.
It automatically captures the pages you read in Chrome (title + canonicalized URL + visible text) and stores them locally in SQLite (FTS5), so you can search everything later from a menu-bar app.
Privacy note: Archivist is designed to be local-first. The Chrome extension only sends captured text to your local app. The app never sends your stored content back to the extension.
- Automatic capture after a page finishes loading (with a small delay)
- Local SQLite + FTS5 full-text search with trigram tokenizer (Japanese-friendly)
- Two-pane search UI with favicon display, keyword highlighting, and keyboard navigation (Arrow Up/Down)
- Menu-bar (system tray) resident — closing the window keeps the ingest server running in the background
- Launch at login — optional auto-start via macOS LaunchAgent (toggle in Settings)
- Domain stats & global stats (page count, total chars/bytes, domain breakdown)
- Content extraction via Readability.js for cleaner text capture
- No "content return path" from the app to the extension (one-way ingest)
apps/archivist-tauri/ Tauri desktop app (macOS)
src/ Frontend (vanilla TypeScript + Vite)
src-tauri/ Rust backend (Axum HTTP server + SQLite + Tauri commands)
extensions/chrome/ Chrome MV3 extension
- Node.js 22+
- Rust toolchain (stable)
- Tauri prerequisites for macOS (Xcode command line tools)
- Node.js 22+
- Rust toolchain (stable)
- MSYS2 / MinGW-w64 environment (for
x86_64-pc-windows-gnutarget)
make setup # install frontend dependencies
make dev # start in development mode (Vite + Tauri hot reload)Or equivalently:
cd apps/archivist-tauri
npm install
npm run tauri devOn first launch, Archivist generates a local ingest token and shows it in Settings.
By default, the app listens on http://127.0.0.1:17373.
- Open
chrome://extensions - Enable Developer mode
- Click Load unpacked
- Select
extensions/chrome
Then open the extension Options page and set:
Ingest URL:http://127.0.0.1:17373/captureToken: copy from the Archivist app Settings
make build # creates .app bundle in src-tauri/target/release/bundle/macos/- Chrome detects
tab.status == "complete" - Waits a short delay (default: 2000ms)
- Extracts title, canonical URL, and visible text (via Readability.js)
- Normalizes the URL (drops fragments + common tracking params)
- Deduplicates via in-memory SHA-1 cache (10-min throttle)
- Sends JSON to the app over
127.0.0.1withAuthorization: Bearer <token>
Archivist uses SQLite with FTS5 (trigram tokenizer) and a pages table for metadata.
See: apps/archivist-tauri/src-tauri/sql/schema.sql
- The ingest server only listens on
127.0.0.1 - Requests require a random token (Bearer auth)
- The extension does not receive stored content back from the app
This is intended to be "reasonable for personal use" rather than "high assurance".
| Target | Description |
|---|---|
make setup |
Install frontend dependencies |
make dev |
Start in development mode |
make build |
Production build (macOS .app bundle) |
make lint |
Run cargo clippy on the Rust backend |
make clean |
Remove build artifacts |
Tauri has an official tauri-plugin-sql for SQLite access, but Archivist uses rusqlite directly because:
- The app runs an Axum HTTP server (
127.0.0.1:17373) to receive page captures from the Chrome extension. This server needs Rust-side DB access, whichtauri-plugin-sqldoes not expose. - Using a single
Arc<Mutex<Connection>>shared between Tauri commands (reads) and Axum handlers (writes) keeps the architecture simple.
The app stays resident in the macOS menu bar. Closing the window hides it rather than quitting, so the HTTP ingest server remains available for the Chrome extension. Use the tray icon to show/hide the window, or Quit from the tray menu.
MIT.
