Skip to main content

Privacy-first, offline knowledge graph for developers

Project description

NervaPack

PyPI version Python Versions License: MIT Token Reduction Verified MCP Registry

NervaPack is a privacy-first, offline knowledge graph for your codebase. It solves two fundamental problems with standard Vector RAG:

  • Token waste — chunk-based RAG retrieves blobs of text that may only tangentially relate to your query, bloating your context window.
  • Privacy risk — sending code to cloud embedding APIs leaks your proprietary logic.

NervaPack runs 100% on your machine. It uses tree-sitter to parse your codebase into a deterministic Abstract Syntax Tree graph, then uses a local Ollama model to draw hard semantic edges between your documentation and your code. Queries traverse this graph with a K-Hop BFS, returning a hyper-targeted, token-efficient context window — no cloud required.


Verified Performance

91.2% Average Token Reduction — independently verified on real-world codebases.

Test Type Tokens (Naive) Tokens (NervaPack) Reduction
Simple Query 10,926 101 99.1%
Medium Query 13,092 164 98.7%
Complex Query 3,290 1,102 66.5%
Average 52,037 2,459 91.2%

Cost Savings: $181–$724 per developer per year (GPT-4o to Claude Sonnet)

📊 View Full Benchmarks · 🧪 Messy Code Performance

Code quality impact: 90–99% reduction on clean code, 50–75% on legacy/messy code. Even poorly structured codebases benefit significantly.


Why NervaPack vs. standard Vector RAG

Standard Vector RAG NervaPack
Parsing Arbitrary text chunks Deterministic AST nodes (class, function, import)
Retrieval Nearest-neighbour blob K-Hop BFS on a structural graph
Doc ↔ Code links None Hard EXPLAINS edges drawn by local LLM
Privacy Cloud embeddings 100% local (ChromaDB + ONNX + optional Ollama)
Incremental sync Re-index everything Surgical per-file update via GitPython diff
Token savings No measurement Built-in dashboard shows exact reduction per query
Graph visibility Black box Interactive HTML visualization of every node and edge
Duplicate-safe Repeated ingest = duplicate data upsert — re-ingest is idempotent
Agent memory None 17-tool MCP server for cross-session memory

Prerequisites

  • Python 3.10+
  • Git — your project must be a git repository (git init if not)

(Optional for semantic code-doc binding) — an LLM provider. Structural graph indexing and basic queries work out-of-the-box with zero configuration and no cloud connection.

Provider Setup Cost Privacy
Ollama (default) brew install ollama && ollama pull llama3 Free 100% local
Claude API pip install "nervapack[claude]" + ANTHROPIC_API_KEY ~$0.25/1k calls Cloud
OpenAI API pip install "nervapack[openai]" + OPENAI_API_KEY ~$0.15/1k calls Cloud
MCP (Claude Code) Zero config Included in subscription Cloud

Installation

# Recommended
pip install nervapack

# With optional features
pip install "nervapack[mcp]"          # MCP server for Claude Code / Cursor
pip install "nervapack[memory]"       # agent memory MCP server
pip install "nervapack[metrics]"      # exact token counts (tiktoken)
pip install "nervapack[dashboard]"    # web dashboard (streamlit + plotly)
pip install "nervapack[claude]"       # Claude API support
pip install "nervapack[openai]"       # OpenAI API support
pip install "nervapack[all]"          # everything

On first run, ChromaDB downloads an ONNX embedding model (~30 MB) to ~/.cache/chroma/. This is a one-time download.


Quick Start

cd your-project/

# 1. Build the knowledge graph (runs locally, no LLM required for basic use)
nervapack ingest .

# 2. Query for context — get focused results + token savings dashboard
nervapack query "How does authentication work?"

# 3. Add semantic doc-to-code edges (requires an LLM)
nervapack enrich .

# 4. Visualize the full graph
nervapack visualize --enhanced --communities

# 5. After changing files, sync incrementally (fast — only changed files)
nervapack sync .

# 6. If you ingested wrong data or need a fresh start
nervapack clean --all
nervapack ingest .

# 7. Check system health
nervapack doctor

Command Reference

nervapack ingest [PATH] — Build the graph

Scans PATH (default: .) and builds the full knowledge graph.

What happens:

  1. Walks the directory tree with tree-sitter, skipping dist/, build/, node_modules/, venv/, site/, .tox/, and dozens of other build directories automatically.
  2. Parses source files into exact AST nodes: classes, functions, imports.
  3. Chunks all .md files by header hierarchy.
  4. Embeds every entity into a local ChromaDB vector store (ONNX by default, Ollama optional).
  5. Optionally binds doc chunks to code nodes via an LLM, adding EXPLAINS edges.
  6. Saves the graph once to .nervapack/graph.graphml.

Re-ingesting is safeupsert is used throughout, so running ingest twice does not duplicate data.

nervapack ingest .                           # auto-detect LLM
nervapack ingest . --llm ollama              # force Ollama
nervapack ingest . --llm claude              # use Claude API
nervapack ingest . --llm openai --model gpt-4o-mini
nervapack ingest . --embeddings ollama       # use Ollama for embeddings too

Supported languages (bundled): Python, JavaScript, JSX, TypeScript, TSX

Additional languages:

pip install "nervapack[go]"            # Go
pip install "nervapack[rust]"          # Rust
pip install "nervapack[java]"          # Java
pip install "nervapack[c]"             # C / C headers
pip install "nervapack[cpp]"           # C++
pip install "nervapack[ruby]"          # Ruby
pip install "nervapack[csharp]"        # C#
pip install "nervapack[all-languages]" # all of the above

Exclude directories — create .nervapackignore in your project root (gitignore syntax):

dist/
build/
site/
generated/
*.egg-info/

nervapack query PROMPT — Query the graph

Retrieves focused context for a natural-language prompt and prints a token savings dashboard.

What happens:

  1. Intent detection — "what breaks if I change X" routes to impact analysis (reverse BFS); exact symbol names bypass vector search.
  2. ChromaDB returns the top-3 most semantically similar nodes.
  3. Those nodes seed a K-Hop BFS through the NetworkX graph (default: 1 hop, both directions).
  4. Adjacent nodes — including any markdown docs via EXPLAINS edges and memory notes via TOUCHES edges — are collected.
  5. A focused Markdown context block is printed, ready to paste into an LLM prompt.
  6. Token efficiency panel shows savings vs. naive "dump the whole file" RAG.
nervapack query "How does authentication work?"
nervapack query "What calls VectorStore?"
nervapack query "what breaks if I change GraphBuilder"  # impact analysis

Example output:

Query: "How does authentication work?"

Query Router: Intent: semantic, Direction: both
Vector Search: Found 3 seed nodes

Retrieved Context:
──────────────────────────────────────────────────────────
# NervaPack Context Retrieval
## File: `src/auth/middleware.py`
### CLASS: AuthMiddleware (L15-L42)
...
──────────────────────────────────────────────────────────

╭──────────────  NervaPack Token Efficiency  ──────────────╮
│  Strategy              Tokens   Reduction                 │
│  Naive RAG (3 files)   12,840   100% (base)              │
│  NervaPack              1,180     9.2%                    │
│ ─────────────────────────────────────────────────────────│
│  Tokens saved: 11,660   Reduction: 90.8%                 │
│  Cost saved (GPT-4o $2.50/1M): $0.0292 per query         │
╰───────────────────────────────────────────────────────────╯

nervapack sync [PATH] — Incremental update

Updates only the files that changed since the last ingest. Uses GitPython to diff the working tree.

nervapack sync .

A full ingest on a large project can take minutes. sync turns that into a 2–5 second surgical update per file. Re-parses changed files, batch-upserts new vectors, and saves the graph once at the end.


nervapack clean [OPTIONS] — Remove ingested data

Wipe graph data and start fresh. Use this when you have duplicate vectors, ingested the wrong directory, or need to reduce disk usage.

nervapack clean --vectors          # wipe ChromaDB only (chroma_db/)
nervapack clean --graph            # delete graph.graphml only
nervapack clean --history          # clear query + graph history logs
nervapack clean --all              # everything above (keeps memory.db)
nervapack clean --all --yes        # skip confirmation (CI / scripts)

Never deleted by clean: memory.db — your agent memory is always safe.

Typical workflow after a bad ingest:

nervapack clean --all
nervapack ingest .

nervapack enrich [PATH] — Add semantic edges

Runs LLM doc-to-code binding on an already-ingested graph. Use this if you:

  • Ran ingest without an LLM and want to add EXPLAINS edges now.
  • Added new documentation and want to bind it without a full re-ingest.
nervapack enrich .                           # auto-detect LLM
nervapack enrich . --llm ollama --model llama3
nervapack enrich . --llm claude              # shows cost estimate before proceeding

nervapack status [--detailed] — Graph health

nervapack status            # node/edge counts + unsynced files
nervapack status --detailed # full analytics: health score, language distribution, coverage

Health score (0–100) factors in documentation coverage, node connectivity, graph density, and edge diversity. A structural-only graph typically scores 30–40; after enrich it rises to 70–90.


nervapack visualize [OPTIONS] — Interactive HTML graph

nervapack visualize                           # basic visualization
nervapack visualize --enhanced                # + real-time search + path finder
nervapack visualize --enhanced --communities  # + community detection (Louvain)
nervapack visualize --output ~/my-graph.html  # custom output path
nervapack visualize --no-browser              # generate without opening

Produces a standalone HTML file with no external dependencies — drag, zoom, search, find shortest paths between nodes.


nervapack explore TARGET [--hops N] — Focused subgraph

Extract and visualize the N-hop neighbourhood of a specific file, class, or function.

nervapack explore GraphBuilder --hops 2
nervapack explore src/auth/middleware.py --hops 1
nervapack explore "function:parse"

nervapack dependencies [FILE] — Import dependency analysis

Analyze file-level import chains, detect circular dependencies, and visualize the dependency graph.

nervapack dependencies                        # full project analysis
nervapack dependencies src/graph/builder.py   # single file
nervapack dependencies --no-cycles            # skip cycle detection

nervapack hotspots [OPTIONS] — Change frequency analysis

Show which files change most often in git history — prime targets for documentation and review.

nervapack hotspots                            # top 20 by commit count
nervapack hotspots --since "6 months ago"    # recent history only
nervapack hotspots --ext .py --churn         # Python files, sort by lines changed

nervapack history [OPTIONS] — Query history

nervapack history              # last 10 queries with token savings
nervapack history --limit 50   # last 50
nervapack history --stats      # aggregate: total savings, cost avoided, top topics
nervapack history --clear      # delete history

nervapack serve [--port N] — Web dashboard

nervapack serve                # http://localhost:8501
nervapack serve --port 8080    # custom port

Requires nervapack[dashboard]. Shows graph overview, language distribution, analytics, query history trends, and an interactive graph explorer.


nervapack doctor — Environment check

nervapack doctor

Verifies Python version, tree-sitter grammars, embedding backend, Ollama connectivity, and MCP config. Run this after installation or when troubleshooting.


Storage Layout

Everything lives in .nervapack/ inside your project root:

.nervapack/
├── graph.graphml          # NetworkX DiGraph (AST + EXPLAINS edges)
├── chroma_db/             # ChromaDB vector store (ONNX embeddings)
├── memory.db              # Agent memory (SQLite + FTS5, bi-temporal)
├── query_history.jsonl    # Per-query token savings log
└── graph_history.jsonl    # Ingest/sync event log

Add .nervapack/ to .gitignore to keep it out of version control.

Disk usage guide:

  • chroma_db/ — typically 10–100 MB depending on project size. Run nervapack clean --vectors && nervapack ingest . if it grows unexpectedly.
  • graph.graphml — typically 0.5–5 MB.
  • memory.db — grows with agent usage; rarely exceeds a few MB.

MCP Integration (Claude Code, Cursor, Windsurf)

NervaPack ships two MCP servers in the same package. Drop this .mcp.json in your project root:

{
  "mcpServers": {
    "nervapack": {
      "command": "nervapack-mcp",
      "description": "NervaPack knowledge graph (v0.6.1) — query, graph_status, explore, impact"
    },
    "nervapack-memory": {
      "command": "nervapack-memory-mcp",
      "description": "NervaPack agent memory (v0.6.1) — store, recall, and reason over facts across sessions"
    }
  }
}

Knowledge Graph MCP tools (nervapack-mcp)

Tool What it does
query Vector search → K-Hop BFS → focused Markdown context + token savings
graph_status Node/edge counts, language breakdown, unsynced file warnings
explore Browse all indexed classes, functions, imports, markdown docs
impact Reverse dependency analysis — find what depends on a given entity

Agent Memory MCP tools (nervapack-memory-mcp) — 17 tools

Tool Purpose
memory_start_session Open a named session
memory_store Persist a fact, decision, outcome, procedure, preference, or action
memory_recall FTS5 search → graph expansion → scored, budget-capped recall
memory_about Entity dossier: all facts/decisions linked to one entity
memory_why Explain a decision: rationale, rejected alternatives, outcomes
memory_timeline Chronological trace including superseded versions
memory_end_session Close session with an outcome summary
memory_forget Tombstone or hard-purge nodes
memory_verify Confirm (confidence +0.1) or refute (close + confidence ×0.5)
memory_stats Node counts, DB size, top entities, all namespaces
memory_list_sessions List all sessions with node counts
memory_clear_session Delete a session and all its nodes
memory_for_code Memories that TOUCH a source file or specific line
memory_to_code Code locations a memory node TOUCHES
memory_import Bulk-seed memory from a JSON array
memory_switch_namespace Switch the active namespace
memory_verify_staleness Flag memories whose source file changed since stored

CLAUDE.md template

Add to your CLAUDE.md to wire NervaPack into every Claude Code session:

## Always use NervaPack MCP tools

At the start of every session:
1. Call `memory_start_session("<task name>")` to open a named session.
2. Call `memory_recall("project context", budget_tokens=400)` to load prior decisions.
3. Call `query("<topic>")` before answering any question about how the code works.

During the session — call `memory_store` for:
- Any decision made (kind="decision" with rationale and alternatives_rejected)
- Any fact discovered about system behaviour (kind="fact")
- Any procedure or convention established (kind="procedure")

At session end — call `memory_end_session("<one-paragraph summary>")`.

Architecture

nervapack ingest .
       │
       ├─ ASTParser (tree-sitter)               16 extensions, 10 languages
       │    └─ ParsedEntity[]: class, function, import
       │
       ├─ GraphBuilder (NetworkX DiGraph)
       │    ├─ Nodes: file, class, function, import, markdown
       │    ├─ Edges: DEFINES (AST, confidence=1.0)
       │    ├─ Edges: REFERENCES (heuristic name overlap, confidence=0.7)
       │    └─ Edges: EXPLAINS (LLM or keyword binding, confidence=0.5–0.9)
       │
       ├─ VectorStore (ChromaDB)
       │    ├─ Embedding: ONNX (default) or Ollama
       │    └─ upsert — re-ingest is idempotent
       │
       └─ GraphHistory  — snapshot recorded after each ingest/sync

nervapack query "..."
       │
       ├─ Intent detection (impact / exact / semantic)
       ├─ VectorStore.search() → seed node IDs
       ├─ GraphRetriever.retrieve_context()
       │    └─ deque BFS, direction: forward / reverse / both
       ├─ MemoryStore.get_touches_for_file() → memory context injection
       └─ TokenMeter → savings vs. naive RAG

nervapack clean --all
       └─ Deletes chroma_db/, graph.graphml, history logs
          Never touches memory.db

Key source modules:

Module Responsibility
nervapack.parser.ast_parser tree-sitter parsing → ParsedEntity; shared singleton parser instance
nervapack.parser.md_chunker Markdown → header-delimited chunks; prunes build dirs from os.walk
nervapack.graph.builder NetworkX DiGraph; O(1) file-index for sync; compiled regex for REFERENCES
nervapack.graph.vector_store ChromaDB upsert (idempotent); pluggable embedding function
nervapack.graph.retrieval K-Hop BFS with deque (O(n) not O(n²))
nervapack.graph.token_meter tiktoken singleton; token savings panel
nervapack.graph.query_history Tail-read JSONL — O(limit) not O(total)
nervapack.graph.analytics Bulk graph.degree() — single call not per-node loop
nervapack.llm.base bind_docs_to_ast with keyword pre-filter (top-12 candidates)
nervapack.llm.providers.ollama ollama.list() cached 60 s
nervapack.memory.store SQLite + FTS5; bi-temporal; batch_neighbors for O(1) hop expansion
nervapack.memory.recall Batched hop expansion; audit trail on recall
nervapack.mcp_server FastMCP — query, graph_status, explore, impact
nervapack.memory.mcp_server FastMCP — 17 memory tools

nervapack.memory — Agent Memory

Stop re-pasting project context into every new chat.

# Store a decision
memory_store(
    "Chose JWT over session cookies for auth_service — stateless horizontal scaling",
    kind="decision",
    entities=["auth_service"],
    confidence=0.9,
    rationale="Stateless tokens enable horizontal scaling without shared session store.",
    alternatives_rejected=["server-side sessions", "PASETO"],
)

# Recall in any future session
memory_recall("project context", budget_tokens=400)
## Memory recall: "project context" (6 items · 171/400 tokens)

### Decisions
- [d_0019f2] 2026-06-05 · conf 0.90 — Chose JWT for auth_service

### Facts
- [f_0019f3] 2026-06-05 · conf 1.00 — auth_service issues 15-min access tokens

### Procedures
- [p_0019f5] 2026-06-12 · conf 1.00 — Deploy: GitHub Actions → staging → prod manual

Token efficiency:

Approach Tokens per session After 20 sessions
Manual paste (architecture doc) ~2,400 ~48,000
memory_recall ~171 ~3,420
Savings 93% fewer tokens

CLI:

nervapack-memory init                          # create schema
nervapack-memory stats                         # counts + top entities
nervapack-memory search "JWT auth"             # FTS search
nervapack-memory timeline "auth service"       # chronological trace
nervapack-memory audit d_0019f2abc             # access audit trail
nervapack-memory rebind old/path.py new/path.py  # update file links after rename
nervapack-memory export --out dump.json        # JSON dump

Data model: 8 node kinds, 7 edge kinds, bi-temporal (valid_from/valid_until), never hard-deletes by default.


Privacy

NervaPack is 100% offline by default:

  • Embeddings use ChromaDB's built-in ONNX model (runs on CPU, no cloud).
  • LLM calls (when using Ollama) go to localhost:11434 only.
  • All graph and vector data lives in .nervapack/ inside your project.
  • No telemetry, no analytics, no network calls at runtime.

Only if you explicitly pass --llm claude or --llm openai does any code leave your machine.


Contributing

  1. Fork the repo and create a branch.
  2. Run tests: python3 -m pytest tests/memory/ -q
  3. Run docs check: python3 -m mkdocs build --strict
  4. Open a pull request against master.

Bug reports and feature requests: issue tracker.


License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nervapack-0.6.2.tar.gz (110.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nervapack-0.6.2-py3-none-any.whl (117.7 kB view details)

Uploaded Python 3

File details

Details for the file nervapack-0.6.2.tar.gz.

File metadata

  • Download URL: nervapack-0.6.2.tar.gz
  • Upload date:
  • Size: 110.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.1

File hashes

Hashes for nervapack-0.6.2.tar.gz
Algorithm Hash digest
SHA256 2b2841fa727d0784a0a393ead707836c0983060441b2caf130908b8569ab6e11
MD5 bd181a0109956542d02f2d5f1c83a2c9
BLAKE2b-256 3e6be04628ed4cd7857e7c307cdb0b69df142ce1e014b18bd85e204578b8e4a0

See more details on using hashes here.

File details

Details for the file nervapack-0.6.2-py3-none-any.whl.

File metadata

  • Download URL: nervapack-0.6.2-py3-none-any.whl
  • Upload date:
  • Size: 117.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.1

File hashes

Hashes for nervapack-0.6.2-py3-none-any.whl
Algorithm Hash digest
SHA256 7a321f44eb8eb19f87b1eae7c561d0b3dd2219c3a1b48358d504d2648e3a5788
MD5 d7ac554d538df6e25de9d2cd5ff45e7e
BLAKE2b-256 426cfbd8317c9b41805e291e5af019c04a6d6c139483a06ac65e35e3c036c196

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page