MemoryForge
Integrates with OpenAI-compatible APIs to provide optional LLM capabilities for condensing memories, resolving contradictions, and dreaming (summarizing duplicate entries), while search remains local.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MemoryForgeremember that this project uses pnpm instead of npm"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MemoryForge
Local memory for coding agents. OpenCode, Cursor, Claude Code, and any other MCP client read and write the same short facts. The data is one SQLite file on your machine. A language model is optional, and search never calls one.
The notebook UI is in English by default; German is a switch in Settings. Deutsche Anleitung.
What it stores
Short facts that should still be true next week: a preference, a decision, a convention, a lesson from a bug. Not chat logs, not the current task, not secrets.
Each fact has a scope.
Scope | Means |
| about you, in every repo |
| about that repository |
A project search also returns global. A global search does not return project facts. Writing, replacing, and dreaming stay inside one scope, so a repo fact cannot overwrite a preference.
If you omit the scope, the CLI and a stdio MCP session run git remote get-url origin in the working directory.
Remote | Scope |
|
|
| same |
no git, or no |
|
The HTTP server cannot see your repo. Pass scope yourself. It binds to 127.0.0.1 unless you change that.
Related MCP server: agent-memory-v1
What it does not do
No account, no hosted vector database. Search and embeddings stay local. Strings that look like secrets (api_key=…, sk-…, ghp_…, private keys) are redacted before they are stored. Do not put secrets in memory anyway.
Dreaming only merges or retires facts that are already stored. It does not invent new ones. With the model switched off, dreaming changes nothing.
Requirements
Python 3.10+
Git, if you want project scopes detected for you
optional: an API key for DeepSeek or another OpenAI-compatible API
The first real embedding downloads BAAI/bge-small-en-v1.5 into the local cache. Without fastembed, search still works, using a hash embedder plus full text. That mode is for tests and for machines where the model download is not wanted. Recall is weaker.
Install
git clone https://github.com/pierelucas/MemoryForge.git
cd MemoryForge
./install.shThe script installs uv if it is missing, then installs the memoryforge command. In a terminal it asks whether to configure a model now. --yes skips the questions.
./install.sh --yes --service--service installs a user service: systemd on Linux, launchd on macOS. On Windows, run memoryforge serve in the foreground. The service starts at login. To keep it running without a login, run loginctl enable-linger "$USER" once.
Config |
|
Database |
|
Service log |
|
XDG_CONFIG_HOME and XDG_DATA_HOME replace those roots.
Notebook
memoryforge # start the server if it is down, print the URL
memoryforge ui # open the notebook
memoryforge serve # foreground
memoryforge serve --detach
memoryforge stop
memoryforge doctorDefault URL: http://127.0.0.1:4737/
The sidebar is the scope list. All shows everything. Global shows only global facts. A repository shows that repository, and underneath the global facts an agent would also see there. Search in a repository searches both. Delete scope on a scope page hides every active fact in it after a confirmation page. The rows stay in the file, and All is a view, not a scope, so it has no delete link.
Remember stores one fact in the scope selected above the button. Other scope is for a scope that does not exist yet. A git URL in that field is normalized. / focuses search. Ctrl+Enter or Cmd+Enter submits the note you are typing.
Pin keeps a fact on the session card (memory_brief). Forget hides a fact from search, the list, and MCP. The row stays in the file. Edit replaces the text and refreshes the embedding, and its scope select moves the fact to another scope or to a new name. A move into a scope that already holds the same text is rejected. The form does not set a kind. With the model off, UI notes are stored as fact. With the model on, a longer note may be split or classified.
Settings holds the AI options, the language (English or German), the check and dream buttons, and the backup download with and without the key.
autostart in the config only records the wish. Login startup comes from memoryforge install-service or ./install.sh --service.
Model
Off is the default. add then stores the text as written, unless that exact text already exists in the scope.
On: one short sentence with no close neighbor is still stored as written. Longer notes, and notes that sit next to a similar fact, go to the model. If the API fails, the original text is stored anyway.
Search does not call the API.
Label in the UI | Model id | Provider |
DeepSeek V4.1 Flash |
|
|
DeepSeek V4 Pro |
| same |
GPT-4.1 nano |
|
|
GPT-4.1 mini |
| same |
GPT-4o mini |
| same |
The label is just a label. The provider has to accept the id. Another id, or a local OpenAI-compatible server, goes in Custom model ID. A filled custom id wins over the list. Choosing a listed model clears the custom field.
memoryforge config models
memoryforge config set llm.enabled true
memoryforge config set llm.provider deepseek
memoryforge config set llm.base_url https://api.deepseek.com
memoryforge config set llm.model deepseek-flash
memoryforge config set llm.api_key sk-...
memoryforge config set llm.thinking false
memoryforge config set ui.lang de
memoryforge config showconfig show masks the key. Leave thinking off for extraction.
The embedding model is not this menu. It stays BAAI/bge-small-en-v1.5 on disk. Changing the chat model does not touch old vectors. Changing the embedding model does: run memoryforge reembed afterwards.
memoryforge dream
memoryforge dream --scope globalCLI
memoryforge add "Bevorzuge pnpm statt npm."
memoryforge add --scope global "Antworten dürfen Deutsch sein."
memoryforge add --scope project:github.com/pierelucas/MemoryForge "Port der UI ist 4737."
echo "ein Fakt" | memoryforge add -
memoryforge search "package manager"
memoryforge search "port" --scope global
memoryforge list
memoryforge list --scope global
memoryforge pin <id>
memoryforge pin <id> --off
memoryforge forget <id>
memoryforge doctorOpenCode
stdio is the one to use. OpenCode starts the process in the project directory, MemoryForge reads origin, and both sides use the same database as the notebook.
~/.config/opencode/opencode.json (OpenCode 2), or the project config:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"servers": {
"memoryforge": {
"type": "local",
"command": ["memoryforge", "mcp"]
}
}
}
}Older configs, without servers:
{
"mcp": {
"memoryforge": {
"type": "local",
"command": ["memoryforge", "mcp"],
"enabled": true
}
}
}The tools do nothing if the agent never calls them. Put this in the project instructions:
At session start call memory_brief. Pass scope project:<host/owner/repo> when you know the git remote, otherwise omit it.
When you learn a durable preference, decision, convention, or debug lesson, call memory_add with one or a few sentences.
Do not store secrets, tokens, or ephemeral task state.Tool | Use |
| session start: pinned facts, then recent ones |
| meaning plus full text |
| store a fact or a raw note |
| active rows |
| pin or unpin |
| hide a row |
Cursor, Claude Code, and other clients on this machine can use the same stdio command. A client that cannot start a process uses HTTP, after memoryforge is running:
http://127.0.0.1:4737/mcpThere is no authentication on that port. Do not bind it to a shared network. On the default loopback bind the notebook rejects requests with a foreign Host header and form posts from another origin. curl and MCP clients that send no origin still work.
Config
[server]
autostart = false
host = "127.0.0.1"
port = 4737
open_browser = false
[llm]
enabled = false
provider = "deepseek"
base_url = "https://api.deepseek.com"
model = "deepseek-flash"
thinking = false
api_key = ""
[embed]
model = "BAAI/bge-small-en-v1.5"
[ui]
lang = "en"memoryforge config set section.field value. Booleans: true, false, ja, nein, an, aus. ui.lang takes en or de; a missing or unknown value falls back to English.
Move to another machine
memoryforge backup
memoryforge backup --without-secrets -o ~/merk.zipThe zip contains three files, nothing else:
manifest.json format version, time, embedding model
config.toml includes the API key, unless you passed --without-secrets
memory.db SQLite backup, not a live WALThe program, the model cache, and logs are not in the zip. The key is plaintext in the archive, so you do not have to type it again. Do not send that file around. --without-secrets blanks the key.
On the new machine, from a fresh clone:
./install.sh --restore memoryforge-backup-20261019-1504.zipIf the command is already installed:
memoryforge restore memoryforge-backup-20261019-1504.zip
memoryforgeRestore stops a running server first. Files land in the usual directories on this machine. Old home paths are not copied. If the embedding model in the manifest does not match the local config, restore says so. Run memoryforge reembed.
A zip with extra paths or .. is rejected. So is a format version this build does not know. Both checks happen before anything is overwritten.
The notebook can download the same zip from Settings under Move: one button with the key, one without.
Uninstall
./uninstall.sh # remove the service and command, keep the data
./uninstall.sh --purge # also remove config and databaseThe script stops the service, disables the systemd unit, removes the macOS LaunchAgent, and uninstalls the command. It leaves uv installed. The OpenCode configuration is not touched; remove the memoryforge entry there or under /mcps.
By hand:
memoryforge stop
uv tool uninstall memoryforge
rm -rf ~/.config/memoryforge ~/.local/share/memoryforgeOn Linux, also systemctl --user disable --now memoryforge and delete ~/.config/systemd/user/memoryforge.service. On macOS, launchctl unload the agent ~/Library/LaunchAgents/com.memoryforge.plist.
Development
uv venv
uv pip install -e ".[dev]"
pytest
memoryforge serveTests force the hash embedder (MEMORYFORGE_EMBED=hash) and do not touch your real database.
License
MIT. See LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
- KogniteOAuthdev.kognite
Hosted agent memory: store, search, and recall facts across sessions from any MCP client.
A second brain for your AI agent. Shared memory for your team's AI agents, plus public and private knowledge bases — works with ChatGPT, Claude, Cursor and any MCP client.
Persistent memory, hybrid search and a goal graph for AI agents, over stdio or remote HTTP.
Private-by-default, local-first memory/context/task orchestrator for MCP apps and agents.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceLocal MCP server for indexing personal knowledge into SQLite with hybrid search, chunk-level citations, memory tools, and agent orchestration.4MIT
- AlicenseNot gradedqualityAmaintenanceEnables coding agents to store and retrieve source-backed context locally in SQLite, with FTS5 search, optional reranking, and stdio MCP tools.MIT
- AlicenseBqualityCmaintenanceGives MCP clients a local, single-tenant SQLite-backed store for saving, searching, bootstrapping and recalling memory records, plus saving and loading session handoffs, using text search by default with optional embeddings. It runs over stdio or an authenticated loopback HTTP gateway with explicit-confirmation pruning, scoped policies, and admin-driven backup, restore-copy and restart-drill verification.16MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to store and recall durable facts, decisions, and lessons over MCP using hybrid semantic and keyword search, typed memories, graph relations, sessions, and time-travel queries. Runs locally with no server process or API key, persisting everything to files that both agents and a CLI can share.14 npmMIT