Spoiler: 497 commits, three sleepless nights with SQLite, and one very stubborn race condition that refused to die.
Reading time: ~12 minutes ยท For: AI agent developers, architecture drama enthusiasts
Introduction: We Had Three Versions, Now We Have... More
If you missed the last few months of LedgerMind's life, here's the short version: we took a system that in version 3.0 simply worked, and turned it into a system that works fast, reliably, and with elements of artificial intelligence.
Sounds like marketing bullshit? I get it. So let's jump straight to the facts:
| Metric | v3.0 | v3.3.2 | Change |
|---|---|---|---|
| Search (OPS) | ~2,000 | 5,500+ | +175% |
| Write (latency) | ~500ms | 14ms | -97% |
| Commits between versions | โ | 497 | ๐ |
| Critical bugs in production | Had them | Zero now | ๐ |
But let's start from the beginning. Because behind these numbers lies a real engineering drama.
Chapter 1: When Everything Broke (And We Fixed It)
The Tale of One Race Condition
We had a problem. A beautiful, classic TOCTOU race (Time-Of-Check-To-Time-Of-Use). Two agents simultaneously decide to write a decision for the same target. First checks โ no conflicts. Second checks โ no conflicts. First writes. Second writes. Boom. Metadata corrupted.
"This rarely happens," someone said.
"Rarely isn't never," replied CI/CD at 3 AM.
The fix: real ACID transactions with BEGIN IMMEDIATE, a global lock registry, and automatic stale lock cleanup after 10 minutes. Now you can run ten agents on one project โ they'll figure it out.
"Database is Locked": A Chronicle of Expected Death
SQLite is a wonderful thing until you try to write to it from a background worker and a user request simultaneously. Then it becomes... less wonderful.
sqlite3.OperationalError: database is locked
This error haunted us like a ghost. We tried:
- โ Increasing timeouts (didn't help)
- โ Adding retry logic (helped, but hacky)
- โ Praying to database gods (didn't work)
What worked: splitting enrichment batches into per-proposal transactions + worker.pid for detecting stuck workers + automatic stale lock cleanup.
Now the background worker calmly runs every 5 minutes, and users don't even notice it exists. As it should be.
Chapter 2: Features We Wanted Ourselves (And Built)
DecisionStream: Knowledge Has a Lifecycle Too
Before, knowledge in LedgerMind was static. You wrote it โ it sat there until you deleted it. Boring.
Now every piece of knowledge has three life phases:
PATTERN โ EMERGENT โ CANONICAL
- PATTERN โ the system noticed a repeating event
- EMERGENT โ the pattern confirmed itself several times
- CANONICAL โ this is no longer just an observation, it's truth
LifecycleEngine manages transitions automatically. You do nothing โ the system decides when knowledge has "grown up."
Why? Because after a month of operation, you accumulate hundreds of decisions. And you want to see current ones in search, not those you wrote on day one and forgot.
Trajectory-Based Reflection: The System Learns to Think Like You
This is probably my favorite feature of v3.3.
Before: you record decisions, the system stores them.
After: the system analyzes sequences of your decisions and identifies thinking patterns.
# You just record decisions
memory.record_decision("Use PostgreSQL", target="db")
memory.record_decision("Add JSONB", target="db")
memory.record_decision("Migrations via Alembic", target="db")
# The system notices the pattern:
# "When user builds API โ PostgreSQL + JSONB + Alembic"
# And next time will suggest this stack automatically
This isn't magic. It's the Trajectory-based Reflection Engine, which builds graphs of your decisions and finds repeating paths in them.
Zero-Touch Automation: Fewer Clicks, More Code
We added Gemini CLI support and brought VS Code integration to "Hardcore" level:
| Client | Automation Level |
|---|---|
| VS Code | Hardcore โ shadow context, terminal, chats |
| Claude Code | Full โ auto-record + RAG |
| Cursor | Full โ auto-record + RAG |
| Gemini CLI | Full โ auto-record + RAG |
What does this mean in practice? You don't think about LedgerMind at all. It just works. Before every LLM request, the system injects context from memory. After every response โ it writes the result automatically.
You work as usual. The system works for you.
Chapter 3: Optimizations, or How We Squeezed Out Milliseconds
Search: From 2,000 to 5,500+ OPS
Early in v3.3 development, we noticed something unpleasant: search slowed down. From ~4,000 OPS to ~2,000 OPS.
Cause: added linked_id validation for connections between events and decisions. Every search did a full table scan.
Fix: index on linked_id + fast-path heuristics for simple queries + metadata batching.
-- Before: slow JOIN without index
SELECT * FROM decisions WHERE linked_id IN (...)
-- After: fast lookup by index
CREATE INDEX idx_linked_id ON episodic_events(linked_id);
Result: 5,500+ OPS for semantic search, 14,000+ OPS for keyword-only.
Write: 8 OPS with Full Git Audit
Writing a decision to LedgerMind isn't just INSERT INTO. It's:
- SQLite WAL write
- Git commit for cryptographic audit
- Vector embedding generation
- Link count updates
And all this fits into 8 operations per second. For comparison: v3.0 had ~2 OPS.
How? Deferred VectorStore loading, splitting transactions into proposals, path validation caching.
Mobile Version: 4-bit GGUF on Termux
Yes, LedgerMind now runs on Android via Termux. With a 4-bit quantized model.
| Metric | Mobile (GGUF) | Server (MiniLM) |
|---|---|---|
| Search (latency) | 0.13ms | 0.05ms |
| Write (latency) | 142.7ms | 14.1ms |
| Search (OPS) | 5,153 | 11,019 |
Why? Because sometimes you need to prototype on the go. And because we can.
Chapter 4: Bugs We Conquered (And How)
"At least 2 targets" โ The Error That Made No Sense
Symptom: when merging duplicates, the system returned at least 2 targets required, even when duplicates existed.
Cause: group size validation happened after transaction start, when data was already partially modified.
Fix: validate group size before transaction + randomize candidates to prevent infinite merge loops.
The Missing vitality Field
Symptom: CANONICAL knowledge ranks lower than fresh PATTERNs.
Cause: the vitality field needed for lifecycle ranking wasn't loaded in search fast-path.
Fix: add vitality calculation to fast-path + fix transitions in LifecycleEngine.
The Infinite Enrichment Loop
Symptom: worker processes the same proposals over and over. Tokens disappear. Time disappears.
Cause: SQL query didn't exclude already-processed records.
Fix: add enrichment_status field with pending โ completed transition + stuck record detection.
Chapter 5: Refactoring Nobody Sees (But Everyone Feels)
Memory API Decomposition
Before: one huge Memory class at 2,000+ lines.
After: nine specialized services:
Memory (coordinator)
โโโ EpisodicStore # short-term events
โโโ SemanticStore # long-term decisions + Git
โโโ VectorStore # embeddings
โโโ ConflictEngine # conflict detection
โโโ ResolutionEngine # supersede validation
โโโ DecayEngine # pruning old data
โโโ ReflectionEngine # pattern discovery
โโโ LifecycleEngine # phase management
Why? Each component can be tested, optimized, and replaced independently. And when a new developer arrives in six months, they won't run away in horror.
Removing Legacy Settings
We removed:
-
preferred_languageโ nowenrichment_language -
arbitration_modeโ replaced with intelligent conflict resolution -
lite modeโ completely cut from architecture
Why does this matter? Less dead code = fewer bugs = fewer questions like "what does this setting do?".
Epilogue: Should You Upgrade?
If you're on v3.0: Yes, immediately
Why:
- Performance: writes are 35x faster (500ms โ 14ms)
- Reliability: race conditions and DB locks fixed
- Features: DecisionStream, Trajectory Reflection, Zero-Touch for Gemini
- Security: Bandit vulnerabilities patched
- Migration: automatic, non-destructive
# Backup
ledgermind-mcp run --path /path/to/v3.0/memory
# Upgrade
pip install --upgrade ledgermind
# Initialize
ledgermind init
What's Next?
Judging by commits and TODOs in the code:
| Feature | Confidence | Evidence |
|---|---|---|
| Real-time collaboration (CRDT) | Medium | Multi-agent namespacing groundwork |
| Cloud hosting | Medium | Docker + REST gateway ready |
| Knowledge graph visualization | High | DecisionStream ontology enables graph queries |
| LangChain/LlamaIndex integration | High | MCP protocol compatibility |
Afterword: Personal Thoughts
When we started v3.3, I thought: "A few features, some optimizations, release in a month."
Reality: 497 commits, three critical bugs in production, one night debugging SQLite locking, and lots of coffee.
But when I see search running at 5,500+ OPS, the background worker doing its job without a single lock, the system automatically "understanding" patterns in my decisions โ I realize: it was worth it.
LedgerMind v3.3.2 isn't just "a new version." It's a system you can trust.
Now go build something awesome.
Article written based on analysis of 497 commits between v3.0.0 and v3.3.2. The author didn't sleep for two nights but will catch up tomorrow.
P.S. If you find a bug โ open an issue. We're fast. Promise.
P.P.S You can watch video tutorial on my X.com
Top comments (0)