Skip to content

nehloo-interactive/graphnosis-app

Repository files navigation

Graphnosis™

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


Status

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.


What it does

  1. You pick a folder (local or iCloud/Drive) where your encrypted memory lives.
  2. 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
  3. 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.
  4. 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.


Screenshots

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.

Graphnosis — unlock screen

Check-in tab
Check-in — connect lonely memories
3D Engram tab
3D Engram — explore the whole graph
Deterministic Consolidation tab
Deterministic Consolidation — vitality & memory health
Go Non-Deterministic tab
Go Non-Deterministic — the optional AI layer

And the recall / remember loop, working live with an AI client:

Saving a memory from an AI client
remember — your AI saves a memory; Graphnosis asks which engram first
Recalling a memory from an AI client
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.


Architecture

┌────────────────────────────────────────────────────────────────────────────┐
│  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)          │
                  └─────────────────────────────┘

Repo layout

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

MCP tools exposed to AI clients

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?"

Local development

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 the correct tool

Setup:

pnpm install
pnpm -r build

Smoke test (no Tauri, no Claude, no LLM required — exercises the full encryption → ingest → recall → forget loop):

pnpm --filter @graphnosis-app/desktop-sidecar smoke

Run the sidecar standalone for MCP wiring into Claude Desktop:

GRAPHNOSIS_CORTEX="$HOME/Graphnosis" \
GRAPHNOSIS_PASSPHRASE="dev-passphrase-change-me" \
pnpm dev:sidecar

Run the full desktop app (requires Rust):

pnpm dev:desktop

Wiring into Claude Desktop

Add 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.


Environment variables

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

Security model — short version

  • 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 .gai files 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 .gai never leaves the device. Every recall returns 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 .gai file, so concurrent edits across devices converge without lost data. (Reducer ready in packages/graphnosis-app-core/src/oplog; materializer pass on load pending.)

Embedding pipeline — why two layers of workers

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.


What's deliberately not here yet

  • 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.


License

Functional Source License, Version 1.1, Apache 2.0 Future LicenseFSL-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.