Projects

Strata: A Tiered Memory System for AI Agents

Creator & Lead Developer

2026-06-18

PythonSQLite FTS5MarkdownCLIMCP

GitHub · Blog Post


Context

I built Strata because I was sick of my AI coding agents waking up with amnesia every morning. Every new session felt like day one. The agent completely forgot the architecture choices we made the night before, the bugs we spent hours tracking down, and the general flow of the codebase. It was an incredibly frustrating loop.

Because I was building this entirely for myself, I acted as the user, the developer, and the product manager all at once.


Problem / Product Goal

The core issue is that AI agents lack persistent, low-cost memory.

Most existing tools try to solve this by throwing expensive engineering at the problem, but they usually fall into a few predictable traps:

  • Massive context windows: Shoving everything into the prompt destroys the agent's reasoning ability and burns through tokens.
  • Vector databases: Converting everything into embeddings relies too heavily on similarity search. It can find specific facts, but it completely misses the broader nuance.
  • Heavy LLM orchestration (mem0, LangMem): Running an LLM to constantly watch, clean, and organize memories gets incredibly expensive. A simple query shouldn't trigger a massive background cleanup loop.

I needed a system that could pull up a design decision from two weeks ago without paying GPT-4o to read a text file just to see if it mattered. My goal was to build a memory architecture that costs nothing during normal operation, saving the expensive AI logic for when you actually need it.


Thought Process

I started by mapping out a two-part setup in a blog post. It featured a tiered storage system paired with a relational database running Postgres and pgvector. In that version, Stratum 1 held active files, Stratum 2 handled vector searches inside Postgres, and Stratum 3 was a compressed archive.

I spent three days writing the core storage layers, the CLI, and an MCP server. But after 11 commits, I realized I was building the wrong thing.

The Postgres setup forced a lot of unnecessary baggage into the project:

  • Users had to install and run a full Postgres instance.
  • Every single file movement incurred embedding costs.
  • Simple lookups required complex vector queries.
  • I was managing database schemas for an unproven feature.

I paused for a couple of days to rethink the architecture. When you look closely at what a background janitor actually does, the tasks are remarkably basic. It checks a timestamp, compares it to a threshold, and moves a file. I was using an LLM for simple lifecycle logic where regular code worked perfectly fine.

So, I ripped out Postgres. Stratum 2 became a regular directory on the local filesystem. Instead of asking an LLM if a file was stale, I set a rule: if it hasn't been touched in 90 days, move it. I cut the entire embedding process out of the application.

Suddenly, the janitor went from parsing complex API responses to executing basic file copies. The test suite ran instantly. Installation turned into a quick package install and an init command (no Docker required).

To make this architecture work, I built the Shadow Index using SQLite FTS5. Other memory tools either hoard data forever or delete it entirely. The Shadow Index takes a different approach by saving only keywords, a brief preview, and the file path. You can store a million entries in less than a megabyte. If a search hits an archived file, the system automatically pulls it back into the active directory.


Solution

Strata manages agent memory across three filesystem tiers using an algorithmic janitor.

strata — zsh
The strata search command showing ranked results from the active, cooled, and archive tiers
One search spans all three tiers — active results rank highest, and an archived hit triggers automatic rehydration back into the active directory.

Tier 1: Active

This tier holds raw markdown files inside an active/ directory. The agent interacts with these files directly. A script automatically generates an index.md file using the first heading of each document, bypassing the need for a database. It runs with sub-millisecond latency and costs nothing.

Tier 2: Cooled

When files hit specific age limits (like 14 days for active projects or 7 days for tasks), they move here. They stay as plain markdown but shift to a read-only search directory. If an agent hits a cooled file three times, the system promotes it back to the active tier.

Tier 3: Archive

Files untouched for 90 days drop into the archive as JSON. The SQLite FTS5 Shadow Index keeps these files searchable by keyword without using vectors. A successful search automatically rehydrates the archived file back to the active tier.

The Janitor

A lightweight background process handles all data migration (moving, evicting, promoting, and rehydrating) based strictly on file age and access frequency. It requires zero LLM calls. The process runs every 15 minutes, always starting with a safe dry-run cycle.

Agent Integration

An extension hook automatically saves chat transcripts from the coding agent. A background script can run a cheap model (like GPT-4o-mini) to pull out key facts for pennies. The system includes an MCP server to expose these tools over JSON-RPC, alongside an installation script that configures the setup for various agent platforms.


Takeaways

Keep the automation simple. Letting go of the idea that the lifecycle manager needed to be smart changed everything. Replacing LLM calls with basic filesystem operations made the tool faster, cheaper, and vastly more dependable.

The Shadow Index solved the retention problem. I originally built the index just to check a box, but it became the core feature that sets the project apart. It avoids the endless growth of vector databases while preventing permanent data loss.

Path matching requires precision. Setting different expiration rates for different directories (like conversations versus core entities) gets tricky quickly. Handling edge cases for deeply nested paths took me three tries to get right. Loop-based prefix matching turned out to be the cleanest approach.

Optimize for simple writes. The system appends facts without checking for duplicates, meaning multiple versions of the same information can live side by side. The agent resolves any conflicts by checking the timestamps when it reads the data. This keeps the write path incredibly fast and avoids complex version-tracking logic.

Data decay is useful. I started this project trying to save every single detail. Eventually, I realized that letting old information fade into the background is exactly what makes a memory system work.