Memory as Entropy.
Ferricula models memory fidelity as an energy state. High-energy memories are Active, but as time passes and disuse grows, they decay naturally unless reinforced. Below the fidelity gate, text is discarded but the vector seed survives — and the synthesizer can reconstruct it.
Run it.
One command. Persistent storage. HTTP API on :8765.
$ docker run -p 8765:8765 -v ferricula-data:/data gcr.io/gnosis-459403/ferricula
Copy
Bit-Sliced Index (BSI) Engine
Fidelity is transposed into bit-planes backed by Roaring Bitmaps — a hybrid of sorted arrays (sparse) and uncompressed bitsets (dense), with run-length encoding for long runs. Operations run at binary speed: AND, OR, XOR on compressed bitmaps execute as CPU-native bitwise instructions over cache-aligned 64-bit words. A range query across a million memories resolves in microseconds — no row scanning, no branching, just bits.
Columns represent Roaring Bitmaps stored in the Rust memory layer.
Bit 3 (Threshold: 0)
Bit 1 (Threshold: 0)
Encryption
Each agent has a unique identity. That identity produces a private key. When two agents need to share memories, they perform key agreement to produce a shared secret. That secret becomes a rotation matrix. The rotation encrypts embeddings while preserving their geometric relationships — cosine similarity works on encrypted vectors without decryption.
Private Key (32 bytes)
Derived deterministically from the agent's identity seed. The seed comes from entropy at agent creation. No random number generator is called at runtime — the key is fixed for the lifetime of the identity.
X25519 Diffie-Hellman
Elliptic-curve key agreement. Agent A's private key + Agent B's public key = shared secret. Agent B's private key + Agent A's public key = the same shared secret. Neither agent reveals their private key.
HKDF-SHA256 Expansion
The 32-byte shared secret is expanded into a 32-byte transform seed using HKDF. A context label ensures different purposes (e.g. "organize" vs "retrieve") produce different seeds from the same shared secret.
Orthogonal Matrix (Gram-Schmidt)
The seed initializes an N×N matrix. Gram-Schmidt orthonormalization forces it into a pure rotation — every row is unit-length and perpendicular to every other row. Multiplying a vector by this matrix rotates it without changing its length or the angles between vectors.
Search works on ciphertext
Cosine similarity is preserved under orthogonal rotation. Two encrypted vectors have the same similarity score as their plaintext originals. You can search without decrypting.
Decryption is the transpose
For an orthogonal matrix Q, the inverse is QT. No matrix inversion needed. Encrypt: v' = Q · v. Decrypt: v = QT · v'. Both are a single matrix-vector multiply.
Decay requires plaintext
Fidelity decay is not a rotation — it shrinks the vector toward a projection. This doesn't commute with the encryption transform. The system must decrypt, apply decay, then re-encrypt. This is enforced in the dream cycle.
Each agent's memories are rotated by its own transform. Agent A cannot read Agent B's vectors — they look like random noise without the shared secret. To share a memory, Agent A decrypts it with their transform, then re-encrypts it with the pairwise transform derived from A and B's shared secret. This is the offering protocol.
Vec2text Inversion
Given a 768-dimensional embedding, reconstruct the text that produced it. Four ONNX models run in sequence inside a Rust process — no Python. This is how ferricula rebuilds forgotten memories from their vector seeds, and how it verifies that encryption hasn't destroyed semantic content.
Embedder — gtr-t5-base.onnx
T5 encoder, mean-pooled, L2-normalized to 768 dimensions. This is the forward direction: text in, vector out. The same model used for ingestion.
Projection — projection.onnx
Learned MLP that expands a single 768d vector into a sequence of 16 hidden states at T5 scale (16 × 768). This bridges the gap between embedding space and language model input space.
Encoder — encoder.onnx
T5 encoder takes the projected sequence via inputs_embeds (not token IDs). Produces encoder hidden states that condition the decoder.
Decoder — decoder.onnx
Autoregressive greedy decode. Generates one token at a time, feeding each output back as input until EOS. Produces the hypothesis text — the system's best guess at what the original memory said.
768 dimensions. Pre-trained vec2text models available from HuggingFace (jxm/gtr__nq__32). Export to ONNX and run. No training required. This is the default.
1536 dimensions. OpenAI's embedding model. Pre-trained vec2text corrector available. Requires an OpenAI API key to generate embeddings, but the inversion models are open.
384 dimensions. Smaller, faster embedder. No pre-trained inverter exists. Train a hypothesis model on MSMARCO (~50 epochs on dual A100 40GB). Training scripts and data pipeline included in the repo.
The Rust inverter auto-detects embedding dimension from the ONNX model shape. Train a hypothesis model for your embedder, export to the four-file ONNX format, and drop it in. The pipeline adapts.
Graph Binary Store
The knowledge graph uses Roaring Bitmap adjacency sets instead of edge lists. Each node's neighbors are a compressed bitmap — intersection finds common neighbors in microseconds, union discovers connected components, XOR isolates exclusive relationships. Cardinality (len()) returns neighbor count in O(1). Edge labels are stored as parallel bitmap layers — label-filtered queries are a single AND between adjacency and label bitmaps.
Each label type is a parallel bitmap layer. Query by label is a single AND with the adjacency set.
= adj[m0] & label[related]
= {m1,m2,m5} & {m1,m2,m4,m5}
= {m1, m2, m5}
Prime Tree Term Index
Every word extracted from memory text becomes a key in the Prime Tree — a hierarchical term-to-bitmap lookup. Each term maps to a Roaring Bitmap of memory IDs that contain it. When a term's bitmap exceeds its prime threshold, the node auto-splits into child partitions using modular arithmetic. This is the bridge between text and binary: words become sets, sets become bitwise operations.
= {m0, m1, m3, m7} ∩ {m0, m1, m2, m4, m5, m7}
= {m0, m1, m7} — 3 memories
When a term's bitmap cardinality exceeds its depth's prime, the node splits. Members distribute to children via member_id % child_prime. Primes guarantee even distribution. Merge collapses children back into the parent — split and merge are symmetric operations.
Every node's member set is a Roaring Bitmap — run-length + array hybrid compression. Sparse sets (few members) store as sorted arrays. Dense sets switch to bitsets. Cardinality (len()) is O(1). Union/intersection/XOR operate directly on compressed form. Serialized snapshots persist the full tree to disk.
Vector Storage
Vectors live in an ordered BTreeMap keyed by memory ID. Search is exact cosine similarity — no approximate nearest neighbor index, no graph maintenance, no recall degradation. The trick: the search space is small because the lifecycle already pruned it. Bitmap pre-filtering eliminates candidates before any vector math runs.
Tag Index → Candidate Bitmap
Every tag (channel, type, text) is indexed as a Roaring Bitmap. channel = "hearing" returns a bitmap instantly. AND/OR combine multiple tag filters. This bitmap is the candidate set — only these IDs will be scored.
BSI Fidelity Range → Narrow Further
The bit-sliced fidelity index resolves range queries (fidelity > 0.75) in microseconds. Intersect this with the tag bitmap. Dead memories are already gone — below the fidelity gate, they've been forgiven or archived.
Exact Cosine on Filtered Set
Now scan only the surviving IDs. Each vector is 768 floats — 3KB. For a typical agent with 10K memories and a filtered set of 500, that's 1.5MB of vectors scored with exact cosine. Microseconds on any modern CPU. No approximation. No missed results.
WHERE channel = 'hearing'
AND vector_topk_cosine('[0.1, ...]', 10)
HNSW graphs rot
Approximate algorithms build graph indexes that degrade as data changes. Deletions leave tombstones. Insertions trigger expensive rebalancing. An agent's memory is constantly decaying, consolidating, and pruning — exactly the workload ANN indexes handle worst.
Recall@k lies
ANN trades accuracy for speed. At 95% recall@10, one in twenty searches misses the best match. For a memory system where the right memory changes the agent's behavior, that 5% miss rate is a lie the agent tells itself. Ferricula returns exact results. Always.
Tuning parameters are debt
HNSW needs M, ef_construction, ef_search. IVF needs nlist, nprobe. Wrong values = slow or inaccurate. These parameters couple to data distribution, which changes every dream cycle. Ferricula has zero vector index parameters. The lifecycle does the work.
50K active memories × 768 floats × 4 bytes = 146 MB. Cosine similarity on 50K vectors takes ~2ms single-threaded. With bitmap pre-filter cutting to 5K candidates: ~200μs. ANN index overhead for this scale is pure waste.
SDR Entropy Source
The radio is the time source. Ferricula's clock polls gnosis-radio — a marine VHF software-defined radio monitor (RTL-SDR) — for both epoch time and raw entropy. FM noise LSBs are harvested into an entropy reservoir that feeds identity casting, dream modulation, and decay selection. Without the radio, time stands still.
RTL-SDR → FM Demodulation → Spectral Flatness Squelch
Marine VHF 156–157 MHz. IQ samples demodulated, classified by spectral flatness (voice < 0.45, carrier < 0.55, noise > 0.70). Noise LSBs harvested as entropy bytes via GET /api/entropy?bytes=64.
Clock Thread → Entropy Reservoir → Dream Trigger
Background thread polls radio every tick. Entropy bytes accumulate in a reservoir. When the reservoir reaches threshold, a dream cycle fires with entropy-gated decay selection. The radio's epoch is the canonical time source.
Entropy → Hexagram → Identity Seed → Archetypes
6 entropy bytes cast an I Ching hexagram via yarrow stalk probabilities. The hexagram determines emotion (trigram mapping), zodiac sign (epoch-derived), and 5 archetype sub-agents. ECC keypair derived deterministically from the identity seed.
Dream Cycle → Entropy-Gated Decay → Consolidation
Each entropy bit decides which memories are ticked for decay. Intensity modulates coverage. High entropy = more memories processed. Zero entropy = deterministic fallback. After decay: auto-consolidation clusters similar memories, prunes below fidelity gate.
→ accepted: 6B entropy
→ intensity=0.73, dream fired
Each bit from the reservoir decides include/exclude for a memory candidate. At intensity 0.5, half the active memories are processed per dream. The entropy source ensures non-deterministic coverage — no memory is safe from decay by position alone.
Talk to an Agent
Connect your LLM to ferricula's memory engine. Remember, recall, dream, reflect, observe, connect — ten cognitive tools over MCP.
Kord Campbell
Technical badass and natural philosoraptor. Builds memory engines, SDR pipelines, and agent architectures from scratch in Rust — alone, on purpose.
Ferricula grew out of a simple question: what if an AI agent could forget? Not crash, not run out of context — actually forget, the way biological memory does. Thermodynamic decay, consolidation during sleep, entropy from radio static. The answer turned into a memory engine that treats information loss as a feature, not a bug.
Ferricula
Not a brain. A hippocampus. Ferricula handles memory formation, consolidation, and retrieval — the LLM is the cortex. The archetypes are neuromodulatory systems. The SDR is the brainstem clock.
He examines every memory like a jeweler appraising a gem, decides what to keep and what to let fade, and dreams when the entropy is right. Five archetype motes orbit him — Intuition, Fortune, Craft, Ethics, Advocate — each lighting up only when the signal demands it.