@cartisien/engram
v0.2.0
Published
Persistent memory for AI assistants. SQLite-backed conversational memory with semantic search.
Maintainers
Readme
Engram
Persistent memory for AI assistants with temporal recall.
import { Engram } from '@cartisien/engram';
const memory = new Engram({ dbPath: './memory.db' });
// Store
await memory.remember('user_123', 'I ride a Triumph Bonneville', 'user');
// Recall with temporal queries
const yesterday = await memory.recallByTime('user_123', 'yesterday');
const lastWeek = await memory.recallByTime('user_123', 'last week');The Problem
AI assistants are amnesiacs. Every conversation starts fresh. Context windows fill up. Important details get lost.
You wouldn't hire an employee who forgot every meeting. Why accept it from your AI?
The Solution
Engram gives your assistants persistent, queryable memory — backed by SQLite, designed for simplicity.
- Zero config: Works out of the box
- Fast: SQLite with proper indexes
- Temporal: Natural language time queries ("yesterday", "last week", "3 days ago")
- Portable: Single file database
- Typed: Full TypeScript support
Installation
npm install @cartisien/engramQuick Start
import { Engram } from '@cartisien/engram';
const memory = new Engram({
dbPath: './bot-memory.db' // or ':memory:' for ephemeral
});
// In your chat handler
async function handleChat(sessionId: string, message: string) {
// 1. Store the user's message
await memory.remember(sessionId, message, 'user');
// 2. Retrieve relevant context
const context = await memory.recall(sessionId, message, 5);
// 3. Build prompt with memory
const prompt = buildPrompt(context, message);
// 4. Get AI response
const response = await openai.chat.completions.create({ messages: prompt });
// 5. Store the response
await memory.remember(sessionId, response.choices[0].message.content, 'assistant');
return response;
}Temporal Recall
Engram understands natural language time expressions. Ask for memories from any point in time:
// Simple temporal queries
const yesterday = await memory.recallByTime('session_123', 'yesterday');
const lastWeek = await memory.recallByTime('session_123', 'last week');
const threeDaysAgo = await memory.recallByTime('session_123', '3 days ago');
// Combined with keyword search
const meetingsLastWeek = await memory.recallByTime(
'session_123',
'last week',
'meeting' // Only entries containing "meeting"
);
// Recent memories (last 7 days)
const recent = await memory.recallRecent('session_123', 7);
// Since a specific date
const sinceLaunch = await memory.recallSince('session_123', new Date('2024-01-01'));
// Daily summaries
const lastWeekByDay = await memory.dailySummary('session_123', 7);
// Returns: [{ date, entries: [...], count }, ...]Supported Temporal Expressions
| Expression | Meaning |
|------------|---------|
| today | From midnight to now |
| yesterday | Full previous day |
| tomorrow | Next day (useful for scheduled items) |
| 3 days ago | Specific day 3 days back |
| a week ago | 7 days ago |
| 2 weeks ago | 14 days ago |
| last monday | Most recent Monday |
| last week | Previous full week (Sun-Sat) |
| last month | Previous full month |
| this week | Current week (Sun-today) |
| this month | Current month |
| last 3 days | Last 72 hours |
| last 7 days | Last week (rolling) |
| january 15 | Specific date |
| 3/15 | March 15 (current year) |
| jan 15 to jan 20 | Date range |
| recent, lately | Last 7 days |
API
new Engram(config?)
Create a memory instance.
const memory = new Engram({
dbPath: './memory.db', // Database file path
maxContextLength: 4000 // Max characters per entry
});remember(sessionId, content, role?, metadata?)
Store a memory entry.
await memory.remember('session_abc', 'User loves Thai food', 'user', {
source: 'preference_extraction'
});recall(sessionId, query?, limit?, options?)
Retrieve memories for a session. Supports temporal filtering via options.temporalQuery.
// Recent memories
const recent = await memory.recall('session_abc', undefined, 10);
// Keyword search
const relevant = await memory.recall('session_abc', 'food preferences', 5);
// Temporal + keyword
const yesterdayMeetings = await memory.recall(
'session_abc',
'meeting',
10,
{ temporalQuery: 'yesterday' }
);
// Filtered by role
const userOnly = await memory.recall('session_abc', undefined, 10, { role: 'user' });recallByTime(sessionId, temporalQuery, keyword?, limit?, options?)
Recall memories by natural language time expression.
const { entries, range } = await memory.recallByTime(
'session_abc',
'last week',
'project update' // optional keyword filter
);
console.log(`Found ${entries.length} entries from ${range.description}`);
console.log(`Range: ${range.start.toDateString()} to ${range.end.toDateString()}`);recallRecent(sessionId, days?, keyword?, limit?, options?)
Get memories from the last N days.
const { entries, days, since } = await memory.recallRecent('session_abc', 7);
console.log(`${entries.length} entries in the last ${days} days`);recallSince(sessionId, since, keyword?, limit?, options?)
Get memories since a specific date.
const { entries, count } = await memory.recallSince(
'session_abc',
new Date('2024-01-01')
);recallBetween(sessionId, start, end, keyword?, limit?, options?)
Get memories between two dates.
const { entries, count } = await memory.recallBetween(
'session_abc',
new Date('2024-01-01'),
new Date('2024-01-31')
);dailySummary(sessionId, days?)
Get memories grouped by day.
const summary = await memory.dailySummary('session_abc', 7);
// [
// { date: Date, entries: MemoryEntry[], count: 5 },
// { date: Date, entries: MemoryEntry[], count: 3 },
// ...
// ]history(sessionId, limit?)
Get chronological conversation history.
const chat = await memory.history('session_abc', 20);forget(sessionId, options?)
Delete memories.
// Delete all for session
await memory.forget('session_abc');
// Delete specific entry
await memory.forget('session_abc', { id: 'entry_id' });
// Delete before a date
await memory.forget('session_abc', { before: new Date('2024-01-01') });
// Delete in a date range
await memory.forget('session_abc', {
after: new Date('2024-01-01'),
before: new Date('2024-02-01')
});stats(sessionId)
Get memory statistics.
const stats = await memory.stats('session_abc');
// { total: 42, byRole: { user: 21, assistant: 21 }, oldest: Date, newest: Date }temporalStats(sessionId, days?)
Get activity statistics grouped by day.
const activity = await memory.temporalStats('session_abc', 30);
// [
// { date: '2024-01-15', count: 5, byRole: { user: 3, assistant: 2 } },
// ...
// ]The TemporalQuery Parser
You can use the temporal parser standalone:
import { TemporalQuery } from '@cartisien/engram';
const parser = new TemporalQuery();
const range = parser.parse('last week');
if (range) {
console.log(range.description); // "last week"
console.log(range.start); // Sun, Jan 07 2024 00:00:00
console.log(range.end); // Sat, Jan 13 2024 23:59:59
}Philosophy
"The trace precedes presence." — Derrida
Memory isn't storage. It's the substrate of self.
Engram doesn't just persist data. It gives your assistants continuity — the ability to learn, reference, and grow across conversations. Time is not a sequence of moments to be archived, but a horizon of meaning that shifts with each recollection.
The Cartesian cogito assumed memory was given. We're making it so.
The Trilogy
Engram is part of the Cartisien Memory Suite:
| Package | Purpose |
|---------|---------|
| @cartisien/engram | This package — persistent memory with temporal recall |
| @cartisien/extensa | Vector infrastructure (coming soon) |
| @cartisien/cogito | Identity & state management (coming soon) |
Res cogitans meets res extensa.
License
MIT © Cartisien Interactive
Built with 🖤 by people who think forgetting is a bug.
