Star 历史趋势
数据来源: GitHub API · 生成自 Stargazers.cn
README.md

True-Mem

A persistent memory plugin for OpenCode with cognitive psychology-based memory management.


Table of Contents


Overview

True-Mem is a memory plugin for OpenCode that enables AI coding agents to remember information across sessions and projects. It doesn't just store information - it manages memory like a human mind would.


The Problem

If you've ever had to repeat your preferences to your AI assistant every time you start a new session, you know the pain. "I prefer TypeScript over JavaScript", "Never use var", "Always run tests before committing" - things you've already said, but the AI forgot.


The Solution

True-Mem automatically extracts and stores memories from your conversations:

  • Preferences: "I prefer functional style over OOP"
  • Constraints: "Never use var keyword"
  • Decisions: "We decided to use SQLite instead of Postgres for this project"
  • Semantic info: "The API uses REST, not GraphQL"
  • Learning: "Learned that bun:sqlite is built-in"

Next time you open OpenCode, it remembers. No more repeating yourself.


The Psychology Behind It

What makes True-Mem different from a simple database? It's modeled after how human memory actually works:

Ebbinghaus Forgetting Curve - Episodic memories fade over time (7-day default), while preferences and decisions stay permanent. Just like your brain forgets what you had for lunch last Tuesday but remembers your favorite color.

7-Feature Scoring Model - Every memory is scored using Recency, Frequency, Importance, Utility, Novelty, Confidence, and Interference. This determines which memories surface when you need them.

Dual-Store Architecture (STM/LTM) - Short-term and long-term memory stores with automatic promotion. High-strength memories get promoted to LTM; weak ones stay in STM or decay.

Four-Layer Defense System - Prevents false positives with Question Detection (filters questions before classification), Negative Pattern filtering (including AI meta-talk detection), Multi-Keyword Scoring with sentence-level isolation, Confidence Thresholds, and Role Validation (only Human messages for user-level preferences).

Reconsolidation - When new information conflicts with existing memories, the system detects similarity and handles it intelligently (merge duplicates, keep both complements, or resolve conflicts).

Dual Similarity Modes - Jaccard (default, fast token matching) or ML embeddings (experimental, semantic understanding).


Key Features

FeatureDescription
Dual-Scope MemoryGlobal (follows you across projects) + Project-specific
Non-BlockingAsync extraction, no UI freezes or QUEUED states
MultilingualFull support for Italian, Spanish, French, German, and 11 more languages
Smart DecayOnly episodic memories fade; preferences and decisions stay forever
Zero Native DependenciesWorks on Bun and Node 22+ with built-in SQLite
MultilingualFull support for Italian, Spanish, French, German, and 11 more languages

Noise Filtering

What truly sets True-Mem apart is its ability to distinguish signal from noise. Unlike simpler memory plugins that store everything matching a keyword, True-Mem understands context and intent:

What gets filtered OUT:

Pattern TypeExampleWhy filtered
Questions"Do you remember this?"It's a question, not a statement
1st person recall"I remember when we fixed that"Recounting, not requesting storage
Remind-me recall"Remind me how we did this"Asking AI to recall info, not store
AI meta-talk"Goal: The user is trying to..."AI-generated, not user content
List selections"I prefer option 3"Context-specific choice, not general preference

What gets stored:

Pattern TypeExampleWhy stored
Imperatives"Remember this: always run tests"Explicit storage request
Preferences"I prefer TypeScript over JavaScript"General, reusable preference
Decisions"We decided to use SQLite"Project-level decision
Constraints"Never use var keyword"Permanent rule

All filtering patterns support 10 languages: English, Italian, Spanish, French, German, Portuguese, Dutch, Polish, Turkish, and Russian.


Installation

Add to your ~/.config/opencode/opencode.jsonc:

{
  "plugin": [
    "true-mem"
  ]
}

OpenCode will automatically download the plugin from npm.

A ~/.true-mem/ directory will be created to store the SQLite database and debug logs.

After restarting OpenCode, you'll see a toast notification confirming the plugin is loaded:

True-Mem vX.X.X
Memory active.

This confirms True-Mem is installed and working correctly.


Configuration

True-Mem creates a configuration file at ~/.true-mem/config.jsonc on first run. You can edit this file to customize behavior:

{
  // Storage location: "legacy" = ~/.true-mem/ (default), "opencode" = ~/.config/opencode/true-mem/
  "storageLocation": "legacy",

  // Injection mode: 0 = session start only (recommended), 1 = every prompt
  "injectionMode": 0,

  // Sub-agent mode: 0 = disabled, 1 = enabled (default)
  "subagentMode": 1,

  // Embeddings: 0 = Jaccard similarity only, 1 = hybrid (Jaccard + embeddings)
  "embeddingsEnabled": 0,

  // Maximum memories to inject per prompt (10-50 recommended)
  "maxMemories": 20
}

Settings Explained

SettingValuesDescription
SettingValuesDescription
------------------------------
storageLocation"legacy" or "opencode"Where to store data. "legacy" = ~/.true-mem/ (default). "opencode" = ~/.config/opencode/true-mem/
injectionMode0 or 10 = inject memories only at session start (saves tokens, default). 1 = inject on every prompt (legacy behavior)
subagentMode0 or 10 = disable memory injection for sub-agents. 1 = enable for sub-agents (default)
embeddingsEnabled0 or 10 = use Jaccard similarity only (fast, default). 1 = use hybrid semantic embeddings (experimental)
maxMemories10-50How many memories to include in each prompt (default: 20). Lower = fewer tokens, Higher = more context

Injection Mode Trade-off:

  • Mode 1 (ALWAYS) - Default. Real-time memory updates, at each prompt. New memories appear immediately. Best for most users.
  • Mode 0 (SESSION_START): Memories are injected once at session start (both /new and --continue). New memories extracted during the session won't appear until you restart OpenCode. Best for long sessions (20+ prompts) where token cost matters.

Environment Variables

You can also configure via environment variables (override config file):

VariableValuesDescription
TRUE_MEM_STORAGE_LOCATIONlegacy or opencodeOverride storageLocation setting
TRUE_MEM_INJECTION_MODE0 or 1Override injectionMode setting
TRUE_MEM_SUBAGENT_MODE0 or 1Override subagentMode setting
TRUE_MEM_EMBEDDINGS0 or 1Override embeddingsEnabled setting
TRUE_MEM_MAX_MEMORIES10-50Override maxMemories setting

Example:

export TRUE_MEM_STORAGE_LOCATION=opencode
export TRUE_MEM_INJECTION_MODE=1
export TRUE_MEM_MAX_MEMORIES=25
opencode

Changing Storage Location

When you change storageLocation (via config or env var), True-Mem automatically migrates your data:

  1. Automatic copy - If the new location has no data, the existing database is copied from the old location
  2. Non-destructive - Original data is preserved as backup (you can revert by switching back)
  3. Config + state - Along with the database, state.json and config.jsonc are also copied if they exist

After migration, you can safely delete the old location's folder to free up disk space:

  • Legacy: rm -rf ~/.true-mem/
  • OpenCode: rm -rf ~/.config/opencode/true-mem/

Note: If the source database has active WAL/SHM files (not cleanly closed), migration is skipped to avoid data inconsistency.


Usage

Automatic Extraction

Just have conversations with OpenCode. True-Mem extracts relevant info in the background.

What gets stored:

  • User preferences: "I prefer TypeScript over JavaScript"
  • Constraints: "Never use var keyword"
  • Decisions: "We decided to use SQLite instead of Postgres"
  • Semantic info: "The API uses REST, not GraphQL"
  • Learning: "I learned that bun:sqlite is built-in"

List Injected Memories

To see which memories are currently injected in your prompt, use one of:

list-memories
list-memory
show-memory

All three commands are equivalent and display all memories grouped by scope (Global/Project) and store (LTM/STM). Useful for debugging or understanding what the AI remembers about you.

Delete a Memory

To delete a specific memory from True-Mem, ask your AI assistant mentioning "true-mem" to avoid confusion with other memory plugins:

"Delete the true-mem memory about using bun"
"Remove from true-mem the memory that says 'always run tests'"

The AI assistant can directly query and update the SQLite database at ~/.true-mem/memory.db.

Explicit Memory Storage

Use phrases like "Remember this:" or "Remember that ..." to force storage:

"Remember this: never commit without running tests first"
"Remember that I prefer to use TypeScript in my projects"

Scope Behavior:

By default, explicit intent memories are stored at project scope (only visible in the current project). To make them global (available in all projects), include a global scope keyword anywhere in your phrase:

LanguageGlobal Scope Keywords
English"always", "everywhere", "for all projects", "in every project", "globally"
Italian"sempre", "ovunque", "per tutti i progetti", "in ogni progetto", "globalmente"
Spanish"siempre", "en todas partes", "para todos los proyectos"
French"toujours", "partout", "pour tous les projets"
German"immer", "überall", "für alle projekte"
Portuguese"sempre", "em todos os projetos"

Examples:

MemoryScopePhrase
Projectproject_scope = current_project"Remember that we use REST for the API"
Globalproject_scope = null"Remember to always run tests before committing"
Globalproject_scope = null"Remember that I always use Typescript in every project"

Advanced: Semantic Embeddings (Experimental)

True-Mem includes an experimental NLP embeddings feature that provides semantic similarity search beyond basic Jaccard matching.

What It Does

When enabled, True-Mem uses a lightweight transformer model (all-MiniLM-L6-v2) to generate 384-dimensional embeddings for each memory. This enables:

  • Semantic retrieval - Find memories by meaning, not just keyword matching
  • Better relevance - Understands that "I like TypeScript" relates to "JavaScript preferences"
  • Cross-lingual support - Works across the 15 supported languages

How It Works

Architecture:

Main Thread (Bun) → Node.js Worker Process → Transformers.js v4 → ONNX Runtime

The plugin spawns a separate Node.js process to run the transformer model in isolation, ensuring Bun stability. The model is automatically downloaded on first use and cached locally.

Trade-offs:

  • Storage: ~23MB for cached model (downloaded once to ~/.true-mem/models/)
  • Memory: ~200MB RAM when worker is active (during embedding generation)
  • Init time: 2-3 seconds on first use (model loading)
  • Hot-reload resilient: Debounce (1s) prevents spawn thrashing

Enabling Embeddings

Edit ~/.true-mem/config.jsonc and set:

{
  "embeddingsEnabled": 1
}

Or use environment variable:

export TRUE_MEM_EMBEDDINGS=1
opencode

To disable, set to 0 or remove the line from config.

Status

Experimental - The feature works well but is still being tested. The Jaccard-only mode (default) is production-stable. When embeddings are enabled, the system gracefully falls back to Jaccard if the worker fails (circuit breaker: 3 failures / 5 minutes).

Checking If Active

# Check config file
cat ~/.true-mem/config.jsonc | grep embeddingsEnabled

# Check logs for [embeddings=true] tag
tail -f ~/.true-mem/plugin-debug.log | grep "\[embeddings=true\]"

Architecture

true-mem/
├── src/
│   ├── index.ts                 # Entry point with fire-and-forget init
│   ├── state.ts                 # Plugin state management
│   ├── logger.ts                # File-based debug logging
│   ├── shutdown.ts              # Graceful shutdown handling
│   ├── config/
│   │   ├── config.ts            # JSONC config loading with comments
│   │   ├── state.ts             # Runtime state persistence
│   │   ├── migration.ts         # Config migration (v1.2 → v1.3)
│   │   └── injection-mode.ts    # Injection mode utilities
│   ├── storage/
│   │   ├── sqlite-adapter.ts    # bun:sqlite + node:sqlite runtime adapter
│   │   └── database.ts          # MemoryDatabase class with scope filtering
│   ├── memory/
│   │   ├── patterns.ts          # Multilingual patterns (15 languages)
│   │   ├── negative-patterns.ts # False positive prevention
│   │   ├── role-patterns.ts     # Role-aware extraction (Human vs Assistant)
│   │   ├── classifier.ts        # Four-layer defense + role validation
│   │   ├── embeddings.ts        # Jaccard similarity search
│   │   ├── embeddings-nlp.ts    # NLP embeddings worker management
│   │   ├── embedding-worker.ts  # Worker process for transformer model
│   │   └── reconsolidate.ts     # Conflict resolution
│   ├── extraction/
│   │   └── queue.ts             # Fire-and-forget extraction queue
│   ├── adapters/
│   │   └── opencode/
│   │       ├── index.ts         # Full extraction + injection hooks
│   │       ├── injection.ts     # Memory injection logic
│   │       └── injection-tracker.ts  # Session injection tracking
│   └── utils/
│       ├── version.ts           # Version utilities
│       ├── jsonc.ts             # JSONC parser with comments
│       └── toast.ts             # Toast notifications
└── dist/
    ├── index.js                 # Bundle (~155KB)
    └── memory/
        └── embedding-worker.js  # Worker bundle (~3KB)

Memory Classifications

TypeDecayStoreScopeExample
constraintNeverSTMGlobal"Never use var"
preferenceNeverSTMGlobal"Prefers functional style"
learningNeverLTMGlobal"Learned bun:sqlite API"
proceduralNeverSTMGlobal"Run tests before commit"
decisionNeverLTMProject"Decided SQLite over Postgres"
semanticNeverSTMProject"API uses REST, not GraphQL"
episodicYes (7d)STMProject"Yesterday we refactored auth"

Technical Details

7-Feature Scoring Model

FeatureWeightDescription
Recency0.20Time since creation (0 = recent, 1 = old)
Frequency0.15Number of accesses (log scale)
Importance0.25Combination of signals (diminishing returns)
Utility0.20Usefulness for current task
Novelty0.10Distance from existing memories
Confidence0.10Consensus of extraction evidence
Interference-0.10Penalty for conflicts

Strength Formula: Strength = Sum(weight_i * feature_i) clamped to [0, 1]

Four-Layer False Positive Prevention

LayerPurpose
1. Question DetectionFilter questions before classification
2. Negative PatternsAI meta-talk, list selections, 1st person recall, remind-me recall (10 languages)
3. Multi-Keyword + Sentence-LevelRequire 2+ signals in the same sentence
4. Confidence ThresholdStore only if score >= 0.6

Decay Strategy

  • Episodic memories: Decay using Ebbinghaus formula (lambda = 0.05 STM, 0.01 LTM)
  • All other types: Permanent (no decay)

Contributing

Want to contribute or test your own changes? Here's how:

  1. Fork this repository

  2. Build the plugin

    cd true-mem
    bun install
    bun run build
  3. Use your local version in ~/.config/opencode/opencode.json:

    {
      "plugin": [
        "file:///path/to/your/fork/true-mem"
      ]
    }
  4. Restart OpenCode - it will load your local build instead of the npm version.

  5. Make your changes, rebuild with bun run build, and test.

  6. Submit a PR when ready!

Inspired by PsychMem - a pioneering plugin for persistent memory in OpenCode.


Debug

# View logs
tail -f ~/.true-mem/plugin-debug.log

# Query database
sqlite3 ~/.true-mem/memory.db "SELECT classification, summary, strength FROM memory_units WHERE status = 'active' ORDER BY strength DESC LIMIT 10;"

License: MIT Status: Actively maintained

关于 About

A persistent memory plugin for OpenCode with cognitive psychology-based memory management

语言 Languages

TypeScript100.0%

提交活跃度 Commit Activity

代码提交热力图
过去 52 周的开发活跃度
235
Total Commits
峰值: 119次/周
Less
More

核心贡献者 Contributors