The answer has no source.
The answer names a value, a date, a decision. Nothing in it says which file, let alone which bytes of that file.
Okto Neuron is a local-first knowledge graph memory for AI agents, made by Okto Labs. It reads a folder of Markdown notes, extracts claims with an LLM you configure, and serves them over MCP. Ask with sources and each cited source comes back with its file path, byte range and content hash.
For developers who want Claude Code to answer from their own notes and show where the answer came from.
curl -fsSL https://raw.githubusercontent.com/OktoLabsAI/okto-neuron/main/install.sh | bash
Free to run locally · No account required · Source-available (ELv2) · Works with Claude Code
See how an answer is groundedMost agent memory tools hand back prose. The paragraph sounds settled, the source is gone, and a confident wrong number reads exactly like a right one. You cannot check what you cannot locate.
Worse, retrieval can fail quietly. The model was unreachable, the context was cut short, the answer was assembled from nothing, and the paragraph still arrives looking finished.
The answer names a value, a date, a decision. Nothing in it says which file, let alone which bytes of that file.
A fluent sentence carries the same weight whether it was read from your notes or extrapolated to fill a gap.
When the model behind the tool is down or truncates, most tools return the same shape of text. You find out later, if at all.
Okto Neuron is a standalone, local-first knowledge graph usable as a Python library, CLI, and authenticated MCP server. Your Markdown files stay the source of record; the graph is derived from them and can be regenerated from the same files.
Init a vault, ingest files, ask and explore from the terminal. The same code path the server uses.
Import it. Every surface below is a thin wrapper over the same library calls.
Five bearer-authenticated tools. Claude Code is the wired client; the protocol is open to any MCP client.
GET /api/v1/nodes/{id} returns a node, its in and out edges, its provenance record, and the block it came from.
Query, Add, Logs, Browse, Graph, Curation, Config. The Query view exposes 13 retrieval controls.
Runs on Okto Grafx, the Okto Labs embedded graph database. Ladybug and Neo4j are selectable backends; Neo4j needs the
neo4j extra, which the installer does not add.
Each claim is anchored by PROV-O edges to the block it was read from, the extractor activity that
produced it, and the agent responsible. Ask with include_sources=true and the pointer comes
back with the answer.
// the excerpt line the model sees, so it can say the sources do not cover a period
[EXCERPT source=decisions/0012-queue-backend.md bytes=0-388,880-1364 of 2210]
// what comes back (abridged)
{
"text": "On 2026-03-04 the team chose Redis Streams for the job queue, citing a smaller operational footprint than Kafka for the current team size.",
"citations": ["..."],
"subgraph_evidence_ids": [],
"retrieval": {
"synthesis_status": "ok",
"finish_reason": "stop",
"vault": "platform-notes"
},
"sources": [
{
"block_id": "blk_4e11c0",
"path": "decisions/0012-queue-backend.md",
"byte_start": 880,
"byte_end": 1364,
"content_hash": "sha256:7c0e...91af"
}
]
}
explore returns
block_id on claims and relationships too, so you can walk the graph without an LLM in the loop.
Values are illustrative. Walk through a full example.
“Every source block declares which bytes of which file it is.” ADR 0043, D7
A degraded answer never looks like a successful one.
synthesis_status comes back in retrieval on every ask. finish_reason joins it
whenever a provider was called and reported one, and vault_override_ignored appears whenever a vault override
is discarded. Read them before trusting the text. They are how the tool reports a failed model call.
ok empty provider_error truncated abnormal_stop no_llm
Empty text plus provider_error means the model was unreachable, not that the graph lacks the answer. no_llm means no model is configured, so none was called; the citations are still the retrieval hits.
“A degraded answer must never look like a successful one.” ADR 0043, D6
The value is normalized, and the provider's raw value comes back as native_finish_reason when the two differ. Anything other than stop sets synthesis_status to truncated or abnormal_stop. The field is absent when no provider reported a reason, as with no_llm, where no model was called.
When a per-call vault override is discarded, the response says so. You never answer from a different vault than you think you did.
Files or raw text go in. Blocks, claims, and entities come out the other side, but only after deduplication, reconciliation, and a confidence gate. Extraction only proposes candidates; the gate is the only thing that commits.
A file path or raw text is chunked into byte-anchored blocks: path, byte_start, byte_end, content_hash.
An LLM extracts atomic claims and entities from each block. These are candidates, not facts.
Candidates are held with their provenance edges: which block, which extractor run, which agent.
Duplicates are collapsed and entities reconciled against what the graph already holds.
Entity candidates at or above confidence 0.75 auto-commit; below that they are held for review in Curation. Relationships, and the claims minted from them, pass a separate gate that checks endpoint types, the predicate and grounding in the source block, then commits, queues or rejects each one. The 0.75 threshold is configurable.
Committed to the graph store (Okto Grafx by default) and embedded locally with fastembed, in-process.
Five primitives: Agent, Activity, InformationObject, Concept, Place. Six support types: Document, Identifier, Annotation, Claim, Block, Finding. Vocabulary follows PROV-O, SKOS, Dublin Core, BIBFRAME, and CiTO.
When an edit replaces the text an old claim was read from, and an LLM correction judge confirms the new
claim corrects it, the old claim is dated and dropped from recall, with a supersedes edge
from the new one. This happens at ingest, within the same document or resolved subject.
The graph is derived from the vault. Delete the graph and rebuild it from the same files. A rebuild re-runs LLM extraction, so the new graph can differ from the old one, and the history of superseded claims is not recreated.
The MCP server listens on 127.0.0.1:8201 and authenticates every call. Each tool's first docstring line is reproduced below unchanged.
Answer a question grounded in the knowledge graph, with citations.
Seeds wide, synthesizes once, and returns synthesis_status, finish_reason when the provider reported one, and optional byte-exact sources.
Drill into the graph around a topic, then walk outward by node id.
Returns graph structure, not prose, and makes no LLM call at all.
Ingest a source and autonomously curate it into the graph.
sensitivity="local_only" refuses any hosted LLM for that ingest.
List the vault NAMES this server can reach, so you can pick one.
Returns names, deliberately not paths.
Create one application-managed named vault without selecting it.
Accepts loopback callers only. Direct remote serving is disabled in 0.3.0.
LLM calls to the endpoint you set, an optional remote Neo4j you explicitly allow, the installer's
downloads, the embedding model download when fastembed does not already have the model cached, and LLM
call traces if you opt in to MLflow tracing. There is no analytics in the shipped package, and tracing is off until you set
OKTO_NEURON_MLFLOW_TRACKING_URI to a tracking server you choose.
Binds 127.0.0.1. Direct remote serving is disabled in 0.3.0; use an SSH tunnel to reach it from another machine.
Every tool call carries a token. remember and init_vault accept loopback callers only.
The default LLM endpoint is http://127.0.0.1:8123/v1, a server you run. Non-loopback endpoints require explicit remote-egress confirmation.
The default embedder is fastembed, running inside the daemon. Nothing about your text is sent anywhere to be embedded. The model itself is downloaded when fastembed does not find it in its cache.
API keys are never written into vault YAML. Stored with POSIX owner-only permissions, or Windows DPAPI. New installs keep vault data in ~/.okto-neuron/vaults/<name>; installs upgraded from Marginalia keep ~/.marginalia/vaults.
A local-first knowledge graph memory for AI agents. It reads Markdown notes, extracts claims with an LLM you configure, and serves them over MCP, a CLI, a Python library and a Web UI. Every claim points back to the file, byte range and content hash it came from.
It is source-available. From 0.3.0 the license is the Elastic License 2.0 with an addendum covering SaaS, competing services, internal use and branding. Releases up to 0.2.0 stay under Apache 2.0. The source is on GitHub.
Run the one-line installer. It sets up the daemon, the UI and the Claude Code registration. Okto Neuron is not on PyPI yet; the PyPI packages named neuron and marginalia are unrelated projects.
The upgrade from 0.2.0 to 0.3.0 has been rehearsed on Linux, with a locally built 0.3.0 wheel. macOS and Windows have not yet been verified on 0.3.0.
Only these: LLM calls to the endpoint you configure, the installer's downloads, and the embedding model download when fastembed does not already have it cached. Two more are optional and happen only when you set them up: a remote Neo4j you explicitly allow, and LLM call traces if you opt in to MLflow. Your text is embedded locally. If your LLM endpoint is hosted, the text sent to it leaves the machine. There is no analytics in the shipped package.
For ingest and for written answers, yes. The default endpoint is http://127.0.0.1:8123/v1, a server you run. If no model is configured, ask returns synthesis_status: no_llm with the retrieval hits as citations. If a model is configured but unreachable, it returns provider_error. explore makes no LLM call.
The installer registers Claude Code (setup guide). The server speaks MCP over HTTP with a bearer token on 127.0.0.1:8201.
Plain retrieval returns chunks of text. Okto Neuron extracts atomic claims into a graph through a confidence gate, keeps a byte-range pointer on each one, can retire a claim when an edit replaces the fact in the same note and a correction judge confirms it, and reports on every answer whether the model call finished cleanly.
On the next ingest, if the edit replaced the old text and an LLM correction judge confirms the change, the new claim supersedes the old one within the same document or resolved subject. The old claim is dated and linked to the new one. Corrections across documents are flagged for you to review instead of being applied.
Yes, on LoCoMo categories 1-4, from our own harness, with the data published. See Benchmarks.
Marginalia, up to 0.2.0.
Prerelease 0.3.0. The upgrade from 0.2.0 to 0.3.0 has been rehearsed on Linux, with a locally built 0.3.0 wheel. macOS and Windows have not yet been verified on 0.3.0. The installer sets up everything listed here.
curl -fsSL https://raw.githubusercontent.com/OktoLabsAI/okto-neuron/main/install.sh | bash
Up to 0.2.0 this project was called Marginalia. Okto Neuron is not on PyPI yet; the PyPI packages named
neuron and marginalia are unrelated projects.
Using Claude Code? The installer registers it for you. How to check or register it by hand.
claude mcp add --scope user.Pass --no-onboard to skip the first-run prompt.
Free to run locally. No account required.