⚖️ 1. The Memory Topology Dilemma: Local Silos vs. Cloud Sprawl
Autonomous software agents require persistent context. When an agent discovers that a legacy endpoint expects ISO-8601 UTC timestamps, or solves a deadlock in a PostgreSQL connection pool, that breakthrough must persist across future coding sessions.
Engineers designing persistent memory for agents typically confront two flawed extremes:
~/.cache/agent_memory.db).
- Device Isolation: Lessons learned on a desktop workstation are invisible when working from a laptop.
- Local VRAM Tax: Running local embedding models (e.g. Ollama with
bge-large1024-d) permanently locks 2GB–4GB of VRAM and burns laptop battery. - Zero Multi-Agent Synergy: Parallel coding agents or subagents cannot share context without manual copying.
- WAN Latency Tax: Every conversational turn stalls for 300ms–800ms awaiting remote network roundtrips.
- Offline Amnesia: If network connectivity drops or the environment is air-gapped, the agent suffers immediate amnesia.
- IP & Security Leakage: Sensitive code context and working-tree fragments are transmitted across third-party subprocessor chains.
Neither extreme is viable for production engineering. Software development is inherently local-first, but collaboration and long-term continuity are inherently multi-device and distributed.
🏛️ 2. The Reference Architecture: SQLite Edge Cache + Postgres Core
To solve this trade-off, krusch-context-mcp implements a conventional, proven distributed caching pattern: local read-replica cache with write-behind log shipping.
Stripping away branding terms like "Lakebase," the architecture is an edge-cache + system-of-record topology:
| Tier & Component | Storage Engine | Read Latency | Offline SLA | Primary Architectural Role |
|---|---|---|---|---|
| Tier 1: Edge Compute Cache | Local SQLite (<project>/.agent/memory.db) with embedded sqlite-vec |
<5ms p95 | 100% Offline Capable | Serves hot episodic memories, holographic steering nuggets, and local symbol lookups directly to the active IDE agent turn without network I/O. |
| Tier 2: System of Record | PostgreSQL 16 + pgvector (Self-hosted or Polygres.com Cloud Platform) | 50ms–150ms (WAN) | Durable Asynchronous Sync | Authoritative multi-device persistence, cross-machine synchronization, versioned lineage history, and multi-agent coordination. |
🔄 3. Cache Freshness, TTL, and Offline Conflict Resolution
In any dual-tier caching architecture, the primary design challenge is cache invalidation and synchronization correctness. If reads are local-first, how does Machine B learn about updates committed by Machine A?
Cache Invalidation & Freshness Policy
krusch-context-mcp implements a pragmatic three-level invalidation policy:
- Boot & Session Start Verification: When an IDE agent initializes (or calls
compile_state), the client performs a lightweight conditional check against PostgreSQL:
IfSELECT MAX(updated_at) AS cloud_watermark FROM ide_agent_memory WHERE project_name = $1;cloud_watermarkexceeds the local SQLite watermark, an incremental sync pull is triggered before serving queries. - Configurable In-Session TTL: During an active session, local cache reads are treated as authoritative for a sliding TTL window (default: 5 minutes). Background polling synchronizes updates periodically without blocking agent turns.
- Explicit Invalidation Broadcasts: Calling
invalidate_memoryorsupersede_memorymarks records with a tombstone timestamp, forcing immediate cache evictions across connected instances.
Offline Writes & Conflict Resolution
When a laptop is offline, mutations queue locally in SQLite under a monotonic staging table (local_mutation_queue). Upon network reconnection:
- Scalar Steering Nuggets: Resolved via Last-Write-Wins (LWW) based on UTC timestamps.
- Episodic Memories: Appended as new immutable records with parent pointers (
parent_id). Because episodic memories are append-only observations, conflicting lessons do not clobber each other; they branch. - Semantic Conflicts: When two contradictory rules are committed simultaneously (e.g. "Use port 4080" vs. "Use port 5000"), both are flagged as
DISPUTEDand surfaced viakrusch_context_resolve_conflictfor explicit developer confirmation.
🔒 4. The Pragmatic Boundaries of Data Sovereignty & Threat Modeling
A common overclaim in cloud memory architectures is proclaiming "100% Data Sovereignty" simply because raw source code files remain on local disk. A serious systems threat model must be transparent about what actually syncs:
While raw source code trees, git blobs, and local staged diffs never touch the network, episodic notes, architectural decisions, and steering nuggets contain sensitive corporate knowledge.
- Internal API routes, port numbers, database credentials patterns, and unpatched vulnerability workarounds are routinely recorded in agent notes.
- Embedding Inversion Attacks: Academic research has proven that high-dimensional vector embeddings (such as 1024-d BGE vectors) can be inverted by adversarial models to reconstruct significant portions of the original text.
- Transmitting notes and embeddings to cloud endpoints (such as OpenRouter or managed databases) introduces third-party subprocessor trust requirements.
Two Calibrated Deployment Postures
Because threat models differ across environments, the stack explicitly supports two operational modes:
Source code stays local on disk; abstract notes and vectors sync to managed PostgreSQL (Polygres Cloud) using OpenRouter cloud embeddings. Best for individual engineers and product teams balancing zero VRAM load against acceptable SaaS risk under zero-data-retention agreements.
100% of compute executes inside the physical perimeter: self-hosted PostgreSQL 16 + pgvector, local Ollama / vLLM embedding inference, and zero WAN egress. Mandatory for law firms (CCP § 128.7 / CRPC 1.6), financial audits, and HIPAA-regulated healthcare.
💰 5. The Truth About "Zero-VRAM" & Production Token Economics
Calling cloud embedding offload "Zero-VRAM" is a marketing simplification. In systems engineering, there is no free compute—only trade-offs:
- Offloading embeddings to OpenRouter removes local GPU VRAM allocation (~2GB–4GB for
bge-large) and eliminates fan noise on laptops. - In exchange, you introduce network latency (100ms–250ms per batch), API key management, vendor dependency, and outbound data transmission.
- When offline, the system cannot generate new cloud vectors; it must either fall back to a local CPU embedder (such as ONNX Runtime) or defer indexing until reconnected.
Realistic Production Token Economics
Claims that "10,000 memories cost less than $0.03/month" represent a toy-scale baseline where each record is a brief 50-token sentence. In production, token consumption scales with corpus depth:
| Workload Category | Monthly Volume | Avg Tokens / Unit | Total Tokens | Est. Monthly Cost (BGE-Large @ $0.01/1M) |
|---|---|---|---|---|
| Micro-Notes & Steering Nuggets | 10,000 facts | ~75 tokens | 750,000 | <$0.01 |
| Session Summaries & Blockers | 500 sessions | ~800 tokens | 400,000 | <$0.01 |
| Codebase Repository Snapshots | 4 full re-indexes | 5,000 chunks × 256 tokens | 5,120,000 | ~$0.05 |
| High-Churn Agent Transcripts & Diffs | 200 tasks | ~50,000 tokens (diffs + logs) | 10,000,000 | ~$0.10 |
| Full Production Fleet (5 Developers) | Comprehensive | Mixed Workloads | ~30M–50M tokens | $0.30 – $0.50 / month |
⚠️ 6. The Embedding Parity Trap: Hybrid Offline/Online Alignment
The most dangerous subtle bug in hybrid local/cloud vector systems is embedding drift.
If an engineer configures cloud embeddings via OpenRouter (using baai/bge-large-en-v1.5) while using local Ollama (ollama run bge-large) when offline on an airplane, the system will silently fail:
- Pooling Strategy Mismatches: One runtime may use
[CLS]token pooling while another uses mean pooling over token embeddings. - L2 Normalization Inconsistencies: Some providers return raw unnormalized vectors while others return unit-normalized vectors. Cosine distance queries across mixed normalization will produce corrupt similarity rankings.
- Quantization Differences: FP16 cloud weights vs. Q4_K_M quantized local GGUF weights produce subtle angular deviations that degrade Top-1 precision.
The Engineering Mandate: In hybrid mode, krusch-context-mcp enforces strict normalization verification:
// Client-Side Vector Normalization Invariant
function normalizeVector(vec) {
const norm = Math.sqrt(vec.reduce((sum, val) => sum + val * val, 0));
if (norm === 0) return vec;
return vec.map(val => val / norm);
}
If local and remote embedders cannot guarantee bit-exact vector alignment, offline writes must be marked PENDING_EMBEDDING and vectorized centrally upon cloud reconnect.
⚡ 7. Indexing Strategy: Two-Stage HNSW Retrieval vs. Naive Sequential Scans
A major flaw in naive vector tutorials is proposing SQL queries that calculate dynamic mathematical decay across the entire table:
-- ❌ THE SCALABILITY TRAP: FORCES A FULL SEQUENTIAL TABLE SCAN
SELECT id, content, (1 - (embedding <=> $1)) * EXP(-0.01 * age) AS score
FROM ide_agent_memory
WHERE project_name = 'my-project'
ORDER BY score DESC LIMIT 5;
Because the decay factor EXP(-0.01 * age) is a dynamic runtime scalar multiplied against the vector distance, PostgreSQL cannot use the HNSW vector index for ordering. As the table grows to tens of thousands of records, this query degrades into an expensive, CPU-bound sequential scan.
The Production Two-Stage Retrieval Pipeline
To preserve sub-25ms execution at scale, krusch-context-mcp executes a Two-Stage Candidate Rescoring Pipeline:
-- ✅ PRODUCTION TWO-STAGE PIPELINE: USES HNSW INDEX FULLY
WITH candidate_pool AS (
-- Stage 1: Fast HNSW vector index scan retrieving top-K nearest neighbors
SELECT
id,
category,
content,
created_at,
(1 - (embedding <=> $1::vector)) AS raw_similarity
FROM ide_agent_memory
WHERE project_name = $2
AND status = 'ACTIVE'
ORDER BY embedding <=> $1::vector ASC
LIMIT 50 -- Bounded candidate pool (K=50)
)
-- Stage 2: In-memory mathematical decay rescoring across the small candidate pool
SELECT
id,
category,
content,
raw_similarity * EXP(-0.01 * (EXTRACT(EPOCH FROM (NOW() - created_at)) / 86400)) AS final_score
FROM candidate_pool
ORDER BY final_score DESC
LIMIT 5;
🚀 8. Compound Retrieval: Eliminating WAN Round Trips
Over high-latency WAN connections, sequential tool hops are the primary bottleneck of agent responsiveness.
Instead of forcing the agent to execute five separate tool invocations, krusch_context_retrieve wraps the entire context payload into a single PostgreSQL transaction:
-- Single-Pass Compound Briefing Query
WITH candidate_memories AS (
SELECT id, category, content, created_at, (1 - (embedding <=> $1::vector)) AS sim
FROM ide_agent_memory
WHERE project_name = $2 AND status = 'ACTIVE'
ORDER BY embedding <=> $1::vector ASC LIMIT 50
),
ranked_memories AS (
SELECT id, category, content, sim * EXP(-0.01 * (EXTRACT(EPOCH FROM (NOW() - created_at))/86400)) AS score
FROM candidate_memories ORDER BY score DESC LIMIT 5
),
active_nuggets AS (
SELECT id, key, value, kind FROM ide_agent_nuggets
WHERE project_name = $2 ORDER BY updated_at DESC LIMIT 10
),
project_state AS (
SELECT summary, active_blockers, recent_priorities
FROM ide_agent_state_compilations
WHERE project_name = $2 ORDER BY compiled_at DESC LIMIT 1
)
SELECT
(SELECT json_agg(m) FROM ranked_memories m) AS memories,
(SELECT json_agg(n) FROM active_nuggets n) AS nuggets,
(SELECT row_to_json(s) FROM project_state s) AS state;
The agent receives memories, steering nuggets, and state compilations in a single 30ms database round trip, saving up to 2.5 seconds of conversational latency.
🧠 9. Multi-Agent Consensus: Branching Lineage & Conflict Hooks
In multi-agent workflows, autonomous subagents frequently produce contradictory observations. Rather than pretending that consensus happens magically, krusch-context-mcp establishes an explicit data model:
-- Multi-Agent Interaction Memory Schema
CREATE TABLE interaction_memory (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
project_id VARCHAR(64) NOT NULL,
parent_id UUID REFERENCES interaction_memory(id),
author_agent VARCHAR(64) NOT NULL, -- e.g. 'cursor-claude-3.5', 'cli-gemini-pro'
memory_type VARCHAR(32) NOT NULL, -- 'fact' | 'decision' | 'rule'
content TEXT NOT NULL,
status VARCHAR(16) NOT NULL DEFAULT 'ACTIVE', -- 'ACTIVE' | 'SUPERSEDED' | 'DISPUTED'
conflict_ids UUID[] DEFAULT NULL,
created_at TIMESTAMPTZ DEFAULT clock_timestamp()
);
CREATE INDEX idx_interaction_lineage ON interaction_memory (parent_id);
CREATE INDEX idx_interaction_project ON interaction_memory (project_id, status);
The Conflict Protocol:
- When Agent A asserts a statement that has high semantic similarity ($>0.85$) with an existing active rule but exhibits contradictory sentiment, the server sets
status = 'DISPUTED'. - The conflicting IDs are registered in
conflict_ids. - The human developer or orchestrating supervisor is notified via
krusch_context_resolve_conflictto select the authoritative branch or author a synthesized invariant.
🛡️ 10. Architectural Decoupling: Context Engine vs. 2PC Execution Harness
It is vital to draw a clean architectural boundary between Context Storage and Execution Safety:
krusch-context-mcpis a Context and Working Memory Engine. It answers: What are the project conventions? Who calls this symbol? What was the outcome of the last refactor?kruschis an Execution and Staging Harness. It answers: Where do staged diffs live? Did ground-truth tests pass? Is working-tree drift detected before atomic fsync?
They interface through a strictly decoupled, asynchronous contract:
Compounds state, memory, and symbol graph in 1 turn.
Diffs SHA-256 hashed into Postgres. Disk untouched.
Ground-truth tests execute in an isolated staged tree.
Verified diffs fsynced to disk on human approval.
📈 11. Operational Baseline & Open Engineering Challenges
As an author-reported operational baseline, this architecture has run in continuous homelab and product development since July 2026:
- 12,398 episodic records migrated and verified without data loss.
- 149 steering nuggets actively guiding daily development across Cursor, Claude Code, and Antigravity.
- 756 interaction memory nodes maintaining multi-agent consensus.
- <4.8ms p95 local edge read latency on local SQLite Lakebase caches.
Open Engineering Challenges
A mature architecture paper must acknowledge what remains unsolved:
- Distributed Three-Way Branch Merges: When two developers work offline on separate git feature branches, reconciling contradictory architectural notes during a git merge currently requires human review.
- Vector Inversion Defense: Obfuscating or differentially privatizing embedding vectors before transmitting them to cloud databases remains an open research frontier.
- Local Cache Pruning: As project histories surpass 100,000 episodic events, SQLite edge caches require tiered LRU compaction to prevent local disk bloat.
🎯 12. The Bottom Line: Reference Architecture Takeaways
Stripping away product branding, the core architectural takeaways for engineering teams building coding-agent memory are clear:
- Keep reads local: Serve hot agent queries from an embedded local cache (SQLite) to maintain sub-5ms latency and preserve offline capability.
- Keep the system of record durable: Rely on proven relational databases (PostgreSQL 16) for multi-device sync, transaction safety, and structured lineage.
- Enforce strict sovereign perimeters: Never upload source code trees or unvetted diffs to external memory SaaS; sync only abstract lessons and steering invariants.
- Use two-stage retrieval for decay: Never execute dynamic recency math across full vector tables; use HNSW index scans to find the top-$K$ candidate pool before rescoring.
- Guarantee embedding parity: Enforce identical model versions, tokenizers, and normalization across offline and online embedders, or decouple offline writes entirely.