F

FERRICULA

Thermodynamic State

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.

Decay α
0.001–0.02
Keystones
Immortal
Synthesizer
vec2text

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.

01: Fidelity Bit-Planes
Mem ID
Fid
B3 (8)
B2 (4)
B1 (2)
B0 (1)
m0
3
0
0
1
1
m1
7
0
1
1
1
m2
5
0
1
0
1
m3
12
1
1
0
0
m4
9
1
0
0
1
m5
2
0
0
1
0

Columns represent Roaring Bitmaps stored in the Rust memory layer.

02: Range Resolution Simulation
QUERY fidelity > 5 (Binary: 0101)
1
Bit 3 (Threshold: 0)
Slice 3
0
0
0
1
1
0
GT-Bit
0
0
0
1
1
0
{m3, m4} definitely greater
2
Bit 1 (Threshold: 0)
Slice 1
1
1
0
0
0
1
New GT
0
1
0
1
1
0
Added m1 via EQ & Slice1
Final Result Set
{m1, m3, m4} → 5+ Fidelity

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.

Key Derivation Pipeline
1
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.

2
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.

shared = diffie_hellman(our_private, their_public)
3
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.

seed = hkdf(shared, context=b"ferricula-transform-seed")
4
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.

ortho = gram_schmidt(seed_matrix) // 768×768
Why Orthogonal
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.

Per-Agent Isolation

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.

Inversion Pipeline (4 ONNX models)
E
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.

P
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.

T5
Encoder — encoder.onnx

T5 encoder takes the projected sequence via inputs_embeds (not token IDs). Produces encoder hidden states that condition the decoder.

D
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.

Quality Check
After inversion, the hypothesis text is compared to the original via word-set Jaccard similarity. This measures how much semantic content survived. Used as a fidelity gate: if the inverted text doesn't resemble the original, something has gone wrong in the manifold.
Supported Models
gtr-t5-base OUT OF THE BOX

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.

text-embedding-ada-002 OUT OF THE BOX

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.

bge-small-en-v1.5 REQUIRES TRAINING

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.

Any embedding model REQUIRES TRAINING

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.

Four Files
gtr-t5-base.onnx embedder
inverter/projection.onnx 768d → 16×768
inverter/encoder.onnx inputs_embeds
inverter/decoder.onnx greedy decode
inverter/tokenizer.json T5 vocab

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.

Bitmap Adjacency Matrix
m0
m1
m2
m3
m4
m5
m0
0
1
1
0
0
1
m1
1
0
0
1
0
0
m2
1
0
0
0
1
0
m3
0
1
0
0
1
1
m4
0
0
1
1
0
0
m5
1
0
0
1
0
0
Intersection
adj[m0] & adj[m3]
→ {m1, m5} common
Union
adj[m0] | adj[m4]
→ {m1,m2,m3,m5} reach
XOR
adj[m0] ^ adj[m3]
→ {m2,m4} exclusive
Edge Label Layers

Each label type is a parallel bitmap layer. Query by label is a single AND with the adjacency set.

caused
1
0
0
1
0
0
m0→m1, m3→m4
related
0
1
1
0
1
1
m1↔m2, m4↔m5
contradicts
0
0
0
0
1
0
m4 contradicts m3
Query Example
neighbors(m0, label="related")
= 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.

01: Word → Bitmap Lookup
"weather" cardinality: 4
1
1
0
1
0
0
0
1
{m0, m1, m3, m7} — RoaringBitmap, compressed
"protocol" cardinality: 2
0
0
1
0
0
1
0
0
{m2, m5} — exact term match
"entropy" cardinality: 6
1
1
1
0
1
1
0
1
{m0, m1, m2, m4, m5, m7} — exceeds prime(2), auto-split
Set Intersection
terms["weather"] & terms["entropy"]
= {m0, m1, m3, m7} ∩ {m0, m1, m2, m4, m5, m7}
= {m0, m1, m7} — 3 memories
02: Prime-Modular Splitting

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.

0
Root: "entropy" prime=2, depth=0
cardinality 6 > prime 2 → SPLIT
1
entropy:0
id%3=0: {m0, m3}
prime=3, depth=1
1
entropy:1
id%3=1: {m1, m4, m7}
prime=3, depth=1
1
entropy:2
id%3=2: {m2, m5}
prime=3, depth=1
Prime Sequence
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53
16 depth levels. Each split distributes members into coprime buckets.
Roaring Bitmap Storage

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.

Search Path: Filter First, Scan Last
1
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.

2
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.

3
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.

SQL Compose
SELECT id FROM docs
WHERE channel = 'hearing'
AND vector_topk_cosine('[0.1, ...]', 10)
Tag filter runs first as bitmap. Vector search runs only on survivors.
Why Not ANN
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.

Scale Profile
Keystones
Permanent reference memories
10–100
immortal, always searched
Active
Working memory set
1K–50K
constantly pruned by decay
Forgiven
Text discarded, vector seed survives
excluded
not searched by default
Archived
Dormant, can be revived
excluded
cold storage
The Math

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.

Entropy Flow: Radio → Clock → Memory
RF
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.

CLK
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.

ID
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.

DRM
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.

Clock Telemetry
Entropy Lifetime
4,096B
Total bytes harvested from FM noise
Reservoir
128B
Current entropy pool (drains into dreams)
Radio
Connected
gnosis-radio :9080
Dream Cycles
17
Entropy-triggered consolidation runs
Manual Entropy
offer deadbeefcafe...
→ accepted: 6B entropy
→ intensity=0.73, dream fired
Entropy Selection

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.

Coming Soon
Kord Campbell
About the Author

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
About the Engine

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.