Norn
Persistent, visible memory for AI coding agents.
Live site · Releases · Quickstart
Your AI forgets you every session. Norn is a local MCP server that remembers your decisions, preferences, and project context across every session and project, for Claude Code, Cursor, and any MCP client. Unlike most memory tools it is fully local and fully inspectable: a dashboard lets you see exactly what it stored and forget anything you do not want.
Quickstart
Requires Node 20+. Add Norn to Claude Code in one line, no clone:
claude mcp add norn -- npx -y @samad001z/norn-server
For Cursor, Claude Desktop, or any MCP client, use the standard config:
{
"mcpServers": {
"norn": {
"command": "npx",
"args": ["-y", "@samad001z/norn-server"]
}
}
}
Restart your agent. Norn registers four tools: remember, recall, forget, list.
The first
rememberorrecalldownloads a local embedding model (all-MiniLM-L6-v2, ~25 MB) once, then runs fully offline.
<details> <summary>Or run from source</summary>
git clone https://github.com/samad001z/Norn.git
cd Norn
npm install
npm run build -w @samad001z/norn-core && npm run build -w @samad001z/norn-server
claude mcp add norn -- node "$(pwd)/server/dist/index.js"
</details>
See it work
Memory survives across sessions, and recall is semantic: it matches meaning, not keywords.
Session 1
You: Remember that we deploy to production from the main branch on Vercel. Claude calls
remember("deploy to production from the main branch on Vercel", project: "acme")
Session 2, the next day, in a fresh context window
You: How do we ship to prod? Claude calls
recall("how do we ship to prod")Norn returns "Deploy to production from the main branch on Vercel." even though the query shares no keywords with the stored note.
How it works
Three local pieces share one local database:
Claude Code / Cursor ──MCP (stdio)──► Norn MCP server ┐
├──► ~/.norn/norn.db
Dashboard (Next.js) ────────────────────────────┘ (SQLite + sqlite-vec)
- MCP server (
/server): exposesremember,recall,forget,listover stdio. - Store (
/core): SQLite + sqlite-vec, with embeddings from a local MiniLM model
(no API key). recall blends semantic similarity with recency and trims results to a token budget; remember dedupes near-identical notes.
- Dashboard (
/web): a Next.js app to browse and manage everything.
All three resolve to the same store, so a memory written by your agent appears in the dashboard, and a memory you forget in the dashboard is gone for the agent too. The store is chosen in this order:
NORN_DB_PATH, if set — an explicit override always wins.- The nearest project-local
.norn/norn.db, walking up from the working directory
(see Per-project memory).
- The global
~/.norn/norn.db.
With no project store and no override, this is the original behavior: one global ~/.norn/norn.db.
Per-project memory
Give a repo its own memory that ships with it. From the project root:
npx @samad001z/norn-core init # or: norn init
This creates a .norn/ directory holding that project's norn.db. Because each project has its own database file, memories never bleed across projects: an agent working in one repo only sees that repo's memory.
How a project is detected
Norn finds your project the way git does — by walking up from the working directory to the nearest ancestor that contains a .norn/ directory. Run your agent (or the CLI) anywhere inside the repo and it resolves to the same store. The store is chosen in this order:
NORN_DB_PATH, if set — an explicit override always wins.- The nearest project-local
.norn/norn.db, walking up from the working directory. - The global
~/.norn/norn.db— the original behavior when no project store exists.
Even without norn init, projects stay isolated in the shared global store: every memory is stamped with the project root it was written under (a scope, derived from the nearest .git/.norn ancestor — distinct from the freeform project label), and recall only returns the current project's memories plus global ones. Separate db files are the primary isolation; the scope stamp is defense in depth for the shared store.
Commit memory with the repo
norn export/norn importare available from v1.1 onward. On earlier versions, commit the binarynorn.dbdirectly (the defaultnorn initsetup).
norn.db is a binary SQLite file — it holds embedding vectors, so it has no readable git diffs and can conflict on merge. To version your memory cleanly, commit a diffable text export instead and let each checkout rebuild its own database:
norn export # writes .norn/memory.json — text, tags, project, ids, timestamps (no vectors)
memory.json is sorted deterministically, so re-exporting an unchanged store produces an empty diff. Embeddings are not stored in it; they are regenerated locally on import, so the file stays small and review-friendly. Commit it and gitignore the binary store with a .norn/.gitignore like:
# .norn/.gitignore — commit memory.json, ignore the binary store.
# norn.db is binary SQLite (it holds embedding vectors): no readable diffs,
# and it can conflict on merge. memory.json (not listed here) is the
# diffable file you commit; the sidecars below are always transient.
norn.db
norn.db-wal
norn.db-shm
norn.db-journal
norn init(v1.1+) writes exactly this.gitignorefor you, somemory.jsonis the committed artifact out of the box. Prefer to commit the binarynorn.dbinstead — no import step on clone, at the cost of readable diffs? Just delete thenorn.dbline.
On a fresh clone, rebuild the local database from the committed file:
norn import # reads .norn/memory.json and regenerates embeddings locally
import upserts by id, so it is safe to re-run; it never duplicates a memory.
Try it: isolation, then commit-and-clone
A self-contained, copy-paste walkthrough (uses npx, no install; needs Node 20+ and git):
# 1. Two separate projects, each with its own committed memory store.
mkdir -p /tmp/demo/alpha /tmp/demo/beta
cd /tmp/demo/alpha
npx @samad001z/norn-core init
npx @samad001z/norn-core remember "Alpha API rate limit is 600 requests per minute per token"
cd /tmp/demo/beta
npx @samad001z/norn-core init
npx @samad001z/norn-core remember "Beta deploys to prod from the main branch on Vercel"
# 2. Isolation: from Beta, ask for Alpha's fact. Beta only ever returns its own
# (and global) memories — Alpha's note never appears here.
npx @samad001z/norn-core recall "what is the request rate limit"
# 3. Export Alpha's memory to a diffable file and commit it.
cd /tmp/demo/alpha
npx @samad001z/norn-core export # writes .norn/memory.json
git init -q && git add .norn/memory.json && git commit -qm "Add project memory"
# 4. Simulate a teammate's fresh clone: bring the export, NOT the binary db.
mkdir -p /tmp/demo/alpha-clone/.norn
cp .norn/memory.json /tmp/demo/alpha-clone/.norn/memory.json
# 5. Rebuild the store from the committed file and confirm recall works.
cd /tmp/demo/alpha-clone
npx @samad001z/norn-core import # regenerates embeddings locally
npx @samad001z/norn-core recall "what is the request rate limit"
# → "Alpha API rate limit is 600 requests per minute per token"
Features
- Remembers across sessions and projects. Stop re-pasting CLAUDE.md by hand.
- See everything it knows. No black box: every memory is visible.
- Forget anything, with undo. Full control over what it keeps.
- Lives in your tools over MCP. Claude Code, Cursor, and any MCP client.
- Local-first. Your context, the embedding model, and the database all stay on your
machine.
Privacy
Local by default. The store is a SQLite file on your disk, the embedding model runs on your machine, and nothing leaves it: no account, no API key, no telemetry. Delete ~/.norn/norn.db and the memory is gone.
Manage your memories
The dashboard lets you browse by project, search, and forget any memory (with undo). It runs from a clone of this repo (it is not part of the npx server package), and it reads the same local store your agent writes to — ~/.norn/norn.db — so whatever Norn remembered shows up here.
Run these four commands from a fresh terminal:
git clone https://github.com/samad001z/Norn.git
cd Norn
npm install # install dependencies
npm run build:core # build the store package the dashboard reads through (required)
npm run dev:web # start the dashboard
Then open http://localhost:3000/app.
Skipping
npm run build:coreis the usual reason the dashboard opens empty: the web app imports the compiled store from@samad001z/norn-core, so that package has to be built once first. After that,npm run dev:webis all you need to reopen it.
To point the dashboard at a store in a non-default location, set NORN_DB_PATH to the same path your agent uses before running dev:web (otherwise the default is fine):
NORN_DB_PATH=/path/to/norn.db npm run dev:web
!The Norn dashboard: browse by project, search, and forget your memories
Prefer the terminal? Inspect the same store without the dashboard:
npm run cli -w @samad001z/norn-core -- init # give this project its own committed store
npm run cli -w @samad001z/norn-core -- list
npm run cli -w @samad001z/norn-core -- recall "how do we deploy"
npm run cli -w @samad001z/norn-core -- export # write .norn/memory.json to commit with the repo
npm run cli -w @samad001z/norn-core -- import # rebuild this checkout's store from memory.json
Roadmap
- Swappable embedding backends (Ollama, OpenAI-compatible) behind the existing
Embedder
interface.
- Create and edit memories from the dashboard, not just browse and forget.
- Optional end-to-end encrypted sync, off by default.
- More editor and MCP-client integrations.
Contributing
Contributions are welcome. See CONTRIBUTING.md. The short version:
npm install
npm run build
npm test -w @samad001z/norn-core
License
MIT. See LICENSE.






