Summary
basic_memory_diagnostics reads config.json off disk and prints it, but the running server's settings are BasicMemoryConfig(BaseSettings) with env_prefix="BASIC_MEMORY_", so every BASIC_MEMORY_* environment variable overrides that file at runtime. The tool therefore reports the file, not what the server is actually using — with no indication that the two can differ.
This matters most in containers and managed deployments, where env vars are the normal way to configure the server and config.json is whatever was auto-created on first start.
Reproduction
Server running with these in the environment (a Docker Compose deployment):
BASIC_MEMORY_SEMANTIC_EMBEDDING_MODEL: "sentence-transformers/paraphrase-multilingual-mpnet-base-v2"
BASIC_MEMORY_DEFAULT_SEARCH_TYPE: "vector"
BASIC_MEMORY_SEMANTIC_MIN_SIMILARITY: "0.49"
What the server actually loaded:
>>> from basic_memory.config import ConfigManager
>>> c = ConfigManager().load_config()
>>> c.semantic_embedding_model
'sentence-transformers/paraphrase-multilingual-mpnet-base-v2'
>>> c.default_search_type
'vector'
>>> c.semantic_min_similarity
0.49
Confirmed by the server's own startup log:
Semantic search: provider=fastembed, model=sentence-transformers/paraphrase-multilingual-mpnet-base-v2, dimensions=768
What config.json on disk says, and therefore what basic_memory_diagnostics reports:
{
"semantic_embedding_model": "bge-small-en-v1.5",
"default_search_type": null,
"semantic_min_similarity": 0.55
}
All three values are wrong in the diagnostic output. Version 0.23.2.
Mechanism
src/basic_memory/mcp/tools/basic_memory_diagnostics.py:51-66 goes straight to the file:
config_file = resolve_data_dir() / CONFIG_FILE_NAME
config_exists = config_file.exists()
if config_exists:
try:
raw_config = json.loads(config_file.read_text(encoding="utf-8"))
while src/basic_memory/config_models.py:899-900 establishes the override layer:
model_config = SettingsConfigDict(
env_prefix="BASIC_MEMORY_",
The file read is deliberate — the comment at basic_memory_diagnostics.py:49-50 explains that ConfigManager would create and chmod the directory, violating the tool's read-only contract. So this isn't an oversight in how the file is read; the gap is that the env layer is never represented at all.
Why it bites
The tool's stated purpose is "troubleshooting installations and gathering information for support requests". In exactly that situation — someone pastes diagnostics output into an issue — it silently reports a configuration the server is not running. An agent using it to confirm a config change will conclude the change did not take effect when it did, or vice versa.
It also makes the output self-inconsistent with the startup log, which does print effective values.
Suggested fix
The minimal change that keeps the read-only contract intact: don't load config at all, just show which BASIC_MEMORY_* variables are set, so the reader can see the file isn't the whole story.
env_overrides = {
k: v for k, v in sorted(os.environ.items())
if k.startswith("BASIC_MEMORY_")
}
rendered as its own section, values passed through the same redaction as the file dump (API keys arrive this way too — BASIC_MEMORY_SEMANTIC_EMBEDDING_API_KEY, BASIC_MEMORY_CLOUD_*), and with a one-line note in the Configuration section that env vars take precedence over the file.
That needs no config loading, creates no directories, and turns a misleading report into a complete one.
A fuller fix would print effective values by giving ConfigManager a read-only load path that skips directory creation, then dumping the resolved BasicMemoryConfig. That's strictly better output, but it's a larger change and touches the contract the existing comment is protecting — happy to go that way instead if you prefer.
I'm glad to open a PR for whichever shape you want.
Found on origin/main @ 3bf2d523.
Summary
basic_memory_diagnosticsreadsconfig.jsonoff disk and prints it, but the running server's settings areBasicMemoryConfig(BaseSettings)withenv_prefix="BASIC_MEMORY_", so everyBASIC_MEMORY_*environment variable overrides that file at runtime. The tool therefore reports the file, not what the server is actually using — with no indication that the two can differ.This matters most in containers and managed deployments, where env vars are the normal way to configure the server and
config.jsonis whatever was auto-created on first start.Reproduction
Server running with these in the environment (a Docker Compose deployment):
What the server actually loaded:
Confirmed by the server's own startup log:
What
config.jsonon disk says, and therefore whatbasic_memory_diagnosticsreports:{ "semantic_embedding_model": "bge-small-en-v1.5", "default_search_type": null, "semantic_min_similarity": 0.55 }All three values are wrong in the diagnostic output. Version 0.23.2.
Mechanism
src/basic_memory/mcp/tools/basic_memory_diagnostics.py:51-66goes straight to the file:while
src/basic_memory/config_models.py:899-900establishes the override layer:The file read is deliberate — the comment at
basic_memory_diagnostics.py:49-50explains thatConfigManagerwould create andchmodthe directory, violating the tool's read-only contract. So this isn't an oversight in how the file is read; the gap is that the env layer is never represented at all.Why it bites
The tool's stated purpose is "troubleshooting installations and gathering information for support requests". In exactly that situation — someone pastes diagnostics output into an issue — it silently reports a configuration the server is not running. An agent using it to confirm a config change will conclude the change did not take effect when it did, or vice versa.
It also makes the output self-inconsistent with the startup log, which does print effective values.
Suggested fix
The minimal change that keeps the read-only contract intact: don't load config at all, just show which
BASIC_MEMORY_*variables are set, so the reader can see the file isn't the whole story.rendered as its own section, values passed through the same redaction as the file dump (API keys arrive this way too —
BASIC_MEMORY_SEMANTIC_EMBEDDING_API_KEY,BASIC_MEMORY_CLOUD_*), and with a one-line note in the Configuration section that env vars take precedence over the file.That needs no config loading, creates no directories, and turns a misleading report into a complete one.
A fuller fix would print effective values by giving
ConfigManagera read-only load path that skips directory creation, then dumping the resolvedBasicMemoryConfig. That's strictly better output, but it's a larger change and touches the contract the existing comment is protecting — happy to go that way instead if you prefer.I'm glad to open a PR for whichever shape you want.
Found on
origin/main@3bf2d523.