Memory Model
How ferricula stores, decays, and consolidates.
Fidelity
Every memory in ferricula carries a fidelity score — an f32 value between 0.0 and 1.0. When a memory is first ingested, its fidelity is set based on the importance parameter (default 0.5). From that point forward, fidelity decays.
Decay is access-weighted. Each time a memory is recalled, its decay curve flattens — the memory stays alive longer because the agent returned to it. Memories that are never recalled decay faster. This is the core mechanic: ferricula forgets what doesn't matter.
When fidelity drops below the survival gate, the memory enters Ghost state. Ghost memories are no longer returned in recall or search results, but they persist briefly as semantic echoes — faint traces that can still influence consolidation during dream cycles. Once a ghost's fidelity reaches zero, it is pruned permanently.
Fidelity lifecycle
Ingest (importance: 0.8)
| fidelity = 0.800
| ... time passes, no recall ...
| fidelity = 0.612
|
Recalled (fidelity curve flattens)
| fidelity = 0.609
| ... more time, recalled again ...
| fidelity = 0.587
|
| ... long silence ...
| fidelity = 0.102
|
Ghost state (below survival gate)
| fidelity = 0.041
|
Pruned (fidelity ~ 0.0)
Cognitive heat
Ferricula tracks cognitive heat at the agent identity level. Every recall operation adds a small amount of heat. Rapid, repeated recalls accumulate heat quickly.
Heat serves as a natural rate limiter. When the Fortune archetype gate is active, it blocks recall when heat exceeds the ceiling threshold. This prevents feedback loops where a small cluster of high-fidelity memories dominate every response, crowding out the rest of the memory graph.
Heat dissipates passively over time. Dream cycles cool heat aggressively — a single dream can drop heat by 40–60%. This creates a natural rhythm: periods of active recall build heat, dreams cool it, and the agent returns to a calmer baseline.
Resonance gates
A memory doesn't automatically appear in recall results just because it scores well on vector similarity. It must pass through the active resonance gates — filters enforced by the five archetypes. A memory must pass all active gates to resonate (be returned to the caller).
| Archetype | Gate | What it blocks |
|---|---|---|
| Advocate | Fidelity threshold | Low-fidelity memories that have decayed too far |
| Fortune | Heat ceiling | All recall when cognitive heat is too high |
| Craft | Load threshold | Memory injection at CRITICAL load tier |
| Intuition | Semantic edge discovery | Active during dream — discovers new connections |
| Ethics | Keystone promotion | Active during dream — promotes important memories |
The Advocate, Fortune, and Craft gates operate at recall time. Intuition and Ethics operate during dream cycles. You can see which gates are currently active via GET /identity.
Dream cycles
Dreams are ferricula's consolidation mechanism. They aren't triggered on a timer — they're triggered by entropy.
The broker feeds raw entropy bytes to ferricula via POST /offer on each turn. When accumulated entropy crosses the internal threshold, a dream fires. You can also trigger a dream manually with POST /dream.
What happens during a dream
Decay step — all memory fidelities drop by a fixed delta. This is the heartbeat of forgetting. Frequently-recalled memories barely notice it; neglected ones take a meaningful hit.
Consolidation — memories with cosine similarity ≥ 0.85 are candidates for merging. The engine combines their text, preserves the higher fidelity, and removes the duplicate. This keeps the memory graph dense without redundancy.
Keystone promotion — memories that have been recalled many times and maintain high fidelity are promoted to keystones by the Ethics archetype. Once keystoned, a memory is immune to decay.
Ghost echoes — memories in ghost state leave behind semantic traces. These echoes can influence which edges survive consolidation, creating a form of "half-remembered" knowledge that shapes the graph even after the original memory is gone.
Heat cooling — cognitive heat drops significantly. A dream resets the agent to a calmer state, reopening Fortune-gated recalls.
Keystones
A keystone memory is immune to decay. Its fidelity never drops. It survives indefinitely, anchoring the memory graph through any number of dream cycles.
Keystones can be created two ways:
1. On ingest — pass "keystone": true in the POST /remember body. Use this for memories you know are foundational from the start.
2. After the fact — call POST /keystone/:id to toggle keystone status on any existing memory. The broker exposes this as the memory_keystone tool.
During dream cycles, the Ethics archetype can also promote heavily-recalled memories to keystone status automatically. This is how organic keystones emerge — not by explicit declaration, but because the agent keeps returning to them.
Important memories should be keystoned early. If a memory decays to ghost state before being keystoned, it cannot be recovered.
Channels
Every memory write includes a channel tag in the tags object. The standard channels are hearing, seeing, and thinking.
Recall and search are scoped to channels. When you call POST /recall with "channel": "hearing", only memories tagged with that channel are searched. This provides per-agent isolation in fleet deployments — agents don't see each other's memories unless you explicitly cross-query.
The broker uses the thinking channel to log its own tool-call audit trail. These thinking-channel memories are invisible to the LLM during normal recall but can be inspected for debugging.
Example: ingest, dream, inspect
import httpx
F = "http://localhost:8765"
# Ingest a memory with high importance
httpx.post(f"{F}/remember", json={
"id": 1,
"vector": [0.12, -0.04, 0.31], # truncated for brevity
"tags": {"text": "Simplicity is the ultimate sophistication.", "channel": "hearing"},
"importance": 0.9
})
# Feed entropy to push toward dream threshold
httpx.post(f"{F}/offer", json={"entropy": "a1b2c3d4e5f6"})
# Trigger a dream manually
dream = httpx.post(f"{F}/dream")
print(dream.json())
# {"dreamed": true, "decayed": 47, "consolidated": 3, "pruned": 2, "keystoned": 1}
# Check the memory's state after dreaming
mem = httpx.get(f"{F}/inspect/1")
print(mem.json())
# {"id": 1, "fidelity": 0.871, "state": "Active", "keystone": false, ...}