npm install latticesql

Persistent memory
for AI agents.

Lattice keeps a SQLite database and a set of context files in sync — so every agent session starts with accurate state, and agent output becomes permanent data.

What it does

01

Always-fresh context

Your agents never read stale data. Lattice renders database rows into text files and re-renders whenever data changes. One call to db.watch() keeps everything current.

02

Scoped context per entity

Each agent loads only the files relevant to its entity — not a giant dump of everything. One directory per entity, one file per relationship, with automatic cleanup when entities are deleted.

03

Agent output becomes data

Agents don't just read context — they write back. Lattice watches output files, parses structured entries, and persists them to the database with deduplication and offset tracking.

04

Zero-boilerplate setup

Declare your schema in YAML, run lattice generate, and get TypeScript types and SQL migrations. No manual table creation, no boilerplate.

The sync loop

LLM context windows are ephemeral. Your application state lives in a database. Every agent session starts cold unless something bridges them. Lattice is that bridge. If you've ever had an agent repeat work, contradict itself, or forget what happened in a previous session — that's the problem Lattice solves.

text
Your DB (SQLite)
     │  Lattice reads rows → render → text
     ▼
Context files (Markdown, JSON, etc.)
     │  LLM agents read these at session start
     ▼
Agent output files
     │  Lattice writeback parses these
     ▼
Your DB (rows inserted/updated)

Lattice reads your database for rendering, and provides a full CRUD API plus a writeback pipeline for persisting agent output back to the DB.

typescript
import { Lattice } from 'latticesql';

const db = new Lattice('./state.db');

db.define('agents', {
  columns: {
    id: 'TEXT PRIMARY KEY',
    name: 'TEXT NOT NULL',
    persona: 'TEXT',
    active: 'INTEGER DEFAULT 1',
  },
  render(rows) {
    return rows
      .filter((r) => r.active)
      .map((r) => `## ${r.name}\n\n${r.persona ?? ''}`)
      .join('\n\n---\n\n');
  },
  outputFile: 'AGENTS.md',
});

await db.init();
await db.insert('agents', { name: 'Alpha', persona: 'Research assistant.' });

// Render DB → context files
await db.render('./context');
// Writes: context/AGENTS.md

// Watch for changes, re-render every 5 seconds
const stop = await db.watch('./context', { interval: 5000 });

Entity context directories

One directory per entity. One file per relationship. Agents load exactly what they need — no giant context dumps.

typescript
db.defineEntityContext('agents', {
  slug: (row) => row.slug as string,

  index: {
    outputFile: 'agents/AGENTS.md',
    render: (rows) => rows.map((r) => `- ${r.name}`).join('\n'),
  },

  files: {
    'AGENT.md': {
      source: { type: 'self' },
      render: ([r]) => `# ${r.name}\n\n${r.bio ?? ''}`,
    },
    'TASKS.md': {
      source: { type: 'hasMany', table: 'tasks', foreignKey: 'agent_id' },
      render: (rows) => rows.map((r) => `- ${r.title}`).join('\n'),
      omitIfEmpty: true,
    },
  },

  combined: { outputFile: 'CONTEXT.md', exclude: [] },
  protectedFiles: ['SESSION.md'],
});

// Produces per-agent directories:
// context/agents/alpha/AGENT.md
// context/agents/alpha/TASKS.md
// context/agents/alpha/CONTEXT.md
Generated tree
text
context/
├── agents/
│   └── AGENTS.md          ← global index
├── agents/alpha/
│   ├── AGENT.md
│   ├── TASKS.md           ← omitted when empty
│   └── CONTEXT.md         ← all files combined
└── agents/beta/
    ├── AGENT.md
    └── CONTEXT.md

Also included

  • Protected files agents write are never deleted during cleanup
  • Budget limits truncate large relationship files
  • reconcile() removes orphaned directories when entities are deleted
  • Manifest-driven — Lattice knows exactly what it wrote

CLI

lattice generate

Generate TypeScript types and SQL migration from YAML config

lattice render

One-shot render — write all context files from the database

lattice reconcile

Render + orphan cleanup — remove stale entity directories

lattice status

Dry-run reconcile — preview what would change

lattice watch

Poll the DB and re-render on every interval

Your schema. Your render logic. Your file format.

Lattice has no opinions about how your data is structured or how your context files look. Define your tables, write your render functions, and Lattice handles sync, cleanup, and persistence.