Store overview

chitta-field is the sole storage substrate for chitta. It was designed to eliminate NFS file handle issues and D-state hangs on shared filesystems. It is a pure Rust library compiled to libchitta_field.a, statically linked into the C++ daemon. The library runs inside the daemon and uses files for snapshots, sidecars, and WAL segments.

Sparse field activation — each pulse encodes one memory as 64 / 16,384 features

Active feature (sparse code)
Inactive dimension
Overlap — associative recall signal
16,384 feature dimensions in the sparse field
64 active features per memory (0.4% sparsity)
<1ms recall via cortical posting index
768 dense embedding dims (bge-base-en-v1.5)

Sparse associative codes

Each memory is encoded as a sparse code: exactly 64 of 16,384 feature dimensions activate. The rest are zero. Sparse distributed representations9 associate memories through overlapping active features.

Sparse codes are derived from the dense 768-dim BGE embedding by projecting through a learned sparse encoder. The result: two memories about the same concept share many active features. Two unrelated memories share almost none.

This makes retrieval geometric: find memories whose active features overlap most with the query's active features. No distance function. No HNSW4 graph traversal. Just intersection and counting.

SSL NL gloss: SSL-encoded memories (compact triplet form) are passed through gloss_ssl_content() — a translation layer in chitta/include/chitta/ssl_gloss.hpp that converts triplets into readable English sentences before embedding. This closes the representation gap between compact SSL storage and natural-language BGE queries, so structured memories surface from prose questions.

Alias memories: every new SSL memory auto-creates a linked kind=alias NL counterpart, connected by an alias-of triplet. NL and SSL representations stay synchronised without content duplication: the alias carries the glossed sentence, the SSL row carries the canonical triplet.

// Sparse code stored per memory struct SparseCode { memory_id: MemoryId, feature_ids: [u32; 64], // which features activations: [f32; 64], // how strongly ts_ms: i64, // when encoded } // Cortical posting index // feature_id → sorted list of memory_ids posting_index: HashMap<u32, Vec<u64>> // Recall: intersect top-k posting lists // from the query's 64 active features

The posting index enables sub-millisecond recall without HNSW or any graph traversal. Each feature maintains a sorted list; recall intersects k lists and scores by hit count.

Write-ahead log

State changes are typed operations appended to the WAL. Startup loads a committed snapshot family and replays uncovered WAL records, rebuilding or loading derived indexes. Snapshot decode runs in parallel; recovery time depends on the store and cache state.

len u32 4 bytes
seqno u64 8 bytes
op_type u8 1 byte
payload (msgpack) Vec<u8> len bytes
crc32 u32 4 bytes

Durability: ordinary WAL syncs run on a timer (200 ms by default, CHITTA_WAL_SYNC_MS). Explicit durable operations force persistence. A returned sequence number alone is not a guarantee against power loss before the next sync.

Integrity: each entry carries a CRC32 over [seqno][op_type][payload]. On replay, a mismatch aborts with a CrcMismatch error rather than silently accepting corrupted state.

Segment rotation: segments rotate at 256 MB. Segment filenames encode instance ID and first seqno: {instance_id:08x}_{first_seqno:012}.seg. This makes ordering unambiguous across multiple writers.

~/.claude/mind/chitta-field/segments/ 00000001_000000000000.seg // instance 1, starts at seqno 0 00000001_000000012847.seg // instance 1, rotated at 12847 00000002_000000000000.seg // instance 2, separate writer // Segment header (16 bytes) CFLOG001 // magic (8 bytes) u64 // first_seqno (8 bytes) // Replay order: alphabetical sort // instance_id prefix ensures stable interleaving

Semantic ANN sidecars

Snapshot families separate payloads and embeddings from derived search caches. Matching sidecars avoid rebuilding normalized search state and event organs. A missing or incompatible derived cache is rebuilt; it is not authoritative memory data.

SidecarContentsIdentityPurpose
.embDense embeddingsCompiled model dimensionVectors for search and rescoring
.lshNormalized search stateSnapshot familyReuse derived semantic state at startup
.turboQuantized index cacheSnapshot familyAvoid a full synchronous index rebuild
.organsDerived event organsSnapshot familyReuse reconstructed event-tape structures

Startup phases

Parallel snapshot decode overlaps triplet reconstruction; keyword reconstruction overlaps semantic-index startup. Logs expose load phase=<name> ms= and cache hit=. Overlapping phases cannot be summed into wall time. See measured phases and unresolved targets.

Readiness and maintenance

The quantized index can finish rebuilding on the maintenance thread a few seconds after ready. Wait 30 s after restart before measuring recall. Warm startup around 9.5 s and first-start time around 20 s describe the measured deployment, not a guarantee for every store.

Cortical posting index

The recall path uses an inverted index over sparse feature activations — the same structure as a text search engine's posting list, applied to neural feature dimensions instead of words. This is why recall is sub-millisecond with no HNSW graph.

Query embedding
768-dim dense
→
Sparse encode
64 active features
→
Lookup each feature
in posting index
→
Intersect lists
count overlap hits
→
Top-K memories
by overlap score

Why it's fast: each of the 64 query features maps to a pre-sorted posting list. Intersecting 64 small lists is O(k·log n) in the worst case, but in practice the lists are small because each feature is shared by only a fraction of all memories (sparsity guarantees this).

Associativity: two memories about the same topic will share many active features. When you recall one, the other lights up because it appears repeatedly in the posting lists being scanned. This is associative retrieval — not a similarity metric, but emergent from the index structure.

Hybrid recall: the posting index handles semantic overlap. A BM2524 keyword index handles exact term matches. Both scores are fused in the resonance pipeline's early phases.

// Posting index: feature → memories posting_index: HashMap<u32, Vec<u64>> // On store: for each active feature, // append memory_id to its posting list fn index_sparse_code(code: &SparseCode) { for fid in code.feature_ids { posting_index[fid].push(code.memory_id); } } // On recall: intersect and score fn recall_sparse(query_features: &[u32; 64]) -> Vec<(u64, u32)> { let mut hits: HashMap<u64, u32> = Default::default(); for fid in query_features { for mid in &posting_index[fid] { *hits.entry(*mid).or_insert(0) += 1; } } // sort by hit count, return top-K }

Store ownership and recovery

Multiple agent sessions send requests to one daemon. The store holds an exclusive .instance.lock; a second daemon must use a private copy. Instance-prefixed segment names support WAL provenance and replay, not concurrent daemons opening the same mind directory.

A stale lock is replaced automatically only when its recorded PID belongs to this host and is dead. A live or other-host owner must not be removed. Open failures log their reason. Operator recovery requires establishing that no daemon owns the store before moving a stale lock aside.

On startup, OpLog::open() scans the segments directory, finds the last segment for this instance ID, and continues appending there. If the last segment is at or above 256 MB, a new segment is created.

The service allows TimeoutStopSec=300 for a clean snapshot on shutdown. Startup on the measured live store is about 9.5 s with sidecar hits and about 20 s on the first start after deployment or a format change.

// Each instance owns its own segment files // Writer 1: 00000001_000000000000.seg 00000001_000000018432.seg // rotated // A previous daemon instance's retained segment: 00000002_000000000000.seg // Reader sees all, sorted: 00000001_000000000000.seg // first 00000001_000000018432.seg 00000002_000000000000.seg // interleaved // One exclusive .instance.lock per store. // Agent sessions share the owning daemon via RPC.

Organic decay

Memories decay through a demotion tier system driven by access recency and frequency. The daemon's subconscious thread runs demotion periodically — memories that are not accessed slide down the tiers and eventually become dormant. Frequent access promotes a memory back toward tier 0.

  • 0HotFreshly accessed or recently stored. Full recall weight. Promoted on each access.
  • 1WarmAccessed in the last week. Present in recall. Slightly reduced score weight.
  • 2CoolNot accessed in weeks. Still recallable but deprioritized. Fade in resonance scoring.
  • 3ColdLong-dormant. Excluded from default recall unless explicitly requested. Candidates for eviction.

Demotion is logged as a DemoteMemory Op, so it survives restarts. A memory that was cold before a restart is still cold after replay. The tier is part of the persisted state, not recomputed on load.

The StateDelta Op handles strength and confidence adjustments separately — the ResonanceLearner applies Bayesian updates via UpdateState ops, which are also WAL-logged before application.

Memory quality layer

Four mechanisms shipped in v5.21.55–59 that turn chitta-field from a write-once store into a self-correcting one: write-gate admission, symbol-event correlation, introspection, and cross-harness disagreement detection.

Write-gate (staged admission)

All new memories start staged=true and are promoted to staged=false on first recall (access_count ≥ 1). Staged memories score 0.80× in the retrieval pipeline — they still surface when no promoted memory wins, but are ranked lower. Stale staged memories (age > 7 days, never recalled) are auto-pruned. A background pass runs every 50 embed cycles via promote_staged_memories(). The write_gate_stats MCP tool reports staged_count and oldest_staged_age_days.

Symbol-keyed event log

A WAL-backed SymbolEventLog organ records typed events keyed on symbol identity: Edited, Created, Deleted, TestFailed, TestPassed, Committed. Each event carries symbol_name, file_path, session_id, harness, and an optional memory_id link. Indexed by symbol name and file path for O(1) lookup; fully rebuilt from WAL on restart (not stored in the full snapshot). upsert_symbol() auto-logs an Edited event on every symbol write. invalidated_by: Option<String> on MemoryState records the commit hash or symbol-change ID that made a memory stale — set via mark_memory_invalidated.

Introspection — what_do_i_know_about

A single MCP call that answers "what does this session believe about X, and how trustworthy is each claim?" For each recalled hit: staged flag, invalidated_by, source_session, source_tool, age_days (from memory_claim_info); a staleness verdict that checks invalidated_by then walks artifact refs against the live symbol index; contradiction peers from get_conflicts. Returns claims[], cross_harness_conflicts[], topic, total.

Cross-harness disagreement

harness: Option<String> is inferred from source_tool on every put_memory() call ("codex" if the tool name starts with codex, "claude-code" otherwise). The cross_harness_conflicts tool scans all live non-staged memories, groups by HNSW proximity, and returns pairs where harnesses differ — ranked by 1 − cosine_similarity as the disagreement score. Wired into what_do_i_know_about as a per-cluster filter. Snapshot V13 (0xF011_5741_7E00_000D) adds LegacyMemoryPayloadV12 migration covering all V1–V12 snapshots on disk.

FEP attractor network

Memory representations self-organize according to the Free Energy Principle (Spisak19 & Friston, Neurocomputing 2026). The encoder, prototype index, and association graph jointly minimize prediction error while controlling model complexity.

♢

Self-orthogonalizing encoder

The FEP-derived learning rule replaces pure Hebbian26 updates. Each atom update includes a complexity penalty (λ=10-4) that pushes unused weights toward zero, plus Gram-Schmidt decorrelation (1% per step) between co-active atoms. Over time, memory representations naturally become orthogonal — maximizing mutual information and resisting catastrophic forgetting.

⇄

Asymmetric couplings

Prototype transitions and triplet weights encode directionality. When memories are co-retrieved, the forward direction (A→B) receives full coupling strength; the reverse (B→A) is attenuated to 0.3×. Sequential data produces non-equilibrium steady-state dynamics — the same asymmetry Spisak & Friston show generalizes Boltzmann Machines.

⦿

Attractor recall

Partial cues converge to stored attractor basins. attractor_settle() iteratively blends query sparse codes with prototype centroids and follows directed transitions (3-5 steps). Pattern completion emerges naturally — a noisy query settles into the nearest stable memory representation.

 

Surprise-modulated plasticity

Reconstruction error (how poorly the encoder predicts a memory) serves as a surprise signal. High-surprise memories resist decay — they carry unique information. Low-surprise memories fade faster — they are redundant with existing knowledge. This balances accuracy and complexity, the core FEP tradeoff.

⬡

Hopfield network33

An asymmetric energy-based network over memory co-activations. settle() propagates activation through multi-hop directed couplings with dynamic neighbor discovery. Seeds are clamped; connected memories activate via sigmoid gating. The result: given a few seed memories, the network completes the pattern.

 

Free-energy merge criterion

Deduplication uses a principled accuracy-vs-complexity tradeoff instead of a fixed cosine threshold. Two memories merge when the complexity saving of eliminating one outweighs the prediction accuracy lost by combining their representations. Fmerge = loss + λ · complexity < 0.

Storage operations

chitta-field provides indexed retrieval, per-memory scoring, lifecycle maintenance, and graph relationships. It also imports and exports Markdown memory files.

Indexed retrieval

The documented retrieval example selects 5–15 memories from 24,000+ in under a millisecond using hybrid recall: semantic ANN + BM25 + cortical SDR bitset intersection + graph spreading activation. At 10,000+ memories, selection bounds the records injected into the context window.

Per-memory scoring

chitta-field scores each candidate on 18 composable factors — semantic similarity, ACT-R1 base-level activation, memory strength, confidence, epistemic status, affect valence, surprise boost, mood congruence, frustration escalation, prediction boost, integration kernel weight, and more. A two-month-old memory can rank above a five-minute-old memory when its combined score is higher.

Memory lifecycle

chitta-field implements per-memory decay, tiered demotion, auto-deduplication by embedding similarity, contradiction tracking, and distillation from episodic memories into durable wisdom nodes. Access and feedback affect memory strength and demotion.

Contradiction edges

Conflicting beliefs need operational representation — contradicts, supersedes, and confirms edges that are queryable and that suppress contradicted memories during scoring. The scorer can use these typed edges during retrieval.

Shared daemon access

Claude Code and Codex sessions share the daemon over RPC. Its instance lock excludes a second owner of the same store; frozen evaluation runs use separate copied stores. Storage can reside on NFS, so filesystem stalls remain possible.

Markdown integration

chitta syncs bidirectionally with Claude Code’s built-in MEMORY.md. What the user writes there is absorbed into chitta; what chitta knows is injected back. Markdown files provide a readable interface and import surface; the Rust store holds the indexed records.

Cognitive organs

chitta-field’s in-RAM state is organized into independent organs — each a self-contained store with its own data model, WAL replay path, and query interface. No organ imports another; the coordinator wires them together.

◌

ThemeOrgan

Centroid-based theme clustering over memory IDs. Each ThemeRecord holds a mean embedding centroid, coherence score, and member set partitioned by realm. recall_by_embedding returns top-k themes by cosine similarity. Periodic maintain() splits oversized themes (k-means, k=2) and merges near-identical centroids (>0.9 cosine). WAL: ThemeEvent (20).

 

SurpriseLearningStore

Hysteresis-gated credit accumulator that translates surprise magnitude into memory strength adjustments. Evidence is quadratic: ((s−0.20)/0.80)². Credit decays at 0.85 per event; gate requires |credit| ≥ 0.75 and streak ≥ 2 consecutive same-direction signals before a ±0.08 max delta fires. Post-apply bleed (0.35×) prevents rapid re-triggering. Also drives integration-kernel feedback via hard/soft magnitude thresholds. WAL: UpdateSurpriseCredit (44).

⯀

WisdomPromotionStore

Lifecycle FSM for recurring behavioral patterns: Candidate → Provisional → Trusted → Demoted. Candidates are keyed by cluster_key (idempotent upsert). Promotion requires support ≥ 4, cross-session ≥ 2, score ≥ 0.72, and zero contradictions. When promoted, a full memory is written and its ID stored in memory_id. One contradiction permanently blocks promotion until manually cleared. WAL: UpsertWisdomCandidate (45), UpdateWisdomLifecycle (46).

 

LearnedScoringModel

Online weight-delta overlay on the static ScoringConfig. Each factor carries a learned delta clamped to its own [min_delta, max_delta] range. The scorer calls effective_weight(factor, baseline) to get the calibrated value. Updates are full-model atomic snapshots keyed by monotonic model_version. baseline_version detects stale deltas after config bumps. EWMA loss and outcome count track calibration health. WAL: UpdateScorerModel (47).

▣

EpistemicDebt + Evidence

Epistemic debts now carry Vec<DebtEvidence> — each with memory IDs, confidence, and optional note. auto_resolve_if_ready(threshold=0.70) resolves a debt when evidence meets the threshold, writing a WAL UpdateDebt with a human-readable resolution. The subconscious learning cycle runs this scan every 30 minutes. WAL: AttachDebtEvidence (48).

 

SkillRegistry

Append-only versioned registry of named skill blobs. Each skill maps to an ordered list of immutable SkillVersion records — version numbers are 1-based positional indices. deprecate() marks only the latest version; search(query) does case-insensitive substring matching across ID, tags, and content of non-deprecated latest versions. New uploads are immutable; revision requires a new version upload.

 

UserModelRegistry

Key-value registry of typed entity records (user, org, person) with opaque JSON payloads and observation counting. upsert() performs a full overwrite; observe() increments the observation count without touching the payload. Supports list_by_type queries. State is reconstructable from higher-level WAL events rather than having its own op type.

 

Session / Transcript / Task

First-class domain registries for AI session management. SessionRegistry tracks active Claude instances with heartbeats and message queues. TranscriptRegistry indexes conversation turns by session with episode creation. TaskRegistry handles sadhana agents, long-running tasks, dream cycles, and background workers — each as a typed state machine persisted to WAL. WAL: SessionEvent (16), TranscriptEvent (17), TaskEvent (18).

Causal Episode Compiler organs v5.25–v5.38 · Phases 1–14

A second, parallel memory substrate that indexes state transitions (tool, entity, outcome) instead of content. Runs alongside HNSW/BM25/HDC10 recall lanes, which are untouched. The atom of memory is a causal edge, not a document.

 

EventTape

Append-only log of (tool_id, entity_key, outcome_class, session_id, ts_ms) with deterministic entity canonicalization (path stripping, FQN lowercasing, URL hostname). Tool and entity names interned to u16/u32. Serialized in FullSnapshot. Also records DecisionPoint branch events (chosen sym + typed rejection reasons). Phase 12: compress_low_surprisal(threshold) tombstones predictable success events.

◆

CdawgOrgan

Online Blumer CDAWG667 over packed u64 symbols. O(1) amortized per extend(). Each state holds RoaringBitmap endpos, fail_count/succ_count, TD(λ)31 credit, and Q-value. Rebuilt from EventTape at load (ephemeral, not in snapshot). Supports PPM30 prediction, counterfactual sibling-edge comparison, top-k Q-value motif retrieval, and TD credit propagation up suffix links weighted by 1/|endpos|.

 

RefutationLedger

Tracks support (sym_a → expected sym_b) and contradict (sym_a → anything else) counts per Sequitur25 rule. Hysteresis: flip to Refuted at ratio > 0.4, reinstate below 0.2. Antecedent index (HashMap<u64, Vec<RefutEntry>>) enables O(1) per-event checks. On refutation, writes a refuted_by triplet to the KG. Ephemeral; rebuilt from EventTape after each Sequitur pass.

 

HypothesisMarket

Wilson2 score CI (95%, z=1.96) + binary entropy per Sequitur rule. probe_value = H(p̂) × (1 − |p̂ − 0.5| × 2) — maximized at p̂=0.5 (maximum uncertainty), zero at certainty. top_probes(k) returns rules the system is most uncertain about, ranked by expected information gain. Drives Phase 14 self-directed experimentation. Ephemeral; rebuilt after each consolidation_pass().

 

InterventionStore (CEC)

Shadow-to-active policy lifecycle for CEC interventions. Three policy kinds: OpenTask, GuardPolicy, TurnInjection. Shadow eval gate: minimum 20 events + expected_lift > 0.15. Adversarial invariant: fire_active() checks refutation_ratio < 0.3 before firing — policies whose source rule is under active refutation are suspended. Auto-proposes tasks on Sequitur rule refutation and on Phase 14 experiment queue.

 

TuriyaMonitor

Pure read-only witness organ. Samples CDAWG state count, EventTape length, tracked/refuted Sequitur rules, HypothesisMarket mean probe_value, Q-value variance, FEP drift/shock EWMAs, and per-sample deltas after each consolidation_pass(). Rolling 100-sample VecDeque. Seven typed diagnoses in priority order: refutation_flood, stale, q_collapse, high_uncertainty, fep_context_drift (ewma_drift > 0.5 — world-model going silently stale), fep_emission_shock (ewma_shock > 0.3 — known context, novel outcomes), healthy. Persisted in FullSnapshot (V16). Zero write surface to any other organ.

 

FepPriorOrgan (Phase 15)

Non-actuating generative model P(sym | context) over the EventTape symbol stream. Factored Dirichlet-multinomial emission: P(tool | state) · P(outcome | state, tool) — entity marginalized. Latent context = CDAWG active state plus its k=4 suffix-link chain (soft posterior, not point-mass). Online Bayesian count update with exponential forgetting (STATE_DECAY = 0.9995). Free energy per step: F = Eq[−log P(sym|z)] + KL(qt || priorz) — variational bound, tractable. Two EWMA diagnostic signals fed to TuriyaMonitor: ewma_drift (rising KL → world-model going stale) and ewma_shock (high NLL + low KL → known context, novel outcome). Fully ephemeral — rebuilt from EventTape on each consolidation_pass(), not persisted in snapshot.

 

MemoryKind lattice (Phase 16)

Four typed memory kinds inferred at write time from kind tag, realm, and content prefix: Thought (speculation, synthesis), Observation (recorded external fact), Decision (chosen action with rationale), CodeFact (symbol, callgraph, file, type). Static edge-legality matrix enforced in add_assoc_edge() before materialization — (Observation, Thought) and (Decision, Thought) are illegal (rationalization: speculation laundered into fact). Existing memories default to Observation via #[serde(default)] on upgrade. The edge-legality check rejects these invalid provenance chains before insertion.

 

QueryRouter (Phase 16)

Typed query grammar over RecallRequest IR: kind_filter, realm, subject, predicate, freetext, time_from_ms/time_to_ms, causal_tool/causal_entity. route() returns a DispatchKind — Exact | Fuzzy | Temporal | Causal | Hybrid | NeedsDisambiguation(Vec<UnboundSlot>). LLM called only when the grammar leaves a named unbound slot — every token spend corresponds to a specific, auditable hole. Fully bound requests execute zero-token deterministic relational algebra. Four falsifiability metrics written per consolidation_pass(): token-displacement ratio, deterministic replay rate, router error rate, contradiction yield.

 

MemProvenance lattice (Phase 17)

First-class provenance axis on every MemoryPayload: Human, Claude, Codex, OpenWeightDistilled, OpenWeightGenerated. can_write_kind(kind) gate: open-weight-generated writes always enter the candidate band — forbidden from direct Decision or CodeFact writes. candidate: bool on payload; promoted only by witness_memory() on a closed-loop signal (user [correction], tool-result outcome, or router hit-rate delta). Candidate-laundering guard in add_assoc_edge(): if src.candidate && !dst.candidate, the edge is rejected — a quarantined memory cannot cite established knowledge as evidence. Stored with #[serde(default)]; no snapshot migration required.

 

Reconciler (R0) (Phase 17)

CPU-native deliberation operator — no model call, deterministically replayable. reconcile_all() scans all assoc_edges for MemoryKind legality violations and candidate→established laundering; results returned as illegal_edges, unresolved. detect_contradictions() groups payloads by (realm, first-6-word content prefix) — kind mismatches within the same prefix group produce a conflict_score=0.6 pair; same-kind body divergence produces 0.4. Capped at 50 pairs to avoid O(n²) on large stores. R0/R1 split is inviolable: R0 ops are structural graph traversal; R1 (model proposal) produces only proposals that R0 validates before commit. Results logged to triplet KG as (contradiction:A-B, “conflict_score”, “0.6”) entries.

Op catalog

Every state change is one of these typed operations. The op_type byte is written to the WAL alongside the msgpack payload, and validated on replay to detect corruption.

OpByteDescription
PutPayload0Store a new memory with content, embedding, metadata, and artifact refs.
UpdateState1Adjust strength, confidence, decay_rate, or touch last_accessed_ms on an existing memory.
DeleteMemory2Soft-delete a memory at a given timestamp.
AddAssocEdge3Add a typed association edge between two memories (DerivedFrom, SameSession, CoRetrieved, Contradicts, Supports…).
UpsertArtifact4Register a file artifact (normalized path, repo root).
AddTriplet5Add a knowledge graph triplet (subject, predicate, object, weight, valid_from_ms).
InvalidateTriplet6Mark a triplet as superseded at a given timestamp.
UpsertSymbol7Insert or update a code symbol (function, class, method) with its embedding.
RemoveSymbol8Remove a code symbol and clean up call graph edges.
AddSymCallEdge9Add a caller→callee edge in the symbol call graph.
RemoveSymCallEdge10Remove a call graph edge.
UpsertCodeFile11Register or update a code file (path, project, mtime).
UpdateSparseCode12Store sparse code for a memory (feature_ids + activations).
DemoteMemory13Move a memory to a lower decay tier.
TrainPQ14Persist trained Product Quantizer codebooks (bincode-serialized).
UpdateResidualPQ15Store PQ residual codes for a single memory (32-byte compressed embedding).
SessionEvent16Session lifecycle event (register, heartbeat, deregister, message_send, message_ack).
TranscriptEvent17Transcript lifecycle event (register, update_progress, add_turn, create_episode).
TaskEvent18Task lifecycle event for sadhana, long_task, dream, background workers.
UserModelEvent19User model entity event (profile, goal, habit, anticipation, calibration).
ThemeEvent20Theme graph event (create, update_centroid, assign_member, remove_member).
AnalyticsEvent21Analytics event (exposure, recall_query, correction, usage_outcome).
ClearProject22Remove all code files and associated symbols for a project.
UpdateSymbolDescription23Update the description string for a symbol.
UpdateMemoryContent24Update content and/or embedding for an existing memory in-place.
AssertFact25Assert a Prolog-style logic fact into the constraint store (Layer 1).
RetractFact26Retract a constraint fact by ID.
BranchEvent27Hypothetical branch lifecycle — create, resolve, or discard.
TriggerEvent28Trigger tissue lifecycle — add, dismiss, or record a firing (Layer 2).
PredictorEvent29Markov chain transition update — bump edge probability or record access (Layer 3).
RecordSurprise39Record a prediction error tuple — expected vs actual outcome (Layer 4).
RegisterDebt40Register a new epistemic debt with competing hypotheses and discriminating tests (Layer 5).
UpdateDebt41Resolve, defer, or update status of an epistemic debt.
UpdateSourceWeight42Update learned recall source weight for a (domain, source) pair (Layer 6).
RecordFeedback43Record whether a recall source was useful — feeds Bayesian weight update.
UpdateSurpriseCredit44Persist per-memory rolling credit state after hysteresis gate — strength delta applied.
UpsertWisdomCandidate45Create or update a wisdom candidate with support evidence and promotion score.
UpdateWisdomLifecycle46Advance wisdom candidate through FSM — candidate → provisional → trusted → demoted.
UpdateScorerModel47Atomic snapshot of the learned scoring model — full factor weight delta map.
AttachDebtEvidence48Attach supporting evidence (memory IDs + confidence) to an epistemic debt.

Integration with chitta

chitta-field is a separate Rust repository included as a git submodule. The C++ daemon calls into it exclusively via a C FFI layer (chitta_field.h), keeping the Rust and C++ build systems fully independent.

Build

chitta-field builds to libchitta_field.a via ./build.sh build --release. The CMake build picks it up from ../chitta-field/ (relative to chitta/CMakeLists.txt) or from a -DCHITTA_FIELD_ROOT override. The smart-installer runs the Rust build automatically before cmake.

FFI layer

All calls go through cf_* C functions defined in chitta_field.h. The C++ side calls cf_open(), gets back an opaque FieldHandle*, and uses it for all subsequent ops. No C++ knows about Rust internals.

FieldRpcHandler

FieldRpcHandler in rpc/field_handler.hpp wraps the Rust store through FFI. See the generated tool reference for MCP and native CLI discovery.

// Build from source (git clone with submodule) git clone --recurse-submodules https://github.com/genomewalker/chitta.git cd chitta // Build chitta-field (Rust, requires 1.92+) cd chitta-field && ./build.sh build --release && cd .. // Build the daemon (C++20 + llama.cpp) cmake -S chitta -B chitta/build -DCMAKE_BUILD_TYPE=Release -DCHITTA_WITH_LLAMA_CPP=ON cmake --build chitta/build --parallel // Or use the all-in-one installer: ./scripts/smart-install.sh

Rust memory store

An embedded Rust store with durable snapshots and WAL, derived search indexes and explicit ownership. Memories can decay and strengthen over time while sessions share one daemon.

References

  1. John R. Anderson and Lael J. Schooler. Reflections of the Environment in Memory. Psychological Science 2(6), 396–408 (1991). https://doi.org/10.1111/j.1467-9280.1991.tb00174.x
  2. Edwin B. Wilson. Probable Inference, the Law of Succession, and Statistical Inference. Journal of the American Statistical Association 22(158), 209–212 (1927). https://doi.org/10.1080/01621459.1927.10502953
  3. Yu. A. Malkov and D. A. Yashunin. Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs. IEEE TPAMI 42(4), 824–836 (2020); arXiv:1603.09320 (2016). https://arxiv.org/abs/1603.09320 https://doi.org/10.1109/TPAMI.2018.2889473
  4. A. Blumer, J. Blumer, D. Haussler, R. McConnell, and A. Ehrenfeucht. Complete inverted files for efficient text retrieval and analysis. Journal of the ACM 34(3), 578–595 (1987). https://doi.org/10.1145/28869.28873
  5. Subutai Ahmad and Jeff Hawkins. Properties of Sparse Distributed Representations and their Application to Hierarchical Temporal Memory. arXiv:1503.07469 (2015). https://arxiv.org/abs/1503.07469
  6. Pentti Kanerva. Hyperdimensional Computing: An Introduction to Computing in Distributed Representation with High-Dimensional Random Vectors. Cognitive Computation 1, 139–159 (2009). https://doi.org/10.1007/s12559-009-9009-8
  7. Tamas Spisak and Karl Friston. Self-orthogonalizing attractor neural networks emerging from the free energy principle. Neurocomputing, article 133472 (2026); arXiv:2505.22749 (2025). https://arxiv.org/abs/2505.22749 https://doi.org/10.1016/j.neucom.2026.133472
  8. Stephen Robertson and Hugo Zaragoza. The Probabilistic Relevance Framework: BM25 and Beyond. Foundations and Trends in Information Retrieval 3(4), 333–389 (2009). https://doi.org/10.1561/1500000019
  9. Craig G. Nevill-Manning and Ian H. Witten. Identifying Hierarchical Structure in Sequences: A linear-time algorithm. Journal of Artificial Intelligence Research 7, 67–82 (1997); arXiv:cs/9709102. https://arxiv.org/abs/cs/9709102
  10. Donald O. Hebb. The Organization of Behavior: A Neuropsychological Theory. Wiley (1949); Psychology Press reissue (2002). https://www.routledge.com/The-Organization-of-Behavior-A-Neuropsychological-Theory/Hebb/p/book/9780415654531
  11. John G. Cleary and Ian H. Witten. Data Compression Using Adaptive Coding and Partial String Matching. IEEE Transactions on Communications 32(4), 396–402 (1984). https://doi.org/10.1109/TCOM.1984.1096090
  12. Richard S. Sutton. Learning to Predict by the Methods of Temporal Differences. Machine Learning 3, 9–44 (1988). https://doi.org/10.1023/A:1022633531479
  13. John J. Hopfield. Neural networks and physical systems with emergent collective computational abilities. PNAS 79(8), 2554–2558 (1982). https://doi.org/10.1073/pnas.79.8.2554
  14. A. Blumer, J. Blumer, D. Haussler, A. Ehrenfeucht, M. T. Chen, and J. Seiferas. The smallest automaton recognizing the subwords of a text. Theoretical Computer Science 40, 31–55 (1985). https://doi.org/10.1016/0304-3975(85)90157-4