Budget-Neutral Synaptic Recall
Displacement Injection with Learned Per-Edge Decay for AI Agent Context Retrieval
Companion publication: the learning loop that produces the graph this method retrieves from is specified in Hebbian Co-Activation with Long-Term Potentiation and Hub-Normalized Spreading Activation. This publication is its retrieval-side complement — the novel claims here are the learned per-edge half-life and budget-neutral injection.
Abstract
A method for injecting learned associative recall into an AI coding agent's context window without increasing its token cost. Code nodes co-activated by agent tool activity are linked by Hebbian reinforcement into a weighted undirected graph. Each edge decays along an exponential half-life that is itself learned per edge from reinforcement frequency and recency. At retrieval time, spreading activation propagates energy outward from the top vector-search hits across namespace-merged edge weights, with square-root hub normalization preventing high-degree utility nodes from dominating recall. The resulting energies are folded into the vector result set budget-neutrally: nodes already present are boosted and re-ranked, and the weakest vector hits are displaced by strongly co-activated neighbors that vector search missed — the result count, and therefore the token budget, never grows. When the graph is cold, output is byte-identical to a build without the associative layer.
Background
Retrieval for AI coding agents is dominated by flat top-k vector search. It fails in a specific, recurring way: the files an agent actually uses together are often lexically unrelated — a JWT verifier and the key-loading helper it depends on share no vocabulary — so vector search never co-surfaces them, and the agent re-discovers the association by trial and error in every session. Existing remedies each have a structural flaw in the agent setting:
- Growing the context: every appended node costs tokens; associative recall that grows the prompt competes with the budget it is meant to protect.
- Static code graphs: capture compile-time structure but not usage — fixtures, config, and docs co-used with code are invisible.
- Fixed-rate memory decay: treats a load-bearing association reinforced daily the same as a one-off co-occurrence.
- Naive spreading activation: without degree normalization, one high-degree utility node floods every recall.
Our approach learns associations from the agent's own tool telemetry, forgets them at a per-edge learned rate, recalls them by hub-normalized spreading activation, and injects them by displacement rather than addition — recall quality improves while the token budget stays fixed.
Core Algorithm
1. Hebbian Co-Activation Reinforcement
Agent activity events yield a set of co-activated node ids. Every pairwise combination is reinforced as an undirected edge under canonical ordering (node_a < node_b):
Δw = 0.30 × clamp(strength, 0.0, 2.0)
weight(a,b) = min(1.0, weight(a,b) + Δw)
activation_count(a,b) += 1
Edge upserts and activation counters commit in one transaction — a partial commit would leave counters ahead of their edges and permanently skew long-term-potentiation gating.
2. Learned Per-Edge Half-Life Decay
Weights decay by wall-clock exponential half-life: w(t) = w₀ × exp(−λ × age_days), λ = ln(2) / half_life_days. Namespace defaults: personal/branch 30 days, shared 60, ephemeral 1. The half-life is then learned per edge, recomputed inside the same transaction as each reinforcement:
freq = activation_count / age_days
confidence = exp(−ln(2) × days_since_last / ns_default)
ratio = log1p(freq × age_days / 10)
learned = lo + (hi − lo) × ratio / (1 + ratio)
half_life = (1 − confidence) × ns_default + confidence × learned
bounded to [3.0, 120.0] days: a rarely-used edge never decays slower than a 3-day half-life, a heavily-used one never faster than 120.
Long-term potentiation: edges with lifetime activation_count ≥ 5 are floored at weight 0.20 during decay — proven associations fade but never vanish. Weights below 0.01 are pruned.
3. Hub-Normalized Spreading Activation
Recall seeds energy at query-relevant nodes and propagates it outward for 2 hops. Edge weights merge across memory namespaces before propagation (active branch 1.0, personal 0.8, shared 0.5):
hub_factor(n) = sqrt(50 / degree(n)) if degree(n) > 50 else 1.0
propagated = energy × merged_weight × 0.6 × hub_factor
The square-root form is deliberate: a linear penalty would mute hubs so hard they stop routing energy; sqrt keeps them useful as conduits while preventing dominance — a degree-200 node propagates at exactly 0.5×, a degree-5000 node at 0.1×.
4. Budget-Neutral Injection: Boost + Displacement
Activation energies fold into the vector result list under a hard invariant — the result count never grows:
(a) BOOST: score += 0.3 × energy for nodes already present; re-sort
(b) DISPLACE: swap ≤ 2 absent nodes with energy ≥ 0.15
in for the weakest vector hits, one-for-one; keep ≥ 1 original hit
Because injection is one-for-one displacement, the context assembled downstream spends exactly the same token budget with or without the associative layer. When recall is unwired, disabled, or the graph is cold, output is byte-identical to a build without a synapse store.
Example Walkthrough
An agent asks about authentication. Vector search returns 8 hits; the top 3 seed spreading activation with energy 1.0.
Missed by vector search
verify_token → load_keys personal 0.9 × 1.0 = 0.9 degree 6 → hub_factor 1.0 1.0 × 0.9 × 0.6 = 0.54
0.54 ≥ 0.15 → displaces weakest hit
Already in results (#7)
login → session.refresh shared 0.5 × 0.5 = 0.25 1.0 × 0.25 × 0.6 = 0.15
boost 0.3 × 0.15 = 0.045 → re-ranked up
Result: 8 hits in, 8 hits out — same token budget
Gained: config/secrets.py::load_keys — lexically unrelated to "auth", learned from co-use
Dropped: a docstring stub that matched on the word "auth"
Properties
Budget Neutrality
Injection is one-for-one displacement with a fixed result count, so total context tokens are invariant to the associative layer. Recall quality and token cost are decoupled: the graph learning more never makes the prompt bigger.
Cold-Start Identity
Every stage no-ops to the identity function when its input signal is absent. A fresh clone produces byte-identical retrievals to a build without the layer; the graph earns influence only through observed usage.
Hub Resistance
With hub_factor = sqrt(50/degree), utility nodes remain traversable conduits but cannot flood the top-k.
Complexity
- Reinforcement: O(k²) edge upserts per k-node activity window, one transaction
- Spread: O(E_frontier) per hop, depth fixed at 2
- Injection: O(n log n) re-sort; displacement is O(1) bounded
Reference Implementation
- Language: Python 3.10+ (stdlib-only synapse layer; SQLite storage)
- Repo: https://github.com/dfrostar/neuralmind
- Commit:
89eff6c(2026-08-07) - Files:
- neuralmind/synapses.py
- neuralmind/learned_decay.py
- neuralmind/context_selector.py
- neuralmind/watcher.py
Prior Art Statement
To the best of our knowledge, the specific combination of: (1) Hebbian edge learning driven by AI-agent tool telemetry, (2) per-edge learned exponential half-life blended by recency confidence toward a namespace default, (3) square-root hub-normalized spreading activation over namespace-merged edge weights, and (4) budget-neutral injection via score boost plus one-for-one displacement with a byte-identical cold-start guarantee — has not been previously published in the context of local-first code intelligence systems.
Related work includes the companion NeuralMind synapse learning loop publication (Frost, 2026 — specifies the capture, reinforcement, LTP, and recall machinery this method builds on, but not learned per-edge half-lives or budget-neutral injection), Hebbian learning (Hebb, 1949), spreading activation in semantic memory (Collins & Loftus, 1975; Anderson's ACT-R, 1983), spreading activation in information retrieval (Crestani, 1997), forgetting curves (Ebbinghaus, 1885), retrieval-augmented generation (Lewis et al., 2020), and LLM memory hierarchies (MemGPT — Packer et al., 2023).