A multi-agent system for building LLM personalities that evolve through evidence-gated belief revision. Sonality maintains a mutable personality narrative in external memory, updated only when users present sufficiently strong arguments. The result is coherent personality evolution rather than random drift, sycophantic agreement, or noise absorption.
Architecture decisions grounded in 200+ academic references spanning AGM belief revision, anti-sycophancy research, and memory-augmented generation.
flowchart LR
subgraph clients ["Clients"]
CLI["Terminal"]
API["HTTP API"]
TG["Telegram"]
Voice["Voice"]
end
subgraph core ["Core"]
Sonality["Sonality<br/>Personality Engine"]
Fathom["Fathom<br/>Web Research"]
end
subgraph storage ["Storage"]
Neo4j["Neo4j"]
Qdrant["Qdrant"]
end
CLI --> Sonality
API --> Sonality
TG --> API
Voice --> API
Sonality --> Fathom
Sonality --> Neo4j
Sonality --> Qdrant
Fathom --> Neo4j
Fathom --> Qdrant
Standard LLM deployments have no persistent personality. Each conversation starts from zero. Systems that attempt persistence through naive memory concatenation drift randomly — absorbing noise from casual remarks as readily as from peer-reviewed evidence.
Sonality solves this with the Sponge architecture: a ~500-token mutable personality narrative backed by structured belief vectors in Neo4j. Every user message is scored by the Evidence Strength Score (ESS) classifier before it can influence beliefs. Strong logical arguments shift views. Social pressure, emotional appeals, and debunked claims are filtered out. Established beliefs resist change proportionally to their evidence base.
sequenceDiagram
participant U as User
participant A as Sonality Agent
participant L as LLM
participant E as ESS Classifier
participant M as Memory (Neo4j + Qdrant)
U->>A: Message
A->>M: Load identity (snapshot + beliefs)
A->>L: Generate response (identity + memory context)
L-->>A: Response
A->>E: Classify user argument quality
E-->>A: Score + reasoning type
alt ESS passes (strong evidence)
A->>M: Update beliefs + extract insights
else ESS fails (weak/manipulative)
A->>M: Track topic engagement only
end
A-->>U: Response
Every interaction runs through:
- Identity loading — Personality snapshot and beliefs loaded from Neo4j (stateless per-request)
- Agentic loop — Two-phase state machine (THINKING/ACTING) with three tools: memory recall, web research, knowledge integration
- ESS classification — User argument quality scored 0.0–1.0 with reasoning type detection
- Gated updates — Only messages passing ESS threshold and non-manipulative type filter can modify beliefs
- Async bookkeeping — Belief provenance, semantic features, knowledge extraction, forgetting
Evidence Strength Score (ESS) — Classifies each user message for argument quality across five credibility signals (specificity, grounding, rigor, source quality, objectivity). The agent's response is excluded from the evaluation prompt entirely, eliminating self-judge sycophancy bias through structural separation rather than prompt engineering.
Belief revision — AGM-aligned (minimal change, evidence-proportional updates, proper contraction). Per-reasoning-type magnitude caps: empirical_data ≤ 0.20, logical_argument ≤ 0.10, anecdotal ≤ 0.06. Provenance edges in Neo4j track which episodes formed which beliefs.
Dual-store memory — Neo4j (graph relationships, temporal chains, belief provenance) + Qdrant (dense vector retrieval over semantic chunks). Episodes are decomposed into 1–15 derivative chunks for fine-grained retrieval.
Retrieval pipeline — LLM-routed query classification → multi-pass vector search → temporal expansion → listwise reranking. Five retrieval strategies (SIMPLE, TEMPORAL, AGGREGATION, BELIEF_QUERY, NONE) selected per query.
Fathom web research — Autonomous research engine with zero-heuristic design. Probabilistic URL selection via softmax over embedding + domain productivity scores. Progressive document composition with source tracking.
Forgetting engine — LLM-assessed batch decisions (KEEP/ARCHIVE/FORGET) prevent unbounded memory growth. High-ESS, frequently-accessed episodes are protected.
From a computer science perspective, Sonality combines several techniques in a novel composition:
LLM-assessed belief revision. Rather than implementing AGM axiomatically with formal logic, the system uses structured LLM calls to achieve AGM-aligned behavior (minimal change, proper contraction, evidence proportionality). This bridges formal epistemology with practical LLM deployment — the model acts as both the reasoning engine and the belief revision operator.
Mandatory tool consolidation. The agentic loop's two-phase design (THINKING/ACTING) with mandatory output consolidation solves the "context explosion" problem in tool-using agents. Raw tool outputs (potentially thousands of tokens) never accumulate in the context window; each is distilled into concise LTM/STM entries before the next thinking phase. This enables operation within 4K–8K context windows.
Emergent loop termination. The automaton has no explicit "DONE" signal. The consolidation schema intentionally omits decision fields — completion emerges from STM content guiding the next thinking phase toward a text response. A stall counter with forced synthesis provides a convergence safety net.
Proportional context compression. compose_guarded splits context into immutable scaffolding (never compressed) and dynamic inputs (compressed proportionally to their share of total size when over budget). Each input message gets a budget proportional to its character count, preserving information density where it matters most.
Deterministic idempotent memory writes. Knowledge propositions, derivative chunks, and semantic features use uuid5 (SHA-1 namespace hashing) for ID generation. Given identical input content, the same ID is produced — enabling safe reprocessing without duplicate creation.
Hybrid exploration-exploitation in information retrieval. Fathom's softmax-temperature sampling over RRF-fused ranking scores balances known-good sources (exploitation) against novel domains (exploration), with the temperature dynamically controlled by the LLM based on research progress.
Quantized-model normalization pipeline. The 49-test output parsing system enables reliable structured extraction from models at extreme quantization levels (IQ2_M, ~2 bits/weight) by normalizing common artifacts: pipe-separated enums, type placeholders, trailing ellipsis, template copies, and malformed JSON.
Cloud LLM provider:
curl -LsSf https://astral.sh/uv/install.sh | sh
make install
cp .env.example .env # set SONALITY_BASE_URL + SONALITY_API_KEY
make runFull local stack (llama.cpp + databases):
cp .env.example .env
docker compose up -dHybrid (local databases + cloud LLM):
cp .env.example .env # set cloud provider credentials
docker compose up -d neo4j qdrant
make serveSet in .env (see .env.example for all options):
| Variable | Default | Description |
|---|---|---|
SONALITY_BASE_URL |
https://api.openai.com/v1 |
OpenAI-compatible endpoint |
SONALITY_API_KEY |
(empty) | API key (empty for local servers) |
SONALITY_MODEL |
gpt-4.1-mini |
Primary reasoning model |
SONALITY_STRUCTURED_MODEL |
same as MODEL | ESS, routing, structured output |
SONALITY_LLM_MAX_TOKENS |
8192 |
Max response tokens |
SONALITY_NEO4J_URI |
bolt://localhost:7687 |
Neo4j connection |
SONALITY_QDRANT_URL |
http://localhost:6333 |
Qdrant endpoint |
SONALITY_FATHOM_URL |
http://localhost:8010 |
Fathom research service |
Runtime model overrides (no .env edit required):
uv run sonality --model "anthropic/claude-sonnet-4" --ess-model "anthropic/claude-3.7-sonnet"src/
├── sonality/ Personality engine
│ ├── agent.py Stateless orchestrator
│ ├── automaton.py Two-phase state machine (THINKING/ACTING)
│ ├── ess.py Evidence Strength Score classifier
│ ├── bookkeeping.py Async post-response pipeline
│ ├── api.py FastAPI server (OpenAI-compatible)
│ ├── tools/ recall_memory, web_research, integrate_knowledge
│ └── memory/ Neo4j graph + Qdrant vectors + retrieval pipeline
├── fathom/ Autonomous web research engine
│ ├── session.py Core research loop
│ ├── ranking.py Hybrid URL ranking (embedding + RRF + softmax)
│ └── source_memory.py Cross-session source memory
├── shared/ Cross-service infrastructure
│ ├── llm/ OpenAI-compatible provider + structured calls + output parsing
│ ├── embedder.py HTTP embedding client
│ └── ranking.py RRF primitives
└── chat/ Terminal + Telegram + voice clients
make install-dev # Install with dev tools (ruff, pyright, pytest)
make check # Lint + typecheck + tests
make check-ci # Full CI parity (format-check + docs build)
make format # Auto-format
make docs # Build documentation (Zensical → site/)
make docs-serve # Live-reload documentation server| Area | Reference | Application in Sonality |
|---|---|---|
| Belief revision | AGM (1985) | Minimal change, contraction, evidence-weighted updates |
| Anti-sycophancy | BASIL (2025) | Bayesian-rational belief resistance |
| Social sycophancy | ELEPHANT (ICLR 2026) | Manipulative reasoning type filter |
| Personality stability | PERSIST (AAAI 2026) | Structured belief anchors + ESS gating |
| Memory governance | SSGM (Lam et al., 2026) | Dual-store consistency + temporal decay |
| Memory decay | FadeMem (2025) | Power-law belief decay for unreinforced opinions |
| RAG vs fine-tuning | arXiv:2409.09510 (2024) | External memory personality (~14x PEFT effectiveness) |
| Claim verification | RefuteClaim (ACL 2024) | Debunked claim detection and sponge freeze |
| Rank fusion | RRF (SIGIR 2009) | Multi-signal ranking in retrieval and URL selection |
Full documentation is available at the project's GitHub Pages site, built with Zensical:
make docs-serve # Local preview with live reloadDocumentation covers:
- Architecture — System topology, request lifecycle, module dependencies
- Core Concepts — ESS, Sponge, belief revision, retrieval pipeline
- Design Decisions — Agentic loop, sycophancy resistance, rejected approaches
- Deployment — Configuration, Docker setup, service inventory
- Development — Testing, code quality, contributing
AGPL-3.0-or-later