# Environment variables

> Gateway, LLM, Hermes supervisor, install root, and data-dir env keys: TDAI_*, MEMORY_TENCENTDB_*, MODEL_*, resolution order for tdai-gateway.json, and client vs server API-key names.

- Repository: TencentCloud/TencentDB-Agent-Memory
- GitHub: https://github.com/TencentCloud/TencentDB-Agent-Memory
- Human docs: https://grok-wiki.com/public/docs/tencentcloud-tencentdb-agent-memory-5a33bbf5540a
- Complete Markdown: https://grok-wiki.com/public/docs/tencentcloud-tencentdb-agent-memory-5a33bbf5540a/llms-full.txt

## Source Files

- `src/gateway/config.ts`
- `src/utils/env.ts`
- `README.md`
- `hermes-plugin/memory/memory_tencentdb/README.md`
- `hermes-plugin/memory/memory_tencentdb/supervisor.py`
- `scripts/README.memory-tencentdb-ctl.md`
- `docker/opensource/README-hermes.md`

---

---
title: "Environment variables"
description: "Gateway, LLM, Hermes supervisor, install root, and data-dir env keys: TDAI_*, MEMORY_TENCENTDB_*, MODEL_*, resolution order for tdai-gateway.json, and client vs server API-key names."
---

Standalone Gateway and Hermes integrations read environment variables in distinct namespaces. The Node Gateway binds and authenticates with `TDAI_*`; the Hermes Python provider dials and authenticates with `MEMORY_TENCENTDB_*`; Docker greenfield images unify model credentials under `MODEL_*` and export them into `TDAI_LLM_*` at container start. Env access in the compiled OpenClaw bundle goes through an indirect `getEnv` helper so the host security scanner does not treat direct `process.env` + network code as credential harvesting.

## Namespaces at a glance

| Prefix | Consumer | Role |
| --- | --- | --- |
| `TDAI_*` | Node Gateway (`loadGatewayConfig`) | Bind host/port, server Bearer secret, CORS, data dir, LLM, config file path |
| `MEMORY_TENCENTDB_*` | Hermes provider, supervisor, `memory-tencentdb-ctl` | Client dial host/port, client Bearer secret, spawn command, logs, install root, ctl mode |
| `MODEL_*` | `Dockerfile.hermes` CMD only | Single operator-facing model surface; mapped to Hermes config + `TDAI_LLM_*` |
| `HERMES_HOME` | Hermes / ctl / install scripts | Hermes home (default `~/.hermes`) |
| `OPENCLAW_*` | OpenClaw plugin paths | State dir / config path when the host does not inject `resolveStateDir()` |

<Warning>
The Gateway never reads `MEMORY_TENCENTDB_GATEWAY_API_KEY` or `MEMORY_TENCENTDB_LLM_*`. The Hermes client never enforces Gateway auth by itself. Matching secrets on both ends is an operator responsibility.
</Warning>

## Config file resolution (Gateway)

`loadGatewayConfig()` builds a full `GatewayConfig` from an optional file plus env overrides.

### File path order

1. `TDAI_GATEWAY_CONFIG` — absolute or relative path; used only if the file exists
2. `./tdai-gateway.yaml` or `./tdai-gateway.json` in the process CWD
3. `<defaultDataDir>/tdai-gateway.yaml` or `<defaultDataDir>/tdai-gateway.json`
4. No file — pure env + defaults

`<defaultDataDir>` is the same path as the data-dir fallback (see [Install root and data directories](#install-root-and-data-directories)).

`memory-tencentdb-ctl config *` writes `$TDAI_DATA_DIR/tdai-gateway.json` (mode `0600`). That file is found via step 3 when CWD is not the data dir and `TDAI_GATEWAY_CONFIG` is unset.

### Field merge rules

| Concern | Precedence | Notes |
| --- | --- | --- |
| Most server / data / LLM scalars | **Env wins** over file | e.g. `TDAI_GATEWAY_PORT` over `server.port` |
| CORS allow-list | **File wins** over env | Explicit `server.corsOrigins: []` disables CORS even if `TDAI_CORS_ORIGINS` is set |
| Memory plugin block | File `memory` only | Parsed by `parseConfig()`; not mirrored field-by-field to env |
| Missing / malformed file | Silent fall-through | Treated as env-only config |

YAML/JSON string leaves that are exactly `${VAR_NAME}` expand to `process.env[VAR_NAME]` (missing → empty string). Only whole-string placeholders expand; partial interpolation is not supported. Leading `~/` in `data.baseDir` / `TDAI_DATA_DIR` expands with `HOME` or `USERPROFILE`.

```json title="Minimal ~/.memory-tencentdb/memory-tdai/tdai-gateway.json"
{
  "llm": {
    "baseUrl": "https://api.openai.com/v1",
    "apiKey": "sk-...",
    "model": "gpt-4o"
  }
}
```

## Gateway server (`TDAI_*`)

Read by `src/gateway/config.ts` when the Node sidecar starts.

### Server bind, auth, CORS

<ParamField body="TDAI_GATEWAY_PORT" type="integer">
Listen port. Default `8420`. Invalid non-integers are ignored (file/default used).
</ParamField>

<ParamField body="TDAI_GATEWAY_HOST" type="string">
Bind address. Default `127.0.0.1`. Docker image defaults to `0.0.0.0`.
</ParamField>

<ParamField body="TDAI_GATEWAY_API_KEY" type="string">
Optional Bearer secret. When non-empty, every route except `GET /health` and CORS `OPTIONS` requires `Authorization: Bearer <key>`. Maps to `server.apiKey`. Unset = open (legacy).
</ParamField>

<ParamField body="TDAI_CORS_ORIGINS" type="string">
Comma-separated CORS allow-list. Empty / unset → no `Access-Control-*` headers. Use `*` only for local development. File `server.corsOrigins` overrides this env.
</ParamField>

<ParamField body="TDAI_GATEWAY_CONFIG" type="string">
Explicit path to `tdai-gateway.yaml` or `.json`.
</ParamField>

### Data directory

<ParamField body="TDAI_DATA_DIR" type="string">
L0–L3 storage root for standalone/Hermes Gateway. Overrides `data.baseDir`. Supports `~/...`.
</ParamField>

Default when unset:

1. `$MEMORY_TENCENTDB_ROOT/memory-tdai` (root defaults to `~/.memory-tencentdb`)
2. Legacy `~/memory-tdai` if the new path does not exist but the legacy path does (stderr deprecation warning)

OpenClaw in-process mode does **not** use `TDAI_DATA_DIR`; plugin data lives under the OpenClaw state dir (typically `~/.openclaw/memory-tdai/`).

### LLM (extraction pipeline)

| Variable | File field | Default |
| --- | --- | --- |
| `TDAI_LLM_BASE_URL` | `llm.baseUrl` | `https://api.openai.com/v1` |
| `TDAI_LLM_API_KEY` | `llm.apiKey` | `""` |
| `TDAI_LLM_MODEL` | `llm.model` | `gpt-4o` |
| `TDAI_LLM_MAX_TOKENS` | `llm.maxTokens` | `4096` |
| `TDAI_LLM_TIMEOUT_MS` | `llm.timeoutMs` | `120000` |
| `TDAI_LLM_DISABLE_THINKING` | `llm.disableThinking` | unset |

`TDAI_LLM_DISABLE_THINKING` accepts booleans (`true`/`false`/`1`/`0`) or a strategy name (e.g. `deepseek`, `anthropic`); values are lowercased then normalized.

<Note>
BYOK/BYOC: any OpenAI-compatible base URL works. No provider is hard-coded beyond defaults.
</Note>

## Hermes client and supervisor (`MEMORY_TENCENTDB_*`)

### Dial and spawn

| Variable | Default | Used by |
| --- | --- | --- |
| `MEMORY_TENCENTDB_GATEWAY_HOST` | `127.0.0.1` | Provider client base URL; supervisor spawn label |
| `MEMORY_TENCENTDB_GATEWAY_PORT` | `8420` | Same; invalid ports fall back to `8420` with a warning |
| `MEMORY_TENCENTDB_GATEWAY_CMD` | _(unset)_ | Shell command the supervisor `Popen`s; if unset, auto-discover `src/gateway/server.ts` |
| `MEMORY_TENCENTDB_LOG_DIR` | see below | Supervisor stdout/stderr log directory |
| `MEMORY_TENCENTDB_GATEWAY_API_KEY` | _(unset)_ | **Client** Bearer header only |

Log directory priority in `GatewaySupervisor._resolve_log_dir()`:

1. `MEMORY_TENCENTDB_LOG_DIR`
2. `~/.hermes/logs/memory_tencentdb` (uses `HOME` / `USERPROFILE`)
3. `<cwd>/.memory-tencentdb-logs`

`memory-tencentdb-ctl` in standalone mode prefers `$TDAI_DATA_DIR/logs/` when `MEMORY_TENCENTDB_LOG_DIR` is unset.

### Client vs server API keys

```text
┌─────────────────────────────┐         HTTP Bearer          ┌──────────────────────────┐
│ Hermes memory_tencentdb     │ ───────────────────────────▶ │ Node Gateway             │
│ MEMORY_TENCENTDB_GATEWAY_   │   Authorization: Bearer …    │ TDAI_GATEWAY_API_KEY     │
│   API_KEY                   │                              │   or server.apiKey       │
│ fallback: TDAI_GATEWAY_     │                              │ (never reads MEMORY_*    │
│   API_KEY                   │                              │  GATEWAY_API_KEY)        │
└─────────────────────────────┘                              └──────────────────────────┘
```

- **Server enforcement:** `TDAI_GATEWAY_API_KEY` / `server.apiKey`. Unset → open routes.
- **Client attachment:** `MEMORY_TENCENTDB_GATEWAY_API_KEY`, then fallback `TDAI_GATEWAY_API_KEY`. Unset → no `Authorization` header.
- Supervisor **does not** inject `TDAI_GATEWAY_API_KEY` into the child env when spawning; configure the Gateway the same way you configure its port and data dir (env, `tdai-gateway.json`, Docker, systemd).

Shared single-name setup (both processes inherit one env file):

```bash
export TDAI_GATEWAY_API_KEY="shared-secret"
# Hermes client falls back to the same name; Gateway reads it for enforcement.
```

Split names (recommended when only Hermes should carry the client secret):

```bash
export TDAI_GATEWAY_API_KEY="shared-secret"                 # Gateway process
export MEMORY_TENCENTDB_GATEWAY_API_KEY="shared-secret"     # Hermes process
```

### LLM schema names vs Gateway names

Hermes `get_config_schema()` advertises:

- `MEMORY_TENCENTDB_LLM_API_KEY` (required in schema)
- `MEMORY_TENCENTDB_LLM_BASE_URL` (default `https://api.openai.com/v1`)
- `MEMORY_TENCENTDB_LLM_MODEL` (default `gpt-4o`)

The **Node Gateway only consumes `TDAI_LLM_*`** (or `llm.*` in the config file). `memory-tencentdb-ctl --hermes config llm` dual-writes:

- `$TDAI_DATA_DIR/tdai-gateway.json` → `$.llm.{baseUrl,apiKey,model}`
- `$HERMES_HOME/env.d/memory-tencentdb-llm.sh` → `TDAI_LLM_*` plus `MEMORY_TENCENTDB_LLM_*=$TDAI_LLM_*` aliases for Hermes inheritance

For a supervised Gateway, set `TDAI_LLM_*` (or write `tdai-gateway.json`) in the environment Hermes copies with `os.environ.copy()`. Setting only `MEMORY_TENCENTDB_LLM_*` without `TDAI_LLM_*` or a config file does not configure the Node sidecar.

### Gateway auto-discovery paths

When `MEMORY_TENCENTDB_GATEWAY_CMD` is unset, the provider searches (in order):

1. In-tree: `<plugin-root>/src/gateway/server.ts`
2. `~/.memory-tencentdb/tdai-memory-openclaw-plugin/src/gateway/server.ts`
3. `~/tdai-memory-openclaw-plugin/src/gateway/server.ts` (legacy)
4. `~/.hermes/plugins/tdai-memory-openclaw-plugin/src/gateway/server.ts` (legacy)

Discovered launch form: `sh -c 'cd <plugin-root> && exec pnpm exec tsx src/gateway/server.ts'`.

### Host / port alignment

The supervisor sets `MEMORY_TENCENTDB_GATEWAY_HOST` / `_PORT` on the child for bookkeeping, but the **bind** address is still `TDAI_GATEWAY_HOST` / `TDAI_GATEWAY_PORT` (or file defaults). Changing only the client port without the server port breaks `/health` and all API calls.

```bash
# Both ends on 18420
export TDAI_GATEWAY_PORT=18420
export MEMORY_TENCENTDB_GATEWAY_PORT=18420
```

## Install root and data directories

Used by install scripts, ctl, and Gateway default data-dir resolution.

| Variable | Default | Purpose |
| --- | --- | --- |
| `MEMORY_TENCENTDB_ROOT` | `~/.memory-tencentdb` | Unified root for install + data |
| `TDAI_INSTALL_DIR` | `$MEMORY_TENCENTDB_ROOT/tdai-memory-openclaw-plugin` | Gateway source + `node_modules` |
| `TDAI_DATA_DIR` | `$MEMORY_TENCENTDB_ROOT/memory-tdai` | Gateway data + `tdai-gateway.json` |
| `HERMES_HOME` | `~/.hermes` | Hermes config, `env.d/`, hermes-mode logs |
| `MEMORY_TENCENTDB_MODE` | `standalone` | ctl mode: `standalone` \| `hermes` (same as `--hermes`) |

Legacy paths `~/tdai-memory-openclaw-plugin` and `~/memory-tdai` are detected with warnings; `install_hermes_memory_tencentdb.sh` migrates them into the new root.

:::files
~/.memory-tencentdb/
├── tdai-memory-openclaw-plugin/   # TDAI_INSTALL_DIR
│   └── src/gateway/server.ts
└── memory-tdai/                   # TDAI_DATA_DIR
    ├── tdai-gateway.json
    ├── conversations/
    ├── records/
    ├── scene_blocks/
    ├── persona/
    └── logs/                      # standalone ctl logs (default)
:::

## Docker greenfield (`MODEL_*`)

`docker/opensource/Dockerfile.hermes` exposes one operator-facing model surface. At `CMD` start it exports Gateway LLM vars and writes Hermes `config.yaml` + `.env`.

| Variable | Default in image | Maps to |
| --- | --- | --- |
| `MODEL_API_KEY` | _(required at run)_ | `TDAI_LLM_API_KEY`, Hermes `model.api_key`, `OPENAI_API_KEY` in `.env` |
| `MODEL_BASE_URL` | `https://api.lkeap.cloud.tencent.com/v1` | `TDAI_LLM_BASE_URL`, Hermes `model.base_url` |
| `MODEL_NAME` | `deepseek-v3.2` | `TDAI_LLM_MODEL`, Hermes `model.default` |
| `MODEL_PROVIDER` | `custom` | Hermes `model.provider` only |

Also set in the image:

| Variable | Image default |
| --- | --- |
| `TDAI_GATEWAY_PORT` | `8420` |
| `TDAI_GATEWAY_HOST` | `0.0.0.0` |
| `TDAI_DATA_DIR` | `/opt/data/tdai-memory` |
| `HERMES_HOME` | `/opt/data` |
| `MEMORY_TENCENTDB_GATEWAY_HOST` | `127.0.0.1` |
| `MEMORY_TENCENTDB_GATEWAY_PORT` | `8420` |

```bash
docker run -d --name hermes-memory -p 8420:8420 \
  -e MODEL_API_KEY="your-api-key" \
  -v hermes_data:/opt/data \
  hermes-memory
```

## OpenClaw-related env (plugin host)

| Variable | Role |
| --- | --- |
| `OPENCLAW_STATE_DIR` | Fallback state dir when the host does not inject `runtime.state.resolveStateDir()` (default `~/.openclaw`) |
| `OPENCLAW_CONFIG_PATH` | Optional explicit path to `openclaw.json` (hook policy helpers) |
| `OPENCLAW_ROOT` | Optional root override for clean-context tooling |

Memory plugin behavior (capture, recall, embedding, TCVDB) is configured in `openclaw.json` under `plugins.entries.memory-tencentdb`, not via `TDAI_*` env vars.

## Ops modes and env sourcing

### ctl standalone vs hermes

| | standalone (default) | hermes (`--hermes` or `MEMORY_TENCENTDB_MODE=hermes`) |
| --- | --- | --- |
| Config write | `$TDAI_DATA_DIR/tdai-gateway.json` | Same + `$HERMES_HOME/env.d/memory-tencentdb-llm.sh` for `config llm` |
| Logs | `$TDAI_DATA_DIR/logs/` | `$HERMES_HOME/logs/memory_tencentdb/` (unless `MEMORY_TENCENTDB_LOG_DIR`) |
| Hermes config | Untouched | `enable-hermes-memory` edits `memory.provider` |

Start command resolution for ctl:

1. `MEMORY_TENCENTDB_GATEWAY_CMD`
2. `sh -c 'cd $TDAI_INSTALL_DIR && exec npx tsx src/gateway/server.ts'`

Sourced before start when present: `/etc/profile.d/memory-tencentdb-env.sh`; in hermes mode also `/etc/profile.d/hermes-env.sh` and `$HERMES_HOME/env.d/*.sh`.

### Supervisor spawn env

On `Popen`, the supervisor copies `os.environ` and sets:

- `MEMORY_TENCENTDB_GATEWAY_PORT`
- `MEMORY_TENCENTDB_GATEWAY_HOST`

It does **not** set `TDAI_GATEWAY_API_KEY` or rewrite LLM credentials. Credentials must already be in Hermes’s environment, `env.d`, or `tdai-gateway.json` under the resolved data dir.

## Quick reference tables

### Gateway process (must bind / extract)

| Env | Default |
| --- | --- |
| `TDAI_GATEWAY_HOST` | `127.0.0.1` |
| `TDAI_GATEWAY_PORT` | `8420` |
| `TDAI_GATEWAY_API_KEY` | unset (open) |
| `TDAI_CORS_ORIGINS` | empty (no CORS headers) |
| `TDAI_GATEWAY_CONFIG` | unset (search order) |
| `TDAI_DATA_DIR` | `$MEMORY_TENCENTDB_ROOT/memory-tdai` |
| `TDAI_LLM_BASE_URL` | `https://api.openai.com/v1` |
| `TDAI_LLM_API_KEY` | `""` |
| `TDAI_LLM_MODEL` | `gpt-4o` |
| `TDAI_LLM_MAX_TOKENS` | `4096` |
| `TDAI_LLM_TIMEOUT_MS` | `120000` |
| `TDAI_LLM_DISABLE_THINKING` | unset |
| `MEMORY_TENCENTDB_ROOT` | `~/.memory-tencentdb` |

### Hermes process (must dial)

| Env | Default |
| --- | --- |
| `MEMORY_TENCENTDB_GATEWAY_HOST` | `127.0.0.1` |
| `MEMORY_TENCENTDB_GATEWAY_PORT` | `8420` |
| `MEMORY_TENCENTDB_GATEWAY_CMD` | auto-discover |
| `MEMORY_TENCENTDB_GATEWAY_API_KEY` | unset (no auth header) |
| `MEMORY_TENCENTDB_LOG_DIR` | `~/.hermes/logs/memory_tencentdb` |
| `MEMORY_TENCENTDB_LLM_*` | schema / dual-write aliases; Gateway needs `TDAI_LLM_*` or JSON |

### Removed / no-ops

| Name | Status |
| --- | --- |
| `MEMORY_TENCENTDB_DATA_DIR` | **Not read** (never matched Gateway). Use `TDAI_DATA_DIR`. |

## Verification

```bash
# Gateway bind + health (no auth on /health)
curl -s http://127.0.0.1:8420/health

# Authenticated route when TDAI_GATEWAY_API_KEY is set
curl -s -H "Authorization: Bearer $TDAI_GATEWAY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query":"test","session_key":"debug"}' \
  http://127.0.0.1:8420/recall

# Hermes-mode: confirm dual env after ctl config llm
tr '\0' '\n' < /proc/$(pgrep -n hermes-agent)/environ | grep -E 'TDAI_|MEMORY_TENCENTDB_'

# Docker image model sync
docker exec hermes-memory env | grep -E '(MODEL_|TDAI_LLM_)'
```

## Related pages

<CardGroup cols={2}>
  <Card title="Secure the Gateway" href="/secure-gateway">
    Bearer auth, CORS allow-list, non-loopback warnings, Hermes client alignment.
  </Card>
  <Card title="Gateway lifecycle" href="/gateway-ops">
    `memory-tencentdb-ctl` modes, start/stop, config llm/embedding/vdb, path layout.
  </Card>
  <Card title="Hermes setup" href="/hermes-setup">
    Docker greenfield, attach to existing Hermes, auto-discovery, health checks.
  </Card>
  <Card title="Gateway HTTP API" href="/gateway-http-api">
    Routes, auth exceptions for `/health`, error envelope.
  </Card>
  <Card title="Plugin configuration reference" href="/plugin-config-reference">
    Full `memory` schema inside `tdai-gateway.json` / OpenClaw config.
  </Card>
  <Card title="Troubleshooting" href="/troubleshooting">
    Auth 401, circuit breaker, missing Gateway command, log probes.
  </Card>
</CardGroup>
