> ## Documentation Index
> Fetch the complete documentation index at: https://docs.claude-mem.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# OpenAI-Compatible Provider (NVIDIA NIM & others)

> Run observation extraction on NVIDIA NIM, DeepSeek, Groq, Together, Ollama, LM Studio, or any OpenAI-compatible endpoint

# OpenAI-Compatible Provider

Claude-mem can run observation extraction against any endpoint that speaks the
OpenAI `/chat/completions` shape. Set `CLAUDE_MEM_PROVIDER` to
`openai-compatible`, pick a preset (or supply a base URL), and memory runs
entirely off your Claude plan.

> [!NOTE]
>
> **claude-mem observer**: choosing the claude-mem observer during
> `npx claude-mem install` runs memory off-plan with nothing to configure. This
> page is for bringing your own endpoint and key.

## Why this is separate from the OpenRouter provider

`CLAUDE_MEM_OPENROUTER_BASE_URL` already lets the OpenRouter client talk to any
OpenAI-compatible endpoint, and it keeps working — nothing on that path changed.
But it carries three things that belong to openrouter.ai specifically:

* **Attribution headers.** `HTTP-Referer` and `X-Title` are sent to whatever
  host the base URL names, so pointing it at NVIDIA announces claude-mem's
  OpenRouter identity to NVIDIA.
* **`usage: { include: true }`**, gated on the URL containing `openrouter.ai`.
* **The cmem.ai gateway's credential-pinning rules**, which decide when a
  persisted base URL pins a persisted key. Those rules exist so an
  account-delivered gateway credential is never sent somewhere else — correct,
  and irrelevant to an endpoint you configured yourself, but you still share
  the same three settings keys with them.

This provider has its own settings keys. The request body is `model`,
`messages`, `temperature`, `max_tokens`, and `reasoning: { enabled: false }`
by default, so a reasoning model cannot spend the output cap thinking and
return an empty observation. Set `CLAUDE_MEM_OPENAI_COMPAT_REASONING` to `on`
to leave reasoning to the endpoint. A strict server (vLLM in particular) that
rejects the `reasoning` field gets the request once more without it. `max_tokens`
is `CLAUDE_MEM_OBSERVER_MAX_OUTPUT_TOKENS` (4096 by default); a model that only
accepts `max_completion_tokens` gets the request again with that field.

A claude-mem observer key (`cm_pro_…`) is never sent to these endpoints. Use the
key the endpoint issued.

## Quick start: NVIDIA NIM

**1. Get a key**

Sign in at [build.nvidia.com](https://build.nvidia.com) and create an API key.
It starts with `nvapi-`. NVIDIA's hosted models are free to start, which suits
observation extraction: it is high-volume and structured, and does not need a
frontier model.

**2. Point claude-mem at it**

Set the endpoint preset and key in `~/.claude-mem/settings.json`:

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "nvidia-nim",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "nvapi-..."
}
```

Or keep the key out of `settings.json` and put it in `~/.claude-mem/.env`:

```
OPENAI_COMPAT_API_KEY=nvapi-...
```

**3. Pick a model (optional)**

The preset defaults to a small, fast NVIDIA-served model. Any model id from
build.nvidia.com works and is passed verbatim:

```json theme={null}
{ "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "nvidia/nemotron-3-super-120b-a12b" }
```

**4. Restart the worker**

```bash theme={null}
npx claude-mem restart
```

## Presets

A preset only supplies a default base URL and a default model. Anything it sets
is overridden by the matching setting, so switching preset never moves an
endpoint or model you pinned yourself.

| Preset | Base URL | Key required |
| - | - | - |
| `nvidia-nim` | `https://integrate.api.nvidia.com/v1` | yes |
| `orcarouter` | `https://api.orcarouter.ai/v1` | yes |
| `api-route` | `https://global.api-route.com/v1` | yes |
| `opper` | `https://api.opper.ai/v3/compat` | yes |
| `atlascloud` | `https://api.atlascloud.ai/v1` | yes |
| `popnow` | `https://api.popnow.ai/v1` | yes |
| `runcrate` | `https://api.runcrate.ai/v1` | yes |
| `cheapaimodel` | `https://api.cheapaimodel.ai/v1` | yes |
| `obscurify-ai` | `https://obscurify.ai/v1` | yes |
| `standardcompute` | `https://api.stdcmpt.com/v1` | yes |
| `uberllm` | `https://api.uberllm.dev/v1` | yes |
| `deepseek` | `https://api.deepseek.com/v1` | yes |
| `opencode-go` | `https://opencode.ai/zen/go/v1` | yes |
| `opencode-zen` | `https://opencode.ai/zen/v1` | yes |
| `groq` | `https://api.groq.com/openai/v1` | yes |
| `together` | `https://api.together.xyz/v1` | yes |
| `minimax` | `https://api.minimax.io/v1` | yes |
| `minimax-cn` | `https://api.minimaxi.com/v1` | yes |
| `iflytek` | `https://maas-api.cn-huabei-1.xf-yun.com/v2` | yes |
| `ollama` | `http://localhost:11434/v1` | no |
| `lmstudio` | `http://localhost:1234/v1` | no |
| `vllm` | `http://localhost:8000/v1` | no |
| `custom` | — set it yourself | no |

> [!NOTE]
>
> Local presets need a model id — claude-mem cannot guess which model you loaded.
> Set `CLAUDE_MEM_OPENAI_COMPAT_MODEL` to whatever `ollama list` (or your server)
> reports, or the provider reports itself unconfigured and dispatch falls through
> to Claude.

## OpenCode Go and Zen

An [OpenCode](https://opencode.ai) Go subscription or Zen key works here.
`opencode-go` defaults to `kimi-k3`; `opencode-zen` ships no default, so set the
model too. Pick ids from `https://opencode.ai/zen/go/v1/models` or
`https://opencode.ai/zen/v1/models`. Only models served on `/chat/completions`
work.

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "opencode-zen",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "<your OpenCode key>",
  "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "deepseek-v4-flash"
}
```

## Settings

| Setting | Default | Description |
| - | - | - |
| `CLAUDE_MEM_PROVIDER` | `claude` | Set to `openai-compatible` to select this provider |
| `CLAUDE_MEM_OPENAI_COMPAT_PRESET` | `''` (= `custom`) | Named endpoint preset from the table above. Settings file or environment only |
| `CLAUDE_MEM_OPENAI_COMPAT_BASE_URL` | preset's | OpenAI-compatible base URL. `/chat/completions` is appended if absent. Settings file or environment only |
| `CLAUDE_MEM_OPENAI_COMPAT_MODEL` | preset's | Model id, passed verbatim |
| `CLAUDE_MEM_OPENAI_COMPAT_OBSERVATION_BATCH_SIZE` | `1` | Queued tool events per observer request (1–32); see [Observation batching](#observation-batching) |
| `CLAUDE_MEM_OPENAI_COMPAT_REASONING` | `''` (= off) | `off` sends `reasoning: { enabled: false }` on every request. `on` leaves reasoning to the endpoint |
| `CLAUDE_MEM_OPENAI_COMPAT_API_KEY` | `''` | API key. Also read from `OPENAI_COMPAT_API_KEY` in `~/.claude-mem/.env` |
| `CLAUDE_MEM_OPENAI_COMPAT_API_KEYS` | `''` | Extra keys for rotation — see [multi-key rotation](https://docs.claude-mem.ai/usage/multi-key-rotation.md) |

An unknown preset id degrades to `custom` rather than failing, because settings
are read during status polling and a typo should not crash a poll.

The viewer's **Settings → Advanced** panel edits the provider and model, and
displays the endpoint preset and base URL read-only. Set the preset and base URL
in `~/.claude-mem/settings.json` or environment variables with the same names.
They determine where requests and stored API keys are sent, so the settings
HTTP API cannot change them. An unrelated viewer save preserves those values.
The API key is set in `~/.claude-mem/settings.json` or `~/.claude-mem/.env` only.

## Observation batching

If tool events arrive faster than a local observer can process them, opt into
batching in `~/.claude-mem/settings.json`:

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_OBSERVATION_BATCH_SIZE": "4"
}
```

Keep your existing endpoint and model settings. An environment variable with the
same name overrides the file. The default is `1`; values outside the integer
range 1–32 use that default. This setting applies only to `openai-compatible`.
Claude and Codex retain their own batch settings, and Gemini/OpenRouter are
unchanged.

The observer takes up to that many events already waiting in the session's queue,
without waiting to fill a batch. A different prompt number, agent ID/type, working
directory, or a summary request ends the batch. Appended events must fit within
twice the model's per-field character cap (32,000 characters at most, lower for
small context windows). A large event that needs condensation waits for its own
turn. The first event still uses the normal field-condensation path; the batching
budget does not further truncate it or bound the entire conversation history.

For example, eight small queued events in the same context can use two requests
with a batch size of four instead of eight requests. The model may combine
related findings, so batching does not guarantee identical summaries. As with
Claude/Codex batching, returned observations share the batch's file evidence and
attribution. The existing invalid-output policy applies to the whole batch: one
retry, then discard if the reply is still invalid. Transport/quota failures and
cancellation do not confirm the claimed events as processed.

## MiniMax

`minimax` is MiniMax's global endpoint and `minimax-cn` the mainland-China one;
use the preset that matches where your account lives. Both default to
`MiniMax-M3`. Any model id MiniMax serves is passed verbatim, including legacy
ids such as `MiniMax-M2.7`.

To use M3.1 Flash instead, set its model id explicitly. The observer sends
`reasoning: { enabled: false }` by default, so Flash does not run its adaptive
thinking at `max` effort on every observation. Set
`CLAUDE_MEM_OPENAI_COMPAT_REASONING` to `on` to leave thinking to MiniMax.
Flash may also need a MiniMax Token Plan rather than pay-as-you-go. See the
[MiniMax OpenAI API reference](https://platform.minimax.io/docs/api-reference/text-openai-api).

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "minimax",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "<key from platform.minimax.io>",
  "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "MiniMax-M3.1-Flash"
}
```

Reasoning models such as the M2 family can open their reply with a
`<think>…</think>` block. claude-mem removes a leading block like that on every
preset (it also covers DeepSeek R1 or Qwen3 on Ollama and vLLM), so the reasoning
is never stored or re-sent with the next request.

## iFlytek Spark

`iflytek` points at iFlytek's Astron MaaS platform and defaults to `spark-x2.5`.
Keys come from the [MaaS console](https://maas.xfyun.cn). The preset's base URL
is the pay-as-you-go endpoint; a Token Plan key is only accepted on the Token
Plan endpoint, so set the base URL as well:

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "iflytek",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "<your MaaS key>",
  "CLAUDE_MEM_OPENAI_COMPAT_BASE_URL": "https://maas-token-api.cn-huabei-1.xf-yun.com/v2"
}
```

A key used on the other endpoint is rejected with a 403 (`11200`). `spark-x2.5`
returns its reasoning in a separate `reasoning_content` field, which claude-mem
ignores, so only the answer is stored.

## Any other endpoint

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_BASE_URL": "https://my-gateway.example.com/v1",
  "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "my-model-id",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "..."
}
```

### When a key is required

Setting `CLAUDE_MEM_OPENAI_COMPAT_BASE_URL` replaces the preset's endpoint, so
whether a key is needed is decided by the endpoint you pointed at, not by the
preset name you started from:

| Endpoint | Key required |
| - | - |
| `localhost`, `127.0.0.1`, `[::1]`, `*.local` | No |
| A private network address (`10.x`, `192.168.x`, `172.16–31.x`) | No |
| Anything else | Yes |

Without an override, the preset decides — the hosted presets need a key, the
local ones do not.

A remote endpoint that genuinely needs no authentication still works: set
`CLAUDE_MEM_OPENAI_COMPAT_API_KEY` to any non-empty value. The default errs
toward asking for a key because the alternative is a provider that reports
itself ready and then fails every observation with a 401.

## OrcaRouter

[OrcaRouter](https://www.orcarouter.ai) serves provider-scoped model ids, such
as `openai/gpt-4o-mini` (the preset's default) or `anthropic/claude-haiku-4.5`,
behind one `sk-orca-` key. Its model list is public at
`https://api.orcarouter.ai/v1/models`.

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "orcarouter",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "sk-orca-...",
  "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "anthropic/claude-haiku-4.5"
}
```

## API Route

[API Route](https://api-route.com) uses the `api-route` preset with an API Route
key. It has no default model: set `CLAUDE_MEM_OPENAI_COMPAT_MODEL` to an exact
model id available to your account on `https://global.api-route.com/v1/models`.
Choose a model served on `/chat/completions`; the id is passed verbatim.

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "api-route",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "<your API Route key>",
  "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "<your chat-completions model id>"
}
```

Alternatively, store the key as `OPENAI_COMPAT_API_KEY` in
`~/.claude-mem/.env`. Restart the worker after changing the configuration.
Without a model or key, this provider is unconfigured and dispatch falls
through to Claude.

## Opper

[Opper](https://opper.ai) is an EU-hosted gateway with one OpenAI-compatible
API and one key for 700+ models. Model ids are pooled names such as
`gpt-5.4-mini` (the preset's default) or `claude-haiku-4-5`, and Opper picks
the route per request. A `provider/model` id such as `aws/claude-haiku-4-5-eu`
pins one provider and region. The catalogue is public at
`https://api.opper.ai/v3/models`, and keys come from
[platform.opper.ai](https://platform.opper.ai).

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "opper",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "<your Opper key>",
  "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "claude-haiku-4-5"
}
```

## Atlas Cloud

[Atlas Cloud](https://www.atlascloud.ai) serves models from DeepSeek, Z.ai,
Moonshot, Qwen and other vendors behind one OpenAI-compatible API key. Model ids
are vendor-prefixed, such as `deepseek-ai/deepseek-v4-flash` (the preset's
default) or `zai-org/glm-5.3`, and are passed verbatim. The model list is public
at `https://api.atlascloud.ai/v1/models`, and keys come from
[console.atlascloud.ai](https://console.atlascloud.ai/api-keys).

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "atlascloud",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "<your Atlas Cloud key>",
  "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "deepseek-ai/deepseek-v4-flash"
}
```

## PopNow

[PopNow](https://popnow.ai/api) serves chat models from DeepSeek, Moonshot, Google,
OpenAI and other vendors behind one OpenAI-compatible API key, billed per token in
USD. Model ids end in a task suffix, such as `deepseek/v4-flash/chat` (the preset's
default) or `moonshot/kimi-k3/chat`, and are passed verbatim. The chat model list
is at `https://api.popnow.ai/v1/models` (it needs the key), and keys come from
[popnow.ai/api/console/keys](https://popnow.ai/api/console/keys).

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "popnow",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "<your PopNow key>",
  "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "deepseek/v4-flash/chat"
}
```

## Runcrate

[Runcrate](https://www.runcrate.ai) is a GPU cloud that also serves open
models such as DeepSeek V4.1 Flash, GLM-5.3, Qwen3.8 Flash and gpt-oss 120B
behind one OpenAI-compatible API key. Model ids are vendor-prefixed, such as `deepseek-ai/DeepSeek-V4.1-Flash` (the preset's default) or
`zai-org/GLM-5.3`, and are passed verbatim. The model list is public at
`https://api.runcrate.ai/v1/models`, and keys come from
[the Runcrate dashboard](https://www.runcrate.ai/dashboard/api-keys).

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "runcrate",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "<your Runcrate key>",
  "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "deepseek-ai/DeepSeek-V4.1-Flash"
}
```

## cheapaimodel

[cheapaimodel](https://cheapaimodel.ai) is a pay-per-token gateway for open
models such as DeepSeek V4.1 Flash, GLM-5.3 and Kimi K3, plus Grok 4.7, behind
one OpenAI-compatible API key. Model ids are plain, such as `deepseek-v4-1-flash`
(the preset's default) or `glm-5.3`, and are passed verbatim. The model list is
at `https://api.cheapaimodel.ai/v1/models` (it needs the key), and keys come
from [the cheapaimodel console](https://console.cheapaimodel.ai/keys).
`glm-5.3` and `glm-5.3-flash` always think and reject `reasoning: { enabled:
false }` on streamed requests, so set `CLAUDE_MEM_OPENAI_COMPAT_REASONING` to
`on` to use them. `kimi-k3` only accepts a temperature of 0.6 or 1, so it
rejects the requests this provider sends; pick another model.

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "cheapaimodel",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "<your cheapaimodel key>",
  "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "deepseek-v4-1-flash"
}
```

## Obscurify.ai

[Obscurify.ai](https://obscurify.ai) is an OpenAI-compatible API for 200+
models. Accounts are a random account number with no email, and Obscurify says
prompts and responses are not stored on its servers. Model ids are
vendor-prefixed, such as `deepseek/deepseek-v4-flash` (the preset's default) or
`z-ai/glm-5.3`, and are passed verbatim. The model list is public at
`https://obscurify.ai/v1/models`, and the key (`sk-obs1_...`) is under "Show API
Key" on [your account page](https://obscurify.ai/account).

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "obscurify-ai",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "<your Obscurify.ai key>",
  "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "deepseek/deepseek-v4-flash"
}
```

## Standard Compute

[Standard Compute](https://standardcompute.com) is an OpenAI-compatible API
gateway that routes requests across open and frontier models behind one key.
Model ids are vendor-prefixed, such as `deepseek/deepseek-v4-flash` (the
preset's default) or `z-ai/glm-5.3`, and are passed verbatim. The model list is
public at `https://api.stdcmpt.com/v1/models`, and keys come from the
[Standard Compute dashboard](https://standardcompute.com/dashboard/api-keys). For the US
endpoint, set `CLAUDE_MEM_OPENAI_COMPAT_BASE_URL` to
`https://us.stdcmpt.com/v1`. Setup notes are in
[the Standard Compute docs](https://docs.standardcompute.com).

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "standardcompute",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "<your Standard Compute key>",
  "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "deepseek/deepseek-v4-flash"
}
```

## UberLLM

[UberLLM](https://uberllm.dev) serves models from DeepSeek, Z.ai, Moonshot,
Qwen, Google, Anthropic and others through one OpenAI-compatible key, billed
from prepaid credit. Model ids are vendor-prefixed, such as
`deepseek/deepseek-v4.1-flash` (the preset's default) or `z-ai/glm-5.2`, and are
passed verbatim. The model list is public at
`https://api.uberllm.dev/v1/models`, and keys come from the
[UberLLM dashboard](https://uberllm.dev/dashboard/keys).

```json theme={null}
{
  "CLAUDE_MEM_PROVIDER": "openai-compatible",
  "CLAUDE_MEM_OPENAI_COMPAT_PRESET": "uberllm",
  "CLAUDE_MEM_OPENAI_COMPAT_API_KEY": "<your UberLLM key>",
  "CLAUDE_MEM_OPENAI_COMPAT_MODEL": "deepseek/deepseek-v4.1-flash"
}
```

## Troubleshooting

**Memory silently runs on Claude instead.** Dispatch falls through to Claude
when the provider is selected but not fully configured — a missing base URL, a
missing model, or a missing key on a preset that needs one. That fall-through is
deliberate: a half-configured endpoint should not fail every observation. Check
`npx claude-mem doctor`.

**404 from the endpoint.** Almost always a wrong base URL or a model the
endpoint does not serve; the error names both settings. Note that some gateways
prefix model ids differently from the vendor's own docs.

**Repeated timeouts.** Requests are streamed, so a request is given up only
after 90 seconds with no token and no keep-alive from the endpoint, or after
300 seconds in total. A self-hosted endpoint that queues requests behind a load
balancer spends that queue wait silent, so the wait reads as idle; raise
`CLAUDE_MEM_LLM_STREAM_IDLE_TIMEOUT_MS` past it. `CLAUDE_MEM_LLM_TIMEOUT_MS`
does not apply to streamed requests; it is the deadline only for an endpoint
that refuses streaming (a 400 naming `stream` or `stream_options`), which
claude-mem then calls non-streamed for the rest of the worker's life. If
requests keep timing out, prefer a small, fast model: observation extraction is
a high-volume structured task, not a reasoning benchmark.

**Empty or cut-off observations.** A model that will not hold to the output
schema produces nothing usable. Small instruct-tuned models generally do better
here than reasoning models, whose thinking output tends to crowd out the
structured reply. When the log says a reply was cut off at the output-token
limit, raise `CLAUDE_MEM_OBSERVER_MAX_OUTPUT_TOKENS`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.