Every agent framework has "memory". In practice that usually means a vector store and a retrieval call. You can't see why something was recalled, you can't diff it, and you can't prove nobody changed it.
I wanted memory that works like source code: written in a language, type-checked, compiled, executed deterministically, and audited. So I built NEUROSA-HB, a small DSL and runtime for describing an agent's "brain" as neurons and synapses.
Give agents a brain, not just a context window.
Repo: github.com/HazEOskA/neurosa-human-brain
A brain is a .nsa file
brain OsaBrain {
region ProjectMemory {
neuron BrainArchitecture {
type: decision
title: "NEUROSA-HB Architecture"
source: obsidian("projects/brain.md")
threshold: 0.72
restingPotential: -0.65
salience: 0.90
confidence: 0.95
}
neuron HydraLab {
type: system
source: obsidian("projects/hydra-lab.md")
threshold: 0.61
}
synapse BrainArchitecture -> HydraLab {
relation: PART_OF
mode: EXCITATORY
weight: 0.64
confidence: 0.90
}
}
}
A neuron is a unit of knowledge: a decision, a system, a fact, backed by a source document. A synapse is a typed, weighted relation between two neurons, and it can be excitatory or inhibitory. Inhibition is the part most memory systems lack: some knowledge should actively suppress other knowledge.
It's a real compiler pipeline
.nsa → lexer → parser → AST → semantic analysis → type checking → IR 0.1 → runtime → activation → SQLite → hash-chain ledger
Every stage is its own package in the monorepo (neurosa-lexer, neurosa-parser, neurosa-type-checker, neurosa-ir, neurosa-activation, neurosa-event-ledger, ...).
Because it's a compiler, memory errors become compile errors. Point a synapse at a neuron that doesn't exist and give it an out-of-range weight:
NEUROSA-E105: Unknown target neuron 'GhostNode'
at bad.nsa:19:34
NEUROSA-E309: Property 'weight' must be in range 0..1; got 1.7
at bad.nsa:24:15
(The CLI speaks Polish, my native language. The commands also accept English aliases (parse, check, compile, run), and I've translated the messages above.)
A valid file compiles to a stable JSON IR in which every default is explicit:
{
"id": "HydraLab",
"regionId": "ProjectMemory",
"type": "SYSTEM",
"threshold": 0.61,
"restingPotential": 0,
"salience": 0.5,
"confidence": 1,
"enabled": true
}
Recall is activation, not similarity
To "remember", you inject an impulse into a neuron and let it propagate:
node --import tsx packages/neurosa-cli/src/cli.ts run \
examples/minimal-brain/brain.nsa \
--stan .neurosa/brain.db \
--neuron BrainArchitecture \
--sila 1 \
--maks-skoki 8 \
--limit-zdarzen 500 \
--limit-czasu-ms 5000 \
--deterministycznie
(The flags are Polish: --stan = state file, --sila = initial strength, --maks-skoki = max hops, --limit-zdarzen = event limit, --limit-czasu-ms = time limit, --deterministycznie = deterministic.)
The core of the activation loop:
const polarity = impulse.mode === "INHIBITORY" ? -1 : 1;
const neuronModulation = neuron.confidence * (0.5 + neuron.salience * 0.5);
const delta = impulse.strength * polarity * neuronModulation;
neuron.activationLevel += delta;
if (neuron.activationLevel < neuron.threshold) continue; // didn't fire
// fired → propagate along outgoing synapses
const strength = impulse.strength * synapse.weight * synapse.confidence;
So the answer to "why did the agent recall X?" is a trace you can read: which impulse arrived, through which synapse, at what strength, on which hop, and whether the neuron fired or was inhibited.
Every activation runs inside hard limits: maximum hops, minimum impulse strength, maximum events, a time limit, cycle detection and cancellation. Impulses travel only through synapses that exist in the compiled IR, so the runtime can't invent a connection.
Tamper-evident memory
State and events are stored in SQLite (WAL, foreign keys, explicit migrations). Next to them is an append-only, SHA-256 hash-chained ledger. verifyLedger() detects:
- a modified event payload
- a deleted or reordered event
- a wrong
previousHashoreventHash
For an agent memory this matters. If an agent decided something because of a memory, you can later prove what that memory said at that moment.
Beyond the DSL
- Native workspace (Checkpoint A): folders, Markdown documents, frontmatter, tags, wikilinks, backlinks, immutable revisions, SQLite FTS5 search. The documents belong to NEUROSA-HB itself, so Obsidian isn't required.
- One-shot Obsidian import (Checkpoint B): read-only. It copies notes and safe attachments, turns notes into neurons and wikilinks into real synapses, and writes a report plus ledger events. The source vault is never modified.
- Connect & Ingest: persistent agent sessions, core context + retrieval, atomic write-back into documents and the ledger. Ingest handles Drive, PDF/DOCX/text and conversation exports. HTTP and MCP adapters share one Brain API.
What is not done
To be straight about the current state:
-
Plasticity is declared, not learned. The language accepts and type-checks
plasticity: HEBBIAN, but activation doesn't update weights yet. Synapses don't strengthen with use today. -
Transmission delay is metadata.
transmissionDelayMsis carried on events, but propagation isn't scheduled in real time. - The "Living Brain" visualization (Checkpoint D) isn't part of the verified build. Its source package still has to be recovered.
- This is a recovery build. The repo is a functional reconstruction after losing an earlier unpushed workspace, and it doesn't claim identical sources.
- Requires Node.js 24+ and pnpm. The native SQLite module won't build on older Node.
Why a language?
You can review a language in a pull request. Memory written as .nsa gets diffs, code review, CI type checks and a deterministic replay. An embedding store gives you none of that.
My bet is that agent memory has to be inspectable and provable, not just relevant.
How do you debug why your agent remembered something?











