Building Snow: Persistent Memory for AI Agents

March 13, 2026

One of the most frustrating aspects of working with AI coding assistants is their inability to remember anything between sessions. Every time you start a new conversation, you're back to square one—explaining your project's conventions, reiterating preferences, and teaching the same context over and over.

Last week I built Snow, a Model Context Protocol (MCP) server that gives AI agents persistent, contextual memory. It bridges stateless AI reasoning with local filesystem persistence, allowing your AI agent to store and recall architectural preferences, project-specific snippets, and frequent instructions in a local SQLite database.

The Problem: Stateless by Design

LLMs are fundamentally stateless. Each session starts fresh, with no memory of previous conversations or decisions. This creates several friction points in development workflows:

  • Repetitive context setting: Every session begins with explaining your project's conventions and preferences
  • Lost decisions: Architectural choices made in previous sessions need to be re-communicated
  • Inconsistent behavior: The same agent can make different decisions across sessions
  • Wasted tokens: Significant context window space devoted to re-establishing known information

While some tools like OpenCode's AGENTS.md files help by providing persistent context, they're limited to a single directory and require manual maintenance. I wanted something more automatic and pervasive.

The Solution: Snow as a Long-Term Memory Layer

Snow creates a long-term memory (LTM) layer for AI agents. It uses a local SQLite database to store memories that persist across sessions, projects, and even different AI tools. The key insight is that this memory should be contextual and scoped:

  • Global preferences: Apply everywhere, like coding style or preferred libraries
  • Project-specific context: Only relevant when working in a specific project directory

Architecture: Clean Layers, Clear Responsibilities

I designed Snow with a clean three-layer architecture that separates concerns and makes the system easy to understand and extend:

Client (AI Agent) | v +------------------+ | MCP Transport | (STDIO via FastMCP) +------------------+ | v +------------------+ | MemoryService | (Validation, Business Logic) +------------------+ | v +------------------+ | Database | (SQLite + FTS5 + WAL) +------------------+ | v ~/.local/share/snow/snow.db

The MCP Transport layer handles communication with AI clients through the Model Context Protocol. The MemoryService layer provides validation and business logic, ensuring data integrity before persistence. The Database layer manages SQLite operations with FTS5 for full-text search and WAL mode for concurrent access.

Entry Types: Structured Memory for Different Needs

Not all memories are created equal. Snow supports four distinct entry types, each with its own validated metadata schema:

  • Preference: Coding style, formatting rules, preferred patterns (scoped as global or project)
  • Instruction: Specific commands or guidelines (with file pattern matching)
  • Snippet: Reusable code blocks (tagged by language and purpose)
  • Context: Reference information (with optional expiration)

This typing ensures that memories are structured and queryable, not just free-form text. Each type has specific metadata fields that get validated on storage.

Five Core Tools for Memory Management

Snow exposes five MCP tools that cover the complete lifecycle of memory management:

store_memory

Stores a new memory with context key, entry type, content, and optional metadata. The context key determines scope: global for universal preferences or project:name for project-specific context.

{ "context_key": "project:myapp", "entry_type": "preference", "content": "Use 4-space indentation for Python files", "metadata": { "scope": "project", "priority": 10 } }

recall_memory

Retrieves all non-deleted memories for a specific context. This is how agents "remember" their previous context when starting a new session.

search_memories

Full-text search across all memories using SQLite's FTS5 for queries of 3+ characters, with fallback to LIKE for shorter queries. Can optionally filter by context key.

update_memory

Updates an existing memory's content or metadata. Metadata is re-validated against the entry type's schema to ensure consistency.

delete_memory

Removes memories with soft delete by default (for recovery), or permanent deletion when explicitly requested.

Implementation Details: What Made This Work

FastMCP for Clean Protocol Handling

I used FastMCP, a Python framework for building MCP servers. It handles the STDIO transport layer and provides clean decorators for defining tools. The lifespan context manager pattern makes database connection management straightforward:

@asynccontextmanager async def lifespan(app: FastMCP): db = await Database.connect() service = MemoryService(db) yield AppContext(db=db, service=service) await db.close()

SQLite with FTS5 and WAL Mode

The database layer uses SQLite with two critical features:

  • FTS5 (Full-Text Search): Enables efficient content search across all memories with automatic indexing
  • WAL (Write-Ahead Logging): Allows concurrent reads and writes, essential when multiple agent sessions might access the database simultaneously

The FTS5 integration uses triggers to keep the search index in sync with the main memories table, ensuring search results are always current.

Typed Metadata with Pydantic

Each entry type has its own metadata schema defined with Pydantic models. This ensures that preferences have scope and priority fields, instructions have file pattern matching, and snippets have language tags. The validation happens in the service layer before any data reaches the database.

XDG Compliance: Following Linux Conventions

Snow stores its database at ~/.local/share/snow/snow.db, following the XDG Base Directory Specification. This keeps user data in the expected location and makes the tool feel like a native part of the Linux ecosystem. The path is configurable through environment variables for non-standard setups.

Integration with AI Tools

Because Snow implements the MCP protocol, it works with any MCP-compatible AI tool. I've tested it with OpenCode, Claude Code, and Cursor. The configuration is straightforward—just point the tool at the Snow server:

{ "mcp": { "snow": { "type": "local", "command": ["uv", "run", "--directory", "/path/to/snow-mcp-server", "python", "-m", "snow.server"], "enabled": true } } }

The uv run command handles dependency management, making installation simple without requiring manual virtual environment setup.

What I Learned Building This

Building Snow taught me several things about AI tooling:

  • Persistence matters more than intelligence: Sometimes the best improvement isn't a smarter model, but better context retention
  • Scope is critical: Global preferences and project-specific context need different handling
  • Validation prevents corruption: Typed metadata schemas catch errors early and keep the database clean
  • Search needs multiple strategies: FTS5 is great for long queries, but LIKE fallback handles short searches better

Future Improvements

There are several directions I'm considering for Snow's future:

  • Memory expiration: Automatic cleanup of stale context entries based on the expires_at metadata field
  • Memory importance scoring: Ranking memories by relevance and usage frequency
  • Export/import: Tools for backing up and transferring memories between machines
  • Memory merging: Detecting and resolving conflicting preferences across projects

Getting Started

Snow is available on GitHub. To get started:

  • Clone the repository
  • Run make install to install dependencies
  • Add the configuration to your AI tool's MCP settings
  • Start storing memories that persist across sessions

Snow is my attempt to solve the statelessness problem that plagues AI-assisted development. It's a simple concept—give agents a place to remember things—but the impact on workflow efficiency has been significant. I'd love to hear how it works for you. Reach out at matt@emmons.club.

© 2026 Matt Emmons