@kovartravis/neuron
v2.5.0
Published
Persistent, local-first memory for AI coding agents (Claude Code, Codex CLI, Cursor, Copilot CLI): plain markdown in your repo, schema-enforced, relevance-gated recall via harness hooks or MCP. 100% offline.
Maintainers
Readme
neuron 🧠
Give your AI coding agent a memory that's actually yours — plain markdown in your repo, enforced by a schema it can't write around.
Website & docs: kovartravis.github.io/neuron · Works with: Claude Code, OpenAI Codex CLI, Cursor, GitHub Copilot CLI, any MCP client · Platforms: macOS, Linux, Windows
30 seconds, start to finish
npm install -g @kovartravis/neuron # or: curl -fsSL https://raw.githubusercontent.com/kovartravis/neuron/main/install.sh | sh
cd your-project
neuron init # detects your agent harness, wires recall hooks, downloads local modelsFrom then on, the agent writes what it learns and the harness injects it back when it's relevant — no prompt instruction the model can skip. This is a verbatim capture from a Claude Code session in this repo, the turn after a fix was recorded:
$ npm test
PreToolUse:Bash hook additional context:
- [learning] Fix for a false-positive Bash-command match in the ticket-07
hint-follow instrument: recordToolUse's QUERY_COMMAND_PATTERN was a bare
substring test, so any Bash command that merely quoted the phrase got
logged as a real query invocation. Fixed by anchoring the pattern to a
shell separator (…)The store behind it is a markdown file in the repo. Open
.neuron/learning.md — that's the real one.
Your agent's memory shouldn't be a black box
Most persistent-memory tools stash what your agent learns in a database or a compiled index — somewhere you'd need a special viewer just to look at. The thing shaping your agent's behavior every session lives somewhere you can't open, diff, or put in a pull request.
Neuron puts it in your repo instead. Conventions, past fixes, decisions,
project notes — all plain .neuron/*.md files, right next to your code.
Open them in any editor. Read them top to bottom. Fix a line by hand.
Review changes to them exactly like you review changes to code, in a normal
git diff.
And it's not just "tell the agent to write markdown" — anyone can write
that prompt, and nothing stops an agent from ignoring it. Neuron's CLI
enforces your schema at write time. Declare that every decisions entry
needs a ticket and a reviewedBy, and the write is refused without
them — no matter what the agent's prompt says.
Why teams reach for Neuron
- 📄 Markdown is the source of truth.
.neuron/*.mdfiles — human-readable, git-diffable, hand-editable. SQLite sits underneath as a disposable semantic-search index, rebuilt from the markdown automatically. Delete it any time; nothing is lost. It lives in a per-machine cache by default — nothing to commit, nothing to.gitignore. - 🔒 A malformed entry simply can't land. Declare required and
enum-typed fields per category in
neuron.yaml, and every write — from the CLI or fromneuron scan— is validated before it lands, with an error naming exactly what's missing. - 🔌 Recall that's guaranteed, not requested. On Claude Code and OpenAI
Codex CLI,
neuron initwires a hook that injects relevant memory before the model ever sees the prompt. The harness enforces it — no agent judgment call required. - 🎯 A two-stage relevance gate. Every candidate clears a lexical filter, then a local ONNX cross-encoder reranker — no remote API call — before it's ever injected. On the hardest out-of-corpus test we could build, that cut the false-accept rate from 99.80% to 19.4%.
- 🏛️ Your architecture, as a living markdown artifact.
neuron scanparses your codebase with real Tree-Sitter ASTs and writes a blueprint card that stays byte-identical until the code actually changes — gate CI on it like any other diff. - 🕵️ Your git history becomes searchable memory too. Commits get indexed and matched against every prompt with the same relevance mechanism as your notes, so "how did we fix X" surfaces the actual commit that did it.
- 🔒 100% offline & private. Local ONNX embeddings, no API keys, no cloud calls, ever. Your code and your memory never leave your machine.
How it compares
| | CLAUDE.md / AGENTS.md | Hosted memory API (Mem0, Zep, …) | neuron |
|---|---|---|---|
| Where memory lives | One growing prose file | Behind a vendor API | Markdown in your repo |
| What enters each prompt | The whole file, every time | Whatever the API returns | Only what clears a relevance gate |
| Structure | None | Vendor schema | Your schema, enforced at write time |
| Reviewing changes | git diff | Vendor dashboard | git diff, same as code |
| Offline / no account | Yes | No | Yes |
| Recall is guaranteed | Only if the model reads it | Only if the agent calls it | The harness hook runs it |
You can keep your CLAUDE.md; neuron handles the part it can't. Named,
sourced comparisons — Mem0, Zep, claude-mem, agentmemory, Beads — are on the
alternatives page.
🚀 Quick start
Two fully-supported ways to install — neither is more "official" than the other, pick whichever fits your workflow.
# npm (requires Node.js)
npm install -g @kovartravis/neuron
# curl (macOS/Linux) — standalone binary, no Node.js required
curl -fsSL https://raw.githubusercontent.com/kovartravis/neuron/main/install.sh | sh# PowerShell (Windows) — standalone binary, no Node.js required
powershell -c "irm https://raw.githubusercontent.com/kovartravis/neuron/main/install.ps1 | iex"Installed via curl/PowerShell? Run neuron upgrade to self-update the
binary. Installed via npm? npm update -g @kovartravis/neuron.
# Initialize in your project (detects CLAUDE.md/AGENTS.md, pre-downloads local models)
neuron init
# Save a note the agent should remember
neuron memory add --category learning "Always use the Repository Pattern for database access in src/services"
# Search stored memory
neuron memory query "How do we handle database access?"Or just tell your agent:
"Set up neuron memory for this project."
It runs the setup interview and configures the project for you.
Recall your agent can't skip
neuron init wires a hook directly into your harness — the harness itself
runs the memory query and injects the result before the model sees the
prompt. No instruction to forget, no judgment call to skip. neuron init
reports exactly what got wired, per harness, straight from each harness's
real hook registration.
| Harness | How recall lands |
|---|---|
| Claude Code | Every turn, automatically — hooked into SessionStart, UserPromptSubmit, and PreCompact |
| OpenAI Codex CLI | Every turn, automatically — same three hook points |
| GitHub Copilot CLI | Once per session, automatically — the harness only exposes a session-start hook |
| Cursor | Once per session, automatically — same session-start-only constraint |
| Anything else | Instruction-based fallback via AGENTS.md, prompting the agent to query the store itself |
Full fidelity details, including exactly which hook points each harness
supports, are in docs/COMMANDS.md.
Your git history is a searchable resident source too
On the two harnesses with a per-turn hook, every prompt is also matched against an index of your repo's own commit history — subject and body, embedded and searched the same way memory content is. Ask about a feature or a bug, and the commit that actually shipped the fix surfaces alongside your notes. It backfills once and stays current incrementally — no git hook to install, nothing to fall out of sync.
Live-measured against the real semantic search mechanism: it matched a
hand-tuned oracle's 0% failure rate and clearly beat an agent manually
running git log on its own (11.1% failure). Full numbers in
benchmarks/token-ab/results/11-rerun-gitlog-ab-semantic-mechanism/findings.md.
Command execution gets the same treatment
neuron exec -- <command> — a pre-execution memory lookup — doesn't have
to be a manual step either. On Claude Code and Codex CLI, neuron init
wires a pre-command hook that fires automatically on every shell tool
call, surfacing a relevant hit as context instead of requiring the agent to
remember to ask. Purely informational — it never blocks the command.
Write-side compliance gets a nudge, not just a reminder
Recall solves reading memory back; it doesn't make an agent write to it in
the first place. An A/B test measured that gap directly: under realistic
multi-step conditions, an agent with no nudge recorded a fix only 20% of the
time it should have. neuron init wires a pre-stop hook that fires when
the agent is about to end its turn, and — once per session — forces one more
turn with a reminder if nothing has been recorded yet:
| Harness | Mechanism |
|---|---|
| Claude Code | Stop — forces a continuation, empirically verified |
| OpenAI Codex CLI | Stop — forces a continuation, per documentation |
| GitHub Copilot CLI | agentStop — forces a continuation, per documentation |
| Cursor | stop's followup_message — auto-submits a continuation, per documentation |
Full fidelity details are in docs/COMMANDS.md.
📁 What it looks like in your repo
.neuron/
learning.md # conventions, rules, failure fixes
decisions.md # architectural decision recordsOpen any of them. They're just markdown, with a small YAML frontmatter block per entry:
# Category: decisions
---
id: e9d606cd-0d61-4073-9da8-1675c6d7adfd
createdAt: 2026-08-05T15:02:38.494Z
importance: 3
tags: []
taskId: null
reviewedBy: alice
ticket: NEU-42
---
Chose Postgres over SQLite for concurrent writesReadable, greppable, diffable, and safe to hand-edit — neuron status
catches anything that ends up missing or malformed, so nothing is ever
silently guessed at.
This isn't a toy example. Neuron dogfoods itself: this repository's own
.neuron/learning.md,
.neuron/decisions.md, and
.neuron/architecture.md are the real store this
project's own agent sessions read from and write to on every release. Open
them to see real usage, not a curated demo.
⚙️ Configuration (neuron.yaml)
This is exactly what neuron init generates for a new project:
version: "1.0"
# Your memory lives in markdown. SQLite is kept as a rebuildable index that is
# reconciled from these files on every command — the .md files are the record.
# md markdown is authoritative, vector index derived from it (default)
# vector local SQLite vector DB with FTS5 only, no .md files
# Any category below may set its own "storage:" to override this just for it.
# Precedence: categories.<name>.storage > storage.mode > "md".
storage:
mode: md
path: .neuron
categories:
# Any category below may set its own "path:" to override storage.path just
# for it (e.g. "path: docs/adr" to keep decisions.md alongside other docs).
# Precedence: categories.<name>.path > storage.path > ".neuron".
learning:
description: Agent conventions, rules, and failure fixes
tags: [rule, convention, failure-fix]
decisions:
description: Architectural Decision Records (ADRs) & design choices
tags: [adr, architecture, design]
architecture:
description: Architectural blueprints & structure cards
tags: [architecture, topology, scan]
# Set enabled: true to scan on init and to surface drift in
# 'neuron status' and 'neuron exec'. Writes into the category named below,
# which must be one of the categories declared above.
scan:
enabled: false
category: architecture
depth: 3
pullRules:
default:
categories: [learning, decisions]
limit: 5
onExec:
- commandPattern: ".*"
categories: [learning]
limit: 5Two storage modes. md (the default) keeps markdown authoritative,
with SQLite as a rebuildable semantic-search index — delete the database
any time and Neuron rebuilds it from your files. vector skips markdown
entirely for projects that want no files on disk at all, same schema
guarantee either way.
Per-category storage path
A category's markdown doesn't have to live under the project-wide
storage.path. Set path on the category itself to send just that one
elsewhere — a shared notes directory, or decisions.md living next to your
other docs:
storage:
mode: md
path: .neuron
categories:
decisions:
description: Architectural Decision Records (ADRs) & design choices
path: docs/adr # overrides storage.path for this category only
learning:
description: Agent conventions, rules, and failure fixesPrecedence is categories.<name>.path > storage.path > ".neuron". Absolute
paths work too — a notes directory shared across projects, even outside
this repo.
Per-category storage mode
Set storage on a category to override the top-level storage.mode just
for it — keep learning in reviewable markdown while routing a high-volume
category straight to SQLite:
storage:
mode: md
path: .neuron
categories:
learning:
description: Agent conventions, rules, and failure fixes
telemetry:
description: High-volume, low-value entries
storage: vector # this category alone skips markdownThe guarantee in practice: declaring required fields
Add a fields block to any category to make specific frontmatter fields
mandatory, and the CLI both enforces them and exposes them as flags:
categories:
decisions:
description: Architectural Decision Records (ADRs) & design choices
fields:
ticket:
type: string
required: true
reviewedBy:
type: enum
values: [alice, bob]
required: true$ neuron memory add --category decisions "Chose Postgres over SQLite"
Error: --ticket is required for category "decisions" (neuron.yaml categories.decisions.fields.ticket). Pass --ticket <value>, or add a "default:" in neuron.yaml.
$ neuron memory add --category decisions --ticket NEU-42 --reviewed-by alice "Chose Postgres over SQLite"
{"id":"e9d606cd-0d61-4073-9da8-1675c6d7adfd","status":"created","project":"neuron"}Every entry conforms to your schema, and serializes identically every time — real, enforced structure, not a convention your agent might forget.
📖 Command reference
| Command | Description |
|---|---|
| neuron init | Bootstraps the project, pre-downloads local ONNX models, fetches Tree-Sitter grammars, wires recall hooks |
| neuron memory add/query/list/get/update/delete/consolidate/prune | Multi-category memory operations, backed by plain .md files by default. list --where/--refs-satisfy filter on any declared field — schema-agnostic, no field name baked into the CLI |
| neuron exec -- <command> | Runs a command with a pre-execution safety lookup pulled from stored memory, plus a non-blocking drift warning if the codebase moved |
| neuron scan / scan --diff / scan --check | Ingests an architectural blueprint card; reports drift; exits non-zero in CI on real drift |
| neuron sync | Explicit forced rebuild between markdown and SQLite — ordinary commands already reconcile automatically |
| neuron status / status --health / status --check | Storage, embedding model, drift and relevance-gate status as JSON; --health reports near-duplicate groups and store-hygiene signals (--repair auto-merges what's safe to); --check validates against your declared schema |
| neuron ui | Launches the local dashboard |
| neuron mcp | Runs an MCP server (stdio transport) exposing neuron_remember/neuron_recall/neuron_query_exec to any MCP-aware client |
| neuron feedback [message] | Generates pre-filled GitHub issue links |
Declared fields extend this automatically — neuron memory --help lists
--ticket, --reviewed-by, or whatever your neuron.yaml declares, so an
agent reading --help learns your project's schema without it being
restated anywhere else. Full flag listings: docs/COMMANDS.md.
Scheduled and cron writers
neuron memory add's write-time supersession gate normally hard-blocks a
near-duplicate write and asks an interactive caller to resolve it — a human
loop a cron job can't complete. Pass --if-novel instead: on a gate hit it
skips the write cleanly (exit 0, job still succeeds) rather than erroring,
and it's never silent about it — the skip is printed to stderr and noted in
the JSON result.
🔌 MCP server
Claude Code and Codex CLI already get neuron's recall deterministically,
re-injected every turn via the hook model above — neuron mcp isn't a
replacement for that. It's for editors with no per-turn hook point (Cursor,
Windsurf, Zed, Claude Desktop, Roo Code), and it's available unconditionally
to every client, hook-covered or not.
neuron mcp runs an MCP server over the standard stdio transport, built on
the official @modelcontextprotocol/sdk, exposing three tools — thin
wrappers over the exact same store methods the CLI itself calls, not a
second logic path:
| Tool | Wraps | Notes |
|---|---|---|
| neuron_remember | memory add | content, category, importance, supersedes, companion_of — tags stay server-inferred, never model-settable |
| neuron_recall | memory query | query, categories — returns { results, rejected }, so an empty result set reads differently from an empty store |
| neuron_query_exec | exec's pre-command lookup | command_text — lookup only, never spawns the command |
No separate auth/scoping layer: a local stdio server is a subprocess your editor spawns directly, inheriting exactly the OS-level access any CLI invocation already has.
neuron init writes this client config for you — .mcp.json (Claude Code,
GitHub Copilot CLI), .cursor/mcp.json (Cursor), and .codex/config.toml
(Codex CLI, as a [mcp_servers.neuron] table) — for every detected harness,
the same run that wires recall hooks. On a harness with no deterministic
hook, the generated instructions file's Recall step also switches to calling
neuron_recall directly once its MCP config is wired, rather than asking the
model to shell out. See docs/COMMANDS.md for
the full per-harness path table and the conflict/overwrite policy (identical
to the hook install's own --overwrite-hooks/--keep-hooks).
This tool-call path is best-effort, not deterministic — a live A/B
(docs/design/rule-recall-ab/findings.md)
found agent-invoked neuron_recall with no hook backing it under-complied
in every session it was tested (called only 5/8 times, never compliant even
when called). It's still strictly additive reach for editors with no hook
point at all, not a regression from some deterministic baseline they'd
otherwise have.
To point a client at it by hand instead — no separate binary, no new bin
entry:
{
"mcpServers": {
"neuron": {
"command": "npx",
"args": ["-y", "@kovartravis/neuron", "mcp"]
}
}
}🏛️ Architecture awareness, as a deterministic artifact
neuron scan turns your codebase's structure into a markdown file that
stays current, instead of something your agent has to re-derive by
re-reading the repo every session.
neuron scan # scan and ingest the blueprint
neuron scan --dry-run # preview without writing to memory
neuron scan --diff # human-readable drift report
neuron scan --check # non-zero exit on drift — for CI gatesReal, parsed Tree-Sitter syntax trees — not a regex guess — across
TypeScript, TSX, JavaScript, Python, Go, Rust, Java and C++. .cs,
.swift, .rb and .php fall back to a line-oriented scanner until they
get a grammar, and every card records which parser produced each file.
The card is byte-identical across repeated scans of an unchanged tree, and
a re-scan updates it in place — so git diff on .neuron/architecture.md
shows real drift, not scan-to-scan noise.
- run: neuron scan --check📊 Measured, not just claimed
We ran a real counterfactual — same agent, same tasks, memory hook on vs. off — on actual SWE-bench Lite instances (real matplotlib and Django checkouts pinned before the real fix landed, so the answer is structurally absent without help) and let a deterministic grader decide.
| Task | Without neuron | With neuron | Reduction |
|---|---|---|---|
| matplotlib-24265 | 26,076 tokens | 6,933 | 73.4% |
| django-11019 | 12,458 tokens | 9,354 | 24.9% |
| Pooled | 19,267 | 8,144 | 57.7% |
16 of 16 sessions answered correctly in both arms — the savings aren't
bought with worse answers. On matplotlib-24265 the two arms separate
completely: every neuron session finished in exactly 2 turns, every
control session took 4–5. Cost per run roughly halved, $0.46 → $0.22.
A narrower follow-up isolated just the architecture card the session-start hook pushes proactively:
| Task | Without the card | With the card | Reduction | |---|---|---|---| | Module/subsystem inventory | 29,244 tokens | 5,112 | 82.5% | | Dependency list | 8,906 tokens | 9,994 | -12% (noise) |
Naming a project's module boundaries is a judgment call a directory listing doesn't hand you for free — the card earns its keep there. Listing npm dependencies is cheap either way, so the card doesn't move that number.
Every harness here is real and re-runnable, documented in
benchmarks/token-ab/README.md:
npm run bench:swebench-ab:dry-run # free — validates fixtures + grading
npm run bench:swebench-ab -- --k=4 --effort=low --cap=2.0 # the run above: ~$0.70, ~15 minEvery session's full answer text, token breakdown, and per-gate grade is
written to results.json, so you can re-grade the verdicts yourself.
npm run bench:report # free, ~10s — re-renders from the result files already in this repo
npm run bench:view # same, then opens benchmarks/reports/index.html🖥️ Local dashboard
neuron ui
Browse categories, run instant semantic queries, filter by tags, and inspect drift reports — all served locally.
🧪 Testing
npm test # unit + integration suite, ~7s
npm run test:e2e # deeper E2E benchmark & correctness suite📚 Documentation
- Website — install, quickstart, per-harness setup guides (Claude Code, Codex CLI, Copilot CLI, Cursor), and how-it-works pages on hybrid search, the relevance gate, and the schema
- Command reference
— every command, flag, exit code, and the full
neuron.yamlschema - Architecture decision records — why it's built the way it is
- Changelog — including upgrade notes
- Releasing — the checklist for cutting a release
🤝 Contributing
Bug reports with a reproduction, a harness you use that neuron doesn't fit
yet, a doc page that was wrong when you needed it, or code — all welcome.
CONTRIBUTING.md has the setup, the repository map, and
the handful of rules that keep the store markdown-first.
neuron feedback --type bug "what happened" opens a pre-filled issue.
📄 License
MIT © Travis Kovar
