Private second memory for any AI. Local-first, encrypted, multi-graph. Attaches a relevant subgraph from your own memory to every prompt you send to any MCP-aware AI — no effort, no API keys, no AI literacy required.
Product name: Graphnosis · Domain: graphnosis.com (primary) · graphnosis.app (downloads) · graphnosis.org (OSS) · graphnosis.ai (reserved)
Repo: Graphnosis App (this monorepo) · Engine: @nehloo/graphnosis
Private alpha. This repository is private during foundational development. Source will be made available at public launch under the Functional Source License 1.1 (FSL-1.1-Apache-2.0) — both so users can verify the privacy promises ("your memory never leaves your device") and so the community can audit and contribute. The license converts to Apache 2.0 two years after each release.
The underlying engine, @nehloo/graphnosis, is already open source under Apache 2.0.
- You pick a folder (local or iCloud/Drive) where your encrypted memory lives.
- You feed it things worth remembering:
- Files from Finder (in place — files stay where they are)
- Web pages or selected text via Share Sheet / global hotkey
- AI conversation notes via "remember this" inside Claude / Cursor / Claude Code
- Anytime you talk to an MCP-aware AI, a relevant federated subgraph from your memory gets attached, within a tight token budget. The AI answers as if it knew you.
- You correct it in natural language ("the trip was September, not August"). A bundled local LLM produces a structured diff, you confirm, the graph updates — privately, on-device.
The full .gai files never reach the AI. The AI only ever sees the scoped subgraph relevant to the current prompt — and that subgraph is hard-capped by per-graph sensitivity tiers (public / personal / sensitive) that the AI cannot override.
Unlock your Cortex with a passphrase or Touch ID, then work across four tabs — daily check-ins, the 3D engram, deterministic consolidation, and the optional non-deterministic layer.
![]() Check-in — connect lonely memories |
![]() 3D Engram — explore the whole graph |
![]() Deterministic Consolidation — vitality & memory health |
![]() Go Non-Deterministic — the optional AI layer |
And the recall / remember loop, working live with an AI client:
![]() remember — your AI saves a memory; Graphnosis asks which engram first |
![]() recall — any client pulls it back from your encrypted graph |
Claude is shown to demonstrate the MCP integration. Graphnosis is an independent product, not affiliated with or endorsed by Anthropic.
┌────────────────────────────────────────────────────────────────────────────┐
│ Tauri shell (Rust) — apps/desktop │
│ - menu bar, hotkeys, Share Sheet receiver │
│ - OS keychain (Touch ID / Windows Hello) │
│ - folder watcher + op-log sync engine │
│ - spawns and supervises the Node sidecar │
└────────────────────────────────┬───────────────────────────────────────────┘
│ Unix socket (newline JSON-RPC)
▼
┌────────────────────────────────────────────────────────────────────────────┐
│ Node sidecar (TypeScript) — apps/desktop-sidecar │
│ - GraphnosisHost: encryption at rest, op-log, source index │
│ - ingest (file / web / clip); large files chunked for responsiveness │
│ - correction pipeline (local LLM via Ollama → structured diff) │
│ - local embeddings via fastembed (BGE-small-en-v1.5, ONNX) │
│ → PDF parsing offloaded to a worker_threads Worker (pure JS, safe) │
│ → ONNX inference runs in a pool of forked child processes (N-API safe) │
│ - federated query across all user graphs with tier-capped budgets │
│ - MCP server over stdio: recall, remember, correct, apply, forget, stats │
└────────────────────────────────┬───────────────────────────────────────────┘
│
▼
┌────────────────────────────────────────────────────────────────────────────┐
│ Embedding worker pool (forked child processes) │
│ - 2 × node embed-worker.js, each with its own fastembed / ONNX session │
│ - Round-robin dispatch; parent event loop never blocked by inference │
│ - Pool size: GRAPHNOSIS_EMBED_WORKERS (default 2) │
└────────────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────┐
│ @nehloo/graphnosis SDK │
│ (Apache 2.0, npm) │
└─────────────────────────────┘
apps/
desktop/ Tauri app (Rust shell + minimal HTML/JS UI)
desktop-sidecar/ Node TypeScript sidecar (Graphnosis + MCP + IPC)
src/
index.ts Entry point — boot, IPC, MCP, signal handling
host.ts GraphnosisHost wrapper (ingest, ingestChunked, save, recover)
ingest.ts File/web/clip ingest; PDF parsed in worker thread
pdf-parse-worker.ts worker_threads PDF parser (pdfjs off the main thread)
local-embed.ts Fork-based embedding pool (round-robin, 2 workers default)
embed-worker.ts Forked child: owns one fastembed / ONNX session
embedding-queue.ts Mutex: serializes ONNX calls between concurrent ingests
ipc.ts Unix-socket JSON-RPC server for Tauri shell
mcp-registry.ts MCP tool definitions (recall, remember, correct, …)
packages/
graphnosis-app-core/ Crypto, op-log, source index, federation,
sensitivity tiers, embeddings cache, policy
| Tool | Purpose |
|---|---|
recall |
Federated semantic search across user graphs; subject to per-graph tier caps. Hard limits: maxNodes ≤ 50, maxTokens ≤ 8000. Sensitive graphs are clamped further (≤ 5 nodes / 500 tokens). Each response includes an audit footer showing exactly which graphs contributed. |
remember |
Save a note from the current AI conversation. Surfaces contradictions if the SDK detects them. |
correct |
Natural-language correction → bundled local LLM produces a structured diff → preview returned. No write happens here. |
apply |
Commit a previewed correction after user confirmation. |
forget |
Remove a source and all nodes derived from it (soft-delete per SDK semantics). |
stats |
Ground-truth inspection: total / active / soft-deleted node counts per graph, sources, and previews. Used to debug "where did my nodes go?" |
Prerequisites:
- Node 20+ (use
nvm install 20 && nvm use 20) - pnpm 9+ (via
corepack enable && corepack prepare pnpm@9 --activate) - Rust toolchain (
curl https://sh.rustup.rs -sSf | sh) — only for the Tauri shell - Ollama +
llama3.2:3b-instruct-q4_K_M— only for thecorrecttool
Setup:
pnpm install
pnpm -r buildSmoke test (no Tauri, no Claude, no LLM required — exercises the full encryption → ingest → recall → forget loop):
pnpm --filter @graphnosis-app/desktop-sidecar smokeRun the sidecar standalone for MCP wiring into Claude Desktop:
GRAPHNOSIS_CORTEX="$HOME/Graphnosis" \
GRAPHNOSIS_PASSPHRASE="dev-passphrase-change-me" \
pnpm dev:sidecarRun the full desktop app (requires Rust):
pnpm dev:desktopAdd to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"Graphnosis": {
"command": "node",
"args": ["/absolute/path/to/GraphnosisApp/apps/desktop-sidecar/dist/index.js"],
"env": {
"GRAPHNOSIS_CORTEX": "/Users/you/Graphnosis",
"GRAPHNOSIS_PASSPHRASE": "your-passphrase",
"GRAPHNOSIS_DEFAULT_GRAPH": "personal",
"GRAPHNOSIS_POLICY": "/Users/you/Graphnosis/policy.json",
"GRAPHNOSIS_LLM": "llama-3.2-3b"
}
}
}
}Optional policy.json for per-graph sensitivity tiers:
{
"graphs": [
{ "graphId": "personal", "tier": "personal" },
{ "graphId": "health", "tier": "sensitive" },
{ "graphId": "work", "tier": "public" }
]
}After saving, restart Claude Desktop. The MCP server appears as Graphnosis in the tool picker with 6 tools.
| Variable | Purpose | Default |
|---|---|---|
GRAPHNOSIS_CORTEX |
Folder where encrypted graphs + op-log + caches live | (required) |
GRAPHNOSIS_PASSPHRASE |
Cortex passphrase, used for Argon2id key derivation | (required) |
GRAPHNOSIS_DEVICE_ID |
Stable device identifier (op-log attribution + sync) | <hostname>-<pid> |
GRAPHNOSIS_DEFAULT_GRAPH |
Graph ID for remember when none specified |
personal |
GRAPHNOSIS_POLICY |
Path to JSON with per-graph sensitivity tiers | (none — defaults apply) |
GRAPHNOSIS_LLM |
Which catalog LLM to use for correct (llama-3.2-3b, qwen-2.5-3b, llama-3.2-1b) |
recommended (llama-3.2-3b) |
GRAPHNOSIS_EMBED_DISABLE |
Set to 1 to skip local embeddings (TF-IDF only) |
unset |
GRAPHNOSIS_EMBED_CACHE |
Override the model cache dir for fastembed | ~/Library/Caches/GraphnosisApp/models |
GRAPHNOSIS_EMBED_WORKERS |
Number of forked ONNX embedding child processes | 2 |
GRAPHNOSIS_IPC_SOCKET |
Override the Unix socket path for Tauri ↔ sidecar IPC | <cortex>/sidecar.sock |
- At-rest encryption: libsodium
crypto_secretstream_xchacha20poly1305, key derived from the user's passphrase via Argon2id. Passphrase lives only in the OS keychain after first unlock. Stored.gaifiles are unreadable without the key — leaked files are inert. - Recovery: a 24-word phrase shown once at setup; can decrypt the data key without the passphrase. (Implementation in
packages/graphnosis-app-core/src/crypto— currently library-side; UI wiring in Tauri shell pending.) - AI exposure: only the federated subgraph chosen for the current prompt, capped by sensitivity tier per graph. Full
.gainever leaves the device. Everyrecallreturns an audit footer showing per-graph attribution. - Local LLM: corrections run on a bundled small model (default Llama 3.2 3B via Ollama). Never call out to a remote AI for graph mutations.
- Op-log syncing: append-only encrypted event log per device. Drive/iCloud syncs the log directory, not the
.gaifile, so concurrent edits across devices converge without lost data. (Reducer ready inpackages/graphnosis-app-core/src/oplog; materializer pass on load pending.)
onnxruntime-node is an N-API native addon that calls V8 APIs without holding the V8 isolate lock. Running it inside a worker_threads Worker crashes Node with HandleScope::HandleScope Entering the V8 API without proper locking in place. To keep the main event loop free during inference, the sidecar uses forked child processes instead — each fork has its own V8 isolate and main thread, so the native addon runs safely. The parent dispatches texts round-robin and never blocks.
PDF parsing (pdfjs-dist via unpdf) is pure JavaScript/WASM and has no lock requirements, so it runs in a worker_threads Worker (pdf-parse-worker.ts). This frees the main thread during the full parse phase of large documents — IPC connections, stats calls, and the UI stay responsive throughout.
For large documents the sidecar uses ingestChunked(): pages are embedded in batches separated by event-loop yields, but only a single SourceRecord is written at the end. This means chunked ingests appear as one source in the UI with the original file path.
- Mobile app (Phase 2 — Capacitor capture + voice).
- Browser extension for ChatGPT / Gemini (Phase 3).
- Op-log merge engine materialization on load — sketched, not yet wired into
loadGraph. - Ambient capture connectors (calendar, mail, Slack) — Phase 3, strictly opt-in.
- Recovery-phrase UI in the Tauri shell — backend ready, frontend pending.
- Tauri shell completion — autostart, global hotkey, Share Sheet receiver, prompt-context inspector all scaffolded but not implemented end-to-end.
See ~/.claude/plans/i-m-imagining-a-desktop-modular-sprout.md for the full phased roadmap.
Functional Source License, Version 1.1, Apache 2.0 Future License — FSL-1.1-Apache-2.0.
This license lets anyone read, audit, fork, modify, and self-host the code, but prevents commercial "Graphnosis as a service" competitors during the 2-year exclusivity window. After that, each release automatically converts to Apache 2.0.
If you want to use Graphnosis App commercially (hosted, embedded, white-labeled) before that window expires, contact the author about a commercial license.
The Graphnosis engine itself (@nehloo/graphnosis) is and remains Apache 2.0.
Made by Nehloo Interactive LLC.






