Grimoire is a local-first bookmark manager for people who save technical resources and need to find them later. Save links, import browser bookmarks, extract readable content, search by keyword or meaning, and let optional AI providers summarize and organize your library β while your data stays on your machine.
Note
The current Grimoire application is a complete rewrite β a fresh start for the project. The legacy Grimoire (v0.5.x, SvelteKit-based) is preserved on the legacy/v0.x branch.
Coming from v0.5.x? Grimoire 1.1.0 includes an experimental littleimp migrate tool for v0.5 SQLite data. See the migration guide before applying it.
Everything remains local-first, private, and 100% open source under the MIT license.
- Screenshots
- Quick Start
- Try the Public Demo
- What Grimoire Does
- How It Works
- Install And Upgrade Paths
- Data, Privacy, And Security
- Configuration
- Backups And Restore
- Migration From v0.5
- Local Integrations
- Development
- Documentation
The screenshots below use synthetic demo data.
| Library | Search | Bookmark detail |
|---|---|---|
![]() |
![]() |
![]() |
| Settings and browser integration | Import flow | Mobile library |
|---|---|---|
![]() |
![]() |
![]() |
Explore the hosted Grimoire demo without installing anything. The demo is a static, client-only profile of the real Grimoire UI. It uses synthetic fixtures and an in-memory API in the browser; it does not start the daemon, create an account, or persist a hosted library.
To run the same demo locally:
npm install
npm run build:demo
npm run preview:demoOpen the local preview at http://127.0.0.1:4173.
This is the recommended development path. It works from a public clone and does not depend on release assets.
git clone https://github.com/goniszewski/grimoire.git
cd grimoire
npm install
cd daemon && bun install
cd ..Start the daemon and frontend in separate terminals:
npm run daemon:devnpm run devOpen the Vite app at http://127.0.0.1:8080. The app talks to the daemon at
http://127.0.0.1:3210.
Docker serves the built frontend and daemon API from one loopback-bound port.
docker compose up -d
curl http://127.0.0.1:3210/healthOpen http://127.0.0.1:3210.
- Saves public
httpandhttpsURLs from the app, API, MCP, import flow, or browser bookmarklet. - Extracts readable content from normal web pages, PDFs, GitHub repositories, GitHub issues, StackOverflow/StackExchange pages, and YouTube metadata/transcripts where available.
- Stores bookmarks, content, tags, categories, jobs, notes, timeline events, backups, and settings locally in SQLite and local files.
- Searches with SQLite FTS5 keyword search, semantic embedding search, or a hybrid ranking mode.
- Supports archive, trash, read state, read-later flags, pinning, notes, category/tag management, import/export, backup/restore, diagnostics, and local update checks.
- Runs without AI providers. Optional providers include OpenAI, Ollama, Anthropic, OpenRouter, DeepSeek international, and custom OpenAI-compatible chat or embeddings endpoints.
Grimoire has two runtime parts:
- Frontend: React 18, Vite, TypeScript, Tailwind CSS, and Radix UI primitives
under
src/. - Daemon: Bun, Hono, and SQLite under
daemon/, listening on127.0.0.1:3210by default.
Bookmark ingestion is progressive:
save URL
-> enqueue durable SQLite job
-> fetch public content
-> extract readable text and metadata
-> enrich with optional AI summary, tags, and category
-> create optional embeddings
-> update search indexes
Bookmarks are visible immediately after save. Pipeline failures keep the bookmark usable and expose retry/reprocess controls.
The source installer copies daemon files, installs production dependencies, builds the frontend, writes a default config, registers the user service, and starts the daemon.
cd daemon
./install.shUpgrade from an unpacked source checkout or release archive:
cd daemon
./install.sh --upgradeUninstall while preserving data:
cd daemon
./install.sh --uninstallPurge data only when you intentionally want to remove the local library:
cd daemon
./install.sh --uninstall --purgeThe repository includes a Homebrew formula, but public install, service lifecycle, and data-preservation checks have not passed against release assets. It is not a supported installation path yet.
Native installs keep user data under ~/.local/share/littleimp/.
| Path | Contents |
|---|---|
~/.local/share/littleimp/littleimp.db |
SQLite database |
~/.local/share/littleimp/.env |
Install-time daemon defaults |
~/.local/share/littleimp/dist/ |
Built frontend served by the daemon |
~/.local/share/littleimp/backups/ |
Local snapshots and encrypted packages |
~/.local/share/littleimp/restore-rollbacks/ |
Pre-restore rollback copies |
~/.local/share/littleimp/logs/ |
Daemon logs |
Runtime user settings live at ~/.config/littleimp/config.json. Homebrew
installs keep Homebrew-managed data under $(brew --prefix)/var/little-imp.
Grimoire is local-first and loopback-first:
- Native daemon default:
127.0.0.1:3210. - Docker host port default:
127.0.0.1:3210:3210. - General REST routes are intended for first-party loopback use.
- MCP and protected capture endpoints require managed local integration bearer tokens.
- Public-network exposure is not a supported mode; put an authenticated tunnel, VPN, or reverse proxy in front of it if you deliberately need remote access.
The static public demo is a separate client-only build: it ships synthetic fixtures, keeps session mutations in memory, makes no daemon or provider requests, and uses no cookies, third-party scripts, or fingerprinting.
See SECURITY.md for the supported network boundary.
The daemon reads install-time defaults from ~/.local/share/littleimp/.env.
| Variable | Default | Description |
|---|---|---|
HOST |
127.0.0.1 |
Bind address. Keep localhost for security. |
PORT |
3210 |
Daemon HTTP port. |
DATA_DIR |
~/.local/share/littleimp |
Database, backups, and logs. |
NODE_ENV |
production |
Use development for local development logging. |
LOG_FORMAT |
json |
json or pretty. |
AI and embedding settings are managed in Settings and persisted in
~/.config/littleimp/config.json. Secret fields are redacted in API responses,
diagnostics, and portable settings backups.
Settings and the packaged littleimp CLI can create, verify, encrypt, and
restore local backup snapshots. Each normal snapshot contains:
snapshot.dbmanifest.jsonchecksums.sha256data/settings.json
CLI examples:
littleimp backup create
littleimp backup list
littleimp backup verify --file ~/.local/share/littleimp/backups/BACKUP_NAME
littleimp backup restore BACKUP_NAME --yesEncrypted package examples:
LITTLEIMP_BACKUP_PASSWORD='use-a-long-unique-password' \
littleimp backup create --encrypt --output ~/Desktop/little-imp-backup.enc
LITTLEIMP_BACKUP_PASSWORD='use-a-long-unique-password' \
littleimp backup verify --encrypted --file ~/Desktop/little-imp-backup.encRestores verify checksums, create a rollback directory, replace local data, and
return a restart command plus /health URL.
The experimental v0.5 migrator imports one owner's SQLite library, categories,
tags, and available local media into Grimoire 1.x. Start with inspect, review
an apply --dry-run, then apply with --yes:
littleimp migrate inspect --data-dir /path/to/grimoire/data
littleimp migrate apply --data-dir /path/to/grimoire/data --owner YOUR_USERNAME --dry-run
littleimp migrate apply --data-dir /path/to/grimoire/data --owner YOUR_USERNAME --yesSee the complete migration guide for archive inputs, owner-password verification, duplicate handling, and unsupported PocketBase backups.
The generated API reference is API.md. The source contract is
docs/api-contract.json, generated from
daemon/src/api/contract.ts.
curl http://127.0.0.1:3210/healthGrimoire exposes Streamable HTTP MCP at http://127.0.0.1:3210/mcp. Create
a local integration token first:
curl -X POST http://127.0.0.1:3210/integration-tokens \
-H "Content-Type: application/json" \
-d '{"name":"Local MCP client"}'Use the returned token as Authorization: Bearer ....
Settings -> Browser Integration can create a token-backed bookmarklet. Drag it to your browser bookmarks bar, then click it on a page to capture the current URL, title, and selected text into Grimoire.
The bookmarklet opens a short-lived local Grimoire capture window so restrictive page CSPs (including GitHub's) cannot block the request. Grimoire reports success only after the daemon confirms the capture. Allow popups for the page if your browser blocks the capture window.
The bookmarklet embeds an integration token. Treat it like a password. Bookmarklets created before the current bridge flow must be replaced after an upgrade; create a new token because the old full secret cannot be recovered.
npm install
cd daemon && bun install
cd ..Core commands:
npm run dev
npm run daemon:dev
npm run lint
npm run type-check
npm run test
npm run test:daemon
npm run test:e2e
npm run buildFull local quality gate:
npm run checkIf node, npm, npx, or bun are missing in a sandboxed environment, run:
npm run tools:setup
export PATH="$PWD/local/bin:$PATH"Then rerun the normal commands.
Guides in this repo (also on the web at goniszewski.com/grimoire):
- Docs index
- Introduction
- Quick start
- Using Grimoire
- Migration from v0.5
- Development
- Install without Docker
- Remote access
- FAQ
Reference and engineering:
See CHANGELOG.md.
MIT. See LICENSE.






