Skip to content

alejandroqh/memory39

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

32 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

▄▄▄▄  ▗▞▀▚▖▄▄▄▄   ▄▄▄   ▄▄▄ ▄   ▄ ▄▄▄▄ ▄▄▄▄ 
█ █ █ ▐▛▀▀▘█ █ █ █   █ █    █   █    █ █  █ 
█   █ ▝▚▄▄▖█   █ ▀▄▄▄▀ █     ▀▀▀█ ▀▀▀█ ▀▀▀█ 
                            ▄   █ ▄▄▄█ ▄▄▄█ 
                             ▀▀▀            

One binary. One local SQLite file. One memory, shared by every MCP client on your machine.

memory39 is a Rust CLI + MCP server backed by SQLite + FTS5. Every MCP-capable AI tool on your machine (Claude Code, Claude Desktop, Codex, OpenCode, OpenClaw) reads and writes the same ~/.memory39/memory39.db, so a fact learned in one client is instantly recallable from any other. No cloud, no daemon, no sync.

Results are ranked by temporal-priority scoring: 0.4 x relevance + 0.3 x importance + 0.3 x recency (30-day half-life), so recent important matches surface first.

Why memory39

  • Persistent across sessions: memories live in an on-disk SQLite file and survive restarts, CLI invocations, and MCP reconnects.
  • One knowledge base across every MCP client: Claude Code, Claude Desktop, Codex, OpenCode, and OpenClaw all point at the same ~/.memory39/memory39.db. A fact stored from Claude is instantly recallable from Codex; a person stored via the CLI shows up in every MCP client. No syncing, no duplication.
  • Local and private: no cloud, no account, no telemetry. Your memory is a single SQLite file on your machine that you can inspect, back up, or move by copying.
  • Single binary, zero daemon: CLI for scripting (memory39 recall ...), MCP server on demand (memory39 mcp). Nothing runs in the background between calls.
  • Portable DB path: point at a different database by exporting MEMORY39_DB=/path/to/other.db (supports ~/ expansion). Useful for project-scoped memory or isolated benchmarks.
  • Cross-type discovery: the connect command links concepts across events, things, persons, and places in a single query, so relationships surface even when facts are stored as different memory types.

Performance

memory39 uses a bloom filter as a pre-check layer before FTS5 queries. On every recall, the bloom filter tests whether the query tokens exist anywhere in the database - if they definitely don't, the FTS5 query is skipped entirely, returning zero results in O(1) with no disk I/O.

Layer When it runs Cost
Bloom filter Every recall query ~nanoseconds, in-memory
FTS5 search Only if bloom says "maybe" Full-text index scan

How it works:

  • Unigrams + bigrams - every memory field is tokenized into individual words and adjacent-word pairs, all stored in the bloom filter. A query for "alice berlin" checks both tokens and the alice+berlin bigram.
  • Unicode-normalized - tokens are lowercased with diacritics removed (matching FTS5's unicode61 remove_diacritics 2), so café and cafe hit the same entry.
  • Prefix-safe - long tokens (>6 chars) that FTS5 would prefix-expand are never skipped, avoiding false negatives.
  • Persisted - the bloom filter is saved to <db>.bloom alongside the database and loaded on startup. Rebuilt automatically after bulk writes.
  • Zero false negatives - if a token exists in any memory, the bloom filter always says "maybe". It can only produce false positives (saying "maybe" when nothing matches), which just fall through to FTS5 as usual.

Configured for 600K items at 0.001% false positive rate.

Measured cost

Numbers from a personal DB (~300 memories, 144 KB SQLite file):

Query Path Avg per call Throughput
Unknown fact Bloom says "no match possible"; no disk I/O ~120 ns ~8.5M ops/sec
Known fact Bloom says "maybe" -> FTS5 search runs ~245 us ~4K ops/sec

Negative queries are ~2000x faster than positive ones. "Nanoseconds, in-memory" is literal: a bloom check is a handful of hash probes into a bitmap sitting in L1/L2 cache.

Install

cargo install memory39

Install for any AI CLI / IDE

Installs the binary and auto-configures it for every MCP client detected: Claude Code, Claude Desktop, Codex, OpenCode, OpenClaw.

curl -fsSL https://raw.githubusercontent.com/alejandroqh/marketplace/main/h39.sh | sh

Single binary: CLI by default, MCP server with memory39 mcp.

Memory Types

Prefix Type What it stores
E# Event (dated) Something that happened/will happen, with date+time
U# Event (undated) Same, without a specific date
T# Thing Object, concept, or fact
P# Person Social memory about someone
L# Place Spatial memory about a location

Every memory has importance (0-10), emotion, and tags. The prefix + rowid (e.g. E3, T12) is the universal ID used by forget and alter.


CLI

Global Flags

Flag Default Description
--db <path> memory39.db SQLite database file
--ram off In-memory database (non-persistent)

Commands

event - Store an event

memory39 event "Had coffee with Alice" --date 2025-03-15 --people Alice --tags coffee,social
Arg/Flag Required Description
<event> yes What happened (max 255 chars)
--date no YYYY-MM-DD - omit for undated
--time no HH:MM (default 00:00)
--note no Additional note
--tags no Comma-separated tags
--importance no 0-10 (default 5)
--emotion no positive, negative, neutral, or free text
--location no Where it happened
--people no Comma-separated names
--source no experienced, told, read, observed

thing - Store a fact or concept

memory39 thing "Rust edition 2024 requires rustc 1.85+" --category programming --confidence 9
Arg/Flag Required Description
<thing> yes What to remember (max 255 chars)
--desc no Description
--category no Free-text category
--tags no Comma-separated tags
--importance no 0-10 (default 5)
--emotion no Emotional valence
--source no Where this knowledge came from
--confidence no Certainty 0-10 (default 5)
--related no Comma-separated related concepts

person - Store a social memory

memory39 person "Alice" --role "ML engineer" --relationship colleague --met-at "KubeCon 2024"
Arg/Flag Required Description
<name> yes Person's name
--role no Role or title
--relationship no friend, colleague, family, etc.
--contact no Email, phone, handle
--met-at no Where/when you met
--last-seen no Last interaction YYYY-MM-DD
--note no Additional note
--tags no Comma-separated tags
--importance no 0-10 (default 5)
--emotion no Emotional valence

place - Store a spatial memory

memory39 place "Blue Bottle Coffee" --address "123 Main St, SF" --kind building --tags coffee,work
Arg/Flag Required Description
<name> yes Place name
--desc no Description
--address no Address or coordinates
--kind no city, building, room, outdoor, virtual, etc.
--note no Additional note
--tags no Comma-separated tags
--importance no 0-10 (default 5)
--emotion no Emotional valence

recall - Search memories

memory39 recall "coffee" --limit 5 --min 3 --kind event
memory39 recall "*"  # list all
Arg/Flag Required Description
<query> yes FTS5 search query (* = all)
-l, --limit no Max results (default 10)
--min no Minimum importance 0-10
--from no Date start YYYY-MM-DD (events only)
--to no Date end YYYY-MM-DD (events only)
--kind no event, undated, events, thing, person, place
--source no experienced, told, read, observed
--offset no Skip first N results (default 0)

connect - Find connections between concepts

memory39 connect Alice Berlin meeting
Arg/Flag Required Description
<concepts...> yes 2-3 concepts to connect
--min no Minimum importance 0-10
--timeout no Timeout in ms (default 2000)

Three-phase discovery: (1) direct - all concepts in one memory, (2) shared - concepts in separate memories linked by a common field, (3) bridge - one-hop connections through shared field values.

forget - Delete a memory

memory39 forget E3

alter - Modify a memory

memory39 alter T2 --text "Updated fact" --importance 8
Flag Description
--text New primary text
--note New note
--tags New tags
--importance New importance 0-10
--emotion New emotion
--location New location (events only)
--people New people (events only)
--source New source
--date New date (dated events only)
--time New time (requires --date)

MCP Server

memory39 mcp starts the MCP server (STDIO transport). It runs purely against the local SQLite database: no network calls, no API keys, no external services.

Database path: ~/.memory39/memory39.db (auto-created). This path is shared across every MCP client on the machine, so configuring memory39 in Claude Code, Claude Desktop, Codex, OpenCode, and OpenClaw gives all of them the same memory. Override with MEMORY39_DB=/path/to/other.db for project-scoped or isolated databases.

Configuration

Add to your MCP client config:

{
  "mcpServers": {
    "memory39": {
      "command": "memory39",
      "args": ["mcp"]
    }
  }
}

Tools

Tool Description Required Params
recall Search with temporal-priority scoring query
event Store an event (dated or undated) event
thing Store a fact, concept, or object thing
person Store a social memory name
place Store a spatial memory name
forget Delete a memory by ID id
alter Modify fields of an existing memory id
connect Find connections between 2-3 concepts concepts

All optional parameters match their CLI counterparts. See the tool schemas for full details.

Scoring

Results from recall are ranked by composite score:

Component Weight Description
Relevance 0.4 FTS5 match quality
Importance 0.3 Memory importance (0-10)
Recency 0.3 Exponential decay, 30-day half-life

Memory IDs

All tools use the same universal ID system:

Prefix Table
E Dated events
U Undated events
T Things
P Persons
L Places

Environment

memory39 has no external dependencies at runtime: no network, no API keys, no .env file. The only environment variable it reads is an optional DB-path override.

Variable Used by Purpose
MEMORY39_DB MCP server Override DB path (supports leading ~/). Default: ~/.memory39/memory39.db. For the CLI, use the --db flag instead.

Built With

License

Apache-2.0

About

Temporal-priority memory system for AI agents

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors