Neuron Documentation
neuron (v1.0.0) is a graph-backed cognitive memory layer for AI agents. It ingests text, abstracts beliefs with an LLM, stores nodes and edges, and retrieves context with vector seeds plus graph expansion—optionally with adaptive strategy evolution and maintenance.
Graph-backed
Beliefs are linked by semantic edges; retrieval walks the graph from vector seeds.
Adaptive
Per-user retrieval strategies evolve from feedback when
ENABLE_ADAPTIVE_MEMORY=true.
Production storage
Postgres+pgvector, Neo4j, or in-memory via pluggable GraphStore.
Technical Pipeline #
Public exports: from neuron import Memory, AdaptiveMemory, Node, Edge, settings.
Requires Python 3.11+.
Quickstart #
cd neuron
pip install -e .
set GRAPH_STORE_TYPE=in_memory
python examples/demo.py
from neuron import Memory
memory = Memory()
memory.process("Project Apollo started in 1961.", user_id="user_1")
ctx = memory.retrieve("When did Apollo start?", user_id="user_1")
print(ctx["direct_beliefs"])
Installation & deployment #
Package install
pip install -e .
Dependencies include FastAPI, uvicorn, pydantic-settings, psycopg2-binary, pgvector, openai, anthropic, sentence-transformers, neo4j, celery, redis.
Postgres + pgvector
docker compose up -d db
set DATABASE_URL=postgresql://postgres:postgres@localhost:5432/neuron
set GRAPH_STORE_TYPE=postgres
Run the API or setup from the repo root so neuron/graph/schema.sql
resolves correctly.
Neo4j
set GRAPH_STORE_TYPE=neo4j
set NEO4J_URI=bolt://localhost:7687
HTTP API
python -m uvicorn neuron.api.server:app --host 0.0.0.0 --port 8000
CLI
neuron init creates .env.example in the current directory.
Configuration #
All settings in neuron/config.py load from env + .env. Use
from neuron import settings in Python.
Data models #
Node
| Field | Type | Default | Description |
|---|---|---|---|
id |
UUID | auto | Primary key |
user_id |
str | required | Tenant isolation |
label |
str | required | Distilled belief text (truncated to max_label_length) |
confidence |
float | 0.5 | 0.0–1.0 |
evidence_count |
int | 1 | Reinforcement count |
contradiction_count |
int | 0 | Contradiction tally |
domain_tags |
List[str] | [] | Topic tags |
entities |
List[str] | [] | Named entities |
temporal_stability |
enum | stable | stable | volatile | time-bound |
abstraction_level |
enum | specific | specific | pattern | principle |
embedding |
List[float]? | None | Vector for search |
deprecated |
bool | false | Archived / pruned |
Edge
| Field | Type | Description |
|---|---|---|
relation |
enum | supports | contradicts | refines | depends_on | derived_from | temporal_successor | unresolved_tension |
weight |
float | 0.0–1.0 connection strength |
Adaptive models
RetrievalStrategy: id, user_id, k_seeds, traversal_depth, min_edge_weight,
fitness_score, generations_survived, parent_id.
RetrievalEvent: id, user_id, query, strategy_id, nodes_found, score (0–1 feedback).
Memory API #
Primary class: neuron.memory.Memory. Dependency injection via store,
embedder, engine.
Wires GraphStore (from GRAPH_STORE_TYPE), Embedder, AbstractionEngine, SurpriseFilter, Retriever. Postgres failure falls back to in-memory when postgres is selected.
| Argument | Type | Default | Description |
|---|---|---|---|
store |
GraphStore? | auto | Custom graph backend |
embedder |
Embedder? | auto | Custom embedding engine |
engine |
AbstractionEngine? | auto | Custom LLM abstraction |
Surprise filter → confirmations (evidence +0.05) → if novel: extract, add node, entity + semantic edges.
node = memory.process("Fact about project X", user_id="user_1")
Delegates to Retriever. Override retrieval via kwargs (else settings defaults).
| Kwarg | Type | Default (settings) | Description |
|---|---|---|---|
k_seeds |
int | K_SEEDS (5) | Vector nearest neighbors |
traversal_depth |
int | TRAVERSAL_DEPTH (3) | Graph hops |
min_edge_weight |
float | MIN_EDGE_WEIGHT (0.6) | Skip weaker edges |
max_context_nodes |
int | MAX_CONTEXT_NODES (50) | Context cap |
min_confidence |
float | MIN_CONFIDENCE (0.35) | direct_beliefs floor |
{
"direct_beliefs": [{"label": "...", "confidence": 0.8, "evidence": 3}],
"related_context": [{"label": "...", "confidence": 0.6}],
"unresolved_tensions": [{"belief_a": "...", "belief_b": "...", "relation": "contradicts"}]
}
Bypass surprise filter; still runs AbstractionEngine.extract.
No LLM: batch embed, cosine dedupe, optional global store dedupe, kNN edges, bulk write.
Returns: {"nodes_added", "edges_added", "duplicates_dropped"}
Alias for process_batch_fast.
Dedupe like fast, then windowed batch_extract; entity hub linking; global dedupe merges entities.
window_size defaults to settings.batch_window_size (20).
Prune stale low-confidence nodes; optional entity-cluster consolidation via LLM.
Returns: {"pruned", "consolidated"}
Batch ingestion pipelines #
process_batch_fast
embed_batch→ cosine similarity matrix- Greedy intra-batch dedupe at
deduplication_threshold(default 0.95) - If
global_deduplication: match store → evidence increment instead of new node - Top
knn_edgesneighbors per kept row →refinesedges add_nodes_batch/add_edges_batch
process_batch_deep
Same dedupe, then AbstractionEngine.batch_extract per window. Nodes use abstraction
metadata; global dedupe also merges entities lists.
Global deduplication
Set global_deduplication=True on fast or deep batch to cross-check the store: matching
nodes get evidence_count += 1 and confidence bump (+0.05, cap 0.95) instead of
duplicate nodes.
Retrieval pipeline #
Implemented in neuron.retrieval.retriever.Retriever.
- Embed query;
search_nearest_nodeswithk_seeds - Deep recall: if no seeds or top similarity < 0.6, search
search_deprecated_nodes; reactivate if archived sim > 0.6 - Graph expansion: native
traverse_graph(Neo4j) or Python BFS viaget_edges_batch - Myelination: traversed edges
weight *= 1.05(cap 1.0),evidence_count += 1, batchupdate_edges_batch - Assemble
direct_beliefs,related_context,unresolved_tensions
Adaptive Memory API #
Use AdaptiveMemory() with ENABLE_ADAPTIVE_MEMORY=true. Mode is
ADAPTIVE_MODE env (auto | manual | off) —
not a constructor argument. auto starts SleepScheduler background
thread.
Same DI as Memory; adds StrategyRegistry, SleepConsolidator.
When adaptive enabled: epsilon-greedy strategy → overrides k_seeds,
traversal_depth, min_edge_weight → logs RetrievalEvent → adds event_id to result.
Updates strategy fitness for the event's strategy (score 0.0–1.0).
Vector search on deprecated nodes only (manual deep recall).
Defaults: pruning=True, consolidation=True, min_confidence from settings.
force_sleep skips if both pruning and consolidation false.
graph_health returns total_nodes, confidence_ratio, prune_ratio,
status: empty | healthy | noisy.
Alias for process_batch_fast; logs ActivityLog on writes when adaptive enabled.
flowchart TD retrieve[retrieve] --> event[Log RetrievalEvent] event --> feedback[submit_feedback] scheduler[SleepScheduler] --> sleep[force_sleep] sleep --> score[ImplicitScorer] score --> evolve[StrategyRegistry.evolve] sleep --> maint[Memory.maintenance]
Maintenance & coherence #
Memory.maintenance
Marks stale nodes deprecated; consolidation clusters entities with ≥5 nodes → LLM master belief (see implementation notes).
CoherenceDaemon.run_cycle
LLM conflict resolution, prune stale, strengthen high-evidence beliefs. Requires store support for contradiction/stale/strengthen queries (no-op on in-memory).
SleepConsolidator
Scores retrieval events, evolves strategies when ≥50 events, runs maintenance.
Internal components #
SurpriseFilter.evaluate(text, user_id)
novelty_score = 1 - max_sim; novel if ≥ BASE_NOVELTY_THRESHOLD; confirmation_targets in [CONFIRMATION_RANGE_START, END].
AbstractionEngine
extract(text, retries=2), batch_extract(texts, retries=2) →
AbstractionResult JSON via LLM provider.
Embedder
SentenceTransformers when groq/ollama or no OpenAI key; OpenAI if key + model name contains text-embedding; else deterministic mock vectors.
StrategyRegistry
select_strategy(user_id), update_fitness, evolve(user_id) with
mutation on k_seeds, depth, min_edge_weight.
ImplicitScorer
Heuristic scoring; judge_with_llm is a stub (JUDGE_LLM_MODEL reserved).
GraphStore interface #
ABC: neuron.graph.store_interface.GraphStore
setup(),add_node,add_nodes_batch,get_node,get_nodes_batchsearch_nearest_nodes(embedding, user_id, k=5),search_deprecated_nodesadd_edge,add_edges_batch,get_edges,get_edges_batch,update_edge,update_edges_batchupdate_node,list_nodes,get_nodes_by_entity- Adaptive:
log_activity,log_retrieval_event,add_strategy,get_strategies,update_strategy,get_users_needing_maintenance,get_retrieval_events,get_retrieval_event - Maintenance:
get_stale_nodes,get_contradiction_pairs,get_nodes_for_strengthening - Optional:
traverse_graph(start_node_ids, depth, user_id)— Neo4j native; Postgres uses Python BFS
| Feature | Postgres | Neo4j | In-memory |
|---|---|---|---|
| Persistence | Yes | Yes | No |
| pgvector / HNSW | Yes | Vector index | Yes |
| traverse_graph | Recursive SQL + edges | APOC or BFS fallback | BFS |
| Coherence / adaptive hooks | Yes | Yes | Yes |
| search_deprecated_nodes | Yes | Yes | Yes |
HTTP API #
FastAPI app uses Memory(), not AdaptiveMemory — no event_id or feedback
endpoints.
| Method | Path | Body | Response |
|---|---|---|---|
| POST | /v1/memory/process |
{text, user_id} |
{status, node} |
| POST | /v1/memory/retrieve |
{query, user_id} |
{status, context} |
| POST | /v1/memory/consolidate/{user_id} |
— | CoherenceDaemon.run_cycle |
| GET | /health |
— | {status: healthy} |
curl -X POST http://localhost:8000/v1/memory/process \
-H "Content-Type: application/json" \
-d "{\"text\": \"Hello\", \"user_id\": \"u1\"}"
TypeScript SDK #
neuron/sdk-ts/memory.ts
import { Memory } from './memory';
const mem = new Memory('user_1', 'http://localhost:8000');
await mem.process('Fact');
await mem.retrieve('query');
await mem.consolidate();
| Method | Args | Returns |
|---|---|---|
constructor |
userId, baseUrl='http://localhost:8000' | Memory |
process(text) |
string | Promise<Node | null> |
retrieve(query) |
string | Promise<RetrievalContext> |
consolidate() |
— | Promise<void> |
Framework integrations #
| Module | Class | Key methods |
|---|---|---|
integrations.langchain |
NEURONMemory | load_memory_variables → retrieve; save_context → process |
integrations.langgraph |
NEURONCheckpointer | get_tuple, put, list |
integrations.llamaindex |
NEURONMemoryStore | get, put, reset, from_defaults(user_id) |
integrations.crewai |
NEURONSharedMemory | save(task_output), search(query) → str |
CLI & daemon #
neuron init — writes .env.example with GROQ_API_KEY, LLM_PROVIDER, DATABASE_URL.
Celery: neuron.daemon.tasks, broker redis://{REDIS_HOST}:6379/0, task
run_coherence_cycle(user_id).
Tuning guide #
- Cheaper ingest: process_batch_fast; raise deduplication_threshold; enable global_deduplication
- Fewer new nodes: raise BASE_NOVELTY_THRESHOLD; widen confirmation band
- Richer context: increase K_SEEDS, TRAVERSAL_DEPTH, MAX_CONTEXT_NODES
- Stricter context: lower depth/seeds; raise MIN_EDGE_WEIGHT, MIN_CONFIDENCE
- Adaptive: ENABLE_ADAPTIVE_MEMORY=true; ADAPTIVE_MODE=manual + force_sleep off-peak
- Custom extraction: override ABSTRACTION_PROMPT or subclass AbstractionEngine
Testing #
pip install -e .
pytest tests/ -q
python tests/batch_fast_test.py
python tests/adaptive_test.py
Implementation notes #
- HTTP API does not expose adaptive feedback or event_id.
- In-memory store returns empty for coherence maintenance queries.
- Postgres unreachable with GRAPH_STORE_TYPE=postgres falls back to in-memory with a warning.