CLI memory system for AI agents. Built on SQLite with FTS5 full-text search.
- Multi-agent support — Each agent has isolated memory via
--user - Event tiers — Automatic hot/warm/cold classification based on age
- Full-text search — FTS5-powered search across events, entities, and lessons
- Session bootstrap — Single command returns all context needed to start a session
- Zero dependencies — Uses Bun's native SQLite, no npm packages required
Requires Bun v1.0+.
# Clone and use directly
git clone https://github.com/SilasReinagel/agentmem.git
cd agentmem
bun index.js session --user=myagent
# Or install globally
bun install -g agentmem
agentmem session --user=myagent# Start a session (compact text — token-efficient for agent bootstrap)
agentmem session --user=myagent
# Full JSON output (backward compatible, for scripts)
agentmem session --user=myagent --format=json
# Store an event
agentmem store --user=myagent --type=event '{"type":"work_session","title":"Built feature X","content":"Implemented the new dashboard..."}'
# Store a lesson learned
agentmem store --user=myagent --type=lesson '{"type":"observation","title":"Always test edge cases","content":"Found a bug because..."}'
# Search memories
agentmem search --user=myagent --query="dashboard"
# Get/set agent state
agentmem state --user=myagent "## Current Focus\nWorking on dashboard"
agentmem state --user=myagentGet everything needed to start a session in one call.
# Default: compact text (best for agent bootstrap)
agentmem session --user=myagent
# JSON: full structured output (for scripts or debugging)
agentmem session --user=myagent --format=jsonDefault output (compact) — scannable text sections:
=STATE (Jul06)=
## Current Focus
...
=EVENTS (12)=
Jul09 10:51 | work_session | Task: Built feature X
Jul09 10:37 | finding | Done in workspace 1...
=PRINCIPLES (4)=
- optimize-for-context-switches: Silas works in rapid context-switching mode...
=LESSONS (10)=
Jul06 | observation | PR 24883 builtin catalog...
JSON output (--format=json) returns the same data as structured objects with full metadata.
Session filtering (signal-only bootstrap):
- Hot events allowlist:
work_session,finding,decisiononly - Noisy types (
tool_result,tool_call, etc.) are excluded — userecallorsearchto find those - Events with identical (normalized) titles within 24 hours are deduplicated (keeps most recent)
- Manual/curated events preferred over memsyncd auto-ingest (
source_path/Task:titles) when capping - State older than 24h (or empty) shows
! STALE STATEin compact output; JSON includesstate.stale/state.age_hours
Returns:
- Current state (with stale flag)
- Hot events (last 72 hours, max 15 after filter/dedupe)
- All principles
- Most recent summary
- Recent unconsolidated lessons (max 10)
Get or set the agent's current state (scratchpad).
# Get state
agentmem state --user=myagent
# Set state
agentmem state --user=myagent "## Focus\nBuilding memory system"Store new memories. Supports: event, entity, lesson, principle, summary.
# Store event
agentmem store --user=myagent --type=event '{"type":"work_session","title":"Title","content":"Details..."}'
# Store entity (project, person, tool, etc.)
agentmem store --user=myagent --type=entity '{"type":"project","name":"myproject","content":"Description..."}'
# Store lesson
agentmem store --user=myagent --type=lesson '{"type":"feedback","title":"Lesson title","content":"What was learned..."}'
# Store principle (consolidated from lessons)
agentmem store --user=myagent --type=principle '{"name":"principle-name","content":"The principle...","source_lessons":["lesson-id-1"]}'
# Pipe from stdin
echo '{"type":"work_session","title":"Test","content":"..."}' | agentmem store --user=myagent --type=eventRecall memories with filters.
# Get hot events
agentmem recall --user=myagent --type=events --filters='{"tier":"hot"}'
# Get events by type
agentmem recall --user=myagent --type=events --filters='{"event_type":"decision"}'
# Get events since date
agentmem recall --user=myagent --type=events --filters='{"since":"2026-01-01T00:00:00Z"}'
# Get entities by type
agentmem recall --user=myagent --type=entities --filters='{"entity_type":"project"}'
# Get all principles
agentmem recall --user=myagent --type=principlesFull-text search across memories.
# Search all types
agentmem search --user=myagent --query="authentication"
# Search specific types
agentmem search --user=myagent --query="authentication" --types=events,lessons
# Limit results
agentmem search --user=myagent --query="authentication" --limit=5Export memories to markdown files.
# Export all
agentmem export --user=myagent --target=./backup
# Export specific types
agentmem export --user=myagent --target=./backup --types=events,lessons
# Export since date
agentmem export --user=myagent --target=./backup --since=2026-01-01T00:00:00ZTime-based memories with automatic tier classification:
- hot — Last 72 hours
- warm — 72 hours to 30 days
- cold — Older than 30 days
{
"type": "work_session|decision|discovery|error|...",
"title": "Short description",
"content": "Full details",
"metadata": { "tags": ["optional"] }
}Reference information about projects, people, tools, etc.
{
"type": "project|person|tool|concept|...",
"name": "unique-name",
"content": "Description and details"
}Learnings that can be consolidated into principles.
{
"type": "feedback|success|failure|observation",
"title": "What was learned",
"content": "Details and context",
"source_event_id": "optional-event-reference"
}Consolidated wisdom from multiple lessons.
{
"name": "principle-name",
"content": "The distilled principle",
"source_lessons": ["lesson-1", "lesson-2"]
}The CLI handles storage and retrieval. Semantic operations (summarization, consolidation) belong in the calling agent. Here are the patterns:
Compress a week's events into a narrative summary.
# 1. Recall events for the period
agentmem recall --user=myagent --type=events \
--filters='{"since":"2026-01-20T00:00:00Z","until":"2026-01-27T00:00:00Z"}' \
--limit=100
# 2. Agent synthesizes summary using LLM (your responsibility)
# Input: the events JSON
# Output: narrative summary + event count
# 3. Store the summary
agentmem store --user=myagent --type=summary '{
"type": "week",
"period": "2026-W04",
"content": "## Week 4 Summary\n\nFocused on authentication system...",
"event_count": 23
}'When patterns emerge across multiple lessons, consolidate into a principle.
# 1. Recall unconsolidated lessons
agentmem recall --user=myagent --type=lessons --limit=50
# Filter for consolidated_to: null in the results
# 2. Agent identifies patterns and synthesizes principle (your responsibility)
# Input: lessons with similar themes
# Output: distilled principle
# 3. Store the principle with source references
agentmem store --user=myagent --type=principle '{
"name": "infrastructure-over-discipline",
"content": "When a behavior must happen reliably, encode it in infrastructure (automation, constraints, defaults) rather than relying on human discipline. Discipline fails under stress; infrastructure persists.",
"source_lessons": ["2026-01-15-003", "2026-01-18-007", "2026-01-22-001"]
}'
# 4. Mark source lessons as consolidated (update each)
agentmem store --user=myagent --type=lesson '{
"id": "2026-01-15-003",
"type": "observation",
"title": "Original title",
"content": "Original content",
"consolidated_to": "myagent/infrastructure-over-discipline"
}'Recommended flow for an agent session:
# 1. Session start: get all context in one call (compact text by default)
agentmem session --user=myagent
# Returns: state, hot_events, principles, recent_summary, recent_lessons
# Use --format=json if a script needs structured output
# 2. During session: store events as they happen
agentmem store --user=myagent --type=event '{"type":"work_session",...}'
# 3. End of session: update state, store lessons learned
agentmem state --user=myagent "## Current Focus\nUpdated focus..."
agentmem store --user=myagent --type=lesson '{"type":"observation",...}'
# 4. Periodic maintenance (weekly): run summary consolidation
# See "Weekly Summary" pattern aboveEvent tiers update automatically when you call store. The thresholds:
- hot: < 72 hours old
- warm: 72 hours to 30 days
- cold: > 30 days
No manual intervention needed. Query by tier using:
agentmem recall --user=myagent --type=events --filters='{"tier":"hot"}'
agentmem recall --user=myagent --type=events --filters='{"tier":"warm"}' --limit=50| Environment Variable | Description | Default |
|---|---|---|
AGENTMEM_DB_PATH |
Custom database path | ~/.agentmem/memory.db |
AGENTMEM_HOST |
Sidecar bind address | 127.0.0.1 |
AGENTMEM_PORT |
Sidecar port | 8422 |
agentmem serve is an HTTP and MCP process in front of the same SQLite file. The CLI keeps working. The id you pass as --user is the project id on the API.
A key authorizes one or more projects. The request selects the project. * allows every project and still requires the caller to name one.
agentmem key create --label=cursor --projects=one-percent-club
agentmem serveThe create command prints the key once. Send it as Authorization: Bearer am_....
curl -s http://127.0.0.1:8422/health
curl -s -X POST http://127.0.0.1:8422/v1/projects/one-percent-club/store \
-H "Authorization: Bearer $AGENTMEM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"type":"event","data":{"type":"decision","title":"Use sqlite","content":"Shared with the CLI"}}'
curl -s -X POST http://127.0.0.1:8422/v1/projects/one-percent-club/search \
-H "Authorization: Bearer $AGENTMEM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"sqlite"}'| Method | Path | Body |
|---|---|---|
GET |
/health |
Open. No key. |
GET |
/v1/projects/:project/session?format=json |
format=compact returns text. Default is JSON. |
GET |
/v1/projects/:project/state |
|
PUT |
/v1/projects/:project/state |
{ "content": "..." } |
POST |
/v1/projects/:project/store |
{ "type": "event", "data": { ... } } |
POST |
/v1/projects/:project/recall |
{ "type": "events", "filters": {}, "limit": 20 } |
POST |
/v1/projects/:project/search |
{ "query": "...", "types": ["events"] } |
POST |
/mcp |
MCP streamable HTTP. Tools: session, get_state, set_state, store, recall, search. |
Claude and Cursor attach to http://127.0.0.1:8422/mcp with the bearer key. If the key allows one project, tools can omit project. Otherwise pass project or the X-Project header.
The process binds to localhost. On a Droplet, publish it through TLS. Do not put the raw port on the public internet.
docker build -t agentmem .
docker run -d --name agentmem \
-p 127.0.0.1:8422:8422 \
-v agentmem-data:/data \
agentmem
docker exec agentmem bun index.js key create --label=cursor --projects=one-percent-club# Run tests
bun test
# Run tests in watch mode
bun test --watch
# Run with coverage
bun test --coverage- Database: SQLite with WAL mode and FTS5 indexes
- Location:
~/.agentmem/memory.dbby default - Runtime: Bun (uses native
bun:sqlite)
MIT