---
title: "Configuration"
description: "Configuration reference for Basic Memory, including project routing, semantic search, and cloud settings."
canonical_url: "https://docs.basicmemory.com/reference/configuration"
---
# Configuration

> Configuration reference for Basic Memory, including project routing, semantic search, and cloud settings.

Basic Memory reads configuration from:

1. Environment variables (`BASIC_MEMORY_*`)
2. Config file (`~/.basic-memory/config.json` by default)
3. Built-in defaults

Environment variables override config file values for the process that sets them. As of v0.24, an override is never written back into `config.json`: when a command saves config (adding a project, a migration, first run), it keeps the file's own value for every env-overridden setting. Commands that name a setting still save it, such as `bm config set`/`unset`, `bm cloud api-key save`, `bm cloud workspace set-default`, `bm cloud logout`, `bm cloud promo`, and `bm project default`. Environment names match config fields in any letter case, so `basic_memory_log_level` works the same as `BASIC_MEMORY_LOG_LEVEL`.

---

## v0.24 changes

<table>
<thead>
  <tr>
    <th>
      Change
    </th>
    
    <th>
      What to do
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        semantic_search_enabled
      </code>
      
       removed; semantic search is always on
    </td>
    
    <td>
      Nothing. Old <code>
        config.json
      </code>
      
       values and <code>
        BASIC_MEMORY_SEMANTIC_SEARCH_ENABLED
      </code>
      
       are ignored, not rejected. Installs that had turned it off now download the embedding model and build vectors
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        disable_permalinks
      </code>
      
       retired; Markdown notes always get a permalink
    </td>
    
    <td>
      Nothing. An existing value (or <code>
        BASIC_MEMORY_DISABLE_PERMALINKS
      </code>
      
      ) is ignored and dropped from <code>
        config.json
      </code>
      
       the next time it is normalized. Notes indexed without a permalink are backfilled during ordinary scans, which writes <code>
        permalink
      </code>
      
       into their frontmatter
    </td>
  </tr>
  
  <tr>
    <td>
      New <code>
        enable_posix_tools
      </code>
      
       (default <code>
        true
      </code>
      
      )
    </td>
    
    <td>
      Set it to <code>
        false
      </code>
      
       to hide the <code>
        cat
      </code>
      
      , <code>
        grep
      </code>
      
      , <code>
        ls
      </code>
      
      , <code>
        find
      </code>
      
      , <code>
        tail
      </code>
      
      , and <code>
        man
      </code>
      
       MCP tools
    </td>
  </tr>
  
  <tr>
    <td>
      New <code>
        date_order
      </code>
      
       (default <code>
        YMD
      </code>
      
      )
    </td>
    
    <td>
      Set it if you write slash-formatted dates in observation time qualifiers
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        openai
      </code>
      
       embedding provider honors <code>
        semantic_embedding_api_base
      </code>
      
       and <code>
        semantic_embedding_api_key
      </code>
    </td>
    
    <td>
      Point it at any OpenAI-compatible endpoint without LiteLLM
    </td>
  </tr>
  
  <tr>
    <td>
      Env overrides no longer persisted into <code>
        config.json
      </code>
    </td>
    
    <td>
      Remove any one-off values an older version already wrote, with <code>
        bm config unset KEY
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        BASIC_MEMORY_PROJECT_ROOT
      </code>
      
       refuses nested project names
    </td>
    
    <td>
      Use single-segment project names under a shared root
    </td>
  </tr>
</tbody>
</table>

See the [v0.24 upgrade guide](https://docs.basicmemory.com/whats-new/v0-24-upgrade) for the full list of behavior changes.

---

## Manage settings from the CLI

Use `bm config` for scalar settings instead of editing JSON by hand:

```bash
bm config list
bm config get reranker_enabled
bm config set reranker_enabled true
bm config unset reranker_enabled
```

`set` validates the complete configuration before writing. `list` shows whether each effective value comes from a default, `config.json`, or an environment override. Secret fields are masked and credentials embedded in URLs are redacted from `list` and `get` output.

Structured project mappings still use `bm project`; `bm config` intentionally handles only scalar settings.

---

## New v0.23 settings

All 28 new settings can be written with `bm config set <key> <value>` or supplied as `BASIC_MEMORY_<KEY>` environment variables.

<table>
<thead>
  <tr>
    <th>
      Key
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Purpose
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        reranker_enabled
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Enable cross-encoder reranking for vector and hybrid candidates.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_provider
      </code>
    </td>
    
    <td>
      <code>
        fastembed
      </code>
    </td>
    
    <td>
      Select local FastEmbed or API-backed LiteLLM reranking.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_model
      </code>
    </td>
    
    <td>
      <code>
        jinaai/jina-reranker-v1-tiny-en
      </code>
    </td>
    
    <td>
      Select the reranker model; LiteLLM uses <code>
        provider/model
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_candidates
      </code>
    </td>
    
    <td>
      <code>
        20
      </code>
    </td>
    
    <td>
      Set the leading retrieval window rescored before returning a page.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_max_document_chars
      </code>
    </td>
    
    <td>
      <code>
        2000
      </code>
    </td>
    
    <td>
      Cap characters per candidate; <code>
        0
      </code>
      
       sends full matched text.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_timeout
      </code>
    </td>
    
    <td>
      <code>
        30.0
      </code>
    </td>
    
    <td>
      Limit each LiteLLM rerank request in seconds; FastEmbed ignores it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_api_base
      </code>
    </td>
    
    <td>
      unset
    </td>
    
    <td>
      Set a custom LiteLLM reranker endpoint.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_api_key
      </code>
    </td>
    
    <td>
      unset
    </td>
    
    <td>
      Pass a reranker credential directly to LiteLLM.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        semantic_vector_index
      </code>
    </td>
    
    <td>
      <code>
        pgvector
      </code>
    </td>
    
    <td>
      Select pgvector or Milvus for Postgres; SQLite remains sqlite-vec.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        milvus_uri
      </code>
    </td>
    
    <td>
      unset
    </td>
    
    <td>
      Connect to Milvus, Milvus Lite, or Zilliz Cloud.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        milvus_token
      </code>
    </td>
    
    <td>
      unset
    </td>
    
    <td>
      Authenticate to Milvus or Zilliz.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        milvus_timeout_seconds
      </code>
    </td>
    
    <td>
      <code>
        30.0
      </code>
    </td>
    
    <td>
      Limit each Milvus client operation.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        milvus_collection_prefix
      </code>
    </td>
    
    <td>
      <code>
        basic_memory
      </code>
    </td>
    
    <td>
      Prefix project-isolated Milvus collections.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        milvus_database
      </code>
    </td>
    
    <td>
      <code>
        default
      </code>
    </td>
    
    <td>
      Select a Milvus database; ignored by Milvus Lite.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        semantic_embedding_api_base
      </code>
    </td>
    
    <td>
      unset
    </td>
    
    <td>
      Set a custom LiteLLM embedding endpoint.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        semantic_embedding_api_key
      </code>
    </td>
    
    <td>
      unset
    </td>
    
    <td>
      Pass an embedding credential directly to LiteLLM.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        semantic_embedding_document_prefix
      </code>
    </td>
    
    <td>
      unset
    </td>
    
    <td>
      Prefix indexed chunks for asymmetric embedding models.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        semantic_embedding_query_prefix
      </code>
    </td>
    
    <td>
      unset
    </td>
    
    <td>
      Prefix queries for asymmetric embedding models.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        redis_url
      </code>
    </td>
    
    <td>
      unset
    </td>
    
    <td>
      Enable optional Redis caching for standalone MCP reads.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        redis_max_connections
      </code>
    </td>
    
    <td>
      <code>
        20
      </code>
    </td>
    
    <td>
      Bound the standalone read-cache connection pool.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        materialization_workers
      </code>
    </td>
    
    <td>
      <code>
        4
      </code>
    </td>
    
    <td>
      Bound local accepted-write materialization concurrency.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sqlite_synchronous
      </code>
    </td>
    
    <td>
      <code>
        NORMAL
      </code>
    </td>
    
    <td>
      Set SQLite <code>
        PRAGMA synchronous
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sqlite_mmap_size
      </code>
    </td>
    
    <td>
      <code>
        268435456
      </code>
    </td>
    
    <td>
      Set SQLite <code>
        PRAGMA mmap_size
      </code>
      
       in bytes.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sqlite_wal_autocheckpoint
      </code>
    </td>
    
    <td>
      <code>
        1000
      </code>
    </td>
    
    <td>
      Set SQLite WAL checkpoint frequency in pages.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sqlite_page_size
      </code>
    </td>
    
    <td>
      <code>
        4096
      </code>
    </td>
    
    <td>
      Set SQLite page size for a new database or the next <code>
        VACUUM
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        index_delay
      </code>
    </td>
    
    <td>
      <code>
        1000
      </code>
    </td>
    
    <td>
      Wait this many milliseconds after file changes before indexing.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        index_changes
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Index local file changes in real time.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cli_output_style
      </code>
    </td>
    
    <td>
      <code>
        rich
      </code>
    </td>
    
    <td>
      Select Rich or plain interactive <code>
        bm tool
      </code>
      
       output.
    </td>
  </tr>
</tbody>
</table>

Detailed constraints and operating guidance follow below.

---

## Config file location

Default location:

```bash
~/.basic-memory/config.json
```

To isolate config and default SQLite data per workspace/process, set:

```bash
export BASIC_MEMORY_CONFIG_DIR=/path/to/custom-dir
```

When set, Basic Memory stores config and default app DB in that directory.

---

## Example config

```json
{
  "default_project": "main",
  "projects": {
    "main": {
      "path": "/Users/you/basic-memory",
      "mode": "local"
    },
    "research": {
      "path": "/Users/you/research-notes",
      "mode": "cloud",
      "local_sync_path": "/Users/you/research-notes",
      "last_sync": "2026-02-15T18:30:00Z"
    }
  },
  "semantic_min_similarity": 0.55,
  "permalinks_include_project": true
}
```

---

## Project and routing settings

### `projects`

Projects are now stored as structured entries, not just name -> path strings.

Each project entry supports:

- `path`: local filesystem path
- `mode`: `local` or `cloud`
- `local_sync_path` (optional; legacy `cloud_sync_path` keys are accepted and migrated on load)
- `last_sync` (optional)

### `default_project`

Fallback project name used when tools/commands do not pass a project.

- Type: `string | null`
- Default: unset — the first configured project is used (`"main"` on fresh installs, where a `main` project is seeded). Setting it explicitly to `null` disables automatic project resolution.

<note>

`default_project_mode` is deprecated/removed from active config behavior. Use `default_project` as fallback instead.

</note>

### `BASIC_MEMORY_MCP_PROJECT`

Environment-level project constraint for MCP sessions.

- Locks operations to one project for that process/session
- Highest-priority project constraint

### Per-project routing mode

Use CLI to manage per-project routing:

```bash
bm project set-cloud research
bm project set-local research
```

Cloud-routed projects use cloud credentials/API key; local-routed projects use local ASGI transport.

### `project_root`

When set, every project must be created underneath this directory, and project paths are sanitized and constrained to it. The Docker image sets it to `/app/data`.

- Type: `string | null`
- Default: `null` (projects can live anywhere)
- Env: `BASIC_MEMORY_PROJECT_ROOT`

As of v0.24, a project name whose permalink contains `/` (such as `Research/2026`) is refused under a project root, so every project stays a single top-level directory and one project's files cannot overlap another's.

---

## Semantic search settings

Semantic search is always on. FastEmbed and sqlite-vec are core dependencies, and embeddings are generated automatically on first startup.

<note>

The `semantic_search_enabled` setting was removed in v0.24. Old `config.json` values and `BASIC_MEMORY_SEMANTIC_SEARCH_ENABLED` are ignored rather than rejected. If sqlite-vec cannot load, as with python.org Python on macOS, search falls back to keyword-only. A vector or hybrid query then says semantic search is unavailable and points at the log. See [Troubleshooting](https://docs.basicmemory.com/reference/troubleshooting#semantic-search-unavailable-sqlite-vec-will-not-load).

</note>

### `semantic_vector_index`

Vector index used by Postgres deployments.

- Type: `"pgvector" | "milvus"`
- Default: `"pgvector"`
- Env: `BASIC_MEMORY_SEMANTIC_VECTOR_INDEX`

SQLite always uses sqlite-vec and ignores this selector. After changing the Postgres index, run `bm reindex --embeddings`; before it succeeds, vector search returns nothing and hybrid search serves full-text results only.

### Milvus settings

<table>
<thead>
  <tr>
    <th>
      Key
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Environment variable
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        milvus_uri
      </code>
    </td>
    
    <td>
      string or null
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_MILVUS_URI
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        milvus_token
      </code>
    </td>
    
    <td>
      string or null
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_MILVUS_TOKEN
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        milvus_timeout_seconds
      </code>
    </td>
    
    <td>
      float greater than 0
    </td>
    
    <td>
      <code>
        30.0
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_MILVUS_TIMEOUT_SECONDS
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        milvus_collection_prefix
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      <code>
        "basic_memory"
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_MILVUS_COLLECTION_PREFIX
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        milvus_database
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      <code>
        "default"
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_MILVUS_DATABASE
      </code>
    </td>
  </tr>
</tbody>
</table>

Install `basic-memory[milvus]` before selecting Milvus. `milvus_uri` accepts a remote Milvus/Zilliz endpoint or a Milvus Lite path. Lite requires a `.db` suffix and an existing parent directory, creates a directory tree at that path, and ignores `milvus_database`. See [Postgres and Milvus](https://docs.basicmemory.com/local/postgres-and-milvus).

### `semantic_embedding_provider`

Embedding provider.

- Type: string
- Default: `"fastembed"`
- Common values: `fastembed`, `openai`, `litellm`
- Env: `BASIC_MEMORY_SEMANTIC_EMBEDDING_PROVIDER`

As of v0.24, the `openai` provider honors `semantic_embedding_api_base` and `semantic_embedding_api_key`. You can point it at any OpenAI-compatible endpoint (llama.cpp, vLLM, TEI, LM Studio, Ollama) without the LiteLLM path:

```bash
bm config set semantic_embedding_provider openai
bm config set semantic_embedding_api_base http://localhost:8080/v1
bm config set semantic_embedding_model your-model-name
bm reindex --embeddings
```

### `semantic_embedding_model`

Embedding model name.

- Type: string
- Default: `"bge-small-en-v1.5"`
- Env: `BASIC_MEMORY_SEMANTIC_EMBEDDING_MODEL`

### `semantic_embedding_dimensions`

Embedding dimensions override.

- Type: integer | null
- Default: `null` (auto)
- Env: `BASIC_MEMORY_SEMANTIC_EMBEDDING_DIMENSIONS`

### `semantic_embedding_batch_size`

Embedding batch size.

- Type: integer
- Default: `2`
- Env: `BASIC_MEMORY_SEMANTIC_EMBEDDING_BATCH_SIZE`

### Embedding endpoint and asymmetric-model settings

<table>
<thead>
  <tr>
    <th>
      Key
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Environment variable
    </th>
    
    <th>
      Purpose
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        semantic_embedding_api_base
      </code>
    </td>
    
    <td>
      string or null
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_SEMANTIC_EMBEDDING_API_BASE
      </code>
    </td>
    
    <td>
      Custom OpenAI-compatible or self-hosted endpoint for the <code>
        openai
      </code>
      
       or <code>
        litellm
      </code>
      
       provider.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        semantic_embedding_api_key
      </code>
    </td>
    
    <td>
      string or null
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_SEMANTIC_EMBEDDING_API_KEY
      </code>
    </td>
    
    <td>
      Credential passed to the <code>
        openai
      </code>
      
       or <code>
        litellm
      </code>
      
       provider. When unset, <code>
        openai
      </code>
      
       falls back to <code>
        OPENAI_API_KEY
      </code>
      
       and <code>
        litellm
      </code>
      
       uses normal provider env vars.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        semantic_embedding_document_prefix
      </code>
    </td>
    
    <td>
      string or null
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_SEMANTIC_EMBEDDING_DOCUMENT_PREFIX
      </code>
    </td>
    
    <td>
      Literal prefix added to indexed chunks.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        semantic_embedding_query_prefix
      </code>
    </td>
    
    <td>
      string or null
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_SEMANTIC_EMBEDDING_QUERY_PREFIX
      </code>
    </td>
    
    <td>
      Literal prefix added to queries.
    </td>
  </tr>
</tbody>
</table>

Use the prefix pair for models whose document and query roles are expressed in input text. Rebuild embeddings after changing either prefix.

### `semantic_vector_k`

Vector candidate count.

- Type: integer
- Default: `100`
- Env: `BASIC_MEMORY_SEMANTIC_VECTOR_K`

### `semantic_min_similarity`

Global minimum similarity threshold for vector results.

- Type: float (`0.0` to `1.0`)
- Default: `0.55`
- Env: `BASIC_MEMORY_SEMANTIC_MIN_SIMILARITY`

Set to `0.0` to disable threshold filtering globally.

On the default embedding model, `write_note`'s "Similar existing notes" advisory uses its own fixed floor of `0.70` instead of this setting. Other embedding models use `semantic_min_similarity` for the advisory too.

<tip>

Semantic search dependencies are included by default in all standard installs.

</tip>

---

## Reranker settings

Reranking is disabled by default and applies only to vector and hybrid search. Enable the local provider with:

```bash
bm config set reranker_enabled true
```

<table>
<thead>
  <tr>
    <th>
      Key
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Environment variable
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        reranker_enabled
      </code>
    </td>
    
    <td>
      boolean
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_RERANKER_ENABLED
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_provider
      </code>
    </td>
    
    <td>
      string (<code>
        fastembed
      </code>
      
       or <code>
        litellm
      </code>
      
      )
    </td>
    
    <td>
      <code>
        "fastembed"
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_RERANKER_PROVIDER
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_model
      </code>
    </td>
    
    <td>
      string
    </td>
    
    <td>
      <code>
        "jinaai/jina-reranker-v1-tiny-en"
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_RERANKER_MODEL
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_candidates
      </code>
    </td>
    
    <td>
      integer greater than 0
    </td>
    
    <td>
      <code>
        20
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_RERANKER_CANDIDATES
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_max_document_chars
      </code>
    </td>
    
    <td>
      integer at least 0
    </td>
    
    <td>
      <code>
        2000
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_RERANKER_MAX_DOCUMENT_CHARS
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_timeout
      </code>
    </td>
    
    <td>
      float greater than 0
    </td>
    
    <td>
      <code>
        30.0
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_RERANKER_TIMEOUT
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_api_base
      </code>
    </td>
    
    <td>
      string or null
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_RERANKER_API_BASE
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reranker_api_key
      </code>
    </td>
    
    <td>
      string or null
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_RERANKER_API_KEY
      </code>
    </td>
  </tr>
</tbody>
</table>

FastEmbed downloads the configured local model on first use. LiteLLM requires an explicit `provider/model` name and uses normal provider credentials when `reranker_api_key` is unset. Increase the candidate window to widen recall at a latency cost; use a positive document-character cap to bound long-note cost. FastEmbed ignores `reranker_timeout` because it runs locally.

See [Semantic Search](https://docs.basicmemory.com/concepts/semantic-search#enable-reranking) for provider setup, measured latency, tuning, and fail-fast `503`/`502` behavior.

---

## Permalink and file behavior

### `permalinks_include_project`

When enabled, generated permalinks include project slug prefix.

- Type: boolean
- Default: `true`
- Env: `BASIC_MEMORY_PERMALINKS_INCLUDE_PROJECT`

### `ensure_frontmatter_on_sync`

Add derived `title` and `type` frontmatter to Markdown files during indexing when they are missing. Canonical permalinks are always added, whatever this setting.

- Type: boolean
- Default: `true`
- Env: `BASIC_MEMORY_ENSURE_FRONTMATTER_ON_SYNC`

### `write_note_overwrite_default`

Default value for the `overwrite` parameter on `write_note`. When `false` (default), writing to an existing note path returns an error unless `overwrite=True` is passed explicitly. Set to `true` to restore the pre-v0.19 upsert behavior.

- Type: boolean
- Default: `false`
- Env: `BASIC_MEMORY_WRITE_NOTE_OVERWRITE_DEFAULT`

### `update_permalinks_on_move`

Update permalinks when files move.

- Type: boolean
- Default: `false`
- Env: `BASIC_MEMORY_UPDATE_PERMALINKS_ON_MOVE`

### `disable_permalinks` (retired)

Retired in v0.24. Markdown notes always get a permalink. An existing `disable_permalinks` value or `BASIC_MEMORY_DISABLE_PERMALINKS` is ignored rather than rejected, and the key is dropped from `config.json` the next time it is normalized. Notes indexed without a permalink under the old setting are backfilled during ordinary scans, which writes a `permalink` into their frontmatter. Non-Markdown files are unchanged.

### `kebab_filenames`

Generate kebab-case filenames for tool-created notes.

- Type: boolean
- Default: `false`
- Env: `BASIC_MEMORY_KEBAB_FILENAMES`

### `date_order`

Component order used to read an ambiguous slash-formatted date in an observation's time qualifier, such as `@10/07/2026`. New in v0.24.

- Type: `"YMD" | "DMY" | "MDY"`
- Default: `"YMD"`
- Env: `BASIC_MEMORY_DATE_ORDER`

`YMD` and `DMY` read `10/07/2026` as 10 July 2026; `MDY` reads it as 7 October 2026. ISO dates such as `2026-07-10` are never re-guessed.

---

## MCP tool settings

### `enable_posix_tools`

Register the POSIX-style read-only MCP tools: `cat`, `grep`, `ls`, `find`, `tail`, and `man`. New in v0.24.

- Type: boolean
- Default: `true`
- Env: `BASIC_MEMORY_ENABLE_POSIX_TOOLS`

With this on, an MCP client sees these six tools alongside the rich tools (`read_note`, `search_notes`, and so on), and the server instructions describe projects as mount points. Set it to `false` to hide them:

```bash
bm config set enable_posix_tools false
```

Restart your MCP client after changing it.

---

## Indexing and watch settings

### `index_changes`

Index local file changes in real time.

- Type: boolean
- Default: `true`
- Env: `BASIC_MEMORY_INDEX_CHANGES`

The old `sync_changes` config key and `BASIC_MEMORY_SYNC_CHANGES` environment variable are migrated automatically. If both old and new names are present, the new name wins.

### `index_delay`

Wait this many milliseconds after a file change before indexing it.

- Type: integer
- Default: `1000`
- Env: `BASIC_MEMORY_INDEX_DELAY`

The old `sync_delay` config key and `BASIC_MEMORY_SYNC_DELAY` environment variable are migrated automatically. If both old and new names are present, the new name wins.

### `materialization_workers`

Bound the number of accepted writes that materialize to local storage concurrently.

- Type: integer greater than `0`
- Default: `4`
- Env: `BASIC_MEMORY_MATERIALIZATION_WORKERS`

This controls local write materialization, not general indexing concurrency. The removed `sync_thread_pool_size` and `sync_max_concurrent_files` settings are silently ignored; use this setting only when tuning concurrent accepted writes.

### `skip_initialization_sync`

Skip local initialization — database setup and project reconciliation/seeding — for cloud/stateless deployments where projects are managed in the database. Not a local performance knob; it does not gate the initial file scan.

- Type: boolean
- Default: `false`
- Env: `BASIC_MEMORY_SKIP_INITIALIZATION_SYNC`

### `watch_project_reload_interval`

Seconds between project list reloads in watch-related services.

- Type: integer
- Default: `300`
- Env: `BASIC_MEMORY_WATCH_PROJECT_RELOAD_INTERVAL`

---

## Update settings

Basic Memory can check for new releases and install them automatically for CLI installs (Homebrew, `uv tool`, `uvx`). MCP server processes check silently in the background and never block. Run `bm update` to check and install on demand. See [`bm update`](https://docs.basicmemory.com/reference/cli-reference#bm-update) in the CLI Reference.

### `auto_update`

Enable automatic update checks and installs when supported. Set to `false` to disable background update checks.

- Type: boolean
- Default: `true`
- Env: `BASIC_MEMORY_AUTO_UPDATE`

### `update_check_interval`

Seconds between automatic update checks.

- Type: integer
- Default: `86400` (24 hours)
- Env: `BASIC_MEMORY_UPDATE_CHECK_INTERVAL`

### `auto_update_last_checked_at`

Timestamp of the last automatic update check. Managed automatically — you don't normally set this yourself.

- Type: datetime
- Default: unset

---

## Formatter settings

### `format_on_save`

Automatically format notes when they are saved via `write_note` or `edit_note`. With no `formatter_command` configured, markdown is formatted by the built-in mdformat; setting a command (or the per-extension `formatters` map) overrides it with an external tool.

- Type: boolean
- Default: `false`
- Env: `BASIC_MEMORY_FORMAT_ON_SAVE`

### `formatter_command`

External command to use for formatting markdown files. The file path is substituted via a `{file}` placeholder — for example `npx prettier --write {file}`. A per-extension `formatters` map is also available for different tools per file type.

- Type: string | null
- Default: `null`
- Env: `BASIC_MEMORY_FORMATTER_COMMAND`

### `formatter_timeout`

Maximum time in seconds to wait for the formatter command to complete.

- Type: float
- Default: `5.0`
- Env: `BASIC_MEMORY_FORMATTER_TIMEOUT`

---

## Database settings

### `database_backend`

Database backend to use for the knowledge index.

- Type: string
- Default: `"sqlite"`
- Values: `sqlite`, `postgres`
- Env: `BASIC_MEMORY_DATABASE_BACKEND`

SQLite is used for local installations. Postgres is used by Basic Memory Cloud and can be configured for self-hosted deployments.

### `database_url`

Connection URL for the database when using the Postgres backend.

- Type: string | null
- Default: `null`
- Env: `BASIC_MEMORY_DATABASE_URL`

Only required when `database_backend` is `postgres`. Example: `postgresql+asyncpg://user:pass@host:5432/dbname`

### SQLite tuning

These settings map directly to SQLite pragmas. The defaults are suitable for most installations.

<table>
<thead>
  <tr>
    <th>
      Key
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Environment variable
    </th>
    
    <th>
      Guidance
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        sqlite_synchronous
      </code>
    </td>
    
    <td>
      <code>
        OFF
      </code>
      
      , <code>
        NORMAL
      </code>
      
      , <code>
        FULL
      </code>
      
      , or <code>
        EXTRA
      </code>
    </td>
    
    <td>
      <code>
        NORMAL
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_SQLITE_SYNCHRONOUS
      </code>
    </td>
    
    <td>
      <code>
        NORMAL
      </code>
      
       is the safe WAL-mode default. Testing found no meaningful gain from <code>
        OFF
      </code>
      
      , which weakens durability.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sqlite_mmap_size
      </code>
    </td>
    
    <td>
      integer at least <code>
        0
      </code>
    </td>
    
    <td>
      <code>
        268435456
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_SQLITE_MMAP_SIZE
      </code>
    </td>
    
    <td>
      Memory-map up to this many bytes; <code>
        0
      </code>
      
       disables memory mapping.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sqlite_wal_autocheckpoint
      </code>
    </td>
    
    <td>
      integer at least <code>
        0
      </code>
    </td>
    
    <td>
      <code>
        1000
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_SQLITE_WAL_AUTOCHECKPOINT
      </code>
    </td>
    
    <td>
      Checkpoint after this many WAL pages; <code>
        0
      </code>
      
       disables automatic checkpoints. Larger values can reduce checkpoint stalls but allow a larger WAL.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sqlite_page_size
      </code>
    </td>
    
    <td>
      integer from <code>
        512
      </code>
      
       to <code>
        65536
      </code>
    </td>
    
    <td>
      <code>
        4096
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_SQLITE_PAGE_SIZE
      </code>
    </td>
    
    <td>
      Applies to a fresh database or after <code>
        VACUUM
      </code>
      
      ; changing it does not rewrite an existing database immediately.
    </td>
  </tr>
</tbody>
</table>

---

## Optional Redis read cache

Standalone MCP servers can cache read results in Redis. Install the optional dependency and set a URL:

```bash
pip install "basic-memory[redis]"
bm config set redis_url redis://localhost:6379/0
```

<table>
<thead>
  <tr>
    <th>
      Key
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Environment variable
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        redis_url
      </code>
    </td>
    
    <td>
      string or null
    </td>
    
    <td>
      <code>
        null
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_REDIS_URL
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        redis_max_connections
      </code>
    </td>
    
    <td>
      integer greater than <code>
        0
      </code>
    </td>
    
    <td>
      <code>
        20
      </code>
    </td>
    
    <td>
      <code>
        BASIC_MEMORY_REDIS_MAX_CONNECTIONS
      </code>
    </td>
  </tr>
</tbody>
</table>

The cache is optional and limited to standalone MCP read paths. An unset URL disables it. If Redis is unavailable, Basic Memory fails open to authoritative storage reads rather than failing the request.

---

## CLI output settings

### `cli_output_style`

Choose the default presentation for interactive `bm tool` commands.

- Type: `"rich" | "plain"`
- Default: `"rich"`
- Env: `BASIC_MEMORY_CLI_OUTPUT_STYLE`

This setting affects interactive `search`, `read-note`, `build-context`, and `recent-activity` output. Redirected output defaults to JSON. Explicit `--json` and `--plain` flags take precedence over TTY detection and this setting.

---

## Cloud settings

### `cloud_mode`

Cloud deployment mode (derived, not a config-file setting).

- Type: boolean (read-only property)
- Env: `BASIC_MEMORY_CLOUD_MODE`

Set by managed cloud deployments via the environment variable. A `cloud_mode` key in `config.json` is ignored and removed on load — don't set it for local installs.

### `cloud_api_key`

Account-level cloud API key (`bmc_...`) used for cloud-routed projects.

- Type: string | null
- Default: `null`
- Env: `BASIC_MEMORY_CLOUD_API_KEY`

Use CLI:

```bash
bm cloud api-key save bmc_...
bm cloud api-key create "my-laptop"
```

### `cloud_promo_opt_out`

Disable CLI cloud promo messages.

- Type: boolean
- Default: `false`
- Env: `BASIC_MEMORY_CLOUD_PROMO_OPT_OUT`

---

## Logging and diagnostics

### `log_level`

- Default: `INFO`
- Env: `BASIC_MEMORY_LOG_LEVEL`

The `basic_memory_diagnostics` MCP tool reports version, system, and redacted configuration. As of v0.24, it also lists the `BASIC_MEMORY_*` environment variables that override `config.json`, redacted the same way as the file. Other `BASIC_MEMORY_*` variables are listed by name only. Use it when the server seems to be using a different value than your config file says.

---

## Migration notes

When loading older config files, Basic Memory automatically migrates legacy keys and formats, including:

- legacy string-valued `projects` mapping
- `project_modes`
- `cloud_projects`
- `default_project_mode`
- `sync_changes` to `index_changes`
- `sync_delay` to `index_delay`
- `disable_permalinks` (v0.24): ignored, and dropped from the file on re-save
- `semantic_search_enabled` (v0.24): ignored

The corresponding `BASIC_MEMORY_SYNC_CHANGES` and `BASIC_MEMORY_SYNC_DELAY` environment variables are also accepted as migration aliases, but the new environment names win when both are set. Removed `sync_thread_pool_size` and `sync_max_concurrent_files` keys are ignored. After file-based migration, config is re-saved in current format.

---

## Related pages

- [CLI Reference](https://docs.basicmemory.com/reference/cli-reference)
- [MCP Tools Reference](https://docs.basicmemory.com/reference/mcp-tools-reference)
- [Semantic Search](https://docs.basicmemory.com/concepts/semantic-search)
- [Postgres and Milvus](https://docs.basicmemory.com/local/postgres-and-milvus)
- [Upgrade to v0.24](https://docs.basicmemory.com/whats-new/v0-24-upgrade)
- [v0.23.0 release notes](https://github.com/basicmachines-co/basic-memory/releases/tag/v0.23.0)


## Sitemap

See the full [sitemap](https://docs.basicmemory.com/sitemap.md) for all pages.
