Recipe: Conversation Memory
This recipe shows two approaches to giving your assistant memory across conversations: explicit recall via a tool, and automatic context via hooks. These serve different purposes and have different tradeoffs.
Approach 1: Memory as a Tool
In this approach, everything is recorded automatically, but the assistant must explicitly search for relevant memories. This keeps the prompt lean and preserves cache efficiency.
The Recording Hook
Add this hook to save every message:
hooks:
- on: [user_message, assistant_message]
do: |
#!/bin/bash
set -euo pipefail
DB="${LECTIC_DATA}/memory.sqlite3"
# Initialize database if needed
sqlite3 "$DB" <<'SQL'
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY,
timestamp TEXT NOT NULL,
role TEXT NOT NULL,
interlocutor TEXT,
file TEXT,
content TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_timestamp ON messages(timestamp);
SQL
# Determine role and content
if [[ -n "${ASSISTANT_MESSAGE:-}" ]]; then
ROLE="assistant"
CONTENT="$ASSISTANT_MESSAGE"
NAME="${LECTIC_INTERLOCUTOR:-}"
else
ROLE="user"
CONTENT="${USER_MESSAGE:-}"
NAME=""
fi
# Escape single quotes for SQL
CONTENT_ESC="${CONTENT//\'/\'\'}"
NAME_ESC="${NAME//\'/\'\'}"
FILE_ESC="${LECTIC_FILE//\'/\'\'}"
sqlite3 "$DB" <<SQL
INSERT INTO messages (timestamp, role, interlocutor, file, content)
VALUES (datetime('now'), '$ROLE', '$NAME_ESC', '$FILE_ESC', '$CONTENT_ESC');
SQLThe Search Tool
Give the assistant a tool to search memory:
tools:
- name: search_memory
usage: |
Search past conversation history. Use this when the user
references something from a previous conversation or when
context from past discussions would be helpful.
exec: |
#!/bin/bash
sqlite3 "${LECTIC_DATA}/memory.sqlite3" <<SQL
SELECT printf('[%s] %s: %s', timestamp, role, content)
FROM messages
WHERE content LIKE '%${QUERY}%'
ORDER BY timestamp DESC
LIMIT 10;
SQL
schema:
QUERY: The search term to look for in past messages.When to Use This
- Long-running assistants where most turns don’t need memory
- When you want the assistant to decide what’s relevant
- When cache efficiency matters (the prompt stays constant)
Approach 2: Automatic Context Injection
In this approach, relevant memories are automatically injected into every prompt. Nothing is recorded automatically — instead, the assistant has a tool to explicitly remember things.
The Remember Tool
tools:
- name: remember
usage: |
Store important information for future reference. Use this when
the user shares preferences, makes decisions, or provides context
that should persist across conversations.
exec: |
#!/bin/bash
set -euo pipefail
DB="${LECTIC_DATA}/memory.sqlite3"
sqlite3 "$DB" <<'SQL'
CREATE TABLE IF NOT EXISTS memories (
id INTEGER PRIMARY KEY,
timestamp TEXT NOT NULL,
content TEXT NOT NULL
);
SQL
CONTENT_ESC="${CONTENT//\'/\'\'}"
sqlite3 "$DB" <<SQL
INSERT INTO memories (timestamp, content)
VALUES (datetime('now'), '$CONTENT_ESC');
SQL
echo "Remembered."
schema:
CONTENT: The information to remember.The Prompt with Memory
Use an exec: prompt to inject stored memories:
interlocutor:
name: Assistant
prompt: |
exec:#!/bin/bash
cat <<'PROMPT'
You are a helpful assistant with access to stored memories.
Things you've been asked to remember:
PROMPT
DB="${LECTIC_DATA}/memory.sqlite3"
if [[ -f "$DB" ]]; then
sqlite3 "$DB" <<'SQL'
SELECT printf('- %s', content)
FROM memories
ORDER BY timestamp DESC
LIMIT 20;
SQL
else
echo "(No memories yet)"
fi
echo ""
echo "Use the remember tool to store new information."When to Use This
- When you want explicit control over what’s remembered
- For preferences and decisions rather than conversation history
- When memories are small and frequently relevant
Tips
Don’t mix these approaches carelessly. Recording everything and injecting it into the prompt will bloat your context and hurt cache performance.
Be selective about what you store. Tool call results and verbose outputs can bloat the database quickly.
Consider privacy. Memory persists across sessions. Don’t store sensitive information you wouldn’t want retrieved later.
Monitor database size. Add a periodic cleanup job or a
forgettool for manual pruning.
A Simple Forget Tool
tools:
- name: forget
usage: Remove a specific memory by its content.
exec: |
#!/bin/bash
sqlite3 "${LECTIC_DATA}/memory.sqlite3" <<SQL
DELETE FROM memories WHERE content LIKE '%${PATTERN}%';
SELECT 'Deleted ' || changes() || ' memories';
SQL
schema:
PATTERN: Pattern to match memories to delete.